一、Docker核心概念与架构

1.1 什么是Docker

Docker是一个开源的容器化平台,由Go语言开发,于2013年由DotCloud公司(后更名为Docker Inc.)开源发布。它通过操作系统内核技术(cgroups和namespace)实现轻量级虚拟化,让开发者可以将应用及其依赖打包成独立的容器,实现"Build Once, Run Anywhere"的理念。

plaintext

┌─────────────────────────────────────────────────────────────────────────┐
│                           Docker 核心价值                                │
├─────────────────────────────────────────────────────────────────────────┤
│  📦 环境一致性    │ 开发、测试、生产环境完全一致,消除"在我机器上能跑"    │
│  ⚡ 快速交付      │ 秒级启动容器,大幅提升部署和扩容效率                   │
│  🔄 资源高效      │ 共享宿主机内核,容器比虚拟机更轻量(MB vs GB)         │
│  🚀 弹性伸缩      │ 基于镜像快速扩缩容,适配云原生微服务架构               │
│  🏗️ 架构先进      │ 支撑Kubernetes、CI/CD、DevOps等现代技术体系            │
│  🌐 生态完善      │ Docker Hub拥有数百万镜像,社区活跃,文档丰富           │
└─────────────────────────────────────────────────────────────────────────┘

1.2 容器 vs 虚拟机:核心差异

理解容器与虚拟机的区别是掌握Docker的关键。两者虽然都提供隔离环境,但实现方式和适用场景有显著差异。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                         容器 vs 虚拟机 架构对比                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   虚拟机架构:                        容器架构:                               │
│   ┌─────────────────────────┐       ┌─────────────────────────┐            │
│   │     Guest OS (完整系统)  │       │     Container (应用)     │            │
│   │   ┌─────────────────┐   │       │   ┌─────────────────┐   │            │
│   │   │   App1   │ App2 │   │       │   │   App1   │ App2 │   │            │
│   │   │  Libs   │ Libs  │   │       │   │  Libs   │ Libs  │   │            │
│   │   └─────────────────┘   │       │   └─────────────────┘   │            │
│   │        Hypervisor        │       │        Docker Engine    │            │
│   │   ┌─────────────────┐   │       ├─────────────────────────┤            │
│   │   │   App3   │ App4 │   │       │   ┌─────────────────┐   │            │
│   │   │  Libs   │ Libs  │   │       │   │   App3   │ App4 │   │            │
│   │   └─────────────────┘   │       │   └─────────────────┘   │            │
│   │     Guest OS (完整系统)  │       ├─────────────────────────┤            │
│   └──────────┬──────────────┘       │      Host OS (Linux)     │            │
│              │                      │    ┌─────────────────┐  │            │
│              ▼                      │    │  Infrastructure │  │            │
│   ┌─────────────────────────┐       │    │  (Physical/VM)  │  │            │
│   │    Hypervisor           │       └─────────────────────────┘            │
│   │  (VMware/KVM/VirtualBox)│                                                │
│   ├─────────────────────────┤                                                │
│   │      Host OS (任意)     │                                                │
│   └─────────────────────────┘                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

详细对比表:

对比维度 容器 (Container) 虚拟机 (VM)
启动速度 秒级(通常1-2秒) 分钟级(通常1-5分钟)
资源占用 MB级别,共享宿主机内核 GB级别,每个VM独立操作系统
隔离级别 进程级隔离 硬件级隔离,完全独立系统
性能损耗 几乎无损耗(1-3%) 明显损耗(8-15%)
镜像大小 通常10-500MB 通常数GB
最大数量 单机可运行数百个 通常数十个
兼容性 必须Linux内核(Windows/Mac需Docker Desktop) 支持所有主流操作系统
安全性 共享内核,隔离较弱 完全隔离,安全性更高
适用场景 微服务、CI/CD、快速部署 兼容多种OS、需要强隔离

1.3 Docker引擎架构

Docker采用客户端-服务器(C/S)架构,主要由Docker Client、Docker Daemon、Containerd、runc等组件构成。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                           Docker 引擎架构                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────┐                                                         │
│  │   Docker CLI    │  (命令行客户端,用户交互入口)                            │
│  │    (docker)     │                                                         │
│  └────────┬────────┘                                                         │
│           │                                                                  │
│           │ REST API                                                         │
│           ▼                                                                  │
│  ┌─────────────────────────┐                                                │
│  │      Docker Daemon      │  (dockerd,守护进程,管理Docker对象)            │
│  │   ┌─────────────────┐   │                                                │
│  │   │  Graph Driver  │   │  (负责镜像层管理,如overlay2、devicemapper)      │
│  │   ├─────────────────┤   │                                                │
│  │   │  Network Driver│   │  (管理容器网络)                                  │
│  │   ├─────────────────┤   │                                                │
│  │   │  Volume Driver │   │  (管理数据卷)                                    │
│  │   ├─────────────────┤   │                                                │
│  │   │  Logging Driver│   │  (日志驱动)                                      │
│  │   └─────────────────┘   │                                                │
│  └────────────┬────────────┘                                                │
│               │ gRPC                                                          │
│               ▼                                                               │
│  ┌─────────────────────────┐                                                │
│  │      Containerd         │  (容器运行时,负责容器生命周期管理)               │
│  │   ┌─────────────────┐   │                                                │
│  │   │    shim        │   │  (隔离容器进程与容器运行时)                       │
│  │   │  ┌───────────┐ │   │                                                │
│  │   │  │  runc     │ │   │  (轻量级运行时,执行容器创建)                      │
│  │   │  └───────────┘ │   │                                                │
│  │   └─────────────────┘   │                                                │
│  └─────────────────────────┘                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

核心组件说明:

组件 说明 作用
Docker Client docker命令行工具 用户与Docker交互的入口
Docker Daemon dockerd守护进程 监听API请求,管理镜像、容器、网络、数据卷
Containerd 容器运行时 容器生命周期管理(创建、启动、停止)
runc 容器运行工具 创建容器的低层工具,遵循OCI规范
shim 容器隔离进程 分离容器进程与Containerd,提高稳定性
Graph Driver 镜像驱动 管理镜像层的存储和读写,如overlay2
OCI 开放容器标准 定义容器格式和运行时规范

1.4 镜像、容器、仓库:三角关系

Docker中有三个核心概念:镜像(Image)、容器(Container)和仓库(Repository),它们之间的关系是Docker技术的基础。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                      Docker 镜像、容器、仓库 关系图                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                           Registry (仓库)                          │   │
│   │   ┌─────────────────────────────────────────────────────────┐    │   │
│   │   │  Docker Hub / Private Registry                           │    │   │
│   │   │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │    │   │
│   │   │  │ nginx    │  │ mysql    │  │ redis    │  │ ubuntu   │  │    │   │
│   │   │  │ :latest  │  │ :8.0     │  │ :7.0     │  │ :22.04   │  │    │   │
│   │   │  │ 100MB    │  │ 500MB    │  │ 150MB    │  │ 80MB     │  │    │   │
│   │   │  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │    │   │
│   │   └─────────────────────────────────────────────────────────┘    │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                    │ pull / push                            │
│                                    ▼                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                        Local Docker Host                            │   │
│   │                                                                       │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                      Image (镜像)                             │  │   │
│   │   │   nginx:latest                                                │  │   │
│   │   │   ┌─────────────────────────────────────────────────────────┐│  │   │
│   │   │   │ Layer 6: nginx.conf  (自定义配置层)                     ││  │   │
│   │   │   ├─────────────────────────────────────────────────────────┤│  │   │
│   │   │   │ Layer 5: app code       (应用代码层)                    ││  │   │
│   │   │   ├─────────────────────────────────────────────────────────┤│  │   │
│   │   │   │ Layer 4: dependencies  (语言运行时层,如Node.js)        ││  │   │
│   │   │   ├─────────────────────────────────────────────────────────┤│  │   │
│   │   │   │ Layer 3: OS libraries  (系统库层)                       ││  │   │
│   │   │   ├─────────────────────────────────────────────────────────┤│  │   │
│   │   │   │ Layer 2: Base Image     (基础镜像层,如Ubuntu)          ││  │   │
│   │   │   ├─────────────────────────────────────────────────────────┤│  │   │
│   │   │   │ Layer 1: Boot filesystem (引导文件系统)                 ││  │   │
│   │   │   └─────────────────────────────────────────────────────────┘│  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   │                                    │ docker run                      │
│   │                                    ▼                                 │   │
│   │   ┌─────────────────────────────────────────────────────────────┐  │   │
│   │   │                     Container (容器)                         │  │   │
│   │   │   ┌───────────────────────────────────────────────────────┐│  │   │
│   │   │   │  nginx-container-001                                  ││  │   │
│   │   │   │  ┌─────────────────────────────────────────────────┐ ││  │   │
│   │   │   │  │  Container Layer (读写层)                       │ ││  │   │
│   │   │   │  │  + /var/log/nginx (新增日志)                     │ ││  │   │
│   │   │   │  │  + /var/cache/nginx (缓存文件)                   │ ││  │   │
│   │   │   │  └─────────────────────────────────────────────────┘ ││  │   │
│   │   │   │  ┌─────────────────────────────────────────────────┐ ││  │   │
│   │   │   │  │  Image Layers (只读层,共享)                    │ ││  │   │
│   │   │   │  └─────────────────────────────────────────────────┘ ││  │   │
│   │   │   └───────────────────────────────────────────────────────┘│  │   │
│   │   └─────────────────────────────────────────────────────────────┘  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

