Skip to content
On this page

Docker 高级特性

多阶段构建

多阶段构建允许在单个 Dockerfile 中使用多个构建阶段,可以显著减少最终镜像的大小。

基本多阶段构建示例

docker
# 构建阶段
FROM node:16-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 运行阶段
FROM node:16-alpine AS runner

WORKDIR /app
COPY package*.json ./
RUN npm install --only=production
RUN npm cache clean --force

# 从构建阶段复制构建产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public

USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

带缓存优化的多阶段构建

docker
# 构建阶段
FROM node:16-alpine AS builder

WORKDIR /app

# 先复制依赖文件,利用 Docker 层缓存
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# 复制源代码并构建
COPY . .
RUN npm run build

# 生产阶段
FROM node:16-alpine AS production

WORKDIR /app

# 复制依赖(利用缓存)
COPY package*.json ./
RUN npm ci --only=production --omit=dev && npm cache clean --force

# 复制构建产物
COPY --from=builder --chown=node:node /app/dist ./dist
COPY --from=builder --chown=node:node /app/public ./public

USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]

构建参数和环境变量

构建参数 (ARG)

docker
FROM node:16-alpine

# 定义构建参数
ARG NODE_ENV=production
ARG BUILD_NUMBER=1
ARG COMMIT_SHA=unknown

ENV NODE_ENV=$NODE_ENV

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

# 使用构建参数
RUN echo "Building version $BUILD_NUMBER with commit $COMMIT_SHA"

EXPOSE 3000
CMD ["npm", "start"]

构建时传入参数:

bash
docker build \
  --build-arg NODE_ENV=production \
  --build-arg BUILD_NUMBER=123 \
  --build-arg COMMIT_SHA=abc123 \
  -t my-app:latest .

环境变量最佳实践

docker
FROM node:16-alpine

# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
ENV TZ=Asia/Shanghai

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=nodejs:nodejs . .

USER nodejs
EXPOSE 3000
CMD ["npm", "start"]

镜像优化技巧

1. 使用 Alpine 镜像

docker
# 使用 Alpine 镜像减小体积
FROM node:16-alpine

# Alpine 镜像需要额外安装依赖
RUN apk add --no-cache \
    curl \
    bash \
    tzdata

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .

EXPOSE 3000
CMD ["npm", "start"]

2. 合并 RUN 指令

docker
FROM node:16-alpine

WORKDIR /app

# 好的做法:合并多个命令
RUN apk add --no-cache curl bash tzdata && \
    npm install -g npm@latest && \
    mkdir -p /app/logs && \
    chmod -R 755 /app/logs

COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .

EXPOSE 3000
CMD ["npm", "start"]

3. 使用 .dockerignore 优化

# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
*.log
.DS_Store
.vscode
.idea

安全最佳实践

1. 使用非 root 用户

docker
FROM node:16-alpine

# 创建用户和组
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 -G nodejs

WORKDIR /app

# 以 root 身份安装依赖
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# 复制文件并更改所有者
COPY . .
RUN chown -R nodejs:nodejs /app

# 切换到非 root 用户
USER nodejs

EXPOSE 3000
CMD ["npm", "start"]

2. 镜像扫描和安全检查

bash
# 使用 Docker Scout 扫描镜像
docker scout cves my-app:latest

# 使用 Trivy 扫描
trivy image my-app:latest

# 使用 Snyk 扫描
snyk container test my-app:latest

3. 安全的 Dockerfile

docker
FROM node:16-alpine

# 设置安全的环境变量
ENV NODE_ENV=production
ENV NPM_CONFIG_LOGLEVEL=warn

# 创建专用用户
RUN addgroup -g 1001 -S appuser && \
    adduser -S appuser -u 1001 -G appuser

# 设置工作目录
WORKDIR /app

# 安装必要的包
RUN apk add --no-cache \
    dumb-init \
    curl \
    ca-certificates

# 复制并安装依赖
COPY package*.json ./
RUN npm ci --only=production --no-audit --no-fund && \
    npm cache clean --force

# 复制应用代码
COPY --chown=appuser:appuser . .

# 使用 dumb-init 作为 PID 1
ENTRYPOINT ["/usr/bin/dumb-init", "--"]

# 切换到非 root 用户
USER appuser

EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
CMD ["npm", "start"]

Docker Compose 高级功能

1. 环境变量管理

