Compose profiles before profiles: two files and a merge

Wanting the mail catcher and phpMyAdmin locally but not in CI, without maintaining two full compose files, is the problem profiles eventually solve. In 2018 the answer is file composition.

# docker-compose.yml            — services everyone needs
# docker-compose.override.yml    — merged automatically, local extras
# docker-compose.ci.yml          — explicit, replaces the override

$ docker-compose up -d                                  # base + override
$ docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d

$ docker-compose -f docker-compose.yml -f docker-compose.ci.yml config

The automatic merge of docker-compose.override.yml is the part people do not know about, and it is what makes the local file able to add bind mounts and exposed ports without the base file mentioning them. Merge semantics differ per key — lists concatenate, scalars replace, and command replaces entirely — which is exactly why the config command is worth running rather than reasoning about it.