Docker开发环境搭建与最佳实践

开发工具分享

Docker开发环境搭建与最佳实践

Docker是现代化的容器化平台,可以极大地简化开发环境的搭建和管理。本文将分享Docker在开发中的最佳实践。

基础概念

1. Docker核心组件

Docker架构:
├── Docker Engine
│   ├── Docker Daemon
│   ├── Docker Client
│   └── Docker API
├── Docker Images(镜像)
├── Docker Containers(容器)
├── Docker Networks(网络)
└── Docker Volumes(存储卷)

2. 基础命令

# 镜像管理
docker pull nginx:latest              # 拉取镜像
docker images                         # 查看镜像列表
docker rmi nginx                      # 删除镜像
docker build -t myapp:1.0 .          # 构建镜像

# 容器管理
docker run -d -p 80:80 nginx         # 运行容器
docker ps                             # 查看运行中的容器
docker ps -a                          # 查看所有容器
docker stop container_id             # 停止容器
docker start container_id            # 启动容器
docker rm container_id               # 删除容器
docker exec -it container_id bash    # 进入容器

# 日志和监控
docker logs container_id             # 查看日志
docker logs -f container_id          # 实时查看日志
docker stats                          # 查看资源使用

Dockerfile最佳实践

1. 基础镜像选择

# 生产环境使用精简镜像
FROM node:18-alpine

# 或者使用多阶段构建的基础镜像
FROM node:18 AS builder
FROM node:18-alpine AS production

# Python项目
FROM python:3.11-slim

# Java项目
FROM eclipse-temurin:17-jre-alpine

# Go项目
FROM golang:1.21-alpine AS builder
FROM alpine:latest AS production

2. 多阶段构建

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

WORKDIR /app

# 复制依赖文件
COPY package*.json ./
RUN npm ci --only=production

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

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

WORKDIR /app

# 只复制必要的文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

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

EXPOSE 3000

CMD ["npm", "start"]

3. 优化构建缓存

FROM node:18-alpine

WORKDIR /app

# 先复制依赖文件(利用缓存)
COPY package*.json ./
RUN npm ci --only=production

# 再复制源代码(经常变化)
COPY . .

# 构建应用
RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]

4. 安全最佳实践

FROM node:18-alpine

# 更新系统包
RUN apk update && apk upgrade

WORKDIR /app

# 使用非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S appuser -u 1001

# 复制应用文件
COPY --chown=appuser:nodejs package*.json ./
RUN npm ci --only=production

COPY --chown=appuser:nodejs . .

# 切换到非root用户
USER appuser

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

EXPOSE 3000

CMD ["node", "server.js"]

Docker Compose开发环境

1. 基础配置

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - db
      - redis
    command: npm run dev

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

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

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

volumes:
  postgres_data:
  redis_data:

2. 多环境配置

# docker-compose.base.yml
version: '3.8'

services:
  app:
    build: .
    volumes:
      - .:/app
      - /app/node_modules

  db:
    image: postgres:15-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
# docker-compose.dev.yml
version: '3.8'

services:
  app:
    environment:
      - NODE_ENV=development
      - DEBUG=true
    ports:
      - "3000:3000"
    command: npm run dev

  db:
    environment:
      POSTGRES_USER: dev_user
      POSTGRES_PASSWORD: dev_pass
      POSTGRES_DB: dev_db
    ports:
      - "5432:5432"
# docker-compose.prod.yml
version: '3.8'

services:
  app:
    environment:
      - NODE_ENV=production
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

  db:
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - /host/path/to/postgres:/var/lib/postgresql/data

3. 使用多配置文件

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

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

# 指定环境变量文件
docker-compose --env-file .env.prod up -d

开发工作流

1. 热重载配置

# docker-compose.yml
services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true
      - WATCHPACK_POLLING=true
    command: npm start

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    ports:
      - "5000:5000"
    volumes:
      - ./backend:/app
      - /app/__pycache__
    environment:
      - FLASK_ENV=development
      - FLASK_DEBUG=1
    command: flask run --host=0.0.0.0 --reload

2. 调试配置

# Dockerfile.debug
FROM node:18-alpine

WORKDIR /app

# 安装调试工具
RUN npm install -g nodemon

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000 9229

CMD ["nodemon", "--inspect=0.0.0.0:9229", "server.js"]
# docker-compose.debug.yml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.debug
    ports:
      - "3000:3000"
      - "9229:9229"
    volumes:
      - .:/app
      - /app/node_modules

3. 开发脚本

#!/bin/bash
# dev.sh - 开发环境管理脚本

