# 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.
[](https://github.com/kitstream/initium/actions/workflows/ci.yml)
[](LICENSE)
## 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 `restricted` compatible** — runs as non-root (UID 65534), read-only filesystem, all capabilities dropped
- **Sidecar mode** — `--sidecar` flag 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
```yaml
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]
```
### Apply a full example
```bash
kubectl apply -f https://raw.githubusercontent.com/kitstream/initium/main/examples/nginx-waitfor/deployment.yaml
```
## Why 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
| `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
```bash
# 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-tls
```
## Cargo Features
Database drivers are optional Cargo features, all enabled by default. Disable unused drivers for a smaller binary:
```bash
# 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
```
| `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.
```bash
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`](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](docs/security.md) for the full threat model and [SECURITY.md](SECURITY.md) for vulnerability reporting.
## FAQ
### How do I wait for Postgres?
```yaml
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.
### How do I wait for multiple services?
Pass multiple `--target` flags. They are checked sequentially:
```yaml
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:
```yaml
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: true
```
See [docs/seeding.md](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:
```yaml
initContainers:
- name: migrate
image: ghcr.io/kitstream/initium:latest
args: ["migrate", "--", "flyway", "migrate"]
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://postgres:5432/mydb"
```
### How do I render config templates?
Use the `render` subcommand with environment variable substitution:
```yaml
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: postgres
```
### How do I run initium as a sidecar container?
Use the `--sidecar` global flag to keep the process alive after tasks complete:
```yaml
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.
### How do I get JSON logs?
Add the `--json` global flag:
```yaml
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"}`
### How do I allow self-signed TLS certificates?
Use `--insecure-tls` (must be explicitly opted in):
```yaml
args: ["wait-for", "--target", "https://vault:8200/v1/sys/health", "--insecure-tls"]
```
### 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:
```bash
docker run --rm ghcr.io/kitstream/initium:latest wait-for --target tcp://db:5432
```
### 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:
```yaml
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**](examples/nginx-waitfor/): Nginx deployment waiting for a backend service
- [**postgres-migrate-seed**](examples/postgres-migrate-seed/): Wait → Migrate → Seed workflow
- [**config-render**](examples/config-render/): Render config from templates before app starts
## How to Run Locally
```bash
# 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
```
## How to Try in a Cluster
```bash
# 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'
```
## Alternatives
Initium was built to address limitations in existing init container tools:
| **Initium** | Rust | ~1.8 MB | Yes | Yes | PSA `restricted`, no OS |
| [wait-for-it](https://github.com/vishnubob/wait-for-it) | Bash | Needs shell | No | No | Requires shell + netcat |
| [dockerize](https://github.com/jwilder/dockerize) | Go | ~17 MB | Partial | No | Full OS image |
| [k8s-wait-for](https://github.com/groundnuty/k8s-wait-for) | Bash | Needs shell | No | No | Requires shell + kubectl|
| [wait4x](https://github.com/atkrad/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](FAQ.md) — Common questions about functionality, security, and deployment
- [Usage Guide](docs/usage.md) — All subcommands, flags, and examples
- [Security](docs/security.md) — Threat model, safe defaults, PSA compatibility
- [Architecture & Design](docs/design.md) — How Initium works and how to extend it
## Contributing
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for build instructions, test commands, and PR expectations. See the [design doc](docs/design.md) for how to add new subcommands.
## License
[Apache License 2.0](LICENSE)