{"id":"cf921f9e-7686-4583-aaa1-2e83eaabc319","shortId":"SBcbyH","kind":"skill","title":"docker","tagline":"Use when editing Dockerfile, Containerfile-like Docker syntax, docker-compose.yml, docker-compose.yaml, .dockerignore, multi-stage builds, BuildKit cache mounts, Compose services, or image optimization.","description":"# Docker\n\n## Overview\n\nDocker provides OS-level virtualization via containers. This skill covers Dockerfile best practices, multi-stage builds, distroless images, Compose orchestration, and BuildKit optimizations.\n\n---\n\n## Multi-Stage Build Quick Reference\n\nMulti-stage builds separate build-time dependencies from the runtime image, producing minimal production images.\n\n```dockerfile\n# ---- Stage 1: dependency builder ----\nFROM python:3.12-slim-bookworm AS builder\nWORKDIR /app\nRUN pip install --no-cache-dir uv\nCOPY pyproject.toml uv.lock ./\n# Cache uv's package download cache across builds\nRUN --mount=type=cache,target=/root/.cache/uv \\\n    uv sync --frozen --no-dev --no-editable\n\n# ---- Stage 2: runtime (distroless, non-root) ----\nFROM gcr.io/distroless/python3-debian12:nonroot\nWORKDIR /app\nCOPY --from=builder /app/.venv/lib/python3.12/site-packages /usr/lib/python3.12/site-packages\nCOPY src/ ./src/\nENTRYPOINT [\"python\", \"-m\", \"myapp\"]\n```\n\nKey rules:\n\n- Name every stage (`AS builder`, `AS runner`, etc.).\n- Only the final stage ends up in the shipped image.\n- Copy only what is needed from earlier stages with `COPY --from=`.\n\n---\n\n## Compose Quick Reference\n\n```yaml\n# compose.yml\nservices:\n  app:\n    build: .\n    image: myapp:dev\n    ports:\n      - \"8000:8000\"\n    environment:\n      DATABASE_URL: postgresql://app:secret@db:5432/mydb\n    depends_on:\n      db:\n        condition: service_healthy\n    restart: unless-stopped\n\n  db:\n    image: postgres:16-alpine\n    environment:\n      POSTGRES_USER: app\n      POSTGRES_PASSWORD: secret\n      POSTGRES_DB: mydb\n    volumes:\n      - pg_data:/var/lib/postgresql/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U app -d mydb\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\nvolumes:\n  pg_data:\n```\n\n```bash\n# Common Compose commands\ndocker compose up -d          # start detached\ndocker compose logs -f app    # follow service logs\ndocker compose exec app bash  # shell into running container\ndocker compose down -v        # stop and remove volumes\ndocker compose build --no-cache  # full rebuild\n```\n\n---\n\n## BuildKit Cache Mounts\n\n`--mount=type=cache` persists a directory between builds so package managers do not re-download.\n\n```dockerfile\n# uv (Python)\nRUN --mount=type=cache,target=/root/.cache/uv \\\n    uv sync --frozen --no-dev\n\n# pip\nRUN --mount=type=cache,target=/root/.cache/pip \\\n    pip install -r requirements.txt\n\n# apt\nRUN --mount=type=cache,target=/var/cache/apt,sharing=locked \\\n    --mount=type=cache,target=/var/lib/apt,sharing=locked \\\n    apt-get update && apt-get install -y --no-install-recommends curl\n\n# npm\nRUN --mount=type=cache,target=/root/.npm \\\n    npm ci --omit=dev\n\n# Go modules\nRUN --mount=type=cache,target=/go/pkg/mod \\\n    go mod download\n```\n\nEnable BuildKit (default in Docker 23+):\n\n```bash\nexport DOCKER_BUILDKIT=1\ndocker build .\n# or\ndocker buildx build .\n```\n\n---\n\n## Production Patterns\n\n### uv Package Manager\n\n`uv` is a fast Python package/project manager. Use it as the build-stage installer, then copy the resulting `.venv` into the runtime stage.\n\n```dockerfile\nFROM python:3.12-slim-bookworm AS builder\nWORKDIR /app\nRUN pip install --no-cache-dir uv\nCOPY pyproject.toml uv.lock ./\nRUN --mount=type=cache,target=/root/.cache/uv \\\n    uv sync --frozen --no-dev --no-editable\n```\n\n### Distroless Base Images\n\n| Image | Use case |\n|-------|----------|\n| `gcr.io/distroless/static-debian12:nonroot` | Statically compiled binaries (Go, Rust) |\n| `gcr.io/distroless/base-debian12:nonroot` | Dynamically linked, needs glibc |\n| `gcr.io/distroless/python3-debian12:nonroot` | Python applications |\n| `gcr.io/distroless/nodejs22-debian12:nonroot` | Node.js applications |\n\nAlways use the `:nonroot` tag — the image user is UID 65532.\n\n### tini Init\n\n`tini` properly forwards signals and reaps zombie processes. Use it when the base image does not include an init system (e.g., non-distroless slim images).\n\n```dockerfile\nFROM python:3.12-slim-bookworm\nRUN apt-get update \\\n && apt-get install -y --no-install-recommends tini \\\n && rm -rf /var/lib/apt/lists/*\nENTRYPOINT [\"tini\", \"--\"]\nCMD [\"python\", \"-m\", \"myapp\"]\n```\n\nDistroless images already run as non-root; for non-distroless images add tini + explicit non-root user.\n\n### Non-Root User (UID 65532)\n\nUID 65532 is the `nonroot` user in distroless images. Align custom user IDs with this value for consistency.\n\n```dockerfile\n# For non-distroless images\nRUN groupadd --gid 65532 nonroot \\\n && useradd --uid 65532 --gid 65532 --no-create-home --shell /bin/false nonroot\nUSER nonroot\n```\n\n### .dockerignore\n\n```text\n.git\n.github\n.venv\n__pycache__\n*.pyc\n*.pyo\nnode_modules\n.env\n.env.*\nDockerfile\ndocker-compose*.yml\ncompose*.yml\n.dockerignore\ncoverage\n.pytest_cache\n.mypy_cache\n.ruff_cache\ndist\nbuild\n*.md\n!README.md\n```\n\n<workflow>\n\n## Workflow\n\n1. **Write Dockerfile** — multi-stage, pin base tags, use cache mounts.\n2. **Write .dockerignore** — exclude `.git`, `.env`, `node_modules`, `__pycache__`.\n3. **Build locally** — `docker buildx build -t myimage:dev .`\n4. **Inspect** — `docker image inspect myimage:dev` for size; `dive myimage:dev` for layer breakdown.\n5. **Run as non-root check** — `docker run --rm myimage:dev id` should print `uid=65532`.\n6. **Compose integration** — use `compose.yml` with health checks and `depends_on` conditions.\n\n</workflow>\n\n<guardrails>\n\n## Guardrails\n\n- **Always multi-stage** — never ship build tools, compilers, or dev dependencies in the final image.\n- **Always non-root** — use `:nonroot` distroless tags or add an explicit non-root user (UID 65532). Never run as root in production.\n- **Always .dockerignore** — prevents leaking `.env`, secrets, `.git`, and large directories into the build context.\n- **Pin base image tags** — use full tags (`python:3.12-slim-bookworm`, not `python:latest`) to ensure reproducible builds.\n- **Use BuildKit cache mounts** for all package managers to keep CI builds fast.\n- **No secrets in layers** — never `COPY .env` or `RUN echo SECRET=...`. Use `--secret` mount or runtime injection.\n\n</guardrails>\n\n<validation>\n\n## Validation Checkpoint\n\nBefore delivering Dockerfile or Compose config, verify:\n\n- [ ] Multi-stage build separates builder from runtime stage\n- [ ] Base image tags are pinned (no `:latest`)\n- [ ] `.dockerignore` is present and excludes secrets/caches\n- [ ] Final image runs as non-root (UID 65532 or equivalent)\n- [ ] No secrets baked into layers\n- [ ] Cache mounts used for package manager steps\n- [ ] Health check defined in Compose or Dockerfile for long-running services\n\n</validation>\n\n---\n\n## References Index\n\nFor detailed guides and code examples, refer to the following documents in `references/`:\n\n- **[Dockerfile Patterns](references/dockerfile.md)**\n  - Multi-stage builds, distroless images, TARGETARCH for multi-arch, non-root users, tini init, .dockerignore, uv cache mounts.\n- **[Compose](references/compose.md)**\n  - docker-compose.yml patterns, service dependencies, volumes, networks, health checks.\n- **[Optimization](references/optimization.md)**\n  - Layer caching, BuildKit cache mounts, minimal base images, bytecode compilation, reducing image size.\n\n---\n\n<example>\n\n## Example: Multi-Stage Python Dockerfile\n\n```dockerfile\n# Build stage\nFROM python:3.12-slim-bookworm AS builder\nWORKDIR /app\nRUN pip install --no-cache-dir uv\nCOPY pyproject.toml uv.lock ./\nRUN --mount=type=cache,target=/root/.cache/uv \\\n    uv sync --frozen --no-dev --no-editable\n\n# Runtime stage\nFROM gcr.io/distroless/python3-debian12:nonroot\nWORKDIR /app\nCOPY --from=builder /app/.venv/lib/python3.12/site-packages /usr/lib/python3.12/site-packages\nCOPY src/ ./src/\nENTRYPOINT [\"python\", \"-m\", \"myapp\"]\n```\n\n</example>\n\n---\n\n## Official References\n\n- <https://docs.docker.com/>\n- <https://github.com/GoogleContainerTools/distroless>\n\n## Shared Styleguide Baseline\n\n- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.\n- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)\n- [Docker](https://github.com/cofin/flow/blob/main/templates/styleguides/tools/docker.md)\n- Keep this skill focused on tool-specific workflows, edge cases, and integration details.","tags":["docker","flow","cofin","agent-skills","ai-agents","beads","claude-code","codex","cursor","developer-tools","gemini-cli","opencode"],"capabilities":["skill","source-cofin","skill-docker","topic-agent-skills","topic-ai-agents","topic-beads","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-gemini-cli","topic-opencode","topic-plugin","topic-slash-commands","topic-spec-driven-development"],"categories":["flow"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cofin/flow/docker","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cofin/flow","source_repo":"https://github.com/cofin/flow","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (8,218 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:36.441Z","embedding":null,"createdAt":"2026-04-23T13:03:59.027Z","updatedAt":"2026-05-18T19:07:36.441Z","lastSeenAt":"2026-05-18T19:07:36.441Z","tsv":"'/app':90,137,447,1002,1036 '/app/.venv/lib/python3.12/site-packages':141,1040 '/bin/false':640 '/cofin/flow/blob/main/templates/styleguides/general.md)':1075 '/cofin/flow/blob/main/templates/styleguides/tools/docker.md)':1079 '/distroless/base-debian12:nonroot':490 '/distroless/nodejs22-debian12:nonroot':502 '/distroless/python3-debian12:nonroot':135,497,1034 '/distroless/static-debian12:nonroot':482 '/go/pkg/mod':387 '/googlecontainertools/distroless':1054 '/root/.cache/pip':334 '/root/.cache/uv':115,321,464,1019 '/root/.npm':375 '/src':145,1044 '/usr/lib/python3.12/site-packages':142,1041 '/var/cache/apt':345 '/var/lib/apt':352 '/var/lib/apt/lists':568 '/var/lib/postgresql/data':230 '1':78,401,676 '10s':243 '16':215 '2':126,688 '23':396 '3':697 '3.12':83,440,547,813,995 '4':706 '5':247,721 '5432/mydb':201 '5s':245 '6':738 '65532':515,600,602,628,632,634,737,784,893 '8000':193,194 'across':108 'add':588,776 'align':610 'alpin':216 'alreadi':577 'alway':505,751,767,791 'app':187,198,220,239,265,272 'applic':499,504 'apt':339,356,360,553,557 'apt-get':355,359,552,556 'arch':948 'bake':898 'base':475,530,683,806,872,977 'baselin':1057 'bash':251,273,397 'best':40 'binari':485 'bookworm':86,443,550,816,998 'breakdown':720 'build':17,45,56,62,65,109,188,288,304,403,407,425,672,698,702,757,803,823,835,866,941,991 'build-stag':424 'build-tim':64 'builder':80,88,140,156,445,868,1000,1039 'buildkit':18,51,294,392,400,825,973 'buildx':406,701 'bytecod':979 'cach':19,96,102,107,113,291,295,299,319,332,343,350,373,385,453,462,666,668,670,686,826,901,957,972,974,1008,1017 'case':479,1090 'check':727,745,909,968 'checkpoint':855 'ci':377,834 'cmd':234,571 'cmd-shell':233 'code':926 'command':254 'common':252 'compil':484,759,980 'compos':21,48,181,253,256,262,270,279,287,659,661,739,860,912,959 'compose.yml':185,742 'condit':205,749 'config':861 'consist':618 'contain':35,277 'containerfil':7 'containerfile-lik':6 'context':804 'copi':99,138,143,170,179,429,456,842,1011,1037,1042 'cover':38 'coverag':664 'creat':637 'curl':368 'custom':611 'd':240,258 'data':229,250 'databas':196 'db':200,204,212,225 'default':393 'defin':910 'deliv':857 'depend':67,79,202,747,762,964 'detach':260 'detail':923,1093 'dev':121,191,327,379,470,705,712,717,732,761,1025 'dir':97,454,1009 'directori':302,800 'dist':671 'distroless':46,128,474,541,575,586,608,623,773,942 'dive':715 'docker':1,9,26,28,255,261,269,278,286,395,399,402,405,658,700,708,728,1076 'docker-compos':657 'docker-compose.yaml':12 'docker-compose.yml':11,961 'dockerfil':5,39,76,313,437,544,619,656,678,858,914,935,989,990 'dockerignor':13,644,663,690,792,879,955 'docs.docker.com':1051 'document':932 'download':106,312,390 'duplic':1067 'dynam':491 'e.g':538 'earlier':176 'echo':846 'edg':1089 'edit':4,124,473,1028 'enabl':391 'end':164 'ensur':821 'entrypoint':146,569,1045 'env':654,655,693,795,843 'environ':195,217 'equival':895 'etc':159 'everi':153 'exampl':927,984 'exclud':691,883 'exec':271 'explicit':590,778 'export':398 'f':264 'fast':416,836 'final':162,765,885 'focus':1083 'follow':266,931 'forward':520 'frozen':118,324,467,1022 'full':292,810 'gcr.io':134,481,489,496,501,1033 'gcr.io/distroless/base-debian12:nonroot':488 'gcr.io/distroless/nodejs22-debian12:nonroot':500 'gcr.io/distroless/python3-debian12:nonroot':133,495,1032 'gcr.io/distroless/static-debian12:nonroot':480 'general':1071 'generic':1062 'get':357,361,554,558 'gid':627,633 'git':646,692,797 'github':647 'github.com':1053,1074,1078 'github.com/cofin/flow/blob/main/templates/styleguides/general.md)':1073 'github.com/cofin/flow/blob/main/templates/styleguides/tools/docker.md)':1077 'github.com/googlecontainertools/distroless':1052 'glibc':494 'go':380,388,486 'groupadd':626 'guardrail':750 'guid':924 'health':744,908,967 'healthcheck':231 'healthi':207 'home':638 'id':613,733 'imag':24,47,71,75,169,189,213,476,477,511,531,543,576,587,609,624,709,766,807,873,886,943,978,982 'includ':534 'index':921 'init':517,536,954 'inject':853 'inspect':707,710 'instal':93,336,362,366,427,450,559,563,1005 'integr':740,1092 'interv':242 'isreadi':237 'keep':833,1080 'key':150 'language/framework':1063 'larg':799 'latest':819,878 'layer':719,840,900,971 'leak':794 'level':32 'like':8 'link':492 'local':699 'lock':347,354 'log':263,268 'long':917 'long-run':916 'm':148,573,1047 'manag':307,412,419,831,906 'md':673 'minim':73,976 'mod':389 'modul':381,653,695 'mount':20,111,296,297,317,330,341,348,371,383,460,687,827,850,902,958,975,1015 'multi':15,43,54,60,680,753,864,939,947,986 'multi-arch':946 'multi-stag':14,42,53,59,679,752,863,938,985 'myapp':149,190,574,1048 'mydb':226,241 'myimag':704,711,716,731 'mypi':667 'name':152 'need':174,493 'network':966 'never':755,785,841 'no-cach':289 'no-cache-dir':94,451,1006 'no-create-hom':635 'no-dev':119,325,468,1023 'no-edit':122,471,1026 'no-install-recommend':364,561 'node':652,694 'node.js':503 'non':130,540,581,585,592,596,622,725,769,780,890,950 'non-distroless':539,584,621 'non-root':129,580,591,595,724,768,779,889,949 'nonroot':508,605,629,641,643,772 'npm':369,376 'offici':1049 'omit':378 'optim':25,52,969 'orchestr':49 'os':31 'os-level':30 'overview':27 'packag':105,306,411,830,905 'package/project':418 'password':222 'pattern':409,936,962 'persist':300 'pg':228,236,249 'pin':682,805,876 'pip':92,328,335,449,1004 'port':192 'postgr':214,218,221,224 'practic':41 'present':881 'prevent':793 'principl':1072 'print':735 'process':525 'produc':72 'product':74,408,790 'proper':519 'provid':29 'pyc':650 'pycach':649,696 'pyo':651 'pyproject.toml':100,457,1012 'pytest':665 'python':82,147,315,417,439,498,546,572,812,818,988,994,1046 'quick':57,182 'r':337 're':311 're-download':310 'readme.md':674 'reap':523 'rebuild':293 'recommend':367,564 'reduc':981,1066 'refer':58,183,920,928,934,1050 'references/compose.md':960 'references/dockerfile.md':937 'references/optimization.md':970 'remov':284 'reproduc':822 'requirements.txt':338 'restart':208 'result':431 'retri':246 'rf':567 'rm':566,730 'root':131,582,593,597,726,770,781,788,891,951 'ruff':669 'rule':151,1064 'run':91,110,276,316,329,340,370,382,448,459,551,578,625,722,729,786,845,887,918,1003,1014 'runner':158 'runtim':70,127,435,852,870,1029 'rust':487 'secret':199,223,796,838,847,849,897 'secrets/caches':884 'separ':63,867 'servic':22,186,206,267,919,963 'share':346,353,1055,1059 'shell':235,274,639 'ship':168,756 'signal':521 'size':714,983 'skill':37,1070,1082 'skill-docker' 'slim':85,442,542,549,815,997 'slim-bookworm':84,441,548,814,996 'source-cofin' 'specif':1087 'src':144,1043 'stage':16,44,55,61,77,125,154,163,177,426,436,681,754,865,871,940,987,992,1030 'start':259 'static':483 'step':907 'stop':211,282 'styleguid':1056,1060 'sync':117,323,466,1021 'syntax':10 'system':537 'tag':509,684,774,808,811,874 'target':114,320,333,344,351,374,386,463,1018 'targetarch':944 'test':232 'text':645 'time':66 'timeout':244 'tini':516,518,565,570,589,953 'tool':758,1086 'tool-specif':1085 'topic-agent-skills' 'topic-ai-agents' 'topic-beads' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-gemini-cli' 'topic-opencode' 'topic-plugin' 'topic-slash-commands' 'topic-spec-driven-development' 'type':112,298,318,331,342,349,372,384,461,1016 'u':238 'uid':514,599,601,631,736,783,892 'unless':210 'unless-stop':209 'updat':358,555 'url':197 'use':2,420,478,506,526,685,741,771,809,824,848,903,1058 'user':219,512,594,598,606,612,642,782,952 'useradd':630 'uv':98,103,116,314,322,410,413,455,465,956,1010,1020 'uv.lock':101,458,1013 'v':281 'valid':854 'valu':616 'venv':432,648 'verifi':862 'via':34 'virtual':33 'volum':227,248,285,965 'workdir':89,136,446,1001,1035 'workflow':675,1088 'write':677,689 'y':363,560 'yaml':184 'yml':660,662 'zombi':524","prices":[{"id":"5d346688-3834-4f90-97e9-743f3f29f632","listingId":"cf921f9e-7686-4583-aaa1-2e83eaabc319","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cofin","category":"flow","install_from":"skills.sh"},"createdAt":"2026-04-23T13:03:59.027Z"}],"sources":[{"listingId":"cf921f9e-7686-4583-aaa1-2e83eaabc319","source":"github","sourceId":"cofin/flow/docker","sourceUrl":"https://github.com/cofin/flow/tree/main/skills/docker","isPrimary":false,"firstSeenAt":"2026-04-23T13:03:59.027Z","lastSeenAt":"2026-05-18T19:07:36.441Z"}],"details":{"listingId":"cf921f9e-7686-4583-aaa1-2e83eaabc319","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cofin","slug":"docker","github":{"repo":"cofin/flow","stars":11,"topics":["agent-skills","ai-agents","beads","claude-code","codex","context-driven-development","cursor","developer-tools","gemini-cli","opencode","plugin","slash-commands","spec-driven-development","subagents","tdd","workflow"],"license":"apache-2.0","html_url":"https://github.com/cofin/flow","pushed_at":"2026-04-27T19:07:26Z","description":"Context-Driven Development toolkit for AI agents — spec-first planning, TDD workflow, and Beads integration.","skill_md_sha":"bad999edb9cb1064f6af71f7b2578f8dedf89cd4","skill_md_path":"skills/docker/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cofin/flow/tree/main/skills/docker"},"layout":"multi","source":"github","category":"flow","frontmatter":{"name":"docker","description":"Use when editing Dockerfile, Containerfile-like Docker syntax, docker-compose.yml, docker-compose.yaml, .dockerignore, multi-stage builds, BuildKit cache mounts, Compose services, or image optimization."},"skills_sh_url":"https://skills.sh/cofin/flow/docker"},"updatedAt":"2026-05-18T19:07:36.441Z"}}