Docker Compose
For local development and small single-host deployments. The simplest pattern: a small entry-point script that reads from ScaiVault, exports env vars, then exec's the real process.
This page focuses on dev-loop ergonomics. For Kubernetes-style production deployments, see Kubernetes.
Authentication for dev#
Use a personal access token from ScaiKey, scoped narrowly (read-only on the paths you care about). Put it in your shell — not in docker-compose.yml:
1 2 3 | |
docker-compose.yml references the env:
1 2 3 4 5 6 7 | |
The container inherits whatever's in your shell. Never commit a .env with a real SCAIVAULT_TOKEN.
Pattern: entrypoint wrapper#
Add a small script to your image that reads secrets and exec's the real binary:
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Compose service:
1 2 3 4 5 6 7 8 9 10 | |
App code reads STRIPE_KEY, DB_URL from env like it always did. The container fetches at start, the app doesn't know ScaiVault exists.
Pattern: file-mount instead of env#
When the app expects to read a file (TLS cert, JSON config), write to disk:
1 2 3 4 5 6 7 8 9 10 11 | |
Mount as tmpfs so the values don't hit disk:
1 2 3 4 5 6 | |
Pattern: shared fetcher service#
For a Compose stack with several services needing the same secrets, run one "secrets-fetcher" service that writes to a shared volume, and have the others wait for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
The fetcher refreshes every 5 minutes. Apps either restart on file change (process supervisor watches), or accept up-to-5-min staleness.
Local development with throwaway tokens#
For laptops, the cleanest setup is a scaivault dev-token command that mints a 24h personal token bound to your laptop session. Add to your ~/.zshrc:
1 2 3 4 | |
Run sv-login once per day. Token expires automatically. No persistent .env file with a long-lived credential.
Production single-host deployments#
Compose is fine for production on small single-host setups (often the case for self-hosted SaaS instances). Two changes from the dev pattern:
- Service account, not personal token. Configure the host with a SCAIVAULT_TOKEN from a ScaiKey service account scoped to that machine.
- No fallback to env. The entrypoint should hard-fail if ScaiVault is unreachable. Better to crash and have orchestration retry than to start with missing values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Common questions#
"Can I use Docker secrets instead?" Sort of. Docker secrets (via Swarm) are an alternative for cluster setups but they have their own quirks (file-mount only, no rotation, no audit). ScaiVault gives you a unified model across dev and production; mixing Docker secrets with ScaiVault adds confusion.
"What about Compose secrets:?" The secrets: directive on Compose works with files, not arbitrary APIs. If you really want to use it, point a secrets: mount at the file your fetcher service writes. But at that point you've just added indirection without value.
"How do I rotate without restarting?" Compose-managed processes don't have a clean reload story without app cooperation. Easiest: signal-on-file-change via a small sidecar watching inotify. Or accept that rotation requires docker compose restart <service>.
"My laptop is offline; how do I work?" Cache the values in a local file the first time you fetch:
1 | |
Then on offline runs, an entrypoint variant reads from the cache. Don't commit the cache. Consider this a debugging tool, not a deployment pattern.
What's next#
- Kubernetes — the production-grade version of these patterns.
- CLI — what the entrypoints are calling.
- Migrate from .env files — to bring existing setups into ScaiVault.