docker-project-foundations
Use this skill when setting up, initializing, or Dockerizing a project, even if the user doesn't explicitly mention Docker but describes a need for containerized local development, adding a database or cache dependency, or running services without host-level installs. Covers Dock
Install
npx skills add https://github.com/docker/skills/tree/main/skills/docker-project-foundations
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install docker-skills@llmmart
git clone https://github.com/docker/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole docker/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Docker Project Foundations
Overview
This skill guides you in Dockerizing a project from scratch. It focuses on creating the initial Docker file set, choosing a sane layout, and preferring containerized dependencies over host-level installs.
When to use this skill
Activate this skill when:
- A user asks you to set up, initialize, or Dockerize a project
- A project needs an initial
Dockerfile,compose.yaml, or.dockerignoreand does not have one - A user wants to add a service dependency (database, cache, message queue) to a project
- A user asks how to run or develop a project locally and Docker is available
Do not use this skill when
Do not use this skill when:
- The user explicitly wants to avoid Docker
- The project already has a mature Docker setup and only needs minor edits
- The main task is optimizing an existing
Dockerfile - The main task is editing or debugging an existing Compose stack
Core guidance
Always create these three files
When Dockerizing a project, always produce all three:
.dockerignore— Create this first so the initial build context is small and safe. Seeassets/dockerignore-examplefor a reference.Dockerfile— Create a working starter image definition that the project can build and run with. Seeassets/Dockerfile.simple.compose.yaml— Create a local development stack that includes the application service and any required dependencies. Seeassets/compose-dev.yaml.
npm registry credentials
- Exclude
.npmrcat every depth with**/.npmrcin.dockerignore; otherwise a broad source copy can persist credentials in image layers. - The Node.js starter mounts
npmrcas a BuildKit secret for bothnpm cisteps. Public-package builds need no secret. For private registries, pass the config explicitly:
Use the actual config path if the project keeps it elsewhere. Never copy the credential file or pass its values throughDOCKER_BUILDKIT=1 docker build --secret id=npmrc,src="$HOME/.npmrc" .ARGorENV. Dependency scripts run during installation can access the mounted secret; use trusted dependencies and a least-privilege registry token. - For private-registry builds through Compose, add this optional override as
compose.npm.yamlalongside the starter'scompose.yaml:
Build withservices: app: build: secrets: - npmrc secrets: npmrc: file: ${NPMRC_PATH:?Set NPMRC_PATH to your npm config file}NPMRC_PATH="$HOME/.npmrc" docker compose -f compose.yaml -f compose.npm.yaml build. This grants build-time access only, not a runtime secret. Public-package builds should omit the override so no credential file is required.
Prefer Dockerized dependencies over host installs
When a project needs a database (Postgres, MySQL, MongoDB), cache (Redis, Memcached), queue (RabbitMQ, Kafka), or any other infrastructure service:
- Always define it as a service in
compose.yamlinstead of telling the user to install it on the host. - Never suggest
brew install postgres,apt install redis, or similar host-level installs for development dependencies. - Use official Docker images from Docker Hub for these services.
- Configure services with environment variables, not config files baked into images.
Bootstrap checklist
- Name the file
compose.yamlrather than legacy Compose filenames. - Put all three files at the project root unless there is a clear multi-service layout that justifies a
docker/subdirectory. - Ensure the initial setup can build and start locally with one command path.
- Bind published application ports to loopback by default. Widen the host address only when another device must reach the development service.
- Keep unauthenticated datastores on the Compose network instead of publishing their ports. If local host tools require database access, publish only to loopback.
- If a development-only credential fallback enables one-command startup, label it clearly and document a
.envoverride. - Use Compose services for local databases, caches, and queues instead of host installs.
- Keep the first scaffold simple; defer detailed image optimization and advanced Compose tuning to the owning skills.
Development vs production
- Development: Use bind mounts for live reload, publish application ports on loopback by default, and enable verbose logging. Keep unauthenticated datastores on the Compose network; publish a datastore port only on loopback when local host tools require it.
- Production: Use multi-stage builds, copy only built artifacts, do not mount source code, minimize image layers, set appropriate resource limits.
- Keep a single
Dockerfilethat supports both via build stages and build arguments when possible.
File placement
- Place
Dockerfileat the project root (or in adocker/subdirectory if the project has multiple services). - Place
compose.yamlat the project root. - Place
.dockerignoreat the project root, next to theDockerfile.
Related skills
- For Dockerfile optimization, cache strategy, non-root execution, and image hardening, use
docker-build-strategies. - For service dependencies, health checks, overrides, volumes, networks, and Compose debugging, use
docker-compose-patterns. - For destructive Docker CLI commands (
docker system prune,docker rm -f, image/network/builder pruning) and a cross-product index of destructive-command guardrails, usedocker-destructive-guardrails.
References
references/project-structure.md— Detailed guidance on Docker project file organization, naming conventions, and multi-service layouts.
Assets
assets/dockerignore-example— A comprehensive.dockerignorefor a typical project.assets/compose-dev.yaml— A development-oriented Compose file with Dockerized dependencies.assets/Dockerfile.simple— A basic multi-stage Dockerfile following best practices.
Scripts
scripts/verify-setup.sh— Checks that required files exist in the current directory and validates itscompose.yaml. Run it from the project root, with the script path resolved under this skill's directory:
Replacebash "<skill-dir>/scripts/verify-setup.sh" [--help]<skill-dir>with the absolute path of the folder that contains thisSKILL.md; thescripts/path is relative to that folder, not to the project. Do not change into the skill directory first: the script checks the current directory. If the skill directory cannot be resolved, check that.dockerignore,Dockerfile, andcompose.yamlexist in the project root, then rundocker compose config --quiet. Exit status is0when verification succeeds or help is requested,1when required files are missing or the Compose configuration is invalid, and2for invalid arguments.
Checks
checks/verification.md— Detailed verification checklist for manual review.
Files (skills)
-
agents
-
openai.yaml 269 B
interface: display_name: Docker Project Foundations short_description: Guidance for initializing and structuring a Dockerized project. default_prompt: Use this skill when setting up or Dockerizing a project from scratch. policy: allow_implicit_invocation: true
-
-
assets
-
compose-dev.yaml 1.5 KB
# Development-oriented compose.yaml # Demonstrates Dockerized dependencies, health checks, bind mounts, and named volumes. # The Postgres password fallback is for development-only one-command startup. # Set POSTGRES_PASSWORD in .env to override it for local development. services: app: build: context: . dockerfile: Dockerfile target: dev # Use the dev stage of a multi-stage Dockerfile ports: - "127.0.0.1:3000:3000" # Use 0.0.0.0 only when other devices need access environment: - DATABASE_URL=postgres://appuser:${POSTGRES_PASSWORD:-apppass}@db:5432/appdb - REDIS_URL=redis://cache:6379 - NODE_ENV=development volumes: - ./src:/app/src # Bind mount for live reload - /app/node_modules # Anonymous volume to avoid overwriting installed deps depends_on: db: condition: service_healthy cache: condition: service_healthy db: image: postgres:17 environment: - POSTGRES_USER=appuser - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-apppass} - POSTGRES_DB=appdb ports: - "127.0.0.1:5432:5432" # Keep the development database local volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped cache: image: redis:7 healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped volumes: db-data: -
Dockerfile.simple 959 B · in bundle
-
dockerignore-example 654 B · in bundle
-
-
checks
-
verification.md 4.1 KB
# Verification Checklist Use this checklist to verify that generated Docker project setup follows the skill's guidance. ## Required files - [ ] `.dockerignore` exists at the project root (or at each build context root in a multi-service setup). - [ ] `Dockerfile` exists at the project root (or at each build context root). - [ ] `compose.yaml` exists at the project root. ## .dockerignore - [ ] Excludes `.git` directory. - [ ] Excludes dependency caches (`node_modules/`, `__pycache__/`, `.venv/`, `vendor/`). - [ ] Excludes IDE/editor configs (`.vscode/`, `.idea/`). - [ ] Excludes secret files (`.env`, `*.pem`, `*.key`). - [ ] Excludes root and nested npm credential files with `**/.npmrc`. - [ ] Does not exclude files that the build actually needs (source code, dependency manifests). ## Dockerfile - [ ] Base image uses a specific version tag, not `latest`. - [ ] Base image uses a minimal variant (`-slim` or `-alpine`) where available. - [ ] Dependency manifests are copied and installed before source code (layer caching). - [ ] A non-root `USER` is set before `CMD`/`ENTRYPOINT`. - [ ] No secrets or credentials are hardcoded (`ENV SECRET=...`, `ARG PASSWORD=...`). - [ ] Neither `COPY` nor `ADD` includes `.npmrc`; both npm installation steps use an optional BuildKit secret mount instead. - [ ] Public-package builds work without `.npmrc`; private-registry builds receive it through `--secret id=npmrc,src=<config-path>`. Never test with real credentials in image layers or logs. - [ ] Multi-stage build is used when a build step exists (compile, bundle, transpile). - [ ] Production stage does not contain dev tools, test frameworks, or build toolchains. ## compose.yaml - [ ] File is named `compose.yaml`, not `docker-compose.yml`. - [ ] Infrastructure dependencies (databases, caches, queues) are defined as Compose services, not expected to be installed on the host. - [ ] `depends_on` uses `condition: service_healthy` for services that need readiness. - [ ] Infrastructure services have `healthcheck` definitions. - [ ] Persistent data uses named volumes, not bind mounts. - [ ] Application source code uses bind mounts for development live-reload. - [ ] Application and datastore credentials use Compose interpolation rather than literal values, including passwords embedded in connection URLs. - [ ] Application ports bind to loopback by default; widening to other interfaces is an explicit development choice. - [ ] Unauthenticated datastores are not published to the host and remain reachable only on the Compose network. - [ ] Datastore ports needed by local host tools bind to loopback only. - [ ] Development-only credential fallbacks are clearly labeled, use Compose interpolation, and document a `.env` override. - [ ] No host-level install instructions (`brew install`, `apt install`) for services that should be containerized. ## Development vs production - [ ] Development configuration uses bind mounts for source code. - [ ] Production configuration does not mount source code. - [ ] A single `Dockerfile` supports both via build stages or build arguments when feasible. ## Validation script Run the bundled script from the project root before the broader smoke tests, with the script path resolved under the skill directory: ```bash bash "<skill-dir>/scripts/verify-setup.sh" [--help] ``` Replace `<skill-dir>` with the absolute path of this skill's directory, the folder that contains `SKILL.md` and this `checks/` folder. Do not change into the skill directory to run it; the script checks the current directory. It checks `.dockerignore`, `Dockerfile`, and `compose.yaml`, then validates the Compose configuration. Exit status is `0` on success or help, `1` for missing files or invalid Compose configuration, and `2` for invalid arguments. ## Validation commands Run these to smoke-test the generated setup: ```bash # Verify compose file is syntactically valid docker compose config --quiet # Verify the Dockerfile builds successfully docker compose build # Verify services start and become healthy docker compose up -d docker compose ps # All services should show "healthy" or "running" # Clean up docker compose down -v ```
-
-
references
-
project-structure.md 3.3 KB
# Docker Project Structure Reference ## Standard single-service layout ``` project-root/ .dockerignore Dockerfile compose.yaml src/ ... ``` For most projects, all Docker files live at the project root. This is the simplest and most conventional layout. ## Multi-service layout When a repository contains multiple independently built services (e.g., a monorepo with `frontend/` and `backend/`): ``` project-root/ compose.yaml frontend/ .dockerignore Dockerfile src/ backend/ .dockerignore Dockerfile src/ ``` Each service gets its own `Dockerfile` and `.dockerignore` at the root of its build context. The `compose.yaml` stays at the repository root and references each service's build context: ```yaml services: frontend: build: context: ./frontend dockerfile: Dockerfile backend: build: context: ./backend dockerfile: Dockerfile ``` ## File naming conventions | File | Correct name | Deprecated/incorrect alternatives | |------|-------------|----------------------------------| | Compose file | `compose.yaml` | `docker-compose.yml`, `docker-compose.yaml` | | Dockerfile | `Dockerfile` | `dockerfile`, `Dockerfile.dev` (use stages instead) | | Ignore file | `.dockerignore` | — | ## Build context considerations The Docker build context is the directory tree sent to the Docker daemon during a build. Key rules: - The `.dockerignore` file controls what is excluded from the build context. - A smaller build context means faster builds. Aggressively exclude anything the build does not need. - The build context root is set by the `context` field in `compose.yaml` or by the path argument to `docker build`. - Files outside the build context cannot be referenced in a `Dockerfile` (no `COPY ../something`). ## Compose file organization ### Environment variables Prefer inline `environment:` blocks for small numbers of variables. Use `env_file:` for larger configurations, but never commit files containing real secrets. ```yaml services: app: environment: - DATABASE_URL=postgres://user:pass@db:5432/myapp - REDIS_URL=redis://cache:6379 ``` ### Volumes - **Named volumes** for data that must survive container restarts (database storage): ```yaml volumes: db-data: services: db: volumes: - db-data:/var/lib/postgresql/data ``` - **Bind mounts** for source code during development: ```yaml services: app: volumes: - ./src:/app/src ``` ### Networks For most single-project development setups, the default Compose network is sufficient. Do not create custom networks unless services need isolation from each other. ### Profiles Use Compose profiles to group optional services (e.g., monitoring, debug tools) that are not needed in every development session: ```yaml services: prometheus: profiles: - monitoring image: prom/prometheus:v3 ``` Start with `docker compose --profile monitoring up` when needed. ## Secrets and credentials - Never bake secrets into images (no `ENV SECRET_KEY=...` in a `Dockerfile`). - Use environment variables or Docker secrets for runtime credentials. - Add secret files (`.env`, `*.pem`, `credentials.json`) to `.dockerignore` and `.gitignore`. - For development, use `env_file:` in Compose pointing to a `.env` file that is gitignored.
-
-
scripts
-
verify-setup.sh 1.1 KB
#!/usr/bin/env bash # Verify Docker project setup. Run from the project root. # Usage: bash "<skill-dir>/scripts/verify-setup.sh" [--help] # <skill-dir> is the directory that contains this skill's SKILL.md. set -euo pipefail usage() { echo "Usage: bash \"<skill-dir>/scripts/verify-setup.sh\" [--help]" echo "Run from the project root; <skill-dir> is the directory that contains this skill's SKILL.md." echo "Checks: .dockerignore, Dockerfile, and compose.yaml exist; compose config passes." } if [[ "${1:-}" == "--help" && $# == 1 ]]; then usage exit 0 fi if (( $# != 0 )); then usage >&2 exit 2 fi status=0 echo "Checking required files..." for file in .dockerignore Dockerfile compose.yaml; do if [[ -f "$file" ]]; then echo "OK: $file" else echo "MISSING: $file" >&2 status=1 fi done if [[ -f compose.yaml ]]; then echo "" echo "Validating compose.yaml..." if docker compose config --quiet; then echo "OK: compose config valid" else echo "FAIL: compose config invalid" >&2 status=1 fi fi exit "$status"
-
-
SKILL.md 7.3 KB
--- name: docker-project-foundations description: Use this skill when setting up, initializing, or Dockerizing a project, even if the user doesn't explicitly mention Docker but describes a need for containerized local development, adding a database or cache dependency, or running services without host-level installs. Covers Dockerfile, compose.yaml, and .dockerignore creation with Docker best practices. license: Apache-2.0 compatibility: Requires Docker 20.10+ and Docker Compose v2. --- # Docker Project Foundations ## Overview This skill guides you in Dockerizing a project from scratch. It focuses on creating the initial Docker file set, choosing a sane layout, and preferring containerized dependencies over host-level installs. ## When to use this skill Activate this skill when: - A user asks you to set up, initialize, or Dockerize a project - A project needs an initial `Dockerfile`, `compose.yaml`, or `.dockerignore` and does not have one - A user wants to add a service dependency (database, cache, message queue) to a project - A user asks how to run or develop a project locally and Docker is available ## Do not use this skill when Do not use this skill when: - The user explicitly wants to avoid Docker - The project already has a mature Docker setup and only needs minor edits - The main task is optimizing an existing `Dockerfile` - The main task is editing or debugging an existing Compose stack ## Core guidance ### Always create these three files When Dockerizing a project, always produce all three: 1. **`.dockerignore`** — Create this first so the initial build context is small and safe. See `assets/dockerignore-example` for a reference. 2. **`Dockerfile`** — Create a working starter image definition that the project can build and run with. See `assets/Dockerfile.simple`. 3. **`compose.yaml`** — Create a local development stack that includes the application service and any required dependencies. See `assets/compose-dev.yaml`. ### npm registry credentials - Exclude `.npmrc` at every depth with `**/.npmrc` in `.dockerignore`; otherwise a broad source copy can persist credentials in image layers. - The Node.js starter mounts `npmrc` as a BuildKit secret for both `npm ci` steps. Public-package builds need no secret. For private registries, pass the config explicitly: ```bash DOCKER_BUILDKIT=1 docker build --secret id=npmrc,src="$HOME/.npmrc" . ``` Use the actual config path if the project keeps it elsewhere. Never copy the credential file or pass its values through `ARG` or `ENV`. Dependency scripts run during installation can access the mounted secret; use trusted dependencies and a least-privilege registry token. - For private-registry builds through Compose, add this optional override as `compose.npm.yaml` alongside the starter's `compose.yaml`: ```yaml services: app: build: secrets: - npmrc secrets: npmrc: file: ${NPMRC_PATH:?Set NPMRC_PATH to your npm config file} ``` Build with `NPMRC_PATH="$HOME/.npmrc" docker compose -f compose.yaml -f compose.npm.yaml build`. This grants build-time access only, not a runtime secret. Public-package builds should omit the override so no credential file is required. ### Prefer Dockerized dependencies over host installs When a project needs a database (Postgres, MySQL, MongoDB), cache (Redis, Memcached), queue (RabbitMQ, Kafka), or any other infrastructure service: - **Always** define it as a service in `compose.yaml` instead of telling the user to install it on the host. - **Never** suggest `brew install postgres`, `apt install redis`, or similar host-level installs for development dependencies. - Use official Docker images from Docker Hub for these services. - Configure services with environment variables, not config files baked into images. ### Bootstrap checklist - Name the file `compose.yaml` rather than legacy Compose filenames. - Put all three files at the project root unless there is a clear multi-service layout that justifies a `docker/` subdirectory. - Ensure the initial setup can build and start locally with one command path. - Bind published application ports to loopback by default. Widen the host address only when another device must reach the development service. - Keep unauthenticated datastores on the Compose network instead of publishing their ports. If local host tools require database access, publish only to loopback. - If a development-only credential fallback enables one-command startup, label it clearly and document a `.env` override. - Use Compose services for local databases, caches, and queues instead of host installs. - Keep the first scaffold simple; defer detailed image optimization and advanced Compose tuning to the owning skills. ### Development vs production - Development: Use bind mounts for live reload, publish application ports on loopback by default, and enable verbose logging. Keep unauthenticated datastores on the Compose network; publish a datastore port only on loopback when local host tools require it. - Production: Use multi-stage builds, copy only built artifacts, do not mount source code, minimize image layers, set appropriate resource limits. - Keep a single `Dockerfile` that supports both via build stages and build arguments when possible. ### File placement - Place `Dockerfile` at the project root (or in a `docker/` subdirectory if the project has multiple services). - Place `compose.yaml` at the project root. - Place `.dockerignore` at the project root, next to the `Dockerfile`. ## Related skills - For Dockerfile optimization, cache strategy, non-root execution, and image hardening, use `docker-build-strategies`. - For service dependencies, health checks, overrides, volumes, networks, and Compose debugging, use `docker-compose-patterns`. - For destructive Docker CLI commands (`docker system prune`, `docker rm -f`, image/network/builder pruning) and a cross-product index of destructive-command guardrails, use `docker-destructive-guardrails`. ## References - `references/project-structure.md` — Detailed guidance on Docker project file organization, naming conventions, and multi-service layouts. ## Assets - `assets/dockerignore-example` — A comprehensive `.dockerignore` for a typical project. - `assets/compose-dev.yaml` — A development-oriented Compose file with Dockerized dependencies. - `assets/Dockerfile.simple` — A basic multi-stage Dockerfile following best practices. ## Scripts - **`scripts/verify-setup.sh`** — Checks that required files exist in the current directory and validates its `compose.yaml`. Run it from the project root, with the script path resolved under this skill's directory: ```bash bash "<skill-dir>/scripts/verify-setup.sh" [--help] ``` Replace `<skill-dir>` with the absolute path of the folder that contains this `SKILL.md`; the `scripts/` path is relative to that folder, not to the project. Do not change into the skill directory first: the script checks the current directory. If the skill directory cannot be resolved, check that `.dockerignore`, `Dockerfile`, and `compose.yaml` exist in the project root, then run `docker compose config --quiet`. Exit status is `0` when verification succeeds or help is requested, `1` when required files are missing or the Compose configuration is invalid, and `2` for invalid arguments. ## Checks - `checks/verification.md` — Detailed verification checklist for manual review. -
skill.yaml 853 B
schema: v1 id: docker-project-foundations version: 0.2.2 title: Docker Project Foundations description: Guidance for initializing and structuring a Dockerized project. owns: - initial-docker-setup - project-layout - dockerized-dev-dependencies use_when: - The project does not yet have a Docker setup and needs an initial scaffold. - The user wants to Dockerize a project from scratch or replace an incomplete setup. - The task is to add baseline local development dependencies as Compose services. do_not_use_when: - The main task is optimizing or hardening an existing Dockerfile. - The main task is editing or debugging an existing Compose stack. - The project already has a mature Docker setup and only needs targeted changes. delegates_to: - docker-build-strategies - docker-compose-patterns - docker-destructive-guardrails
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.