case "$1" in
  start)
    echo "Starting development environment..."
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
    ;;
  stop)
    echo "Stopping development environment..."
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml down
    ;;
  restart)
    echo "Restarting development environment..."
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml restart
    ;;
  logs)
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml logs -f
    ;;
  build)
    echo "Building images..."
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml build
    ;;
  clean)
    echo "Cleaning up..."
    docker-compose -f docker-compose.yml -f docker-compose.dev.yml down -v
    docker system prune -f
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|logs|build|clean}"
    exit 1
    ;;
esac

数据库管理

1. 数据库迁移

# docker-compose.yml
services:
  migrate:
    build: .
    command: npm run migrate
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp

  seed:
    build: .
    command: npm run seed
    depends_on:
      - migrate
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp

2. 数据备份

#!/bin/bash
# backup.sh

BACKUP_DIR="./backups"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# 备份数据库
docker-compose exec -T db pg_dump -U user myapp > $BACKUP_DIR/backup_$DATE.sql

# 压缩备份
gzip $BACKUP_DIR/backup_$DATE.sql

# 删除旧备份(保留7天)
find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +7 -delete

echo "Backup completed: backup_$DATE.sql.gz"

网络配置

1. 自定义网络

version: '3.8'

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

services:
  web:
    image: nginx
    networks:
      - frontend
    ports:
      - "80:80"

  app:
    build: .
    networks:
      - frontend
      - backend

  db:
    image: postgres
    networks:
      - backend

2. 服务发现

version: '3.8'

services:
  web:
    image: nginx
    networks:
      - mynet

  api:
    build: .
    networks:
      - mynet
    # 可以通过服务名访问其他服务
    # http://web, http://api

networks:
  mynet:
    driver: bridge

性能优化

1. 镜像优化

# 使用多阶段构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]

2. 构建缓存

# 优化层缓存
FROM node:18-alpine

WORKDIR /app

# 依赖层(不经常变化)
COPY package*.json ./
RUN npm ci --only=production

# 应用层(经常变化)
COPY . .

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

3. 资源限制

version: '3.8'

services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

安全实践

1. 镜像安全扫描

# 使用Trivy扫描
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image myapp:latest

# 使用Docker Scout
docker scout cves myapp:latest

2. 非root用户

FROM node:18-alpine

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

WORKDIR /app

COPY --chown=appuser:nodejs package*.json ./
RUN npm ci --only=production

COPY --chown=appuser:nodejs . .

USER appuser

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

3. 只读文件系统

version: '3.8'

services:
  app:
    image: myapp
    read_only: true
    tmpfs:
      - /tmp
      - /var/cache
    volumes:
      - app_logs:/app/logs

volumes:
  app_logs:

故障排查

1. 日志查看

# 查看容器日志
docker logs container_id
docker logs -f container_id  # 实时日志
docker logs --tail 100 container_id  # 最后100行

# 查看多个服务日志
docker-compose logs -f app db

2. 进入容器

# 进入运行中的容器
docker exec -it container_id /bin/sh
docker exec -it container_id /bin/bash

# 以root用户进入
docker exec -it -u root container_id /bin/sh

3. 网络调试

# 查看容器网络
docker network ls
docker network inspect bridge

# 测试网络连通性
docker exec container_id ping db
docker exec container_id curl http://api:3000/health

CI/CD集成

1. GitHub Actions

# .github/workflows/docker.yml
name: Docker Build and Push

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Login to Docker Hub
      uses: docker/login-action@v3
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
    
    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: |
          ${{ secrets.DOCKER_USERNAME }}/myapp:${{ github.sha }}
          ${{ secrets.DOCKER_USERNAME }}/myapp:latest
        cache-from: type=gha
        cache-to: type=gha,mode=max

2. GitLab CI

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

test:
  stage: test
  image: $DOCKER_IMAGE
  script:
    - npm test

deploy:
  stage: deploy
  image: alpine/k8s:latest
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE
  only:
    - main

总结

Docker开发环境的关键点:

  1. 镜像优化:使用多阶段构建,减小镜像体积
  2. 缓存利用:合理组织Dockerfile指令顺序
  3. 安全配置:使用非root用户,定期扫描漏洞
  4. 开发体验:配置热重载,优化调试流程
  5. 多环境管理:使用Compose覆盖文件管理不同环境
  6. 数据持久化:正确使用Volumes管理数据
  7. CI/CD集成:自动化构建和部署流程

通过合理使用Docker,可以实现开发环境的一致性和可移植性,提高开发效率。