Skip to content

Consolidate compose files into single profile-gated docker-compose.yml#18

Open
jinglemansweep wants to merge 3 commits into
mainfrom
chore/consolidate-compose-profiles
Open

Consolidate compose files into single profile-gated docker-compose.yml#18
jinglemansweep wants to merge 3 commits into
mainfrom
chore/consolidate-compose-profiles

Conversation

@jinglemansweep

@jinglemansweep jinglemansweep commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the seven compose/*.yml files with a single root docker-compose.yml whose services are selected via --profile. This moves the Compose project directory to the repo root so the root .env is auto-discovered for ${VAR} interpolation — eliminating the need for --env-file flags or shell exports (direnv) when managing the stack.

Why

The per-service files in compose/ were invoked with -f compose/xxx.yml, which set the project directory to compose/. Compose looks for .env in the project directory, so the root .env was never picked up automatically — operators had to export the values or rely on direnv. A single root compose file fixes the root cause.

Profile model

Per-service profiles plus an all aggregate:

Profile Services
traefik traefik
mqtt mqtt
postgres postgres
redis redis
monitoring prometheus, alertmanager
logto logto, postgres (postgres is a member so depends_on resolves)
backup backup
all everything

postgres is also a member of the logto profile because profile-gated dependencies are not auto-started by Compose — this keeps --profile logto self-contained.

Volume naming (all 8 external)

All volumes are now declared external: true with un-prefixed names, so volume names no longer depend on the Compose project directory. Previously the two managed volumes were named compose_acme / compose_mqtt_broker_data (because the project dir was compose/). They are now acme_data / mqtt_data, created manually like the others:

```bash
docker volume create acme_data
docker volume create mqtt_data
docker volume create postgres_data
docker volume create pgdump_data
docker volume create prometheus_data
docker volume create redis_data
```

The ACME cert/key data is regenerated by Traefik on first start (Let's Encrypt re-issue via Cloudflare DNS challenge), and the MQTT broker's abuse-detection DB is non-critical — so no data migration or docker volume rename is required.

Changes

  • New docker-compose.yml — merge of all 7 files; service definitions (images, container_names, env, labels, command args, healthchecks) preserved verbatim; bind-mount paths shifted from ../<dir> to ./<dir> (project dir is now the repo root). All volumes external.
  • Removed compose/{traefik,mqtt,postgres,redis,monitoring,logto,backup}.yml and the compose/ directory.
  • DocsREADME.md and AGENTS.md updated to the --profile command form (start/stop/logs/verify), the new directory layout, the auto-loaded .env note, and the updated volume-create list.
  • .env.example — one comment reference updated.
  • .gitignore — adds .env.test.

Hub-instance commands (-f docker-compose.yml -f docker-compose.prod.yml …) and scripts/bootstrap-instance.sh are unchanged — those reference the separate MeshCore Hub stacks.

Resulting UX

```bash
docker compose --profile traefik up -d
docker compose --profile logto up -d # brings postgres along
docker compose --profile all up -d # everything
docker compose --profile all down
docker compose --profile postgres logs -f
```

Verification

  • docker compose --env-file .env.test --profile all config -q → parses clean; interpolation resolved (e.g. Host(\mqtt.ipnt.uk`), DB_URL, AWS_S3_BUCKET_NAME, CF_API_EMAIL`).
  • Per-profile config --services counts confirmed (e.g. --profile logtopostgres logto; --profile all → 8 services).
  • Volumes render as external un-prefixed (acme_data, mqtt_data, …).
  • No lifecycle commands (up/down/restart) were run, per the AGENTS.md production guidance.

Operator rollout runbook

```bash

1. Stop the old infra services (old compose/ layout)

docker compose -f compose/traefik.yml down
docker compose -f compose/mqtt.yml down

...and the other services (postgres, redis, monitoring, logto, backup)

2. Create the two new external volumes

docker volume create acme_data
docker volume create mqtt_data

3. Switch to the branch and bring up under the new file

git checkout chore/consolidate-compose-profiles
docker compose --profile traefik up -d # re-issues certs via Cloudflare DNS challenge
docker compose --profile mqtt up -d # fresh abuse-detection state
docker compose --profile all up -d # (or bring up the rest)

4. (Optional, later) remove the orphaned old volumes

docker volume rm compose_acme compose_mqtt_broker_data
```

Note: Traefik will re-register with Let's Encrypt and re-issue certificates (one-time; well within the 5 duplicate-certs/week limit), with a brief gap while the DNS challenge completes. MQTT abuse-detection state resets — acceptable. Container names and the six pre-existing external volumes (postgres_data, etc.) are unchanged, so the running services carry over cleanly.

Merge the seven compose/*.yml files into one root docker-compose.yml and
select services via --profile instead of -f compose/xxx.yml. Because the
compose file now lives at the repo root, the root .env is auto-discovered
for ${VAR} interpolation — removing the need for --env-file flags or shell
exports (direnv).

Profiles (per-service + all):
  traefik, mqtt, postgres, redis, monitoring, logto, backup, all
postgres is also a member of the logto profile so --profile logto starts
it via logto's depends_on (profile-gated deps are not auto-started).

All service definitions (images, container_names, volumes, env, labels,
command args, healthchecks) are preserved verbatim; only bind-mount paths
shifted from ../<dir> to ./<dir> now that the project dir is the repo root.

Updates docs (README.md, AGENTS.md) and the .env.example comment to the
new --profile command form and the new directory layout.
All eight volumes are now external and un-prefixed, so volume names no
longer depend on the Compose project directory (the old layout produced
compose_acme / compose_mqtt_broker_data because the project dir was
compose/). acme_data and mqtt_data are created manually via 'docker
volume create' like the other external volumes.

The acme cert/key data is regenerated by Traefik on first start (Let's
Encrypt re-issue via Cloudflare DNS challenge) and the MQTT broker's
abuse-detection state is non-critical, so no data migration is needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant