🐳 Docker 完全指南

📌 Docker 核心概念

什么是 Docker?

Docker 是一个开源的应用容器引擎,使用 Go 语言开发,基于 Linux 内核的 cgroup、namespace、Union FS 等技术,对应用进程进行封装隔离,属于操作系统层面的虚拟化技术。

核心组件

组件 说明 类比
Docker Daemon Docker 守护进程,负责创建、运行容器 工厂的生产线
Docker Client 客户端,通过 CLI 与 Daemon 交互 工厂的控制台
Images 只读模板,用于创建容器 产品的设计图纸
Containers 运行中的镜像实例 根据图纸生产的产品
Registry 镜像仓库(Docker Hub) 产品仓库
Dockerfile 构建镜像的指令文件 产品生产说明书

🚀 快速开始

1. 安装 Docker

# macOS (使用 Homebrew)
brew install --cask docker

# Ubuntu/Debian
sudo apt update
sudo apt install docker.io docker-compose

# CentOS/RHEL
sudo yum install docker
sudo systemctl start docker
sudo systemctl enable docker

# Windows
# 下载 Docker Desktop: https://www.docker.com/products/docker-desktop

# 验证安装
docker --version
docker-compose --version
docker run hello-world

2. 配置镜像加速(中国用户)

// Docker Desktop: Preferences → Docker Engine
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ],
  "experimental": false,
  "features": {
    "buildkit": true
  }
}

// Linux: /etc/docker/daemon.json
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
EOF
sudo systemctl restart docker

🛠️ Docker 基础命令

镜像管理

# 搜索镜像
docker search nginx

# 拉取镜像
docker pull nginx:latest
docker pull node:18-alpine

# 查看本地镜像
docker images
docker image ls

# 删除镜像
docker rmi nginx:latest
docker image rm <image_id>

# 清理未使用镜像
docker image prune -a

# 查看镜像详情
docker inspect nginx:latest

# 导出/导入镜像
docker save -o nginx.tar nginx:latest
docker load -i nginx.tar

容器管理

# 运行容器
docker run nginx
docker run -d --name my-nginx -p 8080:80 nginx
docker run -it node:18-alpine sh

# 查看容器
docker ps          # 运行中的容器
docker ps -a       # 所有容器
docker ps -q       # 只显示容器ID

# 停止/启动容器
docker stop my-nginx
docker start my-nginx
docker restart my-nginx

# 进入容器
docker exec -it my-nginx bash
docker exec -it my-nginx sh

# 查看日志
docker logs my-nginx
docker logs -f my-nginx      # 实时日志
docker logs --tail 100 my-nginx

# 删除容器
docker rm my-nginx
docker rm -f my-nginx       # 强制删除运行中的容器
docker container prune      # 清理已停止的容器

# 复制文件
docker cp ./file.txt my-nginx:/app/file.txt
docker cp my-nginx:/app/logs ./logs

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

网络管理

# 查看网络
docker network ls

# 创建网络
docker network create my-network

# 连接容器到网络
docker network connect my-network my-nginx

# 断开网络
docker network disconnect my-network my-nginx

# 查看网络详情
docker network inspect bridge

# 清理未使用网络
docker network prune

数据卷管理

# 创建数据卷
docker volume create my-volume

# 查看数据卷
docker volume ls
docker volume inspect my-volume

# 使用数据卷
docker run -v my-volume:/data nginx
docker run --mount source=my-volume,target=/data nginx

# 删除数据卷
docker volume rm my-volume
docker volume prune

📦 Dockerfile 深度指南

基础结构

# Dockerfile 示例
# 1. 基础镜像
FROM node:18-alpine AS builder

# 2. 元数据标签
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="Frontend application"

# 3. 工作目录
WORKDIR /app

# 4. 环境变量
ENV NODE_ENV=production
ENV PORT=3000

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

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

# 7. 复制源代码
COPY . .

# 8. 构建应用
RUN npm run build

# 9. 多阶段构建 - 生产阶段
FROM nginx:alpine AS production

# 10. 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

# 11. 暴露端口
EXPOSE 80

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

# 13. 启动命令
CMD ["nginx", "-g", "daemon off;"]

最佳实践指南

# ✅ 最佳实践 Dockerfile
# 1. 使用官方镜像作为基础
FROM node:18-alpine AS base

