{
 "id": "docker-compose",
 "kind": "skill",
 "name": "Docker and Compose",
 "description": "Write and debug Dockerfiles and Docker Compose files, build images and read container logs.",
 "version": "1.0.0",
 "author": "Hexa Hub",
 "files": {
  "SKILL.md": "---\nname: docker-compose\ndescription: Write and debug Dockerfiles and Docker Compose files, build images and read container logs.\ntitle: Docker and Compose\nicon: tabler:brand-docker\ncategory: Containers\ntriggers: docker, dockerfile, compose, container, image, volume, entrypoint, docker-compose\nmarkers: docker\nrecipes: docker.ps, docker.logs, docker.compose-config, docker.build, help.docker\nrelated: kubernetes-helm, gitlab-ci\n---\n\n# Docker and Compose\n\n## Workflow\n1. Read the existing `Dockerfile`, `compose.yaml` and `.dockerignore` first and follow their style.\n2. Edit. For Compose: `docker.compose-config` validates the file and shows the resolved result (variables filled in, anchors expanded). Fix every error it reports.\n3. To build: `docker.build` (asks; it creates an image on this PC). Read the failing step from the output; fix that step only.\n4. To look at what is running: `docker.ps`, then `docker.logs` for one container. Say what the logs show; do not guess.\n\nExample: `run_recipe {\"recipe\":\"docker.logs\",\"args\":{\"container\":\"shop-web-1\"}}`\n\n## Dockerfile habits\n- Small, pinned base image (`python:3.12-slim`, not `latest`). Multi-stage builds: build in one stage, copy only the result into a small runtime stage.\n- Order for the cache: copy dependency files first (`package*.json`, `composer.json`, `requirements.txt`), install, then copy the rest, so code changes do not reinstall everything.\n- Run as a non-root `USER`. One process per container; `CMD`/`ENTRYPOINT` in exec form (`[\"node\",\"server.js\"]`) so signals reach the app.\n- `.dockerignore` for `.git`, `node_modules`, build output and `.env`. **Never put secrets in the image**: not in `ENV`, `ARG` or a copied file. Use BuildKit secrets (`RUN --mount=type=secret`) at build time and environment or mounted secrets at run time.\n- `HEALTHCHECK` when the app has a status endpoint.\n\n## Compose habits\n- Use named volumes for data, bind mounts only for development code. Do not publish database ports to all interfaces (`127.0.0.1:5432:5432`).\n- `depends_on` with `condition: service_healthy` and a `healthcheck` when startup order matters; it does not wait for readiness otherwise.\n- Configuration through `environment:` or an `env_file` that is not committed. Keep `compose.yaml` generic and put development overrides in `compose.override.yaml`.\n- Service names are DNS names on the network: an app connects to `db`, not `localhost`.\n\n## Typical problems\n| Symptom | Check |\n|---|---|\n| Container exits at once | `docker.logs`: the last lines; wrong CMD, missing env var, file not copied |\n| Port already in use | another container or program holds the host port; change the left side of `ports:` |\n| \"No such file\" in build | the path is relative to the build context, and `.dockerignore` may exclude it |\n| Changes to code not visible | image not rebuilt, or a bind mount hides the copied files |\n| Cannot connect to the other service | wrong host name (use the service name), service not ready, different network |\n\n## Report\nSay what you changed, whether the compose file validated, what the build or logs showed, and what you did not run.\n"
 }
}
