正在加载,请稍候…

Docker 开发工作流:Compose、多阶段构建与开发环境

使用 Docker 优化开发工作流。学习多阶段构建、用于本地开发的 Docker Compose、绑定挂载、热重载以及生产级 Docker 模式。

Docker 开发工作流:Compose、多阶段构建与开发环境

Docker 开发工作流

多阶段 Dockerfile

# 阶段 1:依赖
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

# 阶段 2:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 阶段 3:生产(最小镜像)
FROM node:20-alpine AS production
WORKDIR /app

# 非 root 用户
RUN addgroup -S app && adduser -S -G app app
USER app

COPY --chown=app:app --from=builder /app/dist ./dist
COPY --chown=app:app --from=deps /app/node_modules ./node_modules
COPY --chown=app:app package.json ./

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

# 阶段 4:开发(包含 devDependencies 和热重载)
FROM node:20-alpine AS development
WORKDIR /app

# 安装所有依赖,包括 devDependencies
COPY package*.json ./
RUN npm install  # 不是 npm ci - 允许更新

COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

Docker 开发工作流:Compose、多阶段构建与开发环境 插图

用于开发的 Docker Compose

# docker-compose.yml
version: '3.9'

services:
  app:
    build:
      context: .
      target: development  # 使用开发阶段
    ports:
      - "3000:3000"
      - "9229:9229"  # 调试端口
    volumes:
      - .:/app                          # 绑定挂载用于热重载
      - /app/node_modules               # 匿名卷(防止主机覆盖)
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@postgres:5432/devdb
      - REDIS_URL=redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    command: npm run dev

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: devdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d devdb"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  adminer:
    image: adminer
    ports:
      - "8080:8080"
    depends_on:
      - postgres

volumes:
  postgres_data:
  redis_data:

用于生产的 Docker Compose 覆盖

# docker-compose.prod.yml
version: '3.9'

services:
  app:
    build:
      target: production
    restart: unless-stopped
    environment:
      - NODE_ENV=production
    volumes: []  # 生产环境无绑定挂载
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
# 使用覆盖文件
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Docker 开发工作流:Compose、多阶段构建与开发环境 插图

在 Docker 中调试

# 进入运行中的容器
docker exec -it myapp-app-1 sh

# 在容器中调试 Node.js
# 在 docker-compose.yml 中:
# command: node --inspect=0.0.0.0:9229 dist/server.js

# 然后连接 VS Code 调试器到端口 9229

# 查看带时间戳的日志
docker compose logs -f --timestamps app

# 检查容器状态
docker inspect myapp-app-1 | jq '.[0].State'
docker stats --no-stream

# 从容器复制文件
docker cp myapp-app-1:/app/logs ./local-logs

BuildKit 高级功能

# 启用 BuildKit 缓存挂载
# syntax=docker/dockerfile:1

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./

# 在构建之间缓存 npm 缓存
RUN --mount=type=cache,target=/root/.npm \
    npm ci --prefer-offline

COPY . .
RUN npm run build
# 使用 BuildKit 构建
DOCKER_BUILDKIT=1 docker build .

# 或在 daemon.json 中设置
{
  "features": { "buildkit": true }
}

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

# 层检查
docker buildx imagetools inspect myapp:latest
docker history myapp:latest

Docker 开发工作流:Compose、多阶段构建与开发环境 插图

Docker 网络

# 创建自定义网络
docker network create myapp-network --driver bridge --subnet 172.20.0.0/16

# 连接容器
docker run --network myapp-network --name backend myapp-backend
docker run --network myapp-network --name frontend myapp-frontend

# DNS 解析:容器可以通过名称互相访问
# 从 frontend 容器中 http://backend:3000 可访问

# 主机网络(仅 Linux,用于性能)
docker run --network host myapp

# 端口检查
docker port myapp-app-1

有用的 Docker 命令

# 清理
docker system prune -af --volumes  # 移除所有未使用的内容
docker image prune -a               # 移除所有未使用的镜像

# 检查构建
docker buildx build --progress=plain . 2>&1 | head -50

# 大小分析
dive myapp:latest  # 交互式层浏览器

# 资源使用
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"