Cloud and infrastructure as code
Twelve-factor config
Keep config in the environment, not the image, so one tested artifact runs in every environment. Separate build, release and run, and promote the same image digest.
The Twelve-Factor App is a set of rules for building software that survives constant deploys. Its most important rule for configuration is simple: keep config in the environment, not in the image. Then one artifact can run in every environment, and its behaviour changes only through its settings.
Concept
A build turns source into an immutable artifact, such as a container image. A release is that artifact plus a specific config bundle. A run is a release executing on some processes. Promoting a release means moving the same image digest, with environment-specific config, not rebuilding from main.
Walking through the factors
Several factors still matter for services on Kubernetes, Cloud Run or ECS.
| Factor | Practice | Why it matters |
|---|---|---|
| Config | Store config in the environment, not the image | One artifact, many environments |
| Backing services | Treat the database, queue and mail server as attached resources by URL | Swap Redis for a managed cache without a rebuild |
| Build, release, run | Keep the three stages strictly separate | Nobody hotfixes by editing a running container |
| Processes | Keep processes stateless. Store durable state in backing services | Any instance can die |
| Disposability | Start fast and shut down gracefully on SIGTERM | Rolling deploys and autoscaling work |
| Dev/prod parity | Keep environments similar | "Works on my machine" shrinks |
The same image digest runs in both places. Only the environment changes.
docker run -e DATABASE_URL="$STAGING_URL" -e LOG_LEVEL=debug gcr.io/acme/api@sha256:abc
docker run -e DATABASE_URL="$PROD_URL" -e LOG_LEVEL=info gcr.io/acme/api@sha256:abcBoth commands start the same program. The only differences are the two values passed in.
What aged less well
Config held only in environment variables becomes hard to manage at large scale. Hundreds of keys have no structure and no types. Teams still inject config at runtime, but they often generate a file from a typed config service or a secret store.
The spirit is unchanged. The image does not contain production credentials or production hostnames. Secrets belong in a manager, as covered in secrets and encryption.
Common mistakes
- Putting a production hostname in the image. The image can then run only in production.
- Rebuilding for production from
main. The tested artifact and the deployed artifact may differ. - Keeping state in the container's filesystem. Replacing the container then loses the state.
Check yourself
- Two environments run the same image digest with different variables. Which factor is that? Answer: Config. The settings live in the environment, and the artifact stays the same.
- Why must the image never contain credentials? Answer: One artifact must run everywhere, and anyone who can pull the image can read what is inside it.
Key takeaways
- Config lives outside the image, in environment variables, mounted files or secret references.
- Keep build, release and run separate, and promote the same image digest.
- Stateless processes can die and be replaced. Durable state lives in backing services.
Further learning
The Twelve-Factor App site has the full list of factors.
The Twelve-Factor AppA methodology for building modern, scalable, maintainable software-as-a-service apps.12factor.netNext, see how many environments you need, and why parity matters: environments and parity.
Related
Configuration, environments and feature flags
Twelve-factor config, environment parity, secrets injection, feature flags and the blast radius of a bad config push.
Containers from the inside
Namespaces, cgroups and layered images - what a container really is, how images are built and shipped, and how to write small, fast, secure Dockerfiles.
Deployment strategies and safe releases
Rolling, blue-green and canary deploys, automated rollback, and zero-downtime schema changes - ship often without betting the fleet on every commit.