Write Dockerfiles, build/run containers, and set up multi-service docker compose stacks. Triggers when containerizing an app, debugging container failures, or orchestrating local services.
./install.sh docker-for-agentsname: "docker_for_agents" description: "Write Dockerfiles, build/run containers, and set up multi-service docker compose stacks. Triggers when containerizing an app, debugging container failures, or orchestrating local services."
Go from an un-containerized app to a working Dockerfile and docker run command, or a multi-service compose.yaml, without guessing at syntax. Covers the instructions and flags that actually matter, layer-cache pitfalls, and the failure modes agents hit most.
1. Check the daemon. docker info should return server details. If it fails with a connection error, the Docker daemon isn't running (or isn't installed) — report that and stop; nothing else below will work.
2. Write the Dockerfile. Start minimal; add only what's needed:
dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
FROM — pinned base image (:3.12-slim, not :latest, so rebuilds don't drift).WORKDIR /app — sets the working directory for everything after it.COPY <host> <image> — copy files in. Copy dependency manifests first, then install, then copy code so a code edit doesn't bust the dependency layer cache.RUN — shell commands at build time (installs, compiles).CMD ["a", "b"] — the default process. Exec form (JSON array, no shell) is the default; CMD python app.py (shell form) runs via /bin/sh -c, which can break signal handling..dockerignore (next to the Dockerfile) keeps build context small: venv/, .git/, __pycache__/, node_modules/, *.pyc.3. Build and run.
bash
docker build -t myapp:0.1.0 .
docker run --rm -p 8000:8000 --name myapp myapp:0.1.0
Flags that matter:
--rm — delete the container when it exits (default to this for one-off runs so dead containers don't pile up).-d — detached (background), for long-running services. -it — interactive TTY, for shells/debugging (docker run --rm -it myapp:0.1.0 bash). Pick one; they're for different jobs.-p 8000:8000 — publish host:container port. Without it, the container's port is unreachable from the host.-v ./data:/app/data — bind-mount a host path for dev or persistence; -v appdata:/app/data — named volume, data survives container removal.--env-file .env — load KEY=VALUE lines (comments with #); -e KEY=VAL for one-offs.--name — stable name so you can docker logs <name> / docker exec -it <name> bash.4. Shrink with multi-stage builds when the final image only needs the built artifact:
dockerfile
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o server ./cmd/server
FROM alpine:3.20
WORKDIR /app
COPY --from=build /src/server .
CMD ["./server"]
Toolchain stays in the build stage; the runtime image only carries the binary.
5. Multi-service: docker compose. Compose v2 is a plugin — the command is docker compose (no hyphen); the legacy standalone docker-compose is end-of-life. Preferred filename is compose.yaml (docker-compose.yml still works). No version: field — it's deprecated.
yaml
services:
api:
build: .
ports:
- "8000:8000"
env_file: .env
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
docker compose up --build builds and starts everything; docker compose up -d runs detached; docker compose down stops and removes containers/network. Services reach each other by service name (db above → api connects to host db).
When asked to containerize something, deliver: a Dockerfile, a .dockerignore, and the exact docker build / docker run commands (or a compose.yaml plus the up/down commands). State the host:container port mapping and where data persists, if anywhere.
COPY . . before RUN pip install means every edit reinstalls dependencies — slow and wasteful.bind: address already in use). Pick a free host port (-p 8001:8000) or stop the conflicting container.docker logs <name> first; check the command actually exists in the image and, for servers, that it binds 0.0.0.0 (a server bound to 127.0.0.1 inside the container is unreachable).--env-file a secrets file into an image build context carelessly: env at docker run stays out of the image; a secret copied in at build time is baked into the image layers forever.CMD a && b.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.