创建 .env 文件:

NODE_ENV=production
PORT=3000
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=user
DB_PASSWORD=password
REDIS_URL=redis://localhost:6379

docker-compose.yml:

yaml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "${PORT}:3000"
    environment:
      - NODE_ENV=${NODE_ENV}
      - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
      - REDIS_URL=${REDIS_URL}
    env_file:
      - .env
    depends_on:
      - db
      - redis

  db:
    image: postgres:13
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "${DB_PORT}:5432"

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

2. 多配置文件

开发环境配置 docker-compose.dev.yml:

yaml
version: '3.8'

services:
  app:
    build:
      context: .
      target: development
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=*
    ports:
      - "3000:3000"
    command: ["npm", "run", "dev"]

生产环境配置 docker-compose.prod.yml:

yaml
version: '3.8'

services:
  app:
    image: my-app:latest
    environment:
      - NODE_ENV=production
    ports:
      - "80:3000"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

使用不同配置:

bash
# 开发环境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

3. 自定义网络

yaml
version: '3.8'

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # 内部网络,无法访问外部

services:
  app:
    build: .
    networks:
      - frontend
      - backend
    ports:
      - "3000:3000"

  db:
    image: postgres:13
    networks:
      - backend
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  nginx:
    image: nginx:alpine
    networks:
      - frontend
    ports:
      - "80:80"
    depends_on:
      - app

volumes:
  postgres_data:

秘钥管理

1. Docker Secrets (Docker Swarm)

创建秘钥文件:

bash
echo "mysecretpassword" | docker secret create db_password -

在 docker-compose.yml 中使用:

yaml
version: '3.8'

services:
  app:
    image: my-app:latest
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    external: true

2. 环境变量加密

使用 sops 加密环境文件:

bash
# 安装 sops
# 创建加密的 .env 文件
sops --encrypt .env > .env.encrypted

构建缓存优化

1. 利用构建缓存

docker
FROM node:16-alpine

WORKDIR /app

# 1. 先复制依赖文件(变化较少)
COPY package*.json ./
RUN npm ci --only=production

# 2. 复制应用代码(变化较多)
COPY . .

EXPOSE 3000
CMD ["npm", "start"]

2. 构建缓存清理

bash
# 清理构建缓存
docker builder prune

# 清理所有构建缓存
docker builder prune -a

# 构建时跳过缓存
docker build --no-cache -t my-app .

容器运行时优化

1. 资源限制

bash
# 限制内存和 CPU
docker run -m 512m --cpus="1.0" my-app:latest

# 在 docker-compose.yml 中
services:
  app:
    image: my-app:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

2. 重启策略

yaml
services:
  app:
    image: my-app:latest
    restart: unless-stopped  # 或 always, on-failure, no
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Docker Buildx

Docker Buildx 是下一代 Docker 构建工具,支持跨平台构建。

安装和使用 Buildx

bash
# 检查是否支持 buildx
docker buildx version

# 创建构建器实例
docker buildx create --name mybuilder --use

# 构建多平台镜像
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest .

# 推送到仓库
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest --push .

高级 Buildx 配置

docker
# 使用 BuildKit 功能
# syntax=docker/dockerfile:1.4

FROM node:16-alpine

# 使用缓存挂载
RUN --mount=type=cache,target=/root/.npm \
    npm ci --only=production

# 使用 SSH 挂载
RUN --mount=type=ssh \
    git clone git@github.com:user/repo.git

# 使用 secret 挂载
RUN --mount=type=secret,id=token \
    npm config set '//registry.npmjs.org/:_authToken' $(cat /run/secrets/token)

容器监控和日志

1. 日志配置

yaml
version: '3.8'

services:
  app:
    image: my-app:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    # 或使用其他日志驱动
    # driver: "syslog"
    # driver: "fluentd"
    # driver: "gelf"

2. 健康检查

docker
FROM node:16-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

CMD ["npm", "start"]

总结

Docker 高级特性包括:

  1. 多阶段构建优化镜像大小
  2. 构建参数和环境变量管理
  3. 安全最佳实践
  4. Docker Compose 高级功能
  5. 秘钥管理
  6. 构建缓存优化
  7. 容器运行时优化
  8. Buildx 跨平台构建
  9. 监控和日志配置

这些高级特性可以帮助您构建更安全、更高效、更可维护的容器化应用。