03 β Dockerfile
What it is: a recipe that tells Docker how to package your application into a container image.
Location: dockerfiles/Dockerfile
Rules
Use a small, official Linux base image:
- Node.js β
node:20-alpine - Python β
python:3.12-slim - Java β
eclipse-temurin:21-jre-alpine
- Node.js β
Target platform is
linux/amd64. On Apple Silicon (M-series) Macs, test withdocker build --platform linux/amd64 β¦β an image that builds as arm64 locally can still fail on the amd64 cluster.Use a multi-stage build: install/build dependencies in a builder stage, copy only what's needed into a lean final stage.
The app must not run as root inside the container, and the final
USERmust be a numeric UID (e.g.USER 10001:10001). Kubernetes'runAsNonRootcheck can only verify numeric users β a named user (USER appuser) makes the pod fail to start with "container has runAsNonRoot and image has non-numeric user".No passwords, API keys, or
.envfiles baked into the image. Also add.envtodockerfiles/.dockerignoreso it can never leak in viaCOPY.Must build successfully from the repo root with:
docker build -f dockerfiles/Dockerfile -t myapp:latest .
Example β Node.js
Note:
COPYpaths start withsource/because the build context is the repo root (the dependency manifest lives insource/, per guide 02).
# syntax=docker/dockerfile:1
# Stage 1: install production dependencies
FROM node:20-alpine AS builder
WORKDIR /app
COPY source/package*.json ./
RUN npm ci --omit=dev
# Stage 2: lean final image
FROM node:20-alpine
# Numeric UID/GID so Kubernetes' runAsNonRoot can verify the user
RUN addgroup -S -g 10001 appgroup && adduser -S -u 10001 -G appgroup appuser
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY source/ ./
USER 10001:10001
EXPOSE 3000
CMD ["node", "server.js"]
(npm ci --only=production is deprecated in npm 8+; use --omit=dev. npm ci requires source/package-lock.json to be committed.)
Example β Python
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS builder
WORKDIR /app
COPY source/requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.12-slim
# Numeric UID so Kubernetes' runAsNonRoot can verify the user
RUN useradd -m -u 10001 appuser
WORKDIR /app
COPY --from=builder /install /usr/local
COPY source/ ./
USER 10001
EXPOSE 8000
CMD ["python", "app.py"]
.dockerignore
Create dockerfiles/.dockerignore (used automatically when building with -f dockerfiles/Dockerfile on Docker β₯ 19.03 as dockerfiles/Dockerfile.dockerignore, otherwise place it at repo root β safest is repo root and keeping secrets out entirely):
node_modules
.git
.env
*.env
__pycache__
dist
target
Prompt tip
"Write a production-ready multi-stage Dockerfile in
dockerfiles/Dockerfile. The build context is the repository root and the app code is insource/. Use a non-root user. Do not copy any.envfiles or secrets into the image. Targetlinux/amd64."