Define your apps in one file. Kustron handles the rest: local cluster, registry, build, deploy.
curl -fsSL https://raw.githubusercontent.com/itsmunim/kustron/master/download.sh | bash
Kustron runs a local k3d cluster with its own registry. You define what to run, it does the heavy lifting.
Create a kustron-env.yaml in your project folder, pre-filled with your app name.
Set ports, add more apps, configure env vars. Or just set the port and move on.
One command spins up the cluster, builds images, and deploys everything.
Add apps, change config, redeploy. The file is the source of truth.
Five situations where the environment is the whole job.
App, database, cache, object store, workers. Everything running together, reachable by name, env up when you start work.
An isolated stack for a demo, a test, or a brief experiment. env down when it's done and nothing lingers.
The same kustron-env.yaml on a cheap Linux VM gives you an identical environment on the real internet. Demos, staging, workshops.
Helm charts, private registries, per-app namespaces, deploy ordering. What production runs, runs the same way locally.
An agent scaffolds the code; Kustron supplies a reproducible environment to run and test it in, and tears it down after.
Apps find each other by name. Exposed apps are reachable at the cluster node IP.
config:
namespace: kustron-env # all apps share this namespace
apps:
# Build from local source or git repo
- name: api
source: ./services/api # or: git@github.com:org/repo.git
port: 3000
exposed: true # reachable at the k3d node IP
ha: true # min 2 replicas, autoscales to 5
env:
NODE_ENV: production
DB_HOST: postgres # 'postgres' resolves via k8s DNS
# Run an existing container image
- name: postgres
image: postgres:15
port: 5432
env:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
# Deploy a Helm chart
- name: prometheus
helm:
chart: kube-prometheus-stack
repo: https://prometheus-community.github.io/helm-charts
version: "45.0.0"
values:
grafana.enabled: "true"
Start inside a source repo with a Dockerfile. Add a local DynamoDB, an S3-compatible store, and a cache, then bring it all up.
cd my-api # your repo, with a Dockerfile
kustron env init # creates kustron-env.yaml
kustron apps add --name local-ddb --image amazon/dynamodb-local:latest --port 8000 --healthcheck tcp
kustron apps add --name local-s3 --image luofuxiang/local-s3 --port 80
kustron apps add --name kivo --image ghcr.io/itsmunim/kivo:v1.5.0 --port 6379 --healthcheck tcp
kustron env up
Your app now talks to local-ddb:8000, local-s3:80 and kivo:6379 by name. The cache is kivo, our Redis-compatible in-memory store: same protocol, same port, so it drops in where you'd use redis. Prefer the real thing? Swap in redis:7, nothing else changes.
Every app type shares the same namespace. They reach each other at http://<name>:<port>.
Point to a folder. Kustron uses your Dockerfile if it exists, or Railpack to containerize automatically.
Provide a git SSH URL. Kustron clones it, builds it, and deploys it. SSH access must already be set up.
Use any image from Docker Hub or any registry. Perfect for databases and third-party services.
Install any Helm chart into your environment. Pass values directly from the yaml file.
| env | |
kustron env init |
Create a kustron-env.yaml in the current folder, pre-filled with the
folder name as the app. |
kustron env up |
Bring up the cluster and deploy all apps from kustron-env.yaml.
Idempotent, safe to re-run. |
kustron env reload |
Tear down and rebuild the entire environment. Run this after changing
kustron-env.yaml. |
kustron env down |
Tear everything down. The yaml file is untouched. |
kustron env show-spec |
Pretty-print the full kustron-env.yaml schema with annotations.
|
kustron env status |
Show the cluster and every app's state (Running, image pull failed, crash loop) in one table. |
| apps | |
kustron apps add [flags]
|
Add an app entry to kustron-env.yaml. Then run
kustron env reload to apply. |
kustron apps remove <name>
|
Remove an app entry from kustron-env.yaml. Then run
kustron env reload to apply. |
| registry | |
kustron registry login <server> |
Log in to a container registry (docker/podman) so private images can be pulled and pushed. |
kustron registry import <image> |
Import a local image directly into the cluster without pushing to the registry. |
Kustron checks for these on install and tells you exactly what to do if anything is missing.
Recommended: OrbStack over Docker Desktop. OrbStack starts in ~2 seconds (vs 30+), uses a fraction of the memory, and has native Apple Silicon support. orbstack.dev →
OrbStack (recommended on macOS) · Podman (any platform) · or Docker Desktop. Kustron auto-detects whichever you have.
brew install k3d
· k3d.io/installation
brew install kubectl
Only needed when deploying source without a Dockerfile. railpack.io
Only needed when deploying Helm chart apps. brew install helm
Only needed when deploying from a git SSH URL. Usually pre-installed.
Not just for local dev. Run it on any cloud VM and your stack, APIs, frontends, databases, is on the real internet. No cluster management, no k8s babysitting.
Any Linux instance works: EC2, DigitalOcean Droplet, Hetzner Cloud, Linode. Even a $6/month box is enough for a real multi-service stack.
Install the container runtime (Docker or podman), k3d, kubectl, and kustron. Add your GitHub (or GitLab) SSH key so kustron can pull private repos directly on the instance.
kustron-env.yamlList your apps with exposed: true for anything
that needs to be public. Kustron maps each port to the VM's network interface.
One command: cluster, registry, images, deployments, all at once.
Allow the exposed ports in your security group (AWS) or firewall rules. That's it, your stack is live
at <vm-ip>:<port>.
postgres and redis stay internal. Never
them.
OrbStack (macOS, recommended): brew install --cask orbstack, open it once, done. Kustron detects it automatically.
Podman (any platform): brew install podman (macOS) or your package manager (Linux), then podman machine init --rootful --cpus 4 --memory 4096 and podman machine start. The kustron installer does all of this for you and checks the daemon is responding.
Docker Desktop works too, but it's heavy with k3d. See the next question.
Docker Desktop runs Linux in a VM, and k3d runs a full Kubernetes cluster inside that VM. Two layers of virtualization means the k3d containers keep chewing CPU even when idle, plus several GB of RAM. OrbStack and Podman don't stack a second VM on top, which is why k3d is much happier on both.
Podman reserves bridge as a network mode keyword, so a network can't be named that. Kustron used to try creating one before starting the cluster, which is exactly where this error came from. k3d handles networking itself (it auto-creates a k3d-<cluster> network on podman), and current kustron versions just let it. Update kustron with ./install.sh and run kustron env up.
Railpack used to ship on npm, so npm i -g railpack broke for anyone pointed at a private registry. It's not on npm anymore: the installer downloads the prebuilt binary straight from GitHub releases. No npm, no brew, no package manager involved.
Building an app that pulls private npm deps (without a Dockerfile)? Keep your .npmrc auth or NPM_TOKEN env var in the app's build environment so railpack can authenticate.
Kustron binds the local image registry to localhost:5000. If something else is listening there, free the port and re-run kustron env up.
A k3d cluster wants around 4GB in the podman VM. On macOS: podman machine init --rootful --cpus 4 --memory 4096 for a new machine, or podman machine set --memory 4096 + restart for an existing one.