Skip to content

Docker 容器化实践 ​

🎯 概述 ​

Docker 是一个开源的容器化平台,能够将应用程序及其依赖项打包到轻量级、可移植的容器中。本文将分享Docker在实际项目中的使用经验和最佳实践。

📚 基础概念 ​

容器 vs 虚拟机 ​

┌─────────────────────────────────────┐
│           虚拟机架构                │
├─────────────────────────────────────┤
│  App1  │  App2  │  App3  │  App4   │
├─────────────────────────────────────┤
│  Guest OS  │  Guest OS  │  Guest OS │
├─────────────────────────────────────┤
│           Hypervisor                │
├─────────────────────────────────────┤
│           Host OS                   │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│           容器架构                  │
├─────────────────────────────────────┤
│  App1  │  App2  │  App3  │  App4   │
├─────────────────────────────────────┤
│           Docker Engine             │
├─────────────────────────────────────┤
│           Host OS                   │
└─────────────────────────────────────┘

核心组件 ​

  • 镜像 (Image): 只读的模板,用于创建容器
  • 容器 (Container): 镜像的运行实例
  • 仓库 (Repository): 存储镜像的地方
  • Dockerfile: 用于构建镜像的文本文件

🛠️ 实践应用 ​

1. 基础Dockerfile ​

dockerfile
# 多阶段构建示例
FROM node:18-alpine AS builder

# 设置工作目录
WORKDIR /app

# 复制package文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用
RUN npm run build

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

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

# 设置工作目录
WORKDIR /app

# 复制构建产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

# 切换到非root用户
USER nextjs

# 暴露端口
EXPOSE 3000

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

# 启动命令
CMD ["npm", "start"]

2. 微服务架构 ​

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

services:
  # API网关
  api-gateway:
    build: ./api-gateway
    ports:
      - "8080:8080"
    environment:
      - NODE_ENV=production
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
      - user-service
      - order-service
    networks:
      - app-network

  # 用户服务
  user-service:
    build: ./user-service
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=user_db
      - DB_USER=root
      - DB_PASSWORD=password
    depends_on:
      - mysql
    networks:
      - app-network

  # 订单服务
  order-service:
    build: ./order-service
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=order_db
      - DB_USER=root
      - DB_PASSWORD=password
    depends_on:
      - mysql
    networks:
      - app-network

  # 数据库
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app_db
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"
    networks:
      - app-network

  # Redis缓存
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - app-network

  # Nginx负载均衡
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - api-gateway
    networks:
      - app-network

volumes:
  mysql_data:
  redis_data:

networks:
  app-network:
    driver: bridge

3. 开发环境配置 ​

yaml
# docker-compose.dev.yml
version: '3.8'

services:
  # 开发服务器
  app-dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
      - "9229:9229"  # Node.js调试端口
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=app:*
    command: npm run dev
    networks:
      - dev-network

  # 开发数据库
  mysql-dev:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: dev_password
      MYSQL_DATABASE: dev_db
    ports:
      - "3307:3306"
    volumes:
      - mysql_dev_data:/var/lib/mysql
    networks:
      - dev-network

  # 开发Redis
  redis-dev:
    image: redis:7-alpine
    ports:
      - "6380:6379"
    networks:
      - dev-network

volumes:
  mysql_dev_data:

networks:
  dev-network:
    driver: bridge

🚀 高级技巧 ​

1. 多阶段构建优化 ​

dockerfile
# 前端应用多阶段构建
FROM node:18-alpine AS dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

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

FROM nginx:alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

2. 健康检查配置 ​

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

# 或者使用自定义脚本
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
  CMD ./health-check.sh
bash
#!/bin/bash
# health-check.sh
set -e

# 检查应用是否响应
curl -f http://localhost:3000/health || exit 1

# 检查数据库连接
node -e "
const mysql = require('mysql2/promise');
mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME
}).then(() => process.exit(0))
.catch(() => process.exit(1));
"

3. 安全配置 ​

dockerfile
# 安全最佳实践
FROM node:18-alpine

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

# 设置工作目录
WORKDIR /app

# 复制文件并设置权限
COPY --chown=nextjs:nodejs package*.json ./
RUN npm ci --only=production && npm cache clean --force

COPY --chown=nextjs:nodejs . .

# 切换到非root用户
USER nextjs

# 设置文件权限
RUN chmod -R 755 /app

# 暴露端口
EXPOSE 3000

# 启动应用
CMD ["npm", "start"]

🔧 监控和日志 ​

1. 日志配置 ​

yaml
# docker-compose.yml 日志配置
services:
  app:
    build: .
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    labels:
      - "com.example.service=app"
      - "com.example.version=1.0.0"

2. 监控配置 ​

yaml
# 监控服务
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'

  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana

📦 部署策略 ​

1. 蓝绿部署 ​

bash
#!/bin/bash
# blue-green-deploy.sh

# 当前运行的是蓝色环境
CURRENT_COLOR="blue"
NEW_COLOR="green"

# 启动绿色环境
docker-compose -f docker-compose.${NEW_COLOR}.yml up -d

# 等待绿色环境就绪
echo "等待绿色环境启动..."
sleep 30

# 健康检查
if curl -f http://localhost:3001/health; then
    echo "绿色环境健康检查通过"
    
    # 切换流量到绿色环境
    docker-compose -f docker-compose.nginx.yml up -d
    
    # 停止蓝色环境
    docker-compose -f docker-compose.${CURRENT_COLOR}.yml down
    
    echo "部署完成,当前环境:${NEW_COLOR}"
else
    echo "绿色环境健康检查失败,回滚到蓝色环境"
    docker-compose -f docker-compose.${NEW_COLOR}.yml down
    exit 1
fi

2. 滚动更新 ​

yaml
# docker-compose.rolling.yml
version: '3.8'

services:
  app:
    image: myapp:latest
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
        order: start-first
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3

🎯 最佳实践 ​

1. 镜像优化 ​

  • 使用多阶段构建减少镜像大小
  • 选择合适的基础镜像
  • 清理不必要的文件和缓存
  • 使用.dockerignore文件

2. 容器编排 ​

  • 合理设置资源限制
  • 使用健康检查
  • 配置重启策略
  • 实现优雅关闭

3. 安全考虑 ​

  • 使用非root用户运行容器
  • 定期更新基础镜像
  • 扫描镜像漏洞
  • 限制容器权限

4. 监控和日志 ​

  • 集中化日志管理
  • 设置监控告警
  • 定期备份数据
  • 性能指标收集

Docker让部署更简单! 🐳