长安的Docker教程长安的Docker教程
首页
快速开始
编程指南
首页
快速开始
编程指南
  • 🎯 Docker入门篇

    • 快速开始
    • Docker是什么?
    • 为什么要用Docker?
    • 安装Docker
    • 第一个容器
  • 📦 Docker基础篇

    • Docker镜像详解
    • 容器操作详解
    • 编写Dockerfile
    • 数据卷(Volumes)
    • Docker网络
  • ⚡ Docker进阶篇

    • Docker Compose
    • 多阶段构建
    • Docker性能优化
    • Docker最佳实践
  • 🚀 实战项目

    • 实战:部署Node.js应用
    • 实战:搭建数据库环境
    • 实战:微服务架构
  • 💡 常见问题

    • 常见问题排查
    • 实用技巧

Docker最佳实践

嘿!长安来总结Docker最佳实践了!这是我多年经验的精华,学会了你就是Docker高手!💪

🎯 安全实践

1. 不要使用root用户

# ❌ 危险:使用root运行
FROM node:18
WORKDIR /app
COPY . .
CMD ["node", "app.js"]    # 默认root用户

# ✅ 安全:创建并使用非root用户
FROM node:18-alpine
WORKDIR /app

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

# 复制文件并设置权限
COPY --chown=nodejs:nodejs . .

# 切换用户
USER nodejs

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

2. 不要在镜像中存储敏感信息

# ❌ 危险:密码硬编码
FROM nginx
ENV DATABASE_PASSWORD=my-secret-password

# ✅ 安全:运行时传入
FROM nginx
# 不设置密码

使用时:

# 通过环境变量传入
docker run -e DATABASE_PASSWORD=secret my-app

# 或使用secrets(Docker Swarm/Kubernetes)
docker secret create db_password ./password.txt

永远不要:

  • 把密码写在Dockerfile里
  • 把密钥提交到Git
  • 把.env文件打包进镜像

3. 扫描镜像漏洞

# 使用Docker Scout
docker scout quickview my-app

# 使用Trivy
trivy image my-app

# 使用Snyk
snyk container test my-app

4. 使用官方镜像

# ✅ 好:官方镜像,有安全保障
FROM node:18-alpine
FROM python:3.11-slim
FROM nginx:alpine

# ❌ 不好:不知名的镜像
FROM random-user/node-with-stuff

5. 保持镜像更新

# 定期拉取最新版本
docker pull node:18-alpine

# 重新构建镜像
docker build -t my-app .

6. 只暴露必要的端口

# ❌ 不好:暴露所有端口
EXPOSE 22 80 443 3000 3306 6379

# ✅ 好:只暴露必要的端口
EXPOSE 80

📦 镜像实践

1. 使用明确的版本标签

# ❌ 不好:latest标签(不确定)
FROM node:latest

# ✅ 好:明确版本
FROM node:18.17.0-alpine3.18

# ✅ 也可以:主版本号
FROM node:18-alpine

2. 保持镜像小巧

# 技巧1:使用alpine
FROM python:3.11-alpine    # 50MB
# 而不是
FROM python:3.11           # 1GB

# 技巧2:多阶段构建
FROM node:18 AS builder
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

# 技巧3:清理缓存
RUN apt-get update && \
    apt-get install -y package && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

3. 合理组织层

# ✅ 好:按变化频率组织
FROM node:18-alpine
WORKDIR /app

# 1. 很少变化:系统依赖
RUN apk add --no-cache curl

# 2. 偶尔变化:应用依赖
COPY package*.json ./
RUN npm ci --only=production

# 3. 经常变化:源代码
COPY . .

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

4. 使用.dockerignore