核心概念详解:

1.4.1 镜像(Image)

镜像是容器的模板,是只读的模板文件,包含运行应用所需的所有内容(代码、运行时、系统工具、系统库)。

bash

# 查看本地镜像
docker images
# 输出示例:
# REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
# nginx         latest    a6bd71f48f68   2 weeks ago    187MB
# mysql         8.0       3218b38490ce   3 weeks ago    516MB
# ubuntu        22.04     8a3cdc4d1d35   4 weeks ago    77.8MB

# 查看镜像详细信息
docker inspect nginx:latest

# 镜像命名规则
# [registry/][repository/]name[:tag]
# 示例:
# docker.io/library/nginx:latest      # 官方镜像
# registry.example.com/myapp:v1.0    # 私有仓库镜像

1.4.2 容器(Container)

容器是镜像的运行实例,是一个可读写、隔离的进程空间。

bash

# 运行一个容器
docker run -d --name my-nginx nginx:latest

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止)
docker ps -a

# 容器生命周期
# 创建 → 启动 → 运行 → 停止 → 销毁
docker create nginx:latest          # 创建容器
docker start my-nginx              # 启动容器
docker stop my-nginx               # 停止容器
docker restart my-nginx            # 重启容器
docker rm my-nginx                 # 删除容器

1.4.3 仓库(Repository)

仓库是存储和分发镜像的场所,类似于代码仓库。

bash

# 从仓库拉取镜像
docker pull nginx:1.24

# 推送到仓库
docker tag myapp:v1.0 registry.example.com/myapp:v1.0
docker push registry.example.com/myapp:v1.0

# 搜索镜像
docker search nginx

二、核心组件详解

2.1 Dockerfile:构建镜像的蓝图

Dockerfile是定义镜像构建过程的文本文件,通过一系列指令描述如何逐步构建自定义镜像。

2.1.1 Dockerfile基础指令

dockerfile

# 基础语法说明
# 格式: INSTRUCTION arguments
# 注释: # 注释内容

# ==================== 必须指令 ====================

# 1. FROM - 指定基础镜像(每个Dockerfile的第一个指令)
# 格式: FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM ubuntu:22.04 AS build

# 2. LABEL - 添加元数据
LABEL maintainer="admin@example.com"
LABEL version="1.0"
LABEL description="Web application container"

