Swiss-army toolbox for Kubernetes initContainers.
Initium replaces fragile bash scripts in your initContainers with a single, security-hardened, multi-tool binary. Wait for dependencies, run migrations, render config files, fetch secrets, and more — all with structured logging, retries, and safe defaults.
- Single static binary — zero runtime dependencies, built
FROM scratch - Tiny image — ~5 MB multi-arch container (amd64 + arm64)
- Zero CVEs — no OS packages, no shell, no attack surface
- PSA
restrictedcompatible — runs as non-root (UID 65534), read-only filesystem, all capabilities dropped - Sidecar mode —
--sidecarflag keeps the process alive for use as a Kubernetes sidecar container - Structured logging — JSON or text output with automatic secret redaction
- Retries with backoff — exponential backoff, jitter, and configurable deadlines on all network operations
- Declarative database seeding — YAML/JSON specs with MiniJinja templating, cross-table references, and idempotency
- Multi-database support — PostgreSQL, MySQL, and SQLite drivers (optional Cargo features)
- Environment variable config — all flags configurable via
INITIUM_*env vars
initContainers:
- name: wait-for-postgres
image: ghcr.io/kitstream/initium:latest
args:
- wait-for
- --target
- tcp://postgres:5432
- --timeout
- "120s"
securityContext:
runAsNonRoot: true
runAsUser: 65534
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]kubectl apply -f https://raw.githubusercontent.com/kitstream/initium/main/examples/nginx-waitfor/deployment.yaml| Bash scripts | Initium | |
|---|---|---|
| Retries with backoff | DIY, error-prone | Built-in, configurable |
| Structured logging | echo statements |
JSON or text with timestamps |
| Security | Runs as root, full shell | Non-root, no shell, read-only FS |
| Secret handling | Easily leaked in logs | Automatic redaction |
| Multiple tools | Install curl, netcat, psql… | Single small image |
| Reproducibility | Shell differences across distros | Single Rust binary, FROM scratch |
| Vulnerability surface | Full OS + shell utils | Zero OS packages |
| Command | Description | Status |
|---|---|---|
wait-for |
Wait for TCP/HTTP/HTTPS endpoints | ✅ Available |
migrate |
Run database migrations | ✅ Available |
seed |
Structured database seeding from YAML/JSON with MiniJinja templating | ✅ Available |
render |
Render config templates | ✅ Available |
fetch |
Fetch secrets/config from HTTP | ✅ Available |
exec |
Run commands with structured logging | ✅ Available |
# Wait for a TCP endpoint
initium wait-for --target tcp://postgres:5432
# Wait for an HTTP health check
initium wait-for --target http://api:8080/healthz
# Wait for multiple endpoints
initium wait-for \
--target tcp://postgres:5432 \
--target tcp://redis:6379 \
--target http://config:8080/healthz
# HTTPS with self-signed certificates
initium wait-for --target https://vault:8200/v1/sys/health --insecure-tlsDatabase drivers are optional Cargo features, all enabled by default. Disable unused drivers for a smaller binary:
# All drivers (default)
cargo build --release
# PostgreSQL + SQLite only (no MySQL)
cargo build --release --no-default-features --features postgres,sqlite
# SQLite only (smallest binary)
cargo build --release --no-default-features --features sqlite| Feature | Default | Description |
|---|---|---|
sqlite |
✅ | SQLite driver |
postgres |
✅ | PostgreSQL driver |
mysql |
✅ | MySQL/MariaDB driver |
The Helm chart makes it easy to inject Initium initContainers into your deployments.
helm install my-app charts/initium \
--set sampleDeployment.enabled=true \
--set 'initContainers[0].name=wait-for-db' \
--set 'initContainers[0].command[0]=wait-for' \
--set 'initContainers[0].args[0]=--target' \
--set 'initContainers[0].args[1]=tcp://postgres:5432'See charts/initium/values.yaml for all options.
Initium is designed to run in security-restricted environments:
- Non-root: Runs as UID 65534 (nobody)
- Read-only filesystem: Compatible with
readOnlyRootFilesystem: true - No capabilities: Drops all Linux capabilities
- No shell: Commands executed via
execve, not through a shell - Secret redaction: Sensitive values automatically redacted in logs
- Minimal image: Built
FROM scratch— zero OS packages, zero CVEs - PSA
restricted: Fully compatible with the Kubernetes restricted Pod Security Standard
See docs/security.md for the full threat model and SECURITY.md for vulnerability reporting.
initContainers:
- name: wait-for-postgres
image: ghcr.io/kitstream/initium:latest
args: ["wait-for", "--target", "tcp://postgres:5432", "--timeout", "120s"]Initium will retry connecting to postgres:5432 with exponential backoff until it succeeds or the timeout is reached.
Pass multiple --target flags. They are checked sequentially:
args:
- wait-for
- --target
- tcp://postgres:5432
- --target
- tcp://redis:6379
- --target
- http://config-service:8080/healthzUse the seed subcommand with a YAML/JSON spec file that defines your seed data declaratively:
initContainers:
- name: seed-data
image: ghcr.io/kitstream/initium:latest
args: ["seed", "--spec", "/seeds/seed.yaml"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
volumeMounts:
- name: seed-specs
mountPath: /seeds
readOnly: trueSee docs/seeding.md for the full schema, features, and examples.
Use the migrate subcommand — it wraps your migration tool with structured logging:
initContainers:
- name: migrate
image: ghcr.io/kitstream/initium:latest
args: ["migrate", "--", "flyway", "migrate"]
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://postgres:5432/mydb"Use the render subcommand with environment variable substitution:
initContainers:
- name: render-config
image: ghcr.io/kitstream/initium:latest
args: ["render", "--template", "/templates/app.conf.tmpl", "--output", "app.conf", "--workdir", "/work"]
env:
- name: DB_HOST
value: postgresUse the --sidecar global flag to keep the process alive after tasks complete:
containers:
- name: initium-sidecar
image: ghcr.io/kitstream/initium:latest
restartPolicy: Always
args: ["--sidecar", "wait-for", "--target", "tcp://postgres:5432"]The process sleeps indefinitely after success. On failure it exits with code 1 immediately.
Add the --json global flag:
args: ["--json", "wait-for", "--target", "tcp://postgres:5432"]Output: {"time":"2025-01-15T10:30:00Z","level":"INFO","msg":"target is reachable","target":"tcp://postgres:5432","attempts":"1"}
Use --insecure-tls (must be explicitly opted in):
args: ["wait-for", "--target", "https://vault:8200/v1/sys/health", "--insecure-tls"]Yes. Initium is a standalone binary. Use it in Docker Compose, CI pipelines, or anywhere you need to wait for services:
docker run --rm ghcr.io/kitstream/initium:latest wait-for --target tcp://db:5432No. Initium runs as a non-root user with no capabilities and a read-only filesystem. It is compatible with the Kubernetes restricted Pod Security Standard.
All retry parameters are configurable:
args:
- wait-for
- --target
- tcp://postgres:5432
- --max-attempts
- "30"
- --initial-delay
- "500ms"
- --max-delay
- "10s"
- --backoff-factor
- "1.5"
- --jitter
- "0.2"- nginx-waitfor: Nginx deployment waiting for a backend service
- postgres-migrate-seed: Wait → Migrate → Seed workflow
- config-render: Render config from templates before app starts
# Build
make build
# Run wait-for against a local service
./bin/initium wait-for --target tcp://localhost:5432 --max-attempts 5
# Run with JSON logs
./bin/initium --json wait-for --target http://localhost:8080/healthz
# Run all tests
make test# Option 1: Use the pre-built image
kubectl apply -f examples/nginx-waitfor/deployment.yaml
# Option 2: Build and push your own image
make docker-build VERSION=dev
make docker-push VERSION=dev
# Option 3: Use the Helm chart
helm install my-app charts/initium \
--set sampleDeployment.enabled=true \
--set 'initContainers[0].name=wait-db' \
--set 'initContainers[0].command[0]=wait-for' \
--set 'initContainers[0].args[0]=--target' \
--set 'initContainers[0].args[1]=tcp://postgres:5432'Initium was built to address limitations in existing init container tools:
| Tool | Language | Image size | Multi-tool | Database seeding | Security posture |
|---|---|---|---|---|---|
| Initium | Rust | ~5 MB | Yes | Yes | PSA restricted, no OS |
| wait-for-it | Bash | Needs shell | No | No | Requires shell + netcat |
| dockerize | Go | ~17 MB | Partial | No | Full OS image |
| k8s-wait-for | Bash | Needs shell | No | No | Requires shell + kubectl |
| wait4x | Go | ~12 MB | No | No | Minimal OS |
If you only need TCP/HTTP readiness checks, any of these tools work. Initium is designed for teams that also need migrations, seeding, config rendering, and secret fetching in a single security-hardened binary.
- FAQ — Common questions about functionality, security, and deployment
- Usage Guide — All subcommands, flags, and examples
- Security — Threat model, safe defaults, PSA compatibility
- Architecture & Design — How Initium works and how to extend it
Contributions are welcome! See CONTRIBUTING.md for build instructions, test commands, and PR expectations. See the design doc for how to add new subcommands.