# .dockerignore
**/.git
**/.DS_Store
**/node_modules
**/npm-debug.log
**/.env
**/.env.*
**/dist
**/build
**/coverage
**/.vscode
**/.idea
**/README.md
**/*.md

5. 单一职责原则

# ✅ 好:一个容器一个服务
docker run nginx              # Web服务器
docker run mysql              # 数据库
docker run redis              # 缓存

# ❌ 不好:一个容器多个服务
# 不要在一个容器里同时运行nginx+mysql+redis

🎨 开发实践

1. 开发环境和生产环境分离

# docker-compose.yml(基础配置)
version: '3.8'

services:
  app:
    build: .
    restart: unless-stopped

# docker-compose.dev.yml(开发环境)
version: '3.8'

services:
  app:
    volumes:
      - .:/app                  # 代码热更新
    environment:
      NODE_ENV: development
    ports:
      - "3000:3000"
      - "9229:9229"             # 调试端口

# docker-compose.prod.yml(生产环境)
version: '3.8'

services:
  app:
    environment:
      NODE_ENV: production
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G

使用:

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

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

2. 使用健康检查

# Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1
# docker-compose.yml
services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s

3. 使用标签管理容器

services:
  app:
    labels:
      com.example.environment: "production"
      com.example.team: "backend"
      com.example.project: "myapp"

查询:

# 查找特定标签的容器
docker ps --filter "label=com.example.environment=production"

4. 日志管理

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

或使用集中式日志:

services:
  app:
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://logs.example.com:514"

5. 环境变量管理

# .env
DB_PASSWORD=secret
API_KEY=key123

# docker-compose.yml
services:
  app:
    env_file:
      - .env
    environment:
      NODE_ENV: production
      DB_HOST: db
      DB_PASSWORD: ${DB_PASSWORD}

记得把.env加入.gitignore!

🚀 运维实践

1. 资源限制

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

或命令行:

docker run \
  --memory="512m" \
  --memory-swap="1g" \
  --cpus="1.5" \
  my-app

2. 重启策略

services:
  app:
    restart: unless-stopped      # 推荐
  
  critical-service:
    restart: always             # 关键服务
    
  one-time-task:
    restart: on-failure         # 一次性任务

3. 数据备份

#!/bin/bash
# 备份脚本

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

# 备份数据卷
docker run --rm \
  -v mysql-data:/data \
  -v $BACKUP_DIR:/backup \
  alpine \
  tar -czf /backup/mysql_$DATE.tar.gz -C /data .

# 备份数据库
docker exec mysql \
  mysqldump -u root -p${DB_PASSWORD} --all-databases \
  > $BACKUP_DIR/db_$DATE.sql

echo "备份完成: $DATE"

4. 监控

# docker-compose.yml
version: '3.8'

services:
  # 应用
  app:
    image: my-app
    
  # Prometheus监控
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"
      
  # Grafana可视化
  grafana:
    image: grafana/grafana
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin

volumes:
  prometheus-data:
  grafana-data:

5. 定期清理

#!/bin/bash
# 清理脚本

echo "清理停止的容器..."
docker container prune -f

echo "清理未使用的镜像..."
docker image prune -a -f

echo "清理未使用的数据卷..."
docker volume prune -f

echo "清理未使用的网络..."
docker network prune -f

echo "清理构建缓存..."
docker builder prune -a -f

echo "清理完成!"
docker system df

📝 命名规范

1. 镜像命名

# 格式:项目名/服务名:版本
myproject/frontend:1.0.0
myproject/backend:1.0.0
myproject/nginx:latest

# 或者:公司名/项目名/服务名:版本
example-com/myproject/api:v1.2.3

2. 容器命名

services:
  # 格式:项目-服务-环境
  myproject-frontend-prod:
    container_name: myproject-frontend-prod
    
  myproject-backend-prod:
    container_name: myproject-backend-prod

3. 数据卷命名

# 格式:项目-服务-用途
myproject-mysql-data
myproject-redis-data
myproject-nginx-logs

4. 网络命名

# 格式:项目-用途
myproject-frontend
myproject-backend
myproject-database

🎯 CI/CD实践

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@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
        
      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
          
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myapp:latest
            myapp:${{ github.sha }}
          cache-from: type=registry,ref=myapp:buildcache
          cache-to: type=registry,ref=myapp:buildcache,mode=max

💡 故障排查实践

1. 查看日志

# 实时日志
docker-compose logs -f

# 特定服务
docker-compose logs -f app

# 最后100行
docker-compose logs --tail=100 app

2. 进入容器调试

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

# 以root用户进入
docker exec -it -u root my-app sh

# 查看进程
docker top my-app

# 查看资源使用
docker stats my-app

3. 检查健康状态

# 查看健康状态
docker inspect --format='{{.State.Health.Status}}' my-app

# 查看健康检查日志
docker inspect --format='{{json .State.Health}}' my-app | jq

📊 性能监控实践

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

services:
  # cAdvisor - 容器监控
  cadvisor:
    image: gcr.io/cadvisor/cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"
      
  # Node Exporter - 系统监控
  node-exporter:
    image: prom/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'

💡 小结

今天长安总结了Docker最佳实践:

安全实践

  1. 使用非root用户
  2. 不存储敏感信息
  3. 扫描镜像漏洞
  4. 使用官方镜像
  5. 定期更新

镜像实践

  1. 明确版本标签
  2. 保持镜像小巧
  3. 合理组织层
  4. 使用.dockerignore
  5. 单一职责

运维实践

  1. 资源限制
  2. 重启策略
  3. 数据备份
  4. 监控告警
  5. 定期清理

开发实践

  1. 环境分离
  2. 健康检查
  3. 标签管理
  4. 日志管理
  5. 命名规范

🚀 下一步

理论学完了,该实战了!下一章长安带你 部署Node.js应用!


💬 长安的最佳实践心得:

最佳实践不是教条,而是经验总结。

我踩过的坑有:

  • 用root用户被黑客攻击
  • 密码提交到Git泄露
  • 镜像太大部署超时
  • 没做备份数据丢失
  • 资源不限制服务器崩溃

每个最佳实践背后,都有血的教训!

所以请认真对待这些实践,它们能帮你避免90%的坑!

下一章咱们实战,加油!💪

在 GitHub 上编辑此页
Prev
Docker性能优化