Initium
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.
Features
- Single static binary — zero runtime dependencies, built
FROM scratch - Tiny image — ~1.8 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
Quickstart
Wait for Postgres before starting your app
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:
Apply a full example
Why Initium?
| 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 |
Subcommands
| 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
# Wait for a TCP endpoint
# Wait for an HTTP health check
# Wait for multiple endpoints
# HTTPS with self-signed certificates
Cargo Features
Database drivers are optional Cargo features, all enabled by default. Disable unused drivers for a smaller binary:
# All drivers (default)
# PostgreSQL + SQLite only (no MySQL)
# SQLite only (smallest binary)
| Feature | Default | Description |
|---|---|---|
sqlite |
✅ | SQLite driver |
postgres |
✅ | PostgreSQL driver |
mysql |
✅ | MySQL/MariaDB driver |
Helm Chart
The Helm chart makes it easy to inject Initium initContainers into your deployments.
See charts/initium/values.yaml for all options.
Security
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.
FAQ
How do I wait for Postgres?
initContainers:
- name: wait-for-postgres
image: ghcr.io/kitstream/initium:latest
args:
Initium will retry connecting to postgres:5432 with exponential backoff until it succeeds or the timeout is reached.
How do I wait for multiple services?
Pass multiple --target flags. They are checked sequentially:
args:
- wait-for
- --target
- tcp://postgres:5432
- --target
- tcp://redis:6379
- --target
- http://config-service:8080/healthz
How do I seed data?
Use 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:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
volumeMounts:
- name: seed-specs
mountPath: /seeds
readOnly: true
See docs/seeding.md for the full schema, features, and examples.
How do I run database migrations?
Use the migrate subcommand — it wraps your migration tool with structured logging:
initContainers:
- name: migrate
image: ghcr.io/kitstream/initium:latest
args:
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://postgres:5432/mydb"
How do I render config templates?
Use the render subcommand with environment variable substitution:
initContainers:
- name: render-config
image: ghcr.io/kitstream/initium:latest
args:
env:
- name: DB_HOST
value: postgres
How do I run initium as a sidecar container?
Use 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:
The process sleeps indefinitely after success. On failure it exits with code 1 immediately.
How do I get JSON logs?
Add the --json global flag:
args:
Output: {"time":"2025-01-15T10:30:00Z","level":"INFO","msg":"target is reachable","target":"tcp://postgres:5432","attempts":"1"}
How do I allow self-signed TLS certificates?
Use --insecure-tls (must be explicitly opted in):
args:
Can I use Initium outside Kubernetes?
Yes. Initium is a standalone binary. Use it in Docker Compose, CI pipelines, or anywhere you need to wait for services:
Does Initium need special permissions?
No. 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.
How do I customize retry behavior?
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"
Examples
- 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
How to Run Locally
# Build
# Run wait-for against a local service
# Run with JSON logs
# Run all tests
How to Try in a Cluster
# Option 1: Use the pre-built image
# Option 2: Build and push your own image
# Option 3: Use the Helm chart
Alternatives
Initium was built to address limitations in existing init container tools:
| Tool | Language | Image size | Multi-tool | Database seeding | Security posture |
|---|---|---|---|---|---|
| Initium | Rust | ~1.8 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.
Documentation
- 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
Contributing
Contributions are welcome! See CONTRIBUTING.md for build instructions, test commands, and PR expectations. See the design doc for how to add new subcommands.