Docker容器
一、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容器技术的核心知识体系,从基础概念到生产级实践,涵盖:
核心要点:
-
架构理解:掌握Docker引擎的客户端-服务器架构,理解镜像、容器、仓库的三角关系
-
核心组件:
- Dockerfile:掌握多阶段构建、层缓存优化、安全最佳实践
- Docker Compose:实现多容器编排和声明式部署
- Docker Network:理解四种网络模式及适用场景
- Docker Volume:掌握数据持久化和共享机制
- Docker Registry:搭建私有镜像仓库
-
部署配置:熟悉CentOS和Ubuntu的安装流程,掌握镜像加速和性能优化配置
-
实战能力:
- 构建生产级Web应用镜像
- 部署LNMP等经典架构
- 实现微服务容器化
-
最佳实践:
- 镜像优化技巧
- 容器安全加固
- 常见问题排查方法
Docker作为云原生时代的基础设施,掌握它不仅能提升开发效率,更是现代DevOps工程师的必备技能。希望本文能帮助你构建完整的Docker知识体系,在实际工作中游刃有余。
参考资源:
- Docker官方文档:https://docs.docker.com/
- Docker Hub:https://hub.docker.com/
- Docker Compose文件参考:https://docs.docker.com/compose/compose-file/
- 阿里云容器镜像服务:https://help.aliyun.com/product/60716.html
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)