Operating Foundations

A production-minded Docker Compose baseline

Docker Compose can describe a reliable single-host service, but starting containers is only one of the tests that matter.

Published
Evidence state
Live patterns and source-reviewed reference configuration; not a universal deployment template

Starting is a test, not the finish line

docker compose up answers a useful but narrow question: did the engine accept this configuration and start the requested containers?

It does not establish that the service is reachable through its intended path, that its database will survive replacement, that a secret is scoped correctly, or that a restore will work. It also does not make an application highly available across hosts.

Compose is still a good fit for many single-host services. The important move is to make the operating decisions as deliberate as the YAML.

Start with a service contract

Before writing a Compose file, record the following for each service:

Decision Minimum answer
Source Who maintains the image, and which reviewed version will run?
Ingress Which one component receives web traffic, and which services stay private?
Persistence Which volumes contain irreplaceable state, and which paths are caches?
Secrets Where does each secret originate, and which service may read it?
Readiness What proves the service is useful rather than merely running?
Recovery What native dump or export exists, and has it been restored in isolation?
Lifecycle How are upgrades, rollback limits, removal, and data export handled?

If any answer is unknown, the next task is to resolve it—not add another container.

A baseline has separate traffic and data paths

The shape I look for is simple: one approved web ingress, an application on a private network, and a database with no accidental host-published port. Named volumes hold durable state; native application backups and isolated restores prove that the state is usable.

Secrets should enter through a deliberate runtime path, not as values copied through source control, image layers, command history, or broad environment files. Compose supports a secrets model, but it does not create a secret source of truth, rotate values, or decide which identity should receive them. Those remain operating decisions. Docker's Compose reference and secrets guidance are useful references for the mechanics.

Health checks must test the dependency you need

A process can be running while its database is unavailable, its migration is unfinished, or its API cannot serve the workflow it exists for. A health check should test the narrowest meaningful readiness condition the image supports.

Where startup order matters, make the dependency explicit and test the bad case: stop the dependency, observe the application behavior, restore it, and confirm the application becomes useful again. Do not make a health check pass by querying only its own process.

The same distinction applies to resource and log limits. A container that works for five minutes can still consume the host’s available memory or disk over a week. Bound what can grow, then observe the bound under representative load.

Harden only what the image can support

Read-only filesystems, a non-root user, dropped Linux capabilities, limited privileges, and temporary writable locations are valuable controls when the application has been tested under them. They are not decorations to paste into every service.

An image may need a writable directory, a specific capability, or an init process to operate correctly. The right response is to identify and narrow that need, document it, and retest after upgrades. A configuration that looks hardened but cannot restart is less safe than a documented exception with a working recovery path.

The operating checklist

Before calling a Compose service ready, I want evidence for these separate activities:

  1. Validate: render and validate the configuration before applying it.
  2. Start: create the service and confirm each expected container state.
  3. Route: test the approved ingress and prove direct backend access is not accidentally available.
  4. Fail: exercise a dependency failure or an equivalent isolated test.
  5. Recover: restore data into a separate environment and verify the application, not just the files.
  6. Change: define the upgrade and rollback boundary before the upgrade.
  7. Remove: prove what survives removal, what is exported, and what is intentionally deleted only with approval.

The seventh item is easy to postpone and expensive to rediscover. A system is not portable merely because its containers can be recreated. Its data, credentials, documentation, and ownership model need a recovery story too.

Compose is not a shortcut around operations. It is a compact way to declare them. That makes it valuable when the declaration is paired with honest tests for running, routing, failing, recovering, changing, and removing.

Three commentaries

These are invited responses to the article's argument and its possible evolution. They are viewpoints, not independent reviews, endorsements, or evidence for the claims above.

Codex

The service-contract table is the durable contribution because it forces operating questions into the design before a container starts. To evolve the baseline, choose one representative service and automate its lifecycle rehearsal—start, route, dependency failure, restore, and removal—so the checklist becomes executable evidence rather than a document that ages separately from the stack.

Qwen, local model

This baseline correctly rejects the naive assumption that container startup equals service readiness. The emphasis on explicit service contracts and isolated recovery testing is vital for operational integrity. However, the manual nature of the proposed checklist is difficult to sustain at scale. The idea should evolve into automated, policy-as-code verification pipelines. By encoding the fail and recover steps into continuous integration tests that run against the Compose definition itself, teams can ensure that operational resilience is verified automatically before deployment, rather than relying on periodic manual audits.

Claude

The service contract table does more work than the YAML advice around it, and starting is a test is the correct correction to compose up. My worry is practical: steps four through seven are the ones a solo operator skips, and the article doesn't make them cheap. The evolution I'd choose is a scripted fail-recover-remove rehearsal against a throwaway stack, run on a schedule rather than on intent.


If this overlaps with something you are working on

Send me a short note describing the workflow, what is frustrating about it today, and any data, timing, or approval constraints that matter. Start a conversation.

How I use AI in my writing