# 2. 设置非root用户(安全)
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# 3. 安装系统依赖(最小化)
RUN apk add --no-cache \
    curl \
    git \
    python3 \
    make \
    g++

# 4. 设置工作目录和权限
WORKDIR /app
RUN chown -R nodejs:nodejs /app
USER nodejs

# 5. 环境变量(构建参数)
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
ENV PATH=/app/node_modules/.bin:$PATH

# 6. 复制包管理文件(利用缓存层)
COPY --chown=nodejs:nodejs package*.json ./

# 7. 根据环境安装依赖
RUN if [ "$NODE_ENV" = "development" ]; \
    then npm install; \
    else npm ci --only=production; \
    fi

# 8. 复制源代码(最后一步,避免缓存失效)
COPY --chown=nodejs:nodejs . .

# 9. 构建应用
RUN npm run build

# 10. 生产阶段
FROM nginx:alpine

# 11. 复制构建产物
COPY --from=base /app/dist /usr/share/nginx/html

# 12. 自定义Nginx配置
COPY nginx/default.conf /etc/nginx/conf.d/default.conf

# 13. 暴露端口
EXPOSE 80

# 14. 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1

# 15. 启动命令
CMD ["nginx", "-g", "daemon off;"]

前端项目 Dockerfile 模板

React 项目

# 多阶段构建:开发 → 构建 → 生产
FROM node:18-alpine AS development

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]

FROM development AS builder
RUN npm run build

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

Vue 项目

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

FROM nginx:alpine
RUN apk add --no-cache curl
COPY --from=builder /app/dist /usr/share/nginx/html
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost/ || exit 1
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

Next.js 项目

# 使用官方 Next.js Docker 镜像
FROM node:18-alpine AS base

# 安装依赖
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci

# 重新构建源码
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# 生产镜像
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

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

构建和优化

# 构建镜像
docker build -t myapp:latest .
docker build -t myapp:v1.0.0 .

# 多阶段构建指定阶段
docker build --target development -t myapp:dev .

# 构建参数
docker build \
  --build-arg NODE_ENV=production \
  --build-arg API_URL=https://api.example.com \
  -t myapp:latest .

# 使用 BuildKit(性能更好)
DOCKER_BUILDKIT=1 docker build -t myapp:latest .

# 查看镜像构建历史
docker history myapp:latest

# 镜像优化技巧
# 1. 使用 .dockerignore 文件
echo "node_modules
npm-debug.log
.git
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
build
dist
coverage" > .dockerignore

# 2. 多阶段构建减少镜像大小
# 3. 使用 Alpine 基础镜像
# 4. 合并 RUN 命令减少层数
# 5. 按顺序复制文件利用缓存

🐙 Docker Compose 完全指南

docker-compose.yml 基础

version: '3.8'

services:
  # 前端应用
  frontend:
    build: 
      context: ./frontend
      dockerfile: Dockerfile
      args:
        NODE_ENV: development
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - REACT_APP_API_URL=http://backend:5000
    depends_on:
      - backend
    networks:
      - app-network

  # 后端 API
  backend:
    build: ./backend
    ports:
      - "5000:5000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # 数据库
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    networks:
      - app-network

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - frontend
      - backend
    networks:
      - app-network

  # 监控服务
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=200h'
      - '--web.enable-lifecycle'
    ports:
      - "9090:9090"
    networks:
      - app-network

  # 日志收集
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - app-network

  grafana:
    image: grafana/grafana:latest
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - "3001:3000"
    depends_on:
      - prometheus
      - loki
    networks:
      - app-network

# 网络配置
networks:
  app-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

# 数据卷配置
volumes:
  postgres-data:
    driver: local
  redis-data:
    driver: local
  prometheus-data:
    driver: local
  grafana-data:
    driver: local

多环境配置

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    env_file:
      - .env.${ENV:-development}
    environment:
      NODE_ENV: ${ENV:-development}
    ports:
      - "${PORT:-3000}:3000"
    configs:
      - source: app_config
        target: /app/config.json
    secrets:
      - db_password
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

configs:
  app_config:
    file: ./config/${ENV:-development}.json

secrets:
  db_password:
    file: ./secrets/db_password.txt

# .env.development
ENV=development
PORT=3000
LOG_LEVEL=debug

# .env.production
ENV=production
PORT=80
LOG_LEVEL=info

Docker Compose 命令

# 启动服务
docker-compose up
docker-compose up -d        # 后台运行
docker-compose up --build   # 重新构建