# 3. RUN - 执行命令(构建时)
# 格式: RUN <command> 或 RUN ["executable", "param1", "param2"]
RUN apt-get update && apt-get install -y \
    nginx \
    curl \
    && rm -rf /var/lib/apt/lists/*

# 清理构建缓存
RUN apt-get update && apt-get install -y package-foo && rm -rf /var/lib/apt/lists/*

# 4. COPY - 复制文件到镜像
# 格式: COPY [--chown=<user>:<group>] <src>... <dest>
COPY --chown=www-data:www-data ./app /var/www/html/
COPY package*.json /app/

# 5. ADD - 复制文件(支持URL和tar自动解压,不推荐)
ADD https://example.com/binary.tar.gz /usr/local/
ADD archive.tar.gz /extract/

# 6. WORKDIR - 设置工作目录
WORKDIR /var/www/html

# 7. ENV - 设置环境变量
ENV NODE_ENV=production
ENV APP_HOME=/app
ENV PATH=/app/bin:$PATH

# 8. EXPOSE - 声明容器监听端口(仅文档作用)
EXPOSE 80 443

# 9. CMD - 容器启动命令(可被docker run参数覆盖)
# 格式: CMD ["executable","param1","param2"] (推荐)
CMD ["nginx", "-g", "daemon off;"]
# CMD command param1 param2 (shell形式)
# CMD ["param1","param2"] (作为ENTRYPOINT参数)

# 10. ENTRYPOINT - 容器入口点(不可被覆盖,用于固定启动命令)
ENTRYPOINT ["nginx", "-c"]
CMD ["/etc/nginx/nginx.conf"]

2.1.2 Dockerfile高级指令

dockerfile

# ==================== 高级指令 ====================

# ARG - 构建参数(仅构建时可用)
ARG APP_VERSION=1.0
ARG USER_ID=1000
ARG GROUP_ID=1000

# 使用构建参数
RUN echo "Building version ${APP_VERSION}"

# USER - 设置运行用户
USER node:node

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

# ONBUILD - 触发器(被继承时执行)
ONBUILD ADD . /app/src
ONBUILD RUN npm install

# SHELL - 指定shell形式
SHELL ["powershell", "-command"]

# 多阶段构建 - 减小镜像大小
# 阶段1: 构建应用
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# 阶段2: 运行应用
FROM node:18-slim AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

# ==================== .dockerignore ====================
# .dockerignore 文件示例
node_modules
npm-debug.log
.git
.gitignore
.env*
*.md
Dockerfile
docker-compose.yml
.vscode
.idea
*.log

2.1.3 Dockerfile最佳实践

dockerfile

# ❌ 错误示例:臃肿镜像
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y git vim curl wget telnet
RUN cd /app && echo "test" > file
COPY . /app
RUN apt-get clean

# ✅ 正确示例:精简高效
FROM ubuntu:22.04

# 合并RUN指令减少层数
RUN apt-get update && apt-get install -y --no-install-recommends \
    nginx \
    curl \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . .

# 使用特定版本而非latest
# ❌ FROM nginx:latest
# ✅ FROM nginx:1.24-alpine

# 多阶段构建示例:Go应用
FROM golang:1.21 AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
COPY --from=builder /build/main .
COPY --from=builder /build/config ./config
EXPOSE 8080
CMD ["./main"]

2.2 Docker Compose:多容器编排

Docker Compose用于定义和运行多容器Docker应用的工具,通过YAML文件声明服务、网络和数据卷。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                       Docker Compose 工作流程                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ① 定义服务        ② 配置依赖        ③ 启动全部          ④ 集中管理       │
│   ┌─────────┐       ┌─────────┐       ┌─────────┐       ┌─────────┐       │
│   │ web     │       │depends_on│      │docker   │       │docker   │       │
│   │ app     │──────►│ ─────── │─────►│compose  │──────►│compose  │       │
│   │ service │       │ db      │       │up       │       │ps/logs  │       │
│   └─────────┘       │ redis   │       └─────────┘       └─────────┘       │
│                      └─────────┘                                              │
│                                                                             │
│   docker-compose.yml                                                         │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  services:                                                         │   │
│   │    web:                                                            │   │
│   │      build: ./web                                                  │   │
│   │      depends_on: [db, redis]                                       │   │
│   │      ports: ["8000:8000"]                                          │   │
│   │    db:                                                             │   │
│   │      image: postgres:15                                           │   │
│   │    redis:                                                          │   │
│   │      image: redis:7-alpine                                         │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.2.1 docker-compose.yml 完整配置

yaml

# Docker Compose 文件版本(根据Docker版本选择)
# Docker Engine 19.03.0+ 推荐使用 version "3.9"
version: "3.9"

# 定义服务
services:
  # ==================== Web应用服务 ====================
  webapp:
    build:
      context: ./app              # 构建上下文路径
      dockerfile: Dockerfile      # Dockerfile文件名
      args:                        # 构建参数
        APP_ENV: production
        NODE_ENV: production
    image: myapp:1.0              # 构建后的镜像名
    container_name: myapp-web     # 容器名称
    restart: unless-stopped       # 重启策略: no/always/unless-stopped/on-failure
    
    # 端口映射
    ports:
      - "80:8080"                 # 宿主机端口:容器端口
      - "443:8443"
      # - "127.0.0.1:8080:8080"  # 仅绑定本地回环接口
    
    # 环境变量
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_PORT=5432
      - REDIS_HOST=redis
      - LOG_LEVEL=info
    env_file:
      - ./config/.env.production
    
    # 依赖服务(启动顺序)
    depends_on:
      db:
        condition: service_healthy  # 等待健康检查
      redis:
        condition: service_started
    
    # 数据卷挂载
    volumes:
      - ./app:/app:ro             # 绑定挂载(只读)
      - app-logs:/var/log/app     # 命名卷
      - /etc/localtime:/etc/localtime:ro
    
    # 网络配置
    networks:
      - frontend
      - backend
    
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
    
    # 健康检查
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    
    # 日志配置
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    
    # 用户权限
    user: "node:node"
    
    # 挂载 tmpfs(内存文件系统)
    # tmpfs:
    #   - /tmp
    #   - /run
    
    # 容器特权模式(生产环境慎用)
    # privileged: true
    
    # DNS配置
    dns:
      - 8.8.8.8
      - 114.114.114.114
  
  # ==================== 数据库服务 ====================
  db:
    image: postgres:15-alpine
    container_name: myapp-db
    restart: unless-stopped
    
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: dbuser
      POSTGRES_PASSWORD: ${DB_PASSWORD}  # 从环境变量读取
      PGDATA: /var/lib/postgresql/data/pgdata
    
    volumes:
      - db-data:/var/lib/postgresql/data
      - ./config/postgres.conf:/etc/postgresql/postgresql.conf
      - ./backup:/backup
    
    ports:
      - "5432:5432"
    
    networks:
      - backend
    
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
  
  # ==================== Redis缓存服务 ====================
  redis:
    image: redis:7-alpine
    container_name: myapp-redis
    restart: unless-stopped
    
    command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
    # 或使用配置文件
    # command: redis-server /usr/local/etc/redis/redis.conf
    
    volumes:
      - redis-data:/data
      # - ./config/redis.conf:/usr/local/etc/redis/redis.conf:ro
    
    ports:
      - "6379:6379"
    
    networks:
      - backend
    
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3
  
  # ==================== Nginx反向代理 ====================
  nginx:
    image: nginx:1.25-alpine
    container_name: myapp-nginx
    restart: unless-stopped
    
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./app:/var/www/html:ro
      - nginx-logs:/var/log/nginx
    
    ports:
      - "80:80"
      - "443:443"
    
    depends_on:
      - webapp
    
    networks:
      - frontend
      - backend
  
  # ==================== 队列服务 ====================
  rabbitmq:
    image: rabbitmq:3.12-management-alpine
    container_name: myapp-rabbitmq
    restart: unless-stopped
    
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
    
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    
    ports:
      - "5672:5672"      # AMQP协议端口
      - "15672:15672"    # 管理界面端口
    
    networks:
      - backend

# ==================== 数据卷定义 ====================
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/postgres
  
  redis-data:
  
  nginx-logs:

# ==================== 网络定义 ====================
networks:
  frontend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.29.0.0/16

# ==================== 秘密管理(需要Docker Secrets)====================
# secrets:
#   db_password:
#     file: ./secrets/db_password.txt

2.2.2 Docker Compose常用命令

bash

# 启动所有服务(后台运行)
docker-compose up -d

# 带日志启动
docker-compose up -d --build

# 启动并指定服务
docker-compose up -d webapp db

# 查看服务状态
docker-compose ps

# 查看服务日志
docker-compose logs -f webapp
docker-compose logs --tail=100 nginx

# 执行命令
docker-compose exec webapp npm run migrate
docker-compose exec db psql -U postgres -d myapp

# 进入容器
docker-compose exec webapp /bin/sh

# 停止并删除服务
docker-compose down

# 停止并删除卷(数据清除)
docker-compose down -v

# 重新构建镜像
docker-compose build --no-cache webapp

# 扩展服务实例
docker-compose up -d --scale webapp=3

# 查看资源使用
docker-compose top

# 验证配置文件
docker-compose config

# 拉取服务镜像
docker-compose pull

2.3 Docker Network:网络模式详解

Docker提供多种网络模式,容器通过这些网络模式实现容器间、容器与外部的网络通信。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Docker 网络模式架构图                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                     Docker Host (宿主机)                             │   │
│   │                                                                       │   │
│   │  ┌───────────────────────┐    ┌───────────────────────┐              │   │
│   │  │   bridge (默认)       │    │   host (主机模式)     │              │   │
│   │  │   ┌─────────┐         │    │  ┌─────────────────┐  │              │   │
│   │  │   │ container│         │    │  │   container     │  │              │   │
│   │  │   └────┬────┘         │    │  │   直接使用宿主机 │  │              │   │
│   │  │        │              │    │  │   网络命名空间    │  │              │   │
│   │  │        ▼              │    │  └─────────────────┘  │              │   │
│   │  │   docker0 bridge      │    │                       │              │   │
│   │  │   172.17.0.0/16        │    │  网络: 无隔离         │              │   │
│   │  └───────────────────────┘    └───────────────────────┘              │   │
│   │                                                                       │   │
│   │  ┌───────────────────────┐    ┌───────────────────────┐              │   │
│   │  │   overlay (跨主机)    │    │   macvlan (物理网络)  │              │   │
│   │  │  ┌─────────────────┐  │    │  ┌─────────────────┐  │              │   │
│   │  │  │ container       │  │    │  │   container     │  │              │   │
│   │  │  │ ┌─────────────┐ │  │    │  │   获得MAC地址    │  │              │   │
│   │  │  │ │  ingress     │ │  │    │  │   直接接入物理网络│  │              │   │
│   │  │  │ │  network     │ │  │    │  └─────────────────┘  │              │   │
│   │  │  │ └─────────────┘ │  │    │                       │              │   │
│   │  │  └─────────────────┘  │    │  父接口: eth0         │              │   │
│   │  │   vxlan tunnel        │    │  macvlan网络: 172.20.0 │              │   │
│   │  └───────────────────────┘    └───────────────────────┘              │   │
│   │                                                                       │   │
│   │  ┌───────────────────────┐                                            │   │
│   │  │   none (无网络)       │                                            │   │
│   │  │   ┌─────────────┐    │                                            │   │
│   │  │   │   container  │    │                                            │   │
│   │  │   │   lo回环设备 │    │                                            │   │
│   │  │   └─────────────┘    │                                            │   │
│   │  └───────────────────────┘                                            │   │
│   │                                                                       │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.3.1 网络模式详解

模式 说明 使用场景 特性
bridge 默认模式,创建docker0网桥 容器间通信 NAT转换,隔离外部
host 容器直接使用宿主机网络 性能敏感场景 无隔离,最高性能
overlay 跨Docker守护进程通信 Docker Swarm集群 VXLAN隧道
macvlan 容器获得独立MAC地址 需直接接入物理网络 网络透明
none 禁用网络 特殊安全场景 完全隔离

2.3.2 网络管理命令

bash

# 查看网络列表
docker network ls
# 输出:
# NETWORK ID     NAME      DRIVER    SCOPE
# abc123...      bridge    bridge    local
# def456...      host      host      local
# ghi789...      none      null      local

# 查看网络详情
docker network inspect bridge

# 创建自定义bridge网络
docker network create --driver bridge \
    --subnet=172.20.0.0/16 \
    --gateway=172.20.0.1 \
    --ip-range=172.20.5.0/24 \
    my-network

# 创建overlay网络(需要Swarm模式)
docker network create --driver overlay --attachable my-overlay

# 创建macvlan网络
docker network create --driver macvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o parent=eth0 \
    my-macvlan

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

# 断开容器网络连接
docker network disconnect my-network container1

# 删除网络
docker network rm my-network

# 清理未使用网络
docker network prune

2.3.3 容器网络配置

bash

# 指定网络模式运行容器
docker run -d --name web --network bridge nginx

# 连接多个网络
docker run -d --name web \
    --network frontend \
    --network backend \
    nginx

# 指定IP(需在自定义网络中使用)
docker run -d --name web \
    --network my-network \
    --ip 172.20.0.10 \
    nginx

# host模式(性能最优,网络无隔离)
docker run -d --name web --network host nginx

# 设置DNS
docker run -d --name web \
    --dns 8.8.8.8 \
    --dns-search example.com \
    nginx

# 添加hosts记录
docker run -d --name web \
    --add-host=app.example.com:127.0.0.1 \
    --add-host=db.example.com:192.168.1.100 \
    nginx

2.4 Docker Volume:数据管理

Docker提供三种数据存储方式,用于持久化和共享容器数据。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Docker 数据卷类型对比                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐        │
│   │  Bind Mount     │    │    Volume       │    │  tmpfs Mount    │        │
│   │  (绑定挂载)      │    │    (数据卷)      │    │  (内存文件系统)  │        │
│   ├─────────────────┤    ├─────────────────┤    ├─────────────────┤        │
│   │  宿主机文件/目录 │    │ Docker管理存储   │    │ 存储在内存中     │        │
│   │  由用户创建管理   │    │ /var/lib/docker │    │ 最高性能         │        │
│   │  路径灵活可控     │    │ 存储位置         │    │ 数据易失性       │        │
│   │  权限可控        │    │ 自动化管理       │    │ 适合敏感数据     │        │
│   └────────┬────────┘    └────────┬────────┘    └─────────────────┘        │
│            │                        │                                        │
│            ▼                        ▼                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                           容器文件系统                                │   │
│   │   /var/lib/docker/volumes/<volume_name>/_data                       │   │
│   │   /home/user/data                    ← 绑定宿主机路径               │   │
│   │   /tmp                               ← tmpfs                        │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.4.1 卷管理命令

bash

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

# 查看数据卷列表
docker volume ls

# 查看数据卷详情
docker volume inspect my-volume
# 输出:
# [
#     {
#         "Name": "my-volume",
#         "Driver": "local",
#         "Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
#         "Scope": "local"
#     }
# ]

# 使用数据卷运行容器
docker run -d --name web \
    -v my-volume:/app/data \
    nginx

# 绑定挂载(指定宿主机路径)
docker run -d --name web \
    -v /opt/data:/app/data \
    nginx

# 只读挂载
docker run -d --name web \
    -v my-volume:/app/data:ro \
    nginx

# tmpfs挂载(内存文件系统)
docker run -d --name web \
    --tmpfs /run:rw,noexec,nosuid,size=64m \
    nginx

# 删除未使用卷
docker volume prune

# 删除指定卷
docker volume rm my-volume

2.4.2 数据卷实战配置

yaml

# docker-compose.yml 中的数据卷配置
services:
  webapp:
    image: nginx
    volumes:
      # 命名卷
      - app-data:/var/www/html
      # 绑定挂载(相对路径)
      - ./config:/etc/nginx/conf.d:ro
      # 绑定挂载(绝对路径)
      - /opt/logs:/var/log/nginx
      # 只读挂载
      - ./static:/usr/share/nginx/html:ro
      # tmpfs挂载
      - type: tmpfs
        target: /session
        tmpfs:
          size: 1000000  # bytes

volumes:
  app-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/app          # 宿主机路径需预先创建

# 备份恢复数据卷
# 备份
docker run --rm \
    -v my-volume:/data \
    -v $(pwd):/backup \
    alpine \
    tar czf /backup/backup.tar.gz -C /data .

# 恢复
docker run --rm \
    -v my-volume:/data \
    -v $(pwd):/backup \
    alpine \
    tar xzf /backup/backup.tar.gz -C /data

2.5 Docker Registry:私有仓库

私有镜像仓库用于存储和管理企业内部的Docker镜像,确保镜像的安全性和部署效率。

2.5.1 私有仓库部署

bash

# 部署私有Registry
docker run -d \
    --name registry \
    --restart=always \
    -p 5000:5000 \
    -v registry-data:/var/lib/registry \
    -v /opt/registry/auth:/auth \
    -e "REGISTRY_AUTH=htpasswd" \
    -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
    -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
    -e "REGISTRY_STORAGE_DELETE_ENABLED=true" \
    registry:2

# 创建认证用户
# 首次需要创建htpasswd文件
docker run --rm --entrypoint htpasswd \
    registry:2 \
    -Bbn admin password123 > /opt/registry/auth/htpasswd

# 添加更多用户
docker run --rm --entrypoint htpasswd \
    registry:2 \
    -Bbn developer dev123 >> /opt/registry/auth/htpasswd

# 验证Registry
curl -u admin:password123 http://localhost:5000/v2/_catalog

2.5.2 镜像推送与拉取

bash

# 登录私有仓库
docker login registry.example.com

# 给镜像打标签
docker tag myapp:v1.0 registry.example.com/myapp:v1.0

# 推送到私有仓库
docker push registry.example.com/myapp:v1.0

# 拉取镜像
docker pull registry.example.com/myapp:v1.0

# 清理本地镜像(可选)
docker rmi registry.example.com/myapp:v1.0

# Harbor部署(更推荐的可视化Registry)
# docker-compose.yml
version: '3.9'
services:
  harbor:
    image: goharbor/harbor-core:v2.9.0
    container_name: harbor
    restart: always
    volumes:
      - ./harbor.yml:/etc/harbor/harbor.yml:ro
    ports:
      - "80:80"
      - "443:443"
      - "4443:4443"

2.5.3 Registry HTTP配置

json

{
  "registry": {
    "version": 2,
    "log": {
      "level": "info",
      "fields": {
        "service": "registry"
      }
    },
    "storage": {
      "filesystem": {
        "rootdirectory": "/var/lib/registry"
      },
      "delete": {
        "enabled": true
      },
      "maintenance": {
        "uploadpurging": {
          "enabled": true,
          "age": "168h",
          "interval": "24h",
          "dryrun": false
        }
      }
    },
    "http": {
      "addr": ":5000",
      "tls": {
        "certificate": "/certs/registry.crt",
        "key": "/certs/registry.key"
      }
    },
    "auth": {
      "htpasswd": {
        "realm": "Docker Registry",
        "path": "/auth/htpasswd"
      }
    },
    "compatibility": {
      "schema1": {
        "enabled": false
      }
    }
  }
}

三、安装部署与基础配置

3.1 CentOS/RHEL 安装 Docker

bash

# ==================== 卸载旧版本 ====================
sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine

# ==================== 安装依赖 ====================
sudo yum install -y yum-utils \
    device-mapper-persistent-data \
    lvm2

# ==================== 添加Docker仓库 ====================
# 官方仓库
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

# 或阿里云仓库(国内加速)
sudo yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# ==================== 安装Docker ====================
# 安装最新版本
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 或安装指定版本
# sudo yum install -y docker-ce-24.0.0 docker-ce-cli-24.0.0 containerd.io-1.6.0

# ==================== 启动Docker ====================
sudo systemctl start docker
sudo systemctl enable docker

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

# ==================== 配置Docker服务 ====================
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<'EOF'
{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3"
    },
    "storage-driver": "overlay2",
    "live-restore": true,
    "default-address-pools": [
        {
            "base": "172.17.0.0/16",
            "size": 24
        }
    ]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

# ==================== 非root用户运行Docker ====================
sudo groupadd docker
sudo usermod -aG docker $USER
# 重新登录或使用以下命令使配置生效
newgrp docker

3.2 Ubuntu 安装 Docker

bash

# ==================== 卸载旧版本 ====================
sudo apt-get remove docker docker-engine docker.io containerd runc

# ==================== 更新apt源 ====================
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# ==================== 添加Docker GPG密钥 ====================
# 官方
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 阿里云(国内加速)
# curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# ==================== 添加Docker仓库 ====================
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# ==================== 安装Docker ====================
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
    docker-buildx-plugin docker-compose-plugin

# ==================== 启动Docker ====================
sudo systemctl start docker
sudo systemctl enable docker

# ==================== 验证安装 ====================
docker --version
sudo docker run --rm hello-world

# ==================== 配置Docker服务 ====================
sudo nano /etc/docker/daemon.json

3.3 镜像加速配置

bash

# ==================== Docker配置目录 ====================
sudo mkdir -p /etc/docker

# ==================== 配置镜像加速器 ====================
# 中国镜像加速器配置
sudo tee /etc/docker/daemon.json <<'EOF'
{
    "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn",
        "https://hub-mirror.c.163.com",
        "https://mirror.baidubce.com"
    ],
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3"
    },
    "storage-driver": "overlay2"
}
EOF

# ==================== 重启Docker ====================
sudo systemctl daemon-reload
sudo systemctl restart docker

# ==================== 验证加速器 ====================
docker info | grep -A 10 "Registry Mirrors"
# 输出示例:
#  Registry Mirrors:
#   https://docker.mirrors.ustc.edu.cn/
#   https://hub-mirror.c.163.com/
#   https://mirror.baidubce.com/

3.4 常用配置优化

bash

# ==================== 完整Docker配置 ====================
sudo tee /etc/docker/daemon.json <<'EOF'
{
    "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn",
        "https://hub-mirror.c.163.com"
    ],
    
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3",
        "compress": "true"
    },
    
    "storage-driver": "overlay2",
    "storage-opts": [
        "overlay2.override_kernel_check=true"
    ],
    
    "live-restore": true,
    "userland-proxy": false,
    "default-address-pools": [
        {
            "base": "172.17.0.0/16",
            "size": 24
        },
        {
            "base": "172.18.0.0/16",
            "size": 24
        }
    ],
    
    "dns": ["8.8.8.8", "114.114.114.114"],
    
    "default-ulimits": {
        "nofile": {
            "Name": "nofile",
            "Hard": 65536,
            "Soft": 65536
        }
    },
    
    "max-concurrent-downloads": 10,
    "max-concurrent-uploads": 5,
    
    "experimental": false,
    "features": {
        "buildkit": true
    },
    
    "builder": {
        "gc": {
            "enabled": true,
            "defaultKeepStorage": "20GB"
        }
    }
}
EOF

# ==================== Docker服务优化 ====================
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建配置目录
sudo tee /etc/systemd/system/docker.service.d/limits.conf <<'EOF'
[Service]
LimitNOFILE=65536
LimitNPROC=4096
LimitCORE=infinity
TasksMax=infinity
OOMScoreAdjust=-500
EOF

# ==================== 禁用桥接流量控制(提升网络性能)====================
cat <<EOF | sudo tee /etc/modules-load.d/br_netfilter.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
net.ipv4.conf.default.forwarding    = 1
net.ipv4.conf.all.forwarding        = 1
EOF

sudo sysctl --system

# ==================== 重启应用配置 ====================
sudo systemctl daemon-reload
sudo systemctl restart docker

# ==================== 配置日志轮转 ====================
sudo tee /etc/logrotate.d/docker <<'EOF'
/var/lib/docker/containers/*/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}
EOF

