Cosmos Image Builder is a Python-based automation tool to generate minimal, production-ready Ubuntu-based Docker images for Cosmos SDK blockchains. Each image is:
- Built from source (no precompiled binaries)
- Includes the
cosmovisor
binary for seamless upgrades - Runs as a non-root user for security
- Exposes all required ports (P2P, RPC, API, gRPC)
- Typically < 500MB in size
- Ready for use in Kubernetes, Docker, or other OCI runtimes
Unlike Alpine- or scratch-based containers, these images are based on Ubuntu 24.04, providing:
- A familiar environment for most operators
- Full shell access with
bash
- A minimal but complete package manager (
apt
) - Better debugging and operational flexibility
- Compatibility with tools and dependencies commonly used in validator stacks
This makes Cosmos Image Builder one of the few tools that can generate Ubuntu-based Cosmos images reliably and reproducibly — something that’s often missing in the ecosystem.
Whether you're building for testnets, mainnets, sentries, or validators, these images are ideal for Infrastructure-as-Code workflows.
cosmos-image-builder/
├── app/ # App logic
│ ├── dockerfile-template.j2 # Jinja2 Dockerfile template
│ └── image-builder.py # Python script to build images
├── chains/ # One config YAML per chain
│ └── atomone.yaml # Example: AtomOne chain
├── requirements.txt # Python dependencies
└── README.md # You're here
- Builds static images from Cosmos SDK chain repos
- Automatically installs
cosmovisor@latest
- Runs as non-root (
UID/GID 1025
) - Exposes P2P, RPC, API, and GRPC ports
- Outputs Docker images tagged by version and chain name
- Ideal for Kubernetes + Helm deployments
git clone https://github.com/nexusecurus/cosmos-image-builder.git
cd cosmos-image-builder
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Add a YAML file under the chains/ directory.
Example: chains/atomone.yaml
name: atomone
go_image: "golang:1.22.10"
repo: https://github.com/atomone-hub/atomone.git
binary_name: atomoned
version: v2.1.0
p2p_port: 26656
rpc_port: 26657
grpc_port: 26617
prom_port: 26690
python app/image-builder.py --chain atomone
This will:
Render a Dockerfile from the Jinja2 template for the specified chain file you flag, file must exist on chains folder.
Build the image using Docker
python app/image-builder.py
This will:
Render a Dockerfile from the Jinja2 template for each chain file you create under chains folder.
Build the image using Docker
Current code tags them as:
ghcr.io/nexusecurus/chain-name:version
NOTE: This assumes that Github-CLI is installed, configured and with access to your GitHub account.
To push built images to GitHub Container Registry (ghcr.io
), make sure:
-
You are authenticated with the GitHub CLI:
gh auth status
-
You have a valid token (with
write:packages
scope):gh auth token
-
Login to GHCR using your current login credentials:
gh auth token | docker login ghcr.io -u <your-github-username> --password-stdin
Replace <your-github-username>
with your actual GitHub handle.
Example:
gh auth token | docker login ghcr.io -u nexusecurus --password-stdin
This ensures your image can be pushed to ghcr.io/<username>/<chain-name>:<version>
during or after build.
The resulting image:
-
Is based on ubuntu:24.04
-
Has the chain binary in /home/nonroot/go/bin/
-
Has cosmovisor in the same path
-
Exposes only the needed chain ports
-
Default ENTRYPOINT to /bin/bash (override in Kubernetes with "command" to start the chain or cosmovisor)
To run cosmovisor properly in Kubernetes or Docker, provide the following variables at runtime:
DAEMON_HOME=/home/nonroot/.<daemon-name>
DAEMON_NAME=<binary_name>
DAEMON_ALLOW_DOWNLOAD_BINARIES=false
DAEMON_RESTART_AFTER_UPGRADE=true
These should be set using your Helm chart or Kubernetes manifest.
docker run -it \
-e DAEMON_NAME=atomoned \
-e DAEMON_HOME=/home/nonroot/.atomone \
-v /path/to/atomone/data:/home/nonroot/.atomone \
ghcr.io/nexusecurus/atomone:v2.1.0 \
cosmovisor run start
Use this image in your Kubernetes setup with:
-
A Helm chart that mounts persistent volumes under $DAEMON_HOME
-
A startup command like cosmovisor run start
-
Environment variables passed via Helm values
-
cosmovisor is installed from cosmossdk.io/tools/cosmovisor with "latest" tag
-
Go is used during build only in a external image, the final image does not contain Go package.
-
The container runs under a nonroot user (UID/GID 1025) for security
-
Entrypoint is left as /bin/bash for flexibility — override as needed
MIT
PRs and issues welcome. Help support more chains, or customize the base image template!