# 指定环境文件
docker-compose --env-file .env.production up

# 指定项目名称
docker-compose -p myproject up

# 管理服务
docker-compose ps
docker-compose logs
docker-compose logs -f frontend
docker-compose exec frontend sh
docker-compose stop
docker-compose start
docker-compose restart

# 清理
docker-compose down
docker-compose down -v      # 删除数据卷
docker-compose down --rmi all  # 删除镜像

# 扩展配置
docker-compose -f docker-compose.yml -f docker-compose.override.yml up
docker-compose -f docker-compose.prod.yml up

# 查看服务状态
docker-compose top
docker-compose config      # 查看合并后的配置

🌐 网络配置深度解析

网络模式

# 1. Bridge 模式(默认)
docker run --network bridge nginx

# 2. Host 模式(直接使用宿主机网络)
docker run --network host nginx

# 3. None 模式(无网络)
docker run --network none nginx

# 4. 自定义网络
docker network create --driver bridge my-network
docker run --network my-network nginx

# 5. 容器网络
docker run --network container:existing-container nginx

自定义网络配置

# docker-compose.yml 网络配置
networks:
  frontend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24
          gateway: 172.20.0.1
  backend:
    driver: bridge
    internal: true  # 内部网络,外部无法访问
  monitoring:
    driver: overlay  # Swarm 集群使用
    attachable: true

services:
  web:
    networks:
      - frontend
      - backend
    dns:
      - 8.8.8.8
      - 1.1.1.1

  api:
    networks:
      backend:
        aliases:
          - api.service
          - internal-api

  database:
    networks:
      - backend
    ports:
      - "5432:5432"
    extra_hosts:
      - "host.docker.internal:host-gateway"

💾 存储与数据持久化

数据卷类型

# 1. 命名卷(推荐)
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /path/on/host

# 2. 绑定挂载
services:
  app:
    volumes:
      - ./data:/app/data
      - /var/log/app:/app/logs

# 3. 临时文件系统
services:
  cache:
    volumes:
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 100000000  # 100MB

# 4. 只读挂载
services:
  app:
    volumes:
      - config:/app/config:ro
      - ./static:/app/static:ro

备份与恢复

# 备份数据卷
docker run --rm -v db-data:/source -v $(pwd):/backup alpine \
  tar czf /backup/db-backup-$(date +%Y%m%d).tar.gz -C /source .

# 恢复数据卷
docker run --rm -v db-data:/target -v $(pwd):/backup alpine \
  tar xzf /backup/db-backup.tar.gz -C /target

# 复制数据卷
docker volume create new-db-data
docker run --rm -v db-data:/source -v new-db-data:/target alpine \
  cp -a /source/. /target/

🔒 安全最佳实践

1. 容器安全配置

services:
  app:
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # 只添加必要的权限
    read_only: true  # 只读文件系统
    tmpfs:
      - /tmp
      - /run
    user: "1000:1000"  # 非root用户

2. 镜像安全扫描

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

# 使用 Docker Scout
docker scout quickview myapp:latest
docker scout cves myapp:latest

# 使用 Snyk
docker scan myapp:latest

# 构建时扫描
docker build \
  --secret id=mysecret,src=./secret.txt \
  --no-cache \
  -t myapp:secure .

3. 秘密管理

# Docker Swarm Secrets
echo "mysecretpassword" | docker secret create db_password -

# Docker Compose v3.8+ Secrets
# docker-compose.yml
services:
  db:
    image: postgres
    secrets:
      - db_password
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

# 使用外部 Secret 管理
# AWS Secrets Manager
docker run --rm \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  amazon/aws-cli secretsmanager get-secret-value \
  --secret-id production/db/password

# HashiCorp Vault
docker run --rm \
  -e VAULT_TOKEN \
  vault:latest \
  vault kv get -field=password secret/db

🚀 生产环境部署

Docker Swarm 集群

# 初始化 Swarm
docker swarm init --advertise-addr <MANAGER-IP>

# 加入工作节点
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

# 部署服务
docker stack deploy -c docker-compose.prod.yml myapp

# 查看服务
docker service ls
docker service ps myapp_web
docker service logs myapp_web

# 伸缩服务
docker service scale myapp_web=5

# 更新服务
docker service update \
  --image myapp:2.0.0 \
  --update-parallelism 2 \
  --update-delay 10s \
  myapp_web