3.5 Docker BuildKit 构建优化

bash

# ==================== 启用BuildKit ====================
export DOCKER_BUILDKIT=1

# 永久启用
echo "DOCKER_BUILDKIT=1" | sudo tee -a /etc/environment

# ==================== daemon.json配置 ====================
# 在 /etc/docker/daemon.json 中添加:
# "features": { "buildkit": true }

# ==================== 并行构建优化 ====================
# 设置并发任务数
export BUILDKIT_PROGRESS=plain
export BUILDKIT_INLINE_CACHE=1

# .dockerignore 优化构建上下文
cat <<EOF > .dockerignore
.git
.gitignore
*.md
node_modules
npm-debug.log
.env
.env.*
.vscode
.idea
*.log
dist
coverage
.nyc_output
EOF

四、实战案例

4.1 构建 Web 应用镜像

本节将详细演示如何为一个Node.js Web应用构建生产级Docker镜像。

4.1.1 项目结构

plaintext

webapp/
├── src/
│   ├── index.js
│   ├── routes/
│   │   └── health.js
│   └── config/
│       └── index.js
├── package.json
├── Dockerfile
├── .dockerignore
└── .env.example

4.1.2 应用代码

javascript

// src/index.js
const express = require('express');
const { healthRouter } = require('./routes/health');
const { config } = require('./config');

