An open API service indexing awesome lists of open source software.

https://github.com/kitstream/initium

Swiss-army toolbox for Kubernetes initContainers
https://github.com/kitstream/initium

cloud-native container database-seeding devops initcontainer kubernetes kubernetes-tools migration rust sidecar

Last synced: 5 days ago
JSON representation

Swiss-army toolbox for Kubernetes initContainers

Awesome Lists containing this project

README

          

# 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, seed databases, render config files, fetch secrets, and more — all with structured logging, retries, and safe defaults.

[![CI](https://github.com/kitstream/initium/actions/workflows/ci.yml/badge.svg)](https://github.com/kitstream/initium/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)

## Features

- **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 `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?

| | 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 |
| `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
```

| 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.

```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 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-seed**](examples/postgres-seed/): Wait → Seed workflow with PostgreSQL
- [**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: Cross-build and push multi-arch images
make docker-multiarch 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:

| Tool | Language | Image size | Multi-tool | Database seeding | Security posture |
| ---------------------------------------------------------- | -------- | ----------- | ---------- | ---------------- | ------------------------ |
| **Initium** | Rust | ~5 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 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

## Development

### Prerequisites

- [Rust toolchain](https://rustup.rs/) with musl targets:
```bash
rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
```
- [Zig](https://ziglang.org/) for cross-compilation: `brew install zig`
- [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild): `cargo install cargo-zigbuild`
- (Optional) [sccache](https://github.com/mozilla/sccache) for build caching across worktrees:
```bash
brew install sccache
export RUSTC_WRAPPER=sccache
```

### Cross-compile for linux/amd64 and linux/arm64

```bash
make cross-build
file bin/initium-amd64 bin/initium-arm64
```

### Build and push multi-arch Docker images

```bash
make docker-multiarch VERSION=dev IMAGE=ghcr.io/kitstream/initium
```

This runs `cross-build` then uses `docker buildx` to assemble and push multi-arch images for both `initium` (scratch) and `initium-jyq` (alpine + jq/yq).

## 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)