# 回滚
docker service update \
  --rollback \
  myapp_web

# 查看节点
docker node ls

生产环境 Compose 文件

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

services:
  web:
    image: myapp:${TAG:-latest}
    deploy:
      replicas: 3
      update_config:
        parallelism: 2
        delay: 10s
        order: start-first
        failure_action: rollback
        monitor: 30s
      rollback_config:
        parallelism: 1
        delay: 5s
        order: stop-first
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      placement:
        constraints:
          - node.role == worker
        preferences:
          - spread: node.labels.zone
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M
    networks:
      - traefik-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
      - "traefik.http.services.myapp.loadbalancer.server.port=80"

  redis:
    image: redis:7-alpine
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.redis == true
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}

  postgres:
    image: postgres:15-alpine
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.database == true
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  traefik:
    image: traefik:v3.0
    deploy:
      placement:
        constraints:
          - node.role == manager
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./letsencrypt:/letsencrypt
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.swarmMode=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=admin@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"

networks:
  traefik-public:
    external: true

volumes:
  redis-data:
    driver: local
  postgres-data:
    driver: local

📊 监控与日志

监控栈配置

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

services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=200h'
      - '--web.enable-lifecycle'
    ports:
      - "9090:9090"
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:latest
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    networks:
      - monitoring

  node-exporter:
    image: prom/node-exporter:latest
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    networks:
      - monitoring

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"
    networks:
      - monitoring

  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - monitoring

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
    command: -config.file=/etc/promtail/config.yml
    networks:
      - monitoring

volumes:
  prometheus-data:
  grafana-data:

networks:
  monitoring:
    driver: bridge

日志配置

# docker-compose.yml 日志配置
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        tag: "{{.Name}}/{{.ID}}"

  # 使用 Loki 收集日志
  app:
    logging:
      driver: loki
      options:
        loki-url: "http://loki:3100/api/prom/push"
        loki-external-labels: "job=docker-logs,container_name={{.Name}},image={{.ImageName}}"

  # 使用 Fluentd
  fluentd:
    image: fluent/fluentd:v1.16-debian-1
    volumes:
      - ./fluentd.conf:/fluentd/etc/fluent.conf
      - ./logs:/fluentd/log
    ports:
      - "24224:24224"
      - "24224:24224/udp"

  app:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: "localhost:24224"
        tag: "docker.{{.Name}}"

🔧 开发工作流优化

开发环境配置

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

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
      - /app/.next  # Next.js 缓存
    environment:
      - WATCHPACK_POLLING=true  # 文件监听
      - CHOKIDAR_USEPOLLING=true
    command: npm run dev
    develop:
      watch:
        - action: rebuild
          path: ./package.json
        - action: sync
          path: ./src
          target: /app/src

  backend:
    build:
      context: ./api
      dockerfile: Dockerfile.dev
    ports:
      - "5000:5000"
    volumes:
      - ./api:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    command: npm run dev:watch

  database:
    image: postgres:15-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app_dev
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes

  mailhog:
    image: mailhog/mailhog:latest
    ports:
      - "8025:8025"  # Web UI
      - "1025:1025"  # SMTP

  # 开发工具
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"

  portainer:
    image: portainer/portainer-ce:latest
    ports:
      - "9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer-data:/data

volumes:
  postgres-data:
  portainer-data:

热重载配置

# Dockerfile.dev
FROM node:18-alpine

WORKDIR /app

# 安装依赖
COPY package*.json ./
RUN npm install

# 安装开发工具
RUN npm install -g nodemon

# 复制源代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动命令(支持热重载)
CMD ["nodemon", "--exec", "npm", "start"]

🧪 测试环境

测试配置

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

services:
  test:
    build:
      context: .
      target: test
    depends_on:
      test-db:
        condition: service_healthy
      test-redis:
        condition: service_healthy
    environment:
      NODE_ENV: test
      DATABASE_URL: postgres://test:test@test-db:5432/test
      REDIS_URL: redis://test-redis:6379
    command: >
      sh -c "
        npm run test:e2e &&
        npm run test:integration &&
        npm run test:coverage
      "
    volumes:
      - ./coverage:/app/coverage

  test-db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: test
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U test"]
      interval: 5s
      timeout: 5s
      retries: 5

  test-redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 5

  test-report:
    image: nginx:alpine
    volumes:
      - ./coverage:/usr/share/nginx/html
    ports:
      - "8081:80"