const app = express();

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 请求日志
app.use((req, res, next) => {
    console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
    next();
});

// 路由
app.use('/health', healthRouter);

app.get('/', (req, res) => {
    res.json({
        name: config.appName,
        version: config.version,
        env: process.env.NODE_ENV
    });
});

app.get('/api/info', (req, res) => {
    res.json({
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        pid: process.pid
    });
});

// 错误处理
app.use((err, req, res, next) => {
    console.error('Error:', err);
    res.status(err.status || 500).json({
        error: err.message || 'Internal Server Error'
    });
});

const PORT = process.env.PORT || 3000;

const server = app.listen(PORT, () => {
    console.log(`Server started on port ${PORT}`);
    console.log(`Environment: ${process.env.NODE_ENV}`);
});

// 优雅关闭
process.on('SIGTERM', () => {
    console.log('SIGTERM received, shutting down gracefully');
    server.close(() => {
        console.log('Server closed');
        process.exit(0);
    });
});

module.exports = app;

javascript

// src/config/index.js
module.exports = {
    appName: 'MyWebApp',
    version: '1.0.0',
    apiPrefix: '/api/v1'
};

javascript

// src/routes/health.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
    res.json({
        status: 'healthy',
        timestamp: new Date().toISOString(),
        uptime: process.uptime()
    });
});

router.get('/ready', (req, res) => {
    // 检查依赖服务
    res.json({
        status: 'ready',
        checks: {
            database: true,
            cache: true
        }
    });
});

module.exports = { healthRouter: router };

4.1.3 优化版 Dockerfile

dockerfile

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

# 设置工作目录
WORKDIR /app

# 设置npm镜像(加速构建)
RUN npm config set registry https://registry.npmmirror.com/

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

# 安装依赖(包含devDependencies用于构建)
RUN npm ci --only=production

# 复制源代码
COPY src/ ./src/

# 构建应用(如果是需要构建的项目)
# RUN npm run build

# 阶段2: 运行阶段
FROM node:18-alpine AS runtime

# 安全:创建非root用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodeapp -u 1001

WORKDIR /app

# 从构建阶段复制产物
COPY --from=builder --chown=nodeapp:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodeapp:nodejs /app/src ./src

# 设置环境变量
ENV NODE_ENV=production \
    PORT=3000

# 切换到非root用户
USER nodeapp

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"

# 启动命令
CMD ["node", "src/index.js"]

4.1.4 构建并测试镜像

bash

# 构建镜像
docker build -t mywebapp:1.0.0 .

# 构建带构建参数
docker build \
    --build-arg APP_VERSION=1.0.0 \
    --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
    -t mywebapp:1.0.0 .

# 构建带缓存标签(用于增量构建)
docker build --cache-from mywebapp:latest -t mywebapp:1.0.1 .

# 查看镜像信息
docker history mywebapp:1.0.0

# 运行容器测试
docker run -d --name mywebapp-test \
    -p 3000:3000 \
    -e NODE_ENV=development \
    --restart unless-stopped \
    mywebapp:1.0.0

# 测试健康检查
curl http://localhost:3000/health

# 测试应用
curl http://localhost:3000/

# 查看日志
docker logs -f mywebapp-test

# 压力测试
ab -n 1000 -c 10 http://localhost:3000/

# 清理测试容器
docker rm -f mywebapp-test

4.2 使用 Docker Compose 部署 LNMP 环境

LNMP(Linux + Nginx + MySQL + PHP)是经典的Web服务架构,以下通过Docker Compose实现一键部署。

