Merge pull request 'feat: add portable docker-compose skill' (#89) from feat/docker-compose-skill-pr into main

This commit is contained in:
Jasper (AI Assistant)
2026-07-11 08:20:56 -04:00
20 changed files with 671 additions and 0 deletions
+1
View File
@@ -84,6 +84,7 @@ When the user mentions these keywords, load the corresponding skill:
| "build a CLI", "make a CLI tool", "agent-friendly CLI", "add --json flag" | [cli-builder](cli-builder/SKILL.md) |
| "SDD", "spec-driven development", "specification driven", "software factory", "spec first", "spec as code", "SPEC.md template", "write a spec for AI", "AI code generation pipeline", "acceptance criteria", "quality gates", "phase gate review", "BDD for AI", "OpenAPI first", "executable specification" | [spec-driven-development](spec-driven-development/SKILL.md) |
| "debug this", "root cause", "why is this broken", "fix this bug" | [systematic-debugging](systematic-debugging/SKILL.md) |
| "Docker Compose", "docker compose", "compose.yaml", "multi-container", "healthcheck", "Compose Watch", "Compose profiles", "Compose networks", "Compose volumes", "Compose secrets", "Compose override" | [docker-compose](docker-compose/SKILL.md) |
| "epub", "ebook", "EPUB file", "ebook format", "read epub", "write epub", "create ebook", "extract from epub", "epub to text", "edit epub", "repair epub", "convert epub2", "epub images", "batch epub", "ebook metadata" | [epub](epub/SKILL.md) |
| "gutenberg", "public domain", "download a book", "classic literature", "free ebook", "gutenberg.org", "project gutenberg", "PG", "gutendex" | [gutenberg](gutenberg/SKILL.md) |
| "self-hosted runner", "github actions runner", "CI runner", "set up a runner", "runner registration", "runner won't register", "autoscaling runners", "runner security", "runner group", "ARC", "Actions Runner Controller", "runner scale set", "myoung34/github-runner", "ephemeral runner", "just-in-time runner", "runner container image", "runner custom image", "runner network", "runner troubleshooting", "runner monitoring" | [github-runner](github-runner/SKILL.md) |
+3
View File
@@ -44,6 +44,9 @@ Act as a virtual data architect. Discover data assets, assess maturity, evaluate
PhD-level expertise in data science, statistics, and machine learning. Rigorous statistical methodology, experimental design, causal inference, Bayesian analysis, model selection and diagnostics, and research-grade communication. Ships five analysis scripts (power analysis, assumption diagnostics, model comparison, effect size calculator, experimental design generator) with Python + R dual-language support.
### [docker-compose](docker-compose/SKILL.md)
Define, run, debug, and harden multi-container applications with Docker Compose. Covers the Compose Specification, lifecycle and healthchecks, service networking, volumes, secrets, profiles, interpolation, overrides, Compose Watch, CI, production patterns, and troubleshooting. Ships 9 references, 5 templates, and a portable diagnostics script.
### [epub](epub/SKILL.md)
EPUB file format expert — read, write, edit, convert, and repair EPUB2/EPUB3 ebooks.
+33
View File
@@ -0,0 +1,33 @@
# Docker Compose — Multi-Container Application Operations
This skill gives an agent a portable, current reference for defining and operating Docker Compose applications without relying on one host, repository, or agent framework.
## Why Install This Skill
Your agent can design a Compose model, resolve interpolation and overrides before deployment, operate services safely, and debug the common gap between “the container is running” and “the application is ready.” It includes patterns for networks, storage, secrets, profiles, healthchecks, Compose Watch, and production hygiene.
The references are distilled from the current Compose Specification and Docker documentation, with tutorials and operational failure patterns used as secondary context. The skill favors verification commands and explicit destructive-action boundaries over copy-paste optimism.
## What You Get
| Directory | Purpose |
|---|---|
| `SKILL.md` | Agent-facing operating loop and decision rules |
| `references/` | Design, lifecycle, networking, configuration, security, troubleshooting, and command references |
| `templates/` | Base, development, production, environment, and secret-file examples |
| `scripts/` | `compose-doctor.sh` validation and diagnostics helper |
## Quick Start
```bash
docker compose -f templates/compose.yaml config --quiet
bash scripts/compose-doctor.sh ./templates
```
## Triggers
Load for `compose.yaml`, Docker Compose, multi-container applications, `docker compose up`, profiles, healthchecks, services that cannot connect, volume or secret problems, override files, Compose Watch, or Compose production troubleshooting.
## Requirements
Docker Engine with the Docker Compose v2 plugin. The templates assume a POSIX shell; the reference material remains useful on other platforms with equivalent commands.
+120
View File
@@ -0,0 +1,120 @@
---
name: docker-compose
description: >-
Use Docker Compose to define, run, debug, and harden multi-container applications.
Load for compose.yaml design, networking, volumes, secrets, profiles, overrides,
watch mode, lifecycle operations, or troubleshooting.
license: MIT
compatibility: Docker Compose v2 or another implementation of the Compose Specification; commands require Docker CLI.
metadata:
source: https://docs.docker.com/compose/
spec: https://github.com/compose-spec/compose-spec
---
# Docker Compose
Use this skill for the whole Compose lifecycle: model the application, validate the resolved configuration, start or update services, inspect runtime state, and diagnose failures. Prefer the current Compose Specification. Do not add a top-level `version` key to new files: it is obsolete and does not select a schema.
## Operating loop
1. **Discover** the Compose file(s), project directory, env files, profiles, external resources, and whether the task is development, CI, staging, or production.
2. **Model** the application with services, named volumes for durable state, explicit networks for isolation, secrets for sensitive files, and profiles for optional services.
3. **Resolve before running**:
```bash
docker compose -f compose.yaml config --quiet
docker compose -f compose.yaml config
docker compose -f compose.yaml config --services
```
4. **Operate** with the narrowest command: `up -d SERVICE`, `restart SERVICE`, `run --rm SERVICE COMMAND`, or `exec SERVICE COMMAND`. Avoid `down -v` unless data deletion is intentional and confirmed.
5. **Verify** with `ps`, health status, logs, an in-container check, and the externally published endpoint where applicable.
6. **Diagnose in order**: resolved model → container state → logs → healthcheck → network membership/DNS → mounts/permissions → image/build architecture → host resources.
## Decision rules
- `depends_on` controls creation order, not readiness. Use a real `healthcheck` plus `condition: service_healthy`; use `service_completed_successfully` for migrations or jobs. Do not use `sleep` as readiness logic.
- Containers reach sibling services by **service name** and **container port** (`db:5432`), not host-published ports or container IPs.
- Use the default network for simple projects. Use separate networks to isolate tiers, `internal: true` for a network with no external gateway, and an explicitly named `external: true` network only when it is created outside the project.
- Use bind mounts for source/configuration during development, named volumes for state, and read-only mounts for immutable inputs. Treat host-path mounts as platform-sensitive.
- Put credentials in Compose secrets or an external secret manager, not in images, Git, or ordinary environment variables. Grant each secret only to services that need it. Compose secrets are mounted at `/run/secrets/<name>`.
- Use profiles for optional tools such as debugging, migrations, observability, or GPU workloads. Core services should have no profile.
- Resolve interpolation explicitly. Shell variables override `--env-file`, which overrides the project `.env`; use `${REQUIRED:?explain}` for mandatory values and `$$` for a literal dollar sign. For example, write `test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]` when the container shell, not Compose, must expand the variable. Check with `docker compose config --environment`.
- In multi-file merges, later files are applied to the base. Relative paths resolve from the first/base file. Inspect the result with `docker compose config`; use `!reset` or `!override` when ordinary merge behavior is not what you want.
- Compose Watch is for services built from local source. Use `sync` for hot-reloadable source, `sync+restart` for configuration, and `rebuild` for dependency or image changes. The container user must be able to write to the target path.
- Treat `deploy` fields as implementation-dependent. Verify what the target Compose implementation enforces; the specification explicitly allows partial support.
## Quick command card
```bash
docker compose version
docker compose config --quiet
docker compose up -d --build
docker compose ps
docker compose logs -f --tail=100 SERVICE
docker compose exec SERVICE COMMAND
docker compose run --rm SERVICE COMMAND
docker compose restart SERVICE
docker compose stop
docker compose down # preserves named volumes
docker compose down --remove-orphans
docker compose pull && docker compose up -d
docker compose --profile debug up -d
docker compose up --watch
docker compose port SERVICE CONTAINER_PORT
docker network inspect PROJECT_default
docker volume inspect PROJECT_VOLUME
```
## High-value defaults
- When `compose.override.yaml` exists beside `compose.yaml` and no `-f` files are supplied, Compose loads the override automatically; use explicit `-f` files for production combinations.
- **Destructive CI gate:** never run `down --volumes` until `docker compose -p ci-${CI_JOB_ID:?CI_JOB_ID is required} config --services` confirms the isolated project name; on shared environments, omit `--volumes` unless the exact data scope is intentional.
- Treat `deploy` resource and placement fields as target-dependent: a rendered field can be valid while the local implementation ignores it. Verify enforcement at runtime.
### Base/dev/prod command matrix
```bash
# Base or default development override
docker compose config --quiet
docker compose up --watch
# Explicit production model
IMAGE_TAG=release-1 docker compose -f compose.yaml -f compose.prod.yaml config --quiet
IMAGE_TAG=release-1 docker compose -f compose.yaml -f compose.prod.yaml up -d
# Optional tooling
docker compose --profile debug up -d
```
The default `compose.override.yaml` is auto-loaded; production overrides must be selected explicitly.
**Rendered configuration is not runtime proof.** `config` can confirm a secret declaration, resource limit, or healthcheck is present, but only runtime inspection proves the secret file is mounted, the healthcheck passes, or the target implementation enforces `deploy` limits. Verify with `exec`, `ps`, `inspect`, and measured behavior on the target host.
## Reference routing
| Load when | Reference |
|---|---|
| Starting a project or choosing primitives | `references/01-model-and-file-design.md` |
| Dependencies, healthchecks, shutdown, or jobs | `references/02-lifecycle-and-health.md` |
| DNS, ports, networks, volumes, or persistence | `references/03-networking-and-storage.md` |
| `.env`, interpolation, profiles, or overrides | `references/04-configuration-and-overrides.md` |
| Watch, builds, CI, or production operations | `references/05-development-and-production.md` |
| Secrets, least privilege, or supply-chain concerns | `references/06-security.md` |
| A failure needs a systematic workflow | `references/07-troubleshooting.md` |
| CLI command or field lookup | `references/08-command-playbook.md` |
| Source coverage and freshness checks | `references/00-source-index.md` |
## Included artifacts
- `templates/`: portable base, development, production, environment, and secret-file examples.
- `assets/project-review-checklist.md`: handoff and pre-deployment review checklist.
- `scripts/compose-doctor.sh`: deterministic validation and runtime diagnostics with text or JSON output.
## Failure boundaries
- `config --quiet` proves model resolution, not image pulls, startup, or application correctness.
- A running container is not a ready service. A passing healthcheck is not end-to-end verification.
- `docker compose down` removes project containers and networks; it normally preserves named volumes. `down -v` is destructive.
## When not to use this skill
Use an orchestrator-specific skill for Kubernetes, Swarm scheduling, or another platform's deployment controller. Compose can describe some deploy concepts, but is not a substitute for that platform's operational API.
@@ -0,0 +1,18 @@
# Compose Project Review Checklist
Use this checklist before starting or handing off a Compose project.
- [ ] `compose.yaml` is the canonical base file and has no obsolete `version` key.
- [ ] `docker compose config --quiet` passes with the intended env file(s).
- [ ] The resolved model was reviewed with `docker compose config`.
- [ ] Internal URLs use service names and container ports, not host ports.
- [ ] Dependencies have readiness healthchecks or an explicit retry strategy.
- [ ] Persistent state uses named or externally managed volumes.
- [ ] Secrets are excluded from Git and granted only to required services.
- [ ] Optional services are behind documented profiles.
- [ ] Development watch rules ignore generated and host-native dependency trees.
- [ ] Production images are immutable enough to identify and roll back.
- [ ] Resource, restart, logging, and shutdown behavior is intentional.
- [ ] CI uses an isolated project name and cleans up only its own resources.
- [ ] Backup and restore procedures for persistent data were tested.
- [ ] Runtime health and the externally reachable endpoint were verified after deployment.
@@ -0,0 +1,25 @@
# Source Index and Freshness
This skill was researched with GroktoCrawl against the following primary sources. The Compose Specification is the semantic authority; Docker documentation is the operational authority for Docker Compose CLI behavior.
## Primary sources
- [Docker Compose overview](https://docs.docker.com/compose/) — purpose, lifecycle, and environments.
- [Compose file reference](https://docs.docker.com/reference/compose-file/) — current field reference.
- [Compose Specification](https://github.com/compose-spec/compose-spec/blob/main/spec.md) — application model and syntax.
- [Startup and shutdown order](https://docs.docker.com/compose/how-tos/startup-order/) — dependency conditions and healthchecks.
- [Networking](https://docs.docker.com/compose/how-tos/networking/) — service DNS, ports, networks, and diagnostics.
- [Interpolation](https://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/) — `.env`, `--env-file`, precedence, and syntax.
- [Profiles](https://docs.docker.com/compose/how-tos/profiles/) — activation and dependency behavior.
- [Compose Watch](https://docs.docker.com/compose/how-tos/file-watch/) — sync, restart, rebuild, ignore rules, and permissions.
- [Secrets](https://docs.docker.com/compose/how-tos/use-secrets/) — runtime and build secret injection.
- [Merge](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/) — file order, path resolution, and merge classes.
- [Compose CLI reference](https://docs.docker.com/reference/cli/docker/compose/) — command flags and lifecycle operations.
- [Compose releases](https://docs.docker.com/compose/releases/release-notes/) — implementation release history.
## Source discipline
- Do not infer a feature's availability from a tutorial's publication date. Check release notes or the field's version marker.
- The Specification marks some attributes optional and platform-dependent. A file can parse while an implementation ignores part of it.
- Docker Compose CLI interpolation is not identical to every deployment target's interpolation; verify the target.
- Secondary tutorials are useful for worked patterns and failure stories, not for settling current syntax or compatibility.
@@ -0,0 +1,41 @@
# Model and File Design
## Canonical shape
Use `compose.yaml` for new projects. The top-level `version` key is obsolete and only retained for backward compatibility. A Compose application normally contains `services`, and may declare `networks`, `volumes`, `configs`, `secrets`, `name`, `include`, fragments, and extensions.
A service is a replaceable application component backed by an image and runtime configuration. Networks provide communication channels; volumes provide persistence; configs and secrets provide explicitly granted read-only files.
## Design checklist
- Name services by role (`api`, `db`, `worker`), not by container hostname.
- Pin image tags or digests for reproducible releases; avoid `latest` for production.
- Keep application configuration in environment variables or mounted files, not image rebuilds.
- Keep state in named volumes or an external storage system, not the writable container layer.
- Make host-published ports intentional. Internal services usually need no `ports` entry.
- Use YAML anchors/extensions only when they reduce repetition without hiding the resolved model.
- Set a top-level `name` or `COMPOSE_PROJECT_NAME` when stable resource names matter.
- Use `include` for independently managed Compose applications whose relative paths should remain local; use `-f` merges for a base plus environment override.
## Minimal application
```yaml
name: example
services:
web:
image: nginx:stable
ports:
- "8080:80"
```
## Validate the model
```bash
docker compose config --quiet
docker compose config --services
docker compose config --images
docker compose config --environment
docker compose config --format json
```
The resolved model reveals interpolation mistakes, unexpected profile activation, path resolution, duplicate mounts, and accidental port exposure.
@@ -0,0 +1,52 @@
# Lifecycle, Readiness, and Jobs
Compose creates and removes services in dependency order, but startup order is not readiness. `depends_on` without a condition only establishes ordering.
## Readiness pattern
```yaml
services:
api:
image: example/api:1.2
depends_on:
db:
condition: service_healthy
restart: true
migrate:
condition: service_completed_successfully
db:
image: postgres:18
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
migrate:
image: example/api:1.2
command: ["./app", "migrate"]
depends_on:
db:
condition: service_healthy
restart: "no"
profiles: [ops]
```
Use a healthcheck that tests actual readiness, not merely that a process exists. Ensure the image contains the probe executable (`curl`, `wget`, `pg_isready`, or an application-specific probe). Use `start_period` for slow initialization. A healthcheck provides a signal; it does not repair the service.
## Safe lifecycle
```bash
docker compose up -d
docker compose up -d --build SERVICE
docker compose restart SERVICE
docker compose stop
docker compose down
docker compose down --remove-orphans
```
`down` removes project containers and networks. Named volumes normally remain. Treat `down -v`, `volume rm`, and host-directory deletion as data-loss operations.
## One-off work
Use `docker compose run --rm SERVICE COMMAND` for migrations, administration, and probes. Use `docker compose exec SERVICE COMMAND` when the service is already running and you need its live environment. Prefer a dedicated job service for repeatable migrations over ad-hoc commands in application startup.
@@ -0,0 +1,54 @@
# Networking and Storage
## Service DNS and ports
Compose creates a project network and registers each service name in Docker's internal DNS. From one container to another, use `http://SERVICE:CONTAINER_PORT`. A host mapping such as `127.0.0.1:8000:8000` is for host-to-container access; it is not the address another service should use.
Container IPs are ephemeral. Applications must reconnect by service name after a container is recreated.
## Network isolation
```yaml
services:
proxy:
image: nginx:stable
networks: [front]
api:
image: example/api:1.2
networks: [front, back]
db:
image: postgres:18
networks: [back]
networks:
front: {}
back:
internal: true
```
Use an external network only when it is intentionally shared:
```yaml
networks:
shared:
name: shared-network
external: true
```
The network must already exist. `network_mode: host` disables normal service DNS and port publishing; use it only when the requirement genuinely needs the host network.
## Storage choice
- **Named volume**: durable application data managed by Docker.
- **Bind mount**: host-controlled source/configuration; sensitive to host paths and permissions.
- **tmpfs**: ephemeral data where supported.
- **External volume**: data managed outside the Compose lifecycle; verify it exists before startup.
```bash
docker compose exec SERVICE sh -lc 'id; df -h; ls -la /mount'
docker volume ls
docker volume inspect PROJECT_VOLUME
docker compose port SERVICE 8080
docker network inspect PROJECT_default
```
If a service cannot write, inspect the container user, mount mode (`:ro`), host ownership, and the image's expected path before changing permissions broadly.
@@ -0,0 +1,43 @@
# Configuration, Interpolation, Profiles, and Overrides
## Interpolation
Supported forms include `$VAR`, `${VAR}`, `${VAR:-default}`, `${VAR-default}`, `${VAR:?error}`, `${VAR?error}`, `${VAR:+replacement}`, and `$$` for a literal dollar sign. Interpolation applies to YAML values before merge, not arbitrary mapping keys.
Precedence for interpolation is shell environment, then the file passed with `--env-file`, then the project `.env` file. Verify the actual inputs:
```bash
docker compose --env-file .env.test config --environment
docker compose --env-file .env.test config
```
Use required forms for values that must not silently become empty:
```yaml
image: example/api:${IMAGE_TAG:?IMAGE_TAG must be set}
environment:
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
```
Do not commit credentials in `.env`. `.env.example` is documentation, not a secret store.
## Profiles
Unprofiled services are always active. Profiled services start only when enabled, or when explicitly targeted. A dependency must be active and compatible with the target's profiles.
```bash
docker compose --profile debug up -d
COMPOSE_PROFILES=debug,ops docker compose up -d
docker compose --profile '*' config
```
Use profiles for optional tools, not for core services that every normal invocation needs.
## Multiple files
```bash
docker compose -f compose.yaml -f compose.dev.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d
```
Later files add or override earlier configuration. Relative paths are resolved from the first/base file, a common monorepo trap. Mappings merge; many sequences append; special resources such as ports, volumes, secrets, and configs have uniqueness rules. Use the Compose Specification's `!reset` and `!override` tags when you need to clear or fully replace values, then inspect the result.
@@ -0,0 +1,48 @@
# Development, Builds, CI, and Production
## Compose Watch
Watch services built from local source:
```yaml
services:
web:
build: .
command: npm start
develop:
watch:
- action: sync
path: ./src
target: /app/src
ignore:
- node_modules/
- action: rebuild
path: package.json
```
Run `docker compose up --watch` or `docker compose watch`. `sync` is for hot-reloadable source, `sync+restart` for changed configuration, and `rebuild` for dependencies or image inputs. The image needs `stat`, `mkdir`, and `rmdir`, and the runtime user must be able to write to the target path. Do not sync host-native dependency trees such as `node_modules` across architectures.
## Build and CI loop
```bash
docker compose build --pull
docker compose config --quiet
docker compose -p ci-${CI_JOB_ID:?CI_JOB_ID required} up -d --wait
docker compose -p ci-${CI_JOB_ID:?CI_JOB_ID required} ps
docker compose -p ci-${CI_JOB_ID:?CI_JOB_ID required} logs --no-color --tail=200
docker compose -p ci-${CI_JOB_ID:?CI_JOB_ID required} down --volumes --remove-orphans
```
Use an isolated project name and deterministic image tags in CI. Do not use destructive volume cleanup against shared environments.
## Production baseline
- Deploy immutable image tags or digests.
- Define healthchecks and graceful `stop_grace_period`.
- Set restart policy deliberately (`unless-stopped` for long-running services, `on-failure` for jobs).
- Bound memory/CPU only after measuring and verifying target implementation support.
- Configure log rotation or a centralized logging driver.
- Run as non-root where supported; use `read_only: true` plus explicit writable mounts when practical.
- Keep databases off public host ports unless required.
- Back up and restore-test named volumes; Compose does not create a backup strategy.
- Verify externally reachable endpoints after deployment. `config` passing is not deployment verification.
+31
View File
@@ -0,0 +1,31 @@
# Security and Trust Boundaries
## Secrets
Runtime secrets are explicitly granted and mounted as files:
```yaml
services:
api:
image: example/api:1.2
secrets: [api_token]
secrets:
api_token:
file: ./secrets/api_token.txt
```
The file appears at `/run/secrets/api_token`. Some official images support `_FILE` variables; confirm the image documentation before using that convention. Build secrets belong under `build.secrets` and must not be baked into an image layer.
A local-file Compose secret protects against casual environment exposure, but is not equivalent to a managed secret store. Protect the source file, exclude it from version control, limit service grants, and use an external manager when the threat model requires it.
## Container hardening
Prefer a non-root `user`, drop unnecessary capabilities, use `read_only: true` where compatible, and add explicit writable `tmpfs` or volume mounts. Avoid mounting the Docker socket into untrusted containers: it is effectively host control. Avoid `privileged: true`, host networking, broad device access, and `cap_add: [ALL]` unless documented and reviewed.
## Supply chain
Pin image references, review base-image provenance, scan images, minimize build context with `.dockerignore`, and never pass secrets through build args or ordinary `ARG` values. Use least privilege for host paths and external networks.
## Portability caveat
The Compose Specification includes platform-dependent and optional attributes. Security settings that work on Linux may behave differently on another runtime. Verify the rendered model and runtime state on the target platform.
@@ -0,0 +1,31 @@
# Troubleshooting Playbook
Start with evidence, not a rewrite:
```bash
docker compose config --quiet
docker compose ps --all
docker compose logs --no-color --tail=200 SERVICE
docker compose events --json
docker compose top SERVICE
docker inspect CONTAINER --format '{{json .State}}'
```
| Symptom | Check first | Likely fix |
|---|---|---|
| Dependency connection refused | `depends_on`, healthcheck, service logs | Gate on `service_healthy`; use `SERVICE:CONTAINER_PORT`; make client retry |
| Name does not resolve | `docker network inspect`; service networks | Put services on the same network; remove accidental host mode |
| Host connects, sibling cannot | URL uses `localhost` or host port | Use service DNS and container port inside Compose |
| Container exits | logs, exit code, effective command | Fix command/entrypoint, missing file, permissions, or architecture |
| Health is unhealthy | health log and probe executable | Run probe manually; check endpoint, credentials, and startup grace |
| Port already allocated | `docker compose port`, host listeners | Change published host port or stop the conflicting project |
| Data disappeared | volume list, mount target, `down -v` history | Restore backup; use a named/external volume and verify mounts |
| Override surprises | `docker compose config` | Remember base-relative paths and merge rules; use `!reset`/`!override` deliberately |
| Environment is wrong | `config --environment`, `config` | Check shell/`--env-file`/`.env` precedence and required substitutions |
| Watch does nothing | `develop.watch`, build, target permissions | Use a built service, required tools, writable target, and ignore rules |
| OOM or throttling | `docker stats`, host memory, limits | Measure, adjust limits, reduce concurrency, or fix workload |
| Works on one machine only | image architecture, bind paths, runtime support | Pin compatible images, remove host-specific paths, verify optional fields |
Never fix connectivity by publishing every internal port or using host networking. That hides the model defect and widens exposure.
For destructive recovery, snapshot or back up first. Do not run `down -v`, `volume rm`, `system prune`, or delete host-mounted data as a diagnostic step.
@@ -0,0 +1,51 @@
# Command Playbook
## Inspect and validate
```bash
docker compose version
docker compose ls
docker compose -f compose.yaml config --quiet
docker compose -f compose.yaml config --services
docker compose -f compose.yaml config --images
docker compose -f compose.yaml config --environment
```
## Lifecycle
```bash
docker compose up -d
docker compose up -d --build SERVICE
docker compose start SERVICE
docker compose stop SERVICE
docker compose restart SERVICE
docker compose pause SERVICE
docker compose unpause SERVICE
docker compose down
docker compose down --remove-orphans
```
## Runtime access
```bash
docker compose ps --all
docker compose logs -f --tail=100 SERVICE
docker compose exec SERVICE sh
docker compose run --rm SERVICE COMMAND
docker compose cp SERVICE:/path ./path
docker compose top SERVICE
docker compose port SERVICE 8080
```
## Images and data
```bash
docker compose pull
docker compose build --pull --no-cache SERVICE
docker compose images
docker compose volumes
docker volume inspect PROJECT_VOLUME
docker network inspect PROJECT_default
```
Use `--project-name` or `COMPOSE_PROJECT_NAME` to isolate concurrent projects. Prefer `--no-color --no-log-prefix` in CI logs. Confirm command availability with `docker compose COMMAND --help`; flags and implementation support evolve.
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
# Portable diagnostics. Never removes containers, networks, or volumes.
project_dir="${1:-.}"
json=false
if [[ "${1:-}" == "--json" ]]; then project_dir="."; json=true; fi
if [[ "${2:-}" == "--json" ]]; then json=true; fi
if [[ ! -d "$project_dir" ]]; then printf 'error: project directory not found: %s\n' "$project_dir" >&2; exit 2; fi
if ! command -v docker >/dev/null 2>&1; then printf 'error: docker CLI not found\n' >&2; exit 127; fi
if ! docker compose version >/dev/null 2>&1; then printf 'error: docker compose plugin unavailable\n' >&2; exit 127; fi
cd "$project_dir"
status=0
docker compose config --quiet >/dev/null 2>&1 || status=$?
services="$(docker compose config --services 2>/dev/null || true)"
if $json; then
python3 - "$status" "$services" <<'PY'
import json, sys
print(json.dumps({"config_valid": int(sys.argv[1]) == 0,
"services": [x for x in sys.argv[2].splitlines() if x]}))
PY
else
printf 'Compose project: %s\n' "$PWD"
if (( status == 0 )); then printf 'Config: valid\n'; else printf 'Config: INVALID (run docker compose config for details)\n'; fi
printf 'Services:\n%s\n' "${services:-<unavailable>}"
docker compose ps --all || true
fi
exit "$status"
+4
View File
@@ -0,0 +1,4 @@
# Compose interpolation inputs. Copy to .env or pass with --env-file.
IMAGE_TAG=dev
ADMINER_PORT=8080
# Never put passwords or API keys here in a committed file.
@@ -0,0 +1,11 @@
services:
api:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
ignore: [node_modules/]
- action: rebuild
path: package.json
@@ -0,0 +1,26 @@
services:
api:
image: example/api:${IMAGE_TAG:?IMAGE_TAG is required}
restart: unless-stopped
stop_grace_period: 30s
read_only: true
tmpfs: [/tmp]
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
logging:
driver: json-file
options:
max-size: 10m
max-file: "3"
db:
restart: unless-stopped
stop_grace_period: 60s
logging:
driver: json-file
options:
max-size: 10m
max-file: "3"
+50
View File
@@ -0,0 +1,50 @@
name: example
services:
api:
image: example/api:${IMAGE_TAG:-dev}
environment:
DATABASE_URL: postgres://app@db:5432/app
DB_PASSWORD_FILE: /run/secrets/db_password
depends_on:
db:
condition: service_healthy
secrets: [db_password]
networks: [app]
db:
image: postgres:18
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
secrets: [db_password]
volumes: [db-data:/var/lib/postgresql/data]
networks: [app]
adminer:
image: adminer@sha256:983261ecc40a4aaf11e25aeda8ef821f5a43a9f024b3967c81cbcc0e6ce43ba3
depends_on:
db:
condition: service_healthy
ports: ["${ADMINER_PORT:-8080}:8080"]
networks: [app]
profiles: [debug]
volumes:
db-data:
networks:
app:
# Internal network: services have no external gateway. Add a front network and publish a proxy/API explicitly when host access is required.
internal: true
secrets:
db_password:
file: ./secret.example.txt
@@ -0,0 +1 @@
replace-me-with-a-local-secret