Skip to content

Commit 97ff56c

Browse files
Remove migrate subcommand — migrations are out of scope
The migrate subcommand was a thin wrapper around external migration tools. Use the exec subcommand instead for running external tools with structured logging. - Deleted src/cmd/migrate.rs and the unused run_command() helper - Replaced postgres-migrate-seed example with postgres-seed - Cleaned all references from docs, Helm chart, and CHANGELOG Closes #11 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a54df25 commit 97ff56c

14 files changed

Lines changed: 38 additions & 231 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- `dprint` formatter for Markdown, JSON, TOML, YAML, and Dockerfile with CI check (`dprint/check@v2.2`) and definition-of-done gate.
1919
- Structured database connection config as an alternative to URL (`host`, `port`, `user`, `password`, `name`, `options` fields). Passwords with URL-reserved characters (`@`, `%`, `:`, etc.) work without encoding. Connections are built using driver-native APIs (PostgreSQL key-value DSN, MySQL `OptsBuilder`), bypassing URL parsing entirely. The `url`/`url_env` fields remain supported for backward compatibility. See [#39](https://github.com/KitStream/initium/issues/39).
2020

21+
### Removed
22+
23+
- `migrate` subcommand: removed the thin command-execution wrapper. Use `exec` subcommand instead if you need to run an external migration tool with structured logging.
24+
2125
### Changed
2226

2327
- Renamed `jyq.Dockerfile` to `Dockerfile.jyq` to follow the `Dockerfile.<variant>` convention.
@@ -78,8 +82,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7882
- `exec` subcommand: run arbitrary commands with structured logging, exit code forwarding, and optional `--workdir` for child process working directory
7983
- `fetch` subcommand and `internal/fetch` package: fetch secrets/config from HTTP(S) endpoints with auth header via env var, retry with backoff, TLS options, redirect control (same-site by default), and path traversal prevention
8084
- `render` subcommand and `internal/render` package: render templates into config files with `envsubst` (default) and Jinja2 template modes, path traversal prevention, and automatic intermediate directory creation
81-
- `seed` subcommand: run database seed commands with structured logging and exit code forwarding (no idempotency — distinct from `migrate`)
82-
- `migrate` subcommand: run database migration commands with structured logging, exit code forwarding, and optional idempotency via `--lock-file`
85+
- `seed` subcommand: run database seed commands with structured logging and exit code forwarding
8386
- Structured database seeding via `seed` subcommand with YAML/JSON spec files
8487
- Seed tracking table (`initium_seed` by default) for idempotent seed application
8588
- Support for PostgreSQL, MySQL, and SQLite database drivers
@@ -117,7 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
117120
- Documentation for building custom images using Initium as a base
118121
- SECURITY.md with vulnerability reporting instructions
119122
- Apache 2.0 LICENSE
120-
- Examples for nginx-waitfor, postgres-migrate-seed, config-render, template-functions, and phased-seed use cases
123+
- Examples for nginx-waitfor, postgres-seed, config-render, template-functions, and phased-seed use cases
121124
- Unit tests for retry logic, logging, safety path validation, wait-for, sha256, base64, template integration, seed schema parsing, database operations, executor logic, references, idempotency, reset, edge cases, duration parsing, and env var support
122125
- Integration tests with docker-compose for end-to-end testing against real Postgres 16, MySQL 8.0, and nginx services
123126
- Helm chart unit tests using helm-unittest plugin covering deployment rendering, securityContext, and configuration

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ license = "Apache-2.0"
1212
readme = "README.md"
1313
repository = "https://github.com/KitStream/initium"
1414
rust-version = "1.88"
15-
description = "Swiss-army toolbox for Kubernetes initContainers — wait-for, migrate, seed, render, fetch in a single static Rust binary"
15+
description = "Swiss-army toolbox for Kubernetes initContainers — wait-for, seed, render, fetch in a single static Rust binary"
1616

1717
[[bin]]
1818
name = "initium"

FAQ.md

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Initium is a single binary that replaces ad-hoc bash scripts in Kubernetes `initContainers`. Use it when your pod needs to do any of these before the main container starts:
88

99
- Wait for a database or API to become reachable
10-
- Run database migrations or seed data
10+
- Seed data into a database
1111
- Render config files from templates
1212
- Fetch secrets or config from an HTTP endpoint
1313
- Run a setup script with structured logging
@@ -82,20 +82,6 @@ initContainers:
8282

8383
Everything after `--` is the command Initium will execute. Initium does not interpret those arguments — it passes them directly via `execve`.
8484

85-
### How do I run database migrations?
86-
87-
Use the `migrate` subcommand. It works the same way as `seed` but is a separate subcommand so you can distinguish migration steps from seed steps in logs:
88-
89-
```yaml
90-
initContainers:
91-
- name: migrate
92-
image: ghcr.io/kitstream/initium:latest
93-
args: ["migrate", "--", "flyway", "migrate"]
94-
env:
95-
- name: FLYWAY_URL
96-
value: "jdbc:postgresql://postgres:5432/mydb"
97-
```
98-
9985
### How do I render a config file from a template before my app starts?
10086

10187
Use the `render` subcommand. Mount a ConfigMap containing your template and let Initium expand environment variables into the output:
@@ -209,11 +195,11 @@ docker run --rm --network mynet ghcr.io/kitstream/initium:latest \
209195
The `--` tells Initium where its own flags end and the wrapped command begins. Without it, Initium might try to interpret your tool's flags as its own:
210196

211197
```yaml
212-
# Correct — Initium sees "migrate" subcommand, then passes "flyway migrate" to execve
213-
args: ["migrate", "--", "flyway", "migrate"]
198+
# Correct — Initium sees "exec" subcommand, then passes "setup.sh" to execve
199+
args: ["exec", "--", "/bin/setup.sh"]
214200
215-
# Wrong — Initium tries to parse "flyway" as a flag to the migrate subcommand
216-
args: ["migrate", "flyway", "migrate"]
201+
# Wrong — Initium tries to parse "/bin/setup.sh" as a flag to the exec subcommand
202+
args: ["exec", "/bin/setup.sh"]
217203
```
218204

219205
This is the same convention used by `kubectl`, `docker`, and many other CLI tools.
@@ -392,7 +378,7 @@ spec:
392378

393379
The initContainer writes to `/work`, and the main container reads from it.
394380

395-
### How do I chain multiple init steps (wait → migrate → seed)?
381+
### How do I chain multiple init steps (wait → seed)?
396382

397383
Define multiple initContainers in order. Kubernetes runs them sequentially:
398384

@@ -409,14 +395,9 @@ initContainers:
409395
capabilities:
410396
drop: [ALL]
411397
412-
- name: migrate
413-
image: ghcr.io/kitstream/initium:latest
414-
args: ["migrate", "--", "/app/migrate", "up"]
415-
securityContext: *initium-security
416-
417398
- name: seed
418399
image: ghcr.io/kitstream/initium:latest
419-
args: ["seed", "--", "/app/seed", "--file", "/seeds/data.sql"]
400+
args: ["seed", "--spec", "/seeds/seed.yaml"]
420401
securityContext: *initium-security
421402
```
422403

README.md

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**Swiss-army toolbox for Kubernetes initContainers.**
44

5-
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.
5+
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.
66

77
[![CI](https://github.com/kitstream/initium/actions/workflows/ci.yml/badge.svg)](https://github.com/kitstream/initium/actions/workflows/ci.yml)
88
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
@@ -66,7 +66,6 @@ kubectl apply -f https://raw.githubusercontent.com/kitstream/initium/main/exampl
6666
| Command | Description | Status |
6767
| ---------- | -------------------------------------------------------------------- | ------------ |
6868
| `wait-for` | Wait for TCP/HTTP/HTTPS endpoints | ✅ Available |
69-
| `migrate` | Run database migrations | ✅ Available |
7069
| `seed` | Structured database seeding from YAML/JSON with MiniJinja templating | ✅ Available |
7170
| `render` | Render config templates | ✅ Available |
7271
| `fetch` | Fetch secrets/config from HTTP | ✅ Available |
@@ -192,20 +191,6 @@ initContainers:
192191

193192
See [docs/seeding.md](docs/seeding.md) for the full schema, features, and examples.
194193

195-
### How do I run database migrations?
196-
197-
Use the `migrate` subcommand — it wraps your migration tool with structured logging:
198-
199-
```yaml
200-
initContainers:
201-
- name: migrate
202-
image: ghcr.io/kitstream/initium:latest
203-
args: ["migrate", "--", "flyway", "migrate"]
204-
env:
205-
- name: FLYWAY_URL
206-
value: "jdbc:postgresql://postgres:5432/mydb"
207-
```
208-
209194
### How do I render config templates?
210195

211196
Use the `render` subcommand with environment variable substitution:
@@ -301,7 +286,7 @@ args:
301286
## Examples
302287

303288
- [**nginx-waitfor**](examples/nginx-waitfor/): Nginx deployment waiting for a backend service
304-
- [**postgres-migrate-seed**](examples/postgres-migrate-seed/): Wait → Migrate → Seed workflow
289+
- [**postgres-seed**](examples/postgres-seed/): Wait → Seed workflow with PostgreSQL
305290
- [**config-render**](examples/config-render/): Render config from templates before app starts
306291

307292
## How to Run Locally
@@ -351,7 +336,7 @@ Initium was built to address limitations in existing init container tools:
351336
| [k8s-wait-for](https://github.com/groundnuty/k8s-wait-for) | Bash | Needs shell | No | No | Requires shell + kubectl |
352337
| [wait4x](https://github.com/atkrad/wait4x) | Go | ~12 MB | No | No | Minimal OS |
353338

354-
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.
339+
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.
355340

356341
## Documentation
357342

charts/initium/Chart.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,4 @@ keywords:
1414
- initcontainer
1515
- init
1616
- wait
17-
- migration
1817
- kubernetes

charts/initium/tests/deployment_test.yaml

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,6 @@ tests:
100100
args:
101101
- --target
102102
- tcp://postgres:5432
103-
- name: run-migration
104-
command:
105-
- migrate
106-
args:
107-
- --
108-
- flyway
109-
- migrate
110-
env:
111-
- name: FLYWAY_URL
112-
value: "jdbc:postgresql://postgres:5432/mydb"
113103
- name: seed-data
114104
command:
115105
- seed
@@ -122,15 +112,9 @@ tests:
122112
value: wait-for-db
123113
- equal:
124114
path: spec.template.spec.initContainers[1].name
125-
value: run-migration
126-
- equal:
127-
path: spec.template.spec.initContainers[1].env[0].name
128-
value: FLYWAY_URL
129-
- equal:
130-
path: spec.template.spec.initContainers[2].name
131115
value: seed-data
132116
- equal:
133-
path: spec.template.spec.initContainers[2].args
117+
path: spec.template.spec.initContainers[1].args
134118
value:
135119
- --spec
136120
- /seeds/seed.yaml

charts/initium/values.yaml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ sampleDeployment:
3535
# Define initContainers that Initium should run.
3636
# Each entry becomes an initContainer in the sample deployment.
3737
#
38-
# Example: wait for Postgres, render config, then run migration
38+
# Example: wait for Postgres, then render config
3939
initContainers:
4040
# - name: wait-for-postgres
4141
# command: ["wait-for"]
@@ -62,16 +62,6 @@ initContainers:
6262
# - name: DB_PORT
6363
# value: "5432"
6464

65-
# - name: run-migration
66-
# command: ["migrate"]
67-
# args:
68-
# - --
69-
# - /usr/bin/flyway
70-
# - migrate
71-
# env:
72-
# - name: FLYWAY_URL
73-
# value: jdbc:postgresql://postgres:5432/mydb
74-
7565
# Additional volumes to mount into initContainers
7666
extraVolumes: []
7767
# - name: templates

docs/design.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Initium is a single Rust binary with multiple subcommands, each addressing a com
1111
├─────────────────────────────────────────┤
1212
│ src/cmd/ │
1313
│ ┌──────────┬──────────┬────────────┐ │
14-
│ │ wait-for │ migrate render │ │
15-
│ │ seed │ fetch exec │ │
14+
│ │ wait-for │ render fetch │ │
15+
│ │ seed │ exec │ │
1616
│ └──────────┴──────────┴────────────┘ │
1717
├─────────────────────────────────────────┤
1818
│ Shared Libraries │
@@ -31,7 +31,6 @@ src/
3131
cmd/ Subcommand implementations (one file per command)
3232
mod.rs Shared command execution helpers
3333
wait_for.rs Wait for endpoints
34-
migrate.rs Database migrations
3534
seed.rs Database seeding
3635
render.rs Template rendering
3736
fetch.rs HTTP fetch

docs/usage.md

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -67,52 +67,6 @@ initium wait-for \
6767

6868
Targets are checked sequentially. All must become reachable before the command succeeds.
6969

70-
### migrate
71-
72-
Run a database migration command with structured logging, exit code forwarding,
73-
and optional idempotency via a lock file.
74-
75-
The command is executed directly via `execve` (no shell). Use `--` to separate
76-
initium flags from the migration command and its arguments.
77-
78-
```bash
79-
# Run a flyway migration
80-
initium migrate -- flyway migrate
81-
82-
# Run with JSON logs
83-
initium migrate --json -- /app/migrate -path /migrations up
84-
85-
# Idempotent: skip if already migrated
86-
initium migrate --lock-file .migrated --workdir /work -- /app/migrate up
87-
```
88-
89-
**Flags:**
90-
91-
| Flag | Default | Env Var | Description |
92-
| ------------- | -------- | ------------------- | ----------------------------------------------------------- |
93-
| `--workdir` | `/work` | `INITIUM_WORKDIR` | Working directory for file operations |
94-
| `--lock-file` | _(none)_ | `INITIUM_LOCK_FILE` | Skip migration if this file exists in workdir (idempotency) |
95-
| `--json` | `false` | `INITIUM_JSON` | Enable JSON log output |
96-
97-
**Behavior:**
98-
99-
- stdout and stderr from the migration command are captured and logged with timestamps
100-
- The child process exit code is forwarded: a non-zero exit code causes `migrate` to fail
101-
- When `--lock-file` is set:
102-
- If the lock file exists in `--workdir`, the migration is skipped (exit 0)
103-
- On successful completion, the lock file is created so subsequent runs become no-ops
104-
- If the migration fails, no lock file is created
105-
- Lock file paths are validated against `--workdir` to prevent path traversal
106-
- No shell is used: the command is executed directly via `execve`
107-
108-
**Exit codes:**
109-
110-
| Code | Meaning |
111-
| ---- | ---------------------------------------------- |
112-
| `0` | Migration succeeded (or skipped via lock file) |
113-
| `1` | Migration command failed, or invalid arguments |
114-
| _N_ | Forwarded from the migration command |
115-
11670
### seed
11771

11872
Apply structured database seeds from a YAML or JSON spec file.
Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
# Postgres migrate + seed example
1+
# Postgres wait + seed example
22
#
33
# This example shows a deployment that:
44
# 1. Waits for Postgres to be reachable
5-
# 2. Runs database migrations
6-
# 3. Seeds initial data
5+
# 2. Seeds initial data
76
#
87
# Usage:
9-
# kubectl apply -f examples/postgres-migrate-seed/deployment.yaml
8+
# kubectl apply -f examples/postgres-seed/deployment.yaml
109
apiVersion: apps/v1
1110
kind: Deployment
1211
metadata:
13-
name: app-with-migration
12+
name: app-with-seed
1413
labels:
15-
app: app-with-migration
14+
app: app-with-seed
1615
spec:
1716
replicas: 1
1817
selector:
1918
matchLabels:
20-
app: app-with-migration
19+
app: app-with-seed
2120
template:
2221
metadata:
2322
labels:
24-
app: app-with-migration
23+
app: app-with-seed
2524
spec:
2625
initContainers:
2726
- name: wait-for-postgres
@@ -41,41 +40,12 @@ spec:
4140
drop:
4241
- ALL
4342

44-
- name: run-migration
45-
image: ghcr.io/kitstream/initium:latest
46-
args:
47-
- migrate
48-
- --
49-
- /app/migrate
50-
- -path
51-
- /migrations
52-
- up
53-
env:
54-
- name: DATABASE_URL
55-
valueFrom:
56-
secretKeyRef:
57-
name: postgres-credentials
58-
key: url
59-
securityContext:
60-
runAsNonRoot: true
61-
runAsUser: 65534
62-
readOnlyRootFilesystem: true
63-
allowPrivilegeEscalation: false
64-
capabilities:
65-
drop:
66-
- ALL
67-
volumeMounts:
68-
- name: workdir
69-
mountPath: /work
70-
7143
- name: seed-data
7244
image: ghcr.io/kitstream/initium:latest
7345
args:
7446
- seed
75-
- --
76-
- /app/seed
77-
- --file
78-
- /seeds/initial.sql
47+
- --spec
48+
- /seeds/seed.yaml
7949
env:
8050
- name: DATABASE_URL
8151
valueFrom:
@@ -93,6 +63,9 @@ spec:
9363
volumeMounts:
9464
- name: workdir
9565
mountPath: /work
66+
- name: seed-specs
67+
mountPath: /seeds
68+
readOnly: true
9669

9770
containers:
9871
- name: app
@@ -107,3 +80,6 @@ spec:
10780
volumes:
10881
- name: workdir
10982
emptyDir: {}
83+
- name: seed-specs
84+
configMap:
85+
name: seed-specs

0 commit comments

Comments
 (0)