4.2.1 项目结构

plaintext

lnmp/
├── docker-compose.yml
├── nginx/
│   ├── nginx.conf
│   └── conf.d/
│       └── default.conf
├── php/
│   ├── Dockerfile
│   └── php.ini
├── mysql/
│   └── my.cnf
├── www/
│   ├── index.php
│   ├── info.php
│   └── wp-config.php
├── redis/
│   └── redis.conf
└── backup/

4.2.2 完整配置文件

yaml

# docker-compose.yml
version: "3.9"

services:
  # ==================== Nginx服务 ====================
  nginx:
    image: nginx:1.25-alpine
    container_name: lnmp-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./www:/var/www/html:ro
      - nginx-logs:/var/log/nginx
    depends_on:
      - php
    networks:
      - lnmp-network
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ==================== PHP-FPM服务 ====================
  php:
    build:
      context: ./php
      dockerfile: Dockerfile
    container_name: lnmp-php
    restart: always
    volumes:
      - ./php/php.ini:/usr/local/etc/php/conf.d/custom.ini:ro
      - ./www:/var/www/html
      - php-sessions:/var/lib/php/sessions
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      PHP_MEMORY_LIMIT: 256M
      PHP_MAX_EXECUTION_TIME: 300
      PHP_UPLOAD_MAX_FILESIZE: 50M
    networks:
      - lnmp-network
    healthcheck:
      test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ==================== MySQL服务 ====================
  mysql:
    image: mysql:8.0
    container_name: lnmp-mysql
    restart: always
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro
      - mysql-data:/var/lib/mysql
      - ./backup:/backup
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      TZ: Asia/Shanghai
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-authentication-plugin=mysql_native_password
    networks:
      - lnmp-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ==================== Redis服务 ====================
  redis:
    image: redis:7-alpine
    container_name: lnmp-redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
      - redis-data:/data
    command: redis-server /usr/local/etc/redis/redis.conf
    networks:
      - lnmp-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

  # ==================== phpMyAdmin(可选)====================
  phpmyadmin:
    image: phpmyadmin:latest
    container_name: lnmp-phpmyadmin
    restart: always
    ports:
      - "8080:80"
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: root
      PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      UPLOAD_LIMIT: 50M
    depends_on:
      mysql:
        condition: service_healthy
    networks:
      - lnmp-network
    profiles:
      - tools

networks:
  lnmp-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/24

volumes:
  mysql-data:
    driver: local
  redis-data:
    driver: local
  nginx-logs:
  php-sessions:

4.2.3 Nginx 配置

nginx

# nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript;

    # 包含站点配置
    include /etc/nginx/conf.d/*.conf;
}

nginx

# nginx/conf.d/default.conf
upstream php_backend {
    server php:9000;
    keepalive 32;
}

server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html index.htm;

    # 健康检查端点
    location = /health {
        access_log off;
        return 200 "OK";
        add_header Content-Type text/plain;
    }

    # 主站配置
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHP处理
    location ~ \.php$ {
        fastcgi_pass php_backend;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 60;
        fastcgi_read_timeout 60;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 4 64k;
        fastcgi_busy_buffers_size 128k;
        fastcgi_temp_file_write_size 128k;
    }

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}

4.2.4 PHP Dockerfile

dockerfile

# php/Dockerfile
FROM php:8.2-fpm-alpine

# 安装扩展依赖
RUN apk add --no-cache \
    postgresql-dev \
    libzip-dev \
    oniguruma-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    && docker-php-ext-install \
        pdo \
        pdo_mysql \
        pdo_pgsql \
        mbstring \
        zip \
        bcmath \
        exif \
        sockets

# 安装Redis扩展
RUN pecl install redis && docker-php-ext-enable redis

# 安装GD扩展
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install gd

# 安装图像处理工具
RUN apk add --no-cache \
    ghostscript \
    poppler-utils

# 安装Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER=1

# 配置PHP
WORKDIR /var/www/html

# 健康检查脚本
RUN echo '#!/bin/sh\n\
php-fpm -t || exit 1\n\
exec php-fpm' > /usr/local/bin/php-fpm-healthcheck \
&& chmod +x /usr/local/bin/php-fpm-healthcheck

EXPOSE 9000

CMD ["php-fpm"]

ini

; php/php.ini
[PHP]
memory_limit = 256M
max_execution_time = 300
upload_max_filesize = 50M
post_max_size = 50M
date.timezone = Asia/Shanghai

[Date]
date.timezone = Asia/Shanghai

[Session]
session.save_handler = redis
session.save_path = "tcp://redis:6379?prefix=PHP_SESSION:"
session.gc_maxlifetime = 3600

[Pdo]
pdo_mysql.default_socket = /var/run/mysqld/mysqld.sock

4.2.5 环境变量与测试

bash

# 创建.env文件
cat > .env <<'EOF'
# MySQL配置
MYSQL_ROOT_PASSWORD=YourSecureRootPassword123!
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=YourAppPassword456!

# Redis配置(可选)
REDIS_PASSWORD=YourRedisPassword789
EOF

# 创建必要目录
mkdir -p backup www nginx/conf.d php mysql redis

# 创建测试PHP文件
cat > www/index.php <<'EOF'
<?php
echo "<h1>LNMP Environment is Working!</h1>";
echo "<p>PHP Version: " . phpversion() . "</p>";
echo "<p>Server: " . $_SERVER['SERVER_SOFTWARE'] . "</p>";
?>
EOF

cat > www/info.php <<'EOF'
<?php phpinfo(); ?>
EOF

# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 测试Nginx
curl http://localhost/health

# 测试PHP
curl http://localhost/info.php

# 连接MySQL
docker-compose exec mysql mysql -u root -p

# 连接Redis
docker-compose exec redis redis-cli

# 数据库备份
docker-compose exec mysql mysqldump -u root -p${MYSQL_ROOT_PASSWORD} myapp > backup/myapp.sql

# 停止服务
docker-compose down

# 停止并清除数据(危险!)
docker-compose down -v

4.3 容器化部署微服务

本节演示如何将一个微服务架构应用Docker化,包括用户服务、订单服务和网关服务。

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                         微服务架构部署图                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                        外部请求                                      │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    ▼                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                      API Gateway (Nginx)                            │   │
│   │                   /api/users → user-service                        │   │
│   │                   /api/orders → order-service                       │   │
│   │                   /api/products → product-service                   │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│           ┌────────────────────────┼────────────────────────┐             │
│           │                        │                        │             │
│           ▼                        ▼                        ▼             │
│   ┌───────────────┐        ┌───────────────┐        ┌───────────────┐     │
│   │ User Service  │        │ Order Service │        │Product Service│     │
│   │ Python/Flask │        │   Java/Spring │        │  Node/Express │     │
│   │    :5001      │        │     :5002     │        │     :5003     │     │
│   └───────┬───────┘        └───────┬───────┘        └───────┬───────┘     │
│           │                        │                        │             │
│           └────────────────────────┼────────────────────────┘             │
│                                    │                                        │
│           ┌────────────────────────┼────────────────────────┐             │
│           │                        │                        │             │
│           ▼                        ▼                        ▼             │
│   ┌───────────────┐        ┌───────────────┐        ┌───────────────┐     │
│   │    MySQL      │        │    MySQL      │        │    MongoDB    │     │
│   │  (Users DB)   │        │ (Orders DB)   │        │ (Products DB) │     │
│   │    :3306      │        │    :3306       │        │    :27017      │     │
│   └───────────────┘        └───────────────┘        └───────────────┘     │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    Redis (共享缓存 &  Sessions)                     │   │
│   │                              :6379                                   │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                     Jaeger (分布式追踪)                             │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.3.1 微服务 docker-compose.yml

yaml

# docker-compose.yml - 微服务架构
version: "3.9"

services:
  # ==================== API网关 ====================
  api-gateway:
    image: nginx:1.25-alpine
    container_name: api-gateway
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./gateway/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./gateway/conf.d:/etc/nginx/conf.d:ro
      - gateway-logs:/var/log/nginx
    depends_on:
      user-service:
        condition: service_healthy
      order-service:
        condition: service_healthy
      product-service:
        condition: service_healthy
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "nginx", "-t"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ==================== 用户服务 ====================
  user-service:
    build:
      context: ./services/user-service
      dockerfile: Dockerfile
    container_name: user-service
    restart: always
    environment:
      - FLASK_ENV=production
      - DB_HOST=mysql-users
      - DB_PORT=3306
      - DB_NAME=users_db
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - JAEGER_HOST=jaeger
      - SERVICE_NAME=user-service
    depends_on:
      mysql-users:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

  # ==================== 订单服务 ====================
  order-service:
    build:
      context: ./services/order-service
      dockerfile: Dockerfile
    container_name: order-service
    restart: always
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_HOST=mysql-orders
      - DB_PORT=3306
      - DB_NAME=orders_db
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - JAEGER_HOST=jaeger
    depends_on:
      mysql-orders:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - microservices
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

  # ==================== 产品服务 ====================
  product-service:
    build:
      context: ./services/product-service
      dockerfile: Dockerfile
    container_name: product-service
    restart: always
    environment:
      - NODE_ENV=production
      - DB_HOST=mongodb
      - DB_PORT=27017
      - DB_NAME=products_db
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - JAEGER_HOST=jaeger
      - SERVICE_NAME=product-service
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5003/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ==================== MySQL - 用户库 ====================
  mysql-users:
    image: mysql:8.0
    container_name: mysql-users
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: users_db
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - mysql-users-data:/var/lib/mysql
      - ./services/user-service/sql:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ==================== MySQL - 订单库 ====================
  mysql-orders:
    image: mysql:8.0
    container_name: mysql-orders
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: orders_db
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - mysql-orders-data:/var/lib/mysql
      - ./services/order-service/sql:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ==================== MongoDB ====================
  mongodb:
    image: mongo:7
    container_name: mongodb
    restart: always
    environment:
      MONGO_INITDB_DATABASE: products_db
    volumes:
      - mongodb-data:/data/db
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ==================== Redis ====================
  redis:
    image: redis:7-alpine
    container_name: redis
    restart: always
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    networks:
      - microservices
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

  # ==================== Jaeger追踪 ====================
  jaeger:
    image: jaegertracing/all-in-one:1.50
    container_name: jaeger
    restart: always
    ports:
      - "16686:16686"  # UI
      - "4317:4317"    # OTLP gRPC
      - "4318:4318"    # OTLP HTTP
    environment:
      - COLLECTOR_OTLP_ENABLED=true
      - SPAN_STORAGE_TYPE=badger
    networks:
      - microservices

networks:
  microservices:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/24

volumes:
  mysql-users-data:
  mysql-orders-data:
  mongodb-data:
  redis-data:
  gateway-logs:

4.3.2 网关配置

nginx

# gateway/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    '"$upstream_addr" $request_time';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;

    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript;

    # 上游服务连接池
    upstream user_backend {
        server user-service:5001;
        keepalive 32;
    }

    upstream order_backend {
        server order-service:8080;
        keepalive 32;
    }

    upstream product_backend {
        server product-service:5003;
        keepalive 32;
    }

    include /etc/nginx/conf.d/*.conf;
}

nginx

# gateway/conf.d/api.conf
server {
    listen 80;
    server_name _;

    # 健康检查
    location /health {
        return 200 "API Gateway OK";
        add_header Content-Type text/plain;
    }

    # 用户服务
    location /api/users/ {
        proxy_pass http://user_backend/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        
        proxy_connect_timeout 30s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 订单服务
    location /api/orders/ {
        proxy_pass http://order_backend/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        
        proxy_connect_timeout 30s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 产品服务
    location /api/products/ {
        proxy_pass http://product_backend/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        
        proxy_connect_timeout 30s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 默认404
    location / {
        return 404 '{"error": "Not Found", "path": "$uri"}';
        add_header Content-Type application/json;
    }
}

4.3.3 微服务部署与验证

bash

# 创建目录结构
mkdir -p services/{user-service,order-service,product-service}/{sql,src}
mkdir -p gateway/{nginx,conf.d}

# 启动所有服务
docker-compose up -d --build

# 查看所有服务状态
docker-compose ps

# 查看服务日志
docker-compose logs -f user-service
docker-compose logs -f order-service

# 测试用户服务
curl http://localhost/api/users/health
curl -X POST http://localhost/api/users/register \
    -H "Content-Type: application/json" \
    -d '{"username":"test","email":"test@example.com","password":"pass123"}'

# 测试订单服务
curl http://localhost/api/orders/health
curl http://localhost/api/orders/1

# 测试产品服务
curl http://localhost/api/products/health
curl http://localhost/api/products

# 查看Jaeger追踪
# 访问 http://localhost:16686

# 水平扩展服务
docker-compose up -d --scale user-service=3

# 滚动更新
docker-compose up -d --build --no-deps user-service
docker-compose up -d --no-deps order-service

# 清理
docker-compose down -v --rmi local

五、最佳实践与常见问题

5.1 镜像优化技巧

5.1.1 减少镜像层数

dockerfile

# ❌ 错误:每个RUN一层,增加镜像大小
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl
RUN apt-get install -y vim
RUN rm -rf /var/lib/apt/lists/*

# ✅ 正确:合并RUN指令
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y --no-install-recommends \
    nginx \
    curl \
    vim \
    && rm -rf /var/lib/apt/lists/*

5.1.2 使用多阶段构建

dockerfile

# 多阶段构建示例:Go应用
# 阶段1:构建
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main .

# 阶段2:运行(使用scratch或alpine)
FROM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
COPY --from=builder /app/main .
COPY --from=builder /app/config ./config
EXPOSE 8080
CMD ["./main"]

# 最终镜像大小对比:~800MB → ~15MB

5.1.3 利用构建缓存

dockerfile

# 利用缓存:按变化频率排序层
FROM node:18-alpine

# 先复制依赖文件(变化少)
COPY package*.json ./
RUN npm ci --only=production

# 后复制源代码(变化多)
COPY src/ ./src/
COPY public/ ./public/

# 避免的写法
# COPY . .      # 每次都使缓存失效
# RUN npm install  # 每次都重新安装

5.1.4 选择合适的基础镜像

镜像类型 示例 大小 适用场景
完整系统 ubuntu:22.04 ~77MB 需要完整系统工具
Alpine alpine:3.19 ~7MB 追求极致轻量
Slim node:18-slim ~180MB 需要部分工具
Scratch scratch 0MB Go/Rust静态编译程序
Distroless gcr.io/distroless/nodejs ~130MB 生产环境安全优先

dockerfile

# 推荐:使用Alpine或官方slim镜像
FROM node:18-alpine
# 或
FROM node:18-slim

5.1.5 优化技巧汇总

dockerfile

# 1. 清理不必要的文件
RUN apt-get update && apt-get install -y package \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# 2. 使用--link删除减少层数
RUN apt-get update && apt-get install -y package \
    && rm -rf /var/lib/apt/lists/*

# 3. 标签使用具体版本而非latest
FROM nginx:1.25.3-alpine

# 4. 设置正确的时区
RUN apk add --no-cache tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 5. 并行下载
RUN echo "options mirrors.aliyun.com" > /etc/apt/mirrors \
    && apt-get update -o Acquire::http::Pipeline-Depth=5

# 6. 使用.dockerignore
# .dockerignore文件
node_modules
npm-debug.log
.git
.env*
dist
coverage
.vscode
.idea
*.md

5.2 容器安全

5.2.1 安全最佳实践

bash

# ==================== 容器安全检查清单 ====================

# 1. 不要以root用户运行容器
docker run -d --user 1000:1000 myapp

# Dockerfile中设置用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodeapp -u 1001
USER nodeapp

# 2. 使用只读文件系统
docker run -d --read-only myapp

# 3. 限制容器能力
docker run -d --cap-drop=ALL myapp
# 只添加必需的能力
docker run -d --cap-add=NET_BIND_SERVICE myapp

# 4. 禁用特权模式
# ❌ 错误
docker run -d --privileged myapp
# ✅ 正确
docker run -d --security-opt=no-new-privileges myapp

# 5. 限制资源使用
docker run -d \
    --memory="512m" \
    --memory-swap="1g" \
    --cpus="1.0" \
    --pids-limit=100 \
    myapp

# 6. 安全扫描镜像
docker scout cves myapp:latest
docker scan myapp:latest
trivy image myapp:latest

# 7. 使用可信基础镜像
# ✅ 使用官方镜像
FROM node:18-alpine
# ✅ 或使用Distroless
FROM gcr.io/distroless/nodejs:18

5.2.2 安全加固配置

yaml

# docker-compose.yml 安全配置
services:
  webapp:
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    read_only: true
    tmpfs:
      - /tmp
      - /run
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
      nproc:
        soft: 4096
        hard: 4096

5.2.3 镜像安全扫描工具

bash

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

# 使用Docker Scout
docker scout cves nginx:latest

# 使用Anchore
docker run --rm -v /tmp/anchore_results:/results \
    anchore/anchore-engine-cli \
    anchore --image nginx:latest

# CI/CD集成示例
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  trivy-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
      - name: Upload to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

5.3 常见问题排查

5.3.1 容器无法启动

bash

# 查看容器详细日志
docker logs mycontainer
docker logs --tail=100 mycontainer
docker logs -f mycontainer

# 查看容器退出码
docker wait mycontainer
docker inspect mycontainer --format='{{.State.ExitCode}}'

# 常见退出码及原因:
# 0    - 正常退出
# 1    - 应用程序错误
# 127  - 命令未找到
# 137  - 被SIGKILL杀死(内存不足)
# 139  - 段错误(内存越界)
# 143  - 被SIGTERM正常终止

# 交互式调试
docker run -it --rm myapp /bin/sh
docker run -it --rm --entrypoint /bin/bash myapp

# 查看容器详细信息
docker inspect mycontainer

# 检查资源限制
docker stats mycontainer --no-stream

5.3.2 网络问题排查

bash

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

# 查看容器IP
docker inspect mycontainer --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

# 容器间通信测试
docker exec container1 ping container2
docker exec container1 curl http://container2:8080

# DNS解析测试
docker exec mycontainer nslookup myservice
docker exec mycontainer cat /etc/hosts

# 进入容器网络命名空间
docker exec -it mycontainer /bin/sh
cat /etc/resolv.conf
netstat -tlnp
ss -tlnp

# 端口映射问题
docker port mycontainer
# 测试端口
telnet localhost 8080
curl http://localhost:8080

5.3.3 性能问题排查

bash

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

# 查看容器进程
docker top mycontainer

# 监控容器IO
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    assaflavie/runlike mycontainer
docker inspect mycontainer | grep -A 10 "Blkio"

# 查看容器磁盘使用
docker system df
docker system df -v

# 清理未使用资源
docker system prune -a
docker image prune -a
docker container prune
docker volume prune
docker network prune

5.3.4 日志问题排查

bash

# 查看日志
docker logs mycontainer
docker logs --since "2024-01-01T10:00:00" mycontainer
docker logs --tail=500 mycontainer

# 日志配置(daemon.json)
{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3",
        "compress": "true"
    }
}

# 日志驱动选择
# json-file(默认)- 适合大多数场景
# syslog - 发送到syslog服务器
# journald - 发送到systemd journal
# fluentd - 发送到Fluentd
# awslogs - 发送到CloudWatch

# 配置syslog日志驱动
docker run -d \
    --log-driver=syslog \
    --log-opt syslog-address=tcp://syslogserver:514 \
    --log-opt tag="{{.Name}}/{{.ID}}" \
    myapp

5.3.5 常见错误与解决方案

问题 原因 解决方案
Container killed (OOM) 内存不足 增加内存限制或优化应用内存使用
Bind mount失败 路径不存在或权限问题 创建目录并检查SELinux/AppArmor
端口冲突 端口已被占用 更换端口或停止占用进程
镜像拉取失败 网络或认证问题 配置镜像加速或登录Registry
Volume权限问题 UID/GID不匹配 使用--chown或调整用户权限
Storage Driver不匹配 文件系统不支持 更改存储驱动或使用支持的文件系统
DNS解析失败 网络配置问题 检查--dns或网络驱动配置

bash

# OOM问题排查
dmesg | grep -i "killed process"
docker stats --no-stream
# 增加内存限制
docker run -d --memory=1g myapp

# 权限问题
ls -la /path/to/volume
chown -R 1000:1000 /path/to/volume

# SELinux问题
# 临时解决
docker run -d --privileged myapp
# 永久解决
chcon -Rt svirt_sandbox_file_t /path/to/volume

# 端口冲突
netstat -tlnp | grep 8080
# 或
ss -tlnp | grep 8080

5.3.6 Docker故障排查流程图

plaintext

┌─────────────────────────────────────────────────────────────────────────────┐
│                         Docker 问题排查流程                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   发现问题                                                                   │
│      │                                                                      │
│      ▼                                                                      │
│   ┌───────────────────┐                                                      │
│   │ docker ps -a     │ 检查容器状态                                          │
│   └─────────┬─────────┘                                                      │
│             │                                                                │
│       ┌─────┴─────┐                                                          │
│       ▼           ▼                                                          │
│   运行中         已停止                                                        │
│       │           │                                                          │
│       ▼           ▼                                                           │
│   ┌─────────┐   ┌─────────┐                                                  │
│   │docker   │   │查看退出 │                                                  │
│   │logs     │   │码和日志 │                                                  │
│   └────┬────┘   └────┬────┘                                                  │
│        │            │                                                        │
│        ▼            ▼                                                        │
│   ┌─────────────────────────┐                                                │
│   │docker inspect           │ 查看详细配置                                    │
│   │docker exec进入容器调试   │                                                │
│   │docker stats资源监控      │                                                │
│   └─────────────────────────┘                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5.4 监控与日志管理

yaml

# docker-compose.monitoring.yml
version: "3.9"

services:
  # ==================== Prometheus ====================
  prometheus:
    image: prom/prometheus:v2.47.0
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
      - '--web.enable-lifecycle'
    networks:
      - monitoring

  # ==================== Grafana ====================
  grafana:
    image: grafana/grafana:10.1.0
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
    networks:
      - monitoring

  # ==================== cAdvisor ====================
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.47.2
    container_name: cadvisor
    restart: always
    privileged: true
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    networks:
      - monitoring

  # ==================== Loki日志系统 ====================
  loki:
    image: grafana/loki:2.8.0
    container_name: loki
    restart: always
    ports:
      - "3100:3100"
    volumes:
      - ./loki/loki-config.yml:/etc/loki/local-config.yaml:ro
      - loki-data:/loki
    networks:
      - monitoring

  # ==================== Promtail日志收集 ====================
  promtail:
    image: grafana/promtail:2.8.0
    container_name: promtail
    restart: always
    volumes:
      - ./promtail/promtail-config.yml:/etc/promtail/config.yml:ro
      - /var/log:/var/log:ro
    command: -config.file=/etc/promtail/config.yml
    networks:
      - monitoring

networks:
  monitoring:
    driver: bridge

volumes:
  prometheus-data:
  grafana-data:
  loki-data:

总结

本文全面介绍了Docker容器技术的核心知识体系,从基础概念到生产级实践,涵盖:

核心要点:

  1. 架构理解:掌握Docker引擎的客户端-服务器架构,理解镜像、容器、仓库的三角关系

  2. 核心组件

     
    • Dockerfile:掌握多阶段构建、层缓存优化、安全最佳实践
    • Docker Compose:实现多容器编排和声明式部署
    • Docker Network:理解四种网络模式及适用场景
    • Docker Volume:掌握数据持久化和共享机制
    • Docker Registry:搭建私有镜像仓库
  3. 部署配置:熟悉CentOS和Ubuntu的安装流程,掌握镜像加速和性能优化配置

  4. 实战能力

     
    • 构建生产级Web应用镜像
    • 部署LNMP等经典架构
    • 实现微服务容器化
  5. 最佳实践

     
    • 镜像优化技巧
    • 容器安全加固
    • 常见问题排查方法

Docker作为云原生时代的基础设施,掌握它不仅能提升开发效率,更是现代DevOps工程师的必备技能。希望本文能帮助你构建完整的Docker知识体系,在实际工作中游刃有余。

参考资源:

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