docker-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Docker Best Practices

Docker最佳实践

Multi-Stage Build

多阶段构建

dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production

FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/healthz || exit 1
CMD ["node", "dist/server.js"]
Separate dependency installation from build steps. Final stage contains only runtime artifacts.
dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production

FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/healthz || exit 1
CMD ["node", "dist/server.js"]
将依赖安装与构建步骤分离。最终阶段仅包含运行时产物。

Python Multi-Stage

Python多阶段构建

dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
RUN useradd --create-home appuser
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . .
USER appuser
CMD ["gunicorn", "app:create_app()", "-b", "0.0.0.0:8000", "-w", "4"]
dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
RUN useradd --create-home appuser
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . .
USER appuser
CMD ["gunicorn", "app:create_app()", "-b", "0.0.0.0:8000", "-w", "4"]

Docker Compose

Docker Compose配置

yaml
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      target: runtime
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/app
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 512M

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru

volumes:
  pgdata:
yaml
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      target: runtime
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/app
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 512M

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru

volumes:
  pgdata:

.dockerignore

.dockerignore配置

node_modules
.git
.env*
*.md
docker-compose*.yml
.github
coverage
dist
Always include a
.dockerignore
to reduce build context size and prevent leaking secrets.
node_modules
.git
.env*
*.md
docker-compose*.yml
.github
coverage
dist
务必添加
.dockerignore
文件以减小构建上下文大小,防止泄露敏感信息。

Image Optimization Tips

镜像优化技巧

bash
undefined
bash
undefined

Check image size breakdown

查看镜像大小明细

docker history --human --no-trunc <image>
docker history --human --no-trunc <image>

Use dive for layer analysis

使用dive分析镜像层

dive <image>
dive <image>

Multi-arch build

多架构构建

docker buildx build --platform linux/amd64,linux/arm64 -t registry/app:1.0 --push .

Combine `RUN` commands to reduce layers. Order instructions from least to most frequently changing for cache efficiency.
docker buildx build --platform linux/amd64,linux/arm64 -t registry/app:1.0 --push .

合并`RUN`命令以减少镜像层数。将指令按从最少变更到最频繁变更的顺序排列,以提高缓存效率。

Anti-Patterns

反模式

  • Running as root inside containers
  • Using
    ADD
    when
    COPY
    suffices (ADD auto-extracts tarballs, pulls URLs)
  • Storing secrets in environment variables in Dockerfiles
  • Not pinning base image versions (
    FROM node:latest
    )
  • Missing
    .dockerignore
    causing large build contexts
  • Installing dev dependencies in production images
  • 在容器内以root用户运行
  • COPY
    足够时使用
    ADD
    (ADD会自动解压tar包、拉取URL)
  • 在Dockerfile的环境变量中存储敏感信息
  • 未固定基础镜像版本(如
    FROM node:latest
  • 缺少
    .dockerignore
    导致构建上下文过大
  • 在生产镜像中安装开发依赖

Checklist

检查清单

  • Multi-stage build separates build and runtime stages
  • Non-root user created and used with
    USER
    directive
  • Base images pinned to specific versions (e.g.,
    node:22-alpine
    )
  • .dockerignore
    excludes
    .git
    ,
    node_modules
    ,
    .env
  • HEALTHCHECK
    instruction defined
  • Production image contains no build tools or dev dependencies
  • docker-compose
    uses
    depends_on
    with health conditions
  • Secrets passed via build secrets or runtime mounts, not
    ENV
    in Dockerfile
  • 多阶段构建分离了构建阶段与运行时阶段
  • 创建并使用非root用户(通过
    USER
    指令)
  • 基础镜像固定到特定版本(例如
    node:22-alpine
  • .dockerignore
    排除了
    .git
    node_modules
    .env
  • 定义了
    HEALTHCHECK
    指令
  • 生产镜像不包含构建工具或开发依赖
  • docker-compose
    使用带健康检查条件的
    depends_on
  • 敏感信息通过构建密钥或运行时挂载传递,而非Dockerfile中的
    ENV