🚢 CI/CD 集成

GitHub Actions 示例

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

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Run tests
        run: docker-compose -f docker-compose.test.yml up --abort-on-container-exit

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Production
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.DEPLOY_KEY }}
          script: |
            cd /opt/app
            docker-compose pull
            docker-compose up -d
            docker system prune -f

📚 学习资源

官方文档

书籍推荐

  1. 《Docker Deep Dive》 - Nigel Poulton
  2. 《Using Docker》 - Adrian Mouat
  3. 《Docker in Action》 - Jeff Nickoloff

在线课程

🎯 实战项目

项目结构示例

my-docker-project/
├── docker-compose.yml
├── docker-compose.dev.yml
├── docker-compose.prod.yml
├── docker-compose.test.yml
├── .env.example
├── .dockerignore
├── frontend/
│   ├── Dockerfile
│   ├── Dockerfile.dev
│   └── ...
├── backend/
│   ├── Dockerfile
│   ├── Dockerfile.dev
│   └── ...
├── nginx/
│   ├── nginx.conf
│   └── ssl/
├── prometheus/
│   └── prometheus.yml
├── grafana/
│   └── provisioning/
├── scripts/
│   ├── deploy.sh
│   └── backup.sh
└── README.md

部署脚本

#!/bin/bash
# deploy.sh

set -e  # 出错时退出

ENV=${1:-production}
TAG=${2:-latest}

echo "🚀 部署环境: $ENV"
echo "🏷️  镜像标签: $TAG"

# 拉取最新镜像
docker-compose -f docker-compose.$ENV.yml pull

# 停止旧容器
docker-compose -f docker-compose.$ENV.yml down

# 启动新容器
docker-compose -f docker-compose.$ENV.yml up -d

# 清理未使用的镜像
docker image prune -f

# 健康检查
sleep 10
curl -f http://localhost/health || exit 1

echo "✅ 部署完成!"

🔧 故障排查

常用诊断命令

# 查看容器状态
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"

# 查看容器资源使用
docker stats --no-stream

# 查看容器日志
docker logs --tail 100 -f container_name

# 进入容器调试
docker exec -it container_name bash

# 查看容器进程
docker top container_name

# 查看容器元数据
docker inspect container_name

# 网络诊断
docker network inspect bridge
docker exec container_name ping google.com
docker exec container_name curl -I http://service:port

# 存储诊断
docker system df
docker volume ls

常见问题解决

1. 容器启动失败

# 查看详细错误
docker logs container_name

# 检查端口冲突
netstat -tulpn | grep :80

# 检查卷挂载
docker volume inspect volume_name
ls -la /path/to/mount

2. 内存/CPU 问题

# 限制资源使用
docker run --memory="512m" --cpus="1.5" nginx

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

# 设置内存交换
docker run --memory="512m" --memory-swap="1g" nginx

3. 网络问题

# 检查 DNS
docker run --rm alpine nslookup google.com

# 检查网络连接
docker run --rm alpine ping -c 4 google.com

# 查看网络配置
docker network inspect network_name

📈 性能优化

镜像优化

# 使用多阶段构建
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm run build

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

# 使用 Alpine 基础镜像
FROM node:18-alpine

# 合并 RUN 命令减少层数
RUN apk add --no-cache \
    curl \
    git \
    python3 \
    make \
    g++ && \
    npm ci --only=production && \
    apk del curl git python3 make g++

# 使用 .dockerignore
# 排除不必要的文件

构建优化

# 使用 BuildKit
DOCKER_BUILDKIT=1 docker build -t myapp .

# 构建缓存
docker build \
  --cache-from myapp:latest \
  -t myapp:new .

# 并行构建
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myapp:multiarch .

🎓 认证与培训

Docker 认证路径

  1. DCA (Docker Certified Associate) - 基础认证
  2. DCP (Docker Certified Professional) - 专业认证
  3. Docker Security Specialist - 安全专家

学习路径

  1. 初学者:Docker Basics → Docker Compose → Docker Networking
  2. 中级:Dockerfile 优化 → Docker Security → Docker Registry
  3. 高级:Docker Swarm → Kubernetes → CI/CD Integration

📋 总结:架构师 Checklist

项目启动检查清单

生产环境检查清单


posted @ 2026-01-04 22:36  转角90  阅读(37)  评论(0)    收藏  举报