第3章 Docker的功能特性

3.1 环境一致性保证

3.1.1 "在我机器上能运行"的困境

传统开发中常见的问题:

复制代码
开发环境 (MacOS)       测试环境 (Ubuntu 20.04)    生产环境 (CentOS 7)
├── Python 3.10        ├── Python 3.8              ├── Python 3.6
├── MySQL 8.0          ├── MySQL 5.7               ├── MariaDB 10.3
├── Redis 7.0          ├── Redis 6.2               ├── Redis 5.0
└── Node.js 18         └── Node.js 16              └── Node.js 14

结果:同一份代码在不同环境表现不一致!

3.1.2 Docker如何保证一致性

Docker通过打包整个运行环境解决这个问题:

dockerfile 复制代码
FROM python:3.9-slim

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    gcc \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# 设置工作目录
WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 设置环境变量
ENV FLASK_APP=app.py
ENV FLASK_ENV=production

# 暴露端口
EXPOSE 5000

# 启动命令
CMD ["flask", "run", "--host=0.0.0.0"]

关键要素

  1. 确定性的基础镜像python:3.9-slim 保证基础环境一致
  2. 声明式依赖管理requirements.txt 锁定依赖版本
  3. 环境变量配置:统一的配置方式
  4. 启动命令标准化:相同的启动流程

3.1.3 一次构建,到处运行

bash 复制代码
# 开发环境构建
docker build -t myapp:1.0 .

# 开发环境运行
docker run -d -p 5000:5000 myapp:1.0

# 推送到仓库
docker push registry.company.com/myapp:1.0

# 测试环境部署(完全相同的镜像)
ssh test-server
docker pull registry.company.com/myapp:1.0
docker run -d -p 5000:5000 registry.company.com/myapp:1.0

# 生产环境部署(完全相同的镜像)
ssh prod-server
docker pull registry.company.com/myapp:1.0
docker run -d -p 5000:5000 registry.company.com/myapp:1.0

保证 :所有环境运行的是完全相同的二进制文件和配置。

3.1.4 配置与代码分离

虽然镜像保持一致,但不同环境的配置可以不同:

bash 复制代码
# 开发环境:使用开发数据库
docker run -d \
  -e DB_HOST=localhost \
  -e DB_PORT=5432 \
  -e DB_NAME=dev_db \
  -e DEBUG=true \
  myapp:1.0

# 生产环境:使用生产数据库
docker run -d \
  -e DB_HOST=prod-db.company.com \
  -e DB_PORT=5432 \
  -e DB_NAME=prod_db \
  -e DEBUG=false \
  myapp:1.0

或使用配置文件:

bash 复制代码
# 使用不同的配置文件
docker run -d -v /config/dev.env:/app/.env myapp:1.0    # 开发
docker run -d -v /config/prod.env:/app/.env myapp:1.0   # 生产

依赖版本锁定

Python示例

txt 复制代码
# requirements.txt - 锁定具体版本
Flask==2.3.0
SQLAlchemy==2.0.15
psycopg2-binary==2.9.6
redis==4.5.5

Node.js示例

json 复制代码
{
  "dependencies": {
    "express": "4.18.2",
    "mongoose": "7.0.3",
    "redis": "4.6.5"
  }
}

Docker镜像包含这些确定版本的依赖,避免"依赖地狱"。

3.2 快速部署与扩展

3.2.1 快速部署

3.2.1.1 传统部署流程
复制代码
1. 准备服务器 (15分钟)
2. 安装操作系统 (30分钟)
3. 配置网络和安全 (20分钟)
4. 安装运行时 (Python/Node.js) (15分钟)
5. 安装系统依赖 (10分钟)
6. 部署应用代码 (10分钟)
7. 配置服务自启动 (10分钟)
8. 测试验证 (20分钟)

总计:约2-3小时
3.2.1.2 Docker部署流程
bash 复制代码
# 一条命令,30秒完成
docker run -d -p 80:80 myapp:latest

# 或使用Docker Compose
docker-compose up -d

时间对比

  • 传统方式:2-3小时
  • Docker方式:30秒
  • 提速200倍+

3.2.2 水平扩展

当流量增加时,快速扩展实例:

bash 复制代码
# 运行3个相同的应用实例
docker run -d --name app1 -p 8001:80 myapp:latest
docker run -d --name app2 -p 8002:80 myapp:latest
docker run -d --name app3 -p 8003:80 myapp:latest

# 配合负载均衡器(如Nginx)分发流量

使用Docker Compose扩展

bash 复制代码
# 启动1个实例
docker-compose up -d

# 扩展到5个实例
docker-compose up -d --scale web=5
yaml 复制代码
# docker-compose.yml
version: '3'
services:
  web:
    image: myapp:latest
    # 不指定具体端口,让Docker自动分配
  
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

3.2.3 蓝绿部署

无停机更新应用:

bash 复制代码
# 当前运行 v1.0(绿色环境)
docker run -d --name app-green -p 80:80 myapp:1.0

# 启动 v2.0(蓝色环境)
docker run -d --name app-blue -p 8080:80 myapp:2.0

# 测试 v2.0
curl http://localhost:8080

# 切换流量到 v2.0(通过负载均衡器)
# 停止 v1.0
docker stop app-green
docker rm app-green

# 如果v2.0有问题,快速回滚
docker stop app-blue
docker start app-green

3.2.4 金丝雀发布

逐步切换流量到新版本:

bash 复制代码
# 运行4个v1.0实例
docker run -d --name app1 myapp:1.0
docker run -d --name app2 myapp:1.0
docker run -d --name app3 myapp:1.0
docker run -d --name app4 myapp:1.0

# 将1个实例更新到v2.0(25%流量)
docker stop app4
docker run -d --name app4 myapp:2.0

# 观察指标,如果正常,继续替换其他实例
docker stop app3
docker run -d --name app3 myapp:2.0

# 逐步完成全部替换

3.2.5 自动化部署

结合CI/CD实现自动部署:

yaml 复制代码
# GitLab CI 示例
stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - docker build -t myapp:$CI_COMMIT_SHA .
    - docker push myapp:$CI_COMMIT_SHA

test:
  stage: test
  script:
    - docker run myapp:$CI_COMMIT_SHA pytest

deploy_production:
  stage: deploy
  script:
    - docker pull myapp:$CI_COMMIT_SHA
    - docker stop myapp-prod || true
    - docker rm myapp-prod || true
    - docker run -d --name myapp-prod -p 80:80 myapp:$CI_COMMIT_SHA
  only:
    - main

3.3 资源隔离与限制

为什么需要资源限制

没有资源限制的风险:

复制代码
场景:3个容器共享主机
- 容器A:正常应用,需要1GB内存
- 容器B:正常应用,需要1GB内存
- 容器C:出现内存泄漏,无限增长

结果:容器C占满所有内存,导致容器A、B和宿主机崩溃!

CPU资源限制

限制CPU份额(相对值)
bash 复制代码
# 设置CPU份额为512(默认1024)
docker run -d --cpu-shares=512 nginx

# 两个容器的CPU使用比例
docker run -d --name app1 --cpu-shares=1024 myapp  # 得到66.7%
docker run -d --name app2 --cpu-shares=512 myapp   # 得到33.3%

注意--cpu-shares 是相对权重,只在CPU竞争时生效。

限制CPU核心数(绝对值)
bash 复制代码
# 限制使用1.5个CPU核心
docker run -d --cpus="1.5" nginx

# 限制使用特定的CPU核心(0和1)
docker run -d --cpuset-cpus="0,1" nginx

# 限制CPU使用率上限为50%
docker run -d --cpu-quota=50000 --cpu-period=100000 nginx

实践建议

bash 复制代码
# 开发环境:不限制
docker run -d myapp

# 测试环境:限制CPU防止干扰
docker run -d --cpus="2" myapp

# 生产环境:根据性能测试结果精确限制
docker run -d --cpus="4" --memory="4g" myapp

内存资源限制

限制内存大小
bash 复制代码
# 限制最大内存为512MB
docker run -d --memory="512m" nginx

# 限制内存和交换空间总和为1GB
docker run -d --memory="512m" --memory-swap="1g" nginx

# 禁用交换空间
docker run -d --memory="512m" --memory-swap="512m" nginx
OOM行为控制
bash 复制代码
# 当内存不足时,不要杀死容器(慎用)
docker run -d --memory="512m" --oom-kill-disable nginx

# 设置OOM分数调整值(-1000到1000,值越低越不容易被杀死)
docker run -d --memory="512m" --oom-score-adj=-500 nginx
内存预留
bash 复制代码
# 预留256MB内存(软限制)
docker run -d --memory="1g" --memory-reservation="256m" nginx

当内存不足时,Docker会尝试将容器内存使用降到预留值以下。

磁盘I/O限制

bash 复制代码
# 限制块设备读取速度为1MB/s
docker run -d --device-read-bps /dev/sda:1mb nginx

# 限制块设备写入速度为1MB/s
docker run -d --device-write-bps /dev/sda:1mb nginx

# 限制读取IOPS为100
docker run -d --device-read-iops /dev/sda:100 nginx

# 限制写入IOPS为100
docker run -d --device-write-iops /dev/sda:100 nginx

# 设置I/O权重(相对值,10-1000)
docker run -d --blkio-weight 500 nginx

资源限制实战示例

yaml 复制代码
# docker-compose.yml - 完整的资源限制配置
version: '3.8'
services:
  web:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G
    restart: unless-stopped

  database:
    image: postgres:13
    deploy:
      resources:
        limits:
          cpus: '4'
          memory: 4G
        reservations:
          cpus: '2'
          memory: 2G
    volumes:
      - db-data:/var/lib/postgresql/data

  cache:
    image: redis:6
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

volumes:
  db-data:

查看资源使用情况

bash 复制代码
# 实时查看所有容器的资源使用
docker stats

# 查看特定容器的资源使用
docker stats myapp

# 输出示例:
# CONTAINER   CPU %   MEM USAGE / LIMIT     MEM %   NET I/O         BLOCK I/O
# myapp       2.5%    256MiB / 512MiB       50%     1.2kB / 648B    0B / 0B

3.4 版本控制与回滚机制

镜像标签策略

语义化版本
bash 复制代码
# 使用语义化版本号
docker build -t myapp:1.0.0 .
docker build -t myapp:1.1.0 .
docker build -t myapp:2.0.0 .

# 同时打多个标签
docker tag myapp:1.1.0 myapp:1.1
docker tag myapp:1.1.0 myapp:1
docker tag myapp:1.1.0 myapp:latest
Git提交哈希
bash 复制代码
# 使用Git提交哈希作为标签
GIT_HASH=$(git rev-parse --short HEAD)
docker build -t myapp:$GIT_HASH .
docker tag myapp:$GIT_HASH myapp:latest

# 可追溯到具体代码版本
docker run -d myapp:a3f7c8e
时间戳标签
bash 复制代码
# 使用时间戳
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
docker build -t myapp:$TIMESTAMP .

# 示例:myapp:20260210-143022

版本回滚

简单回滚
bash 复制代码
# 当前运行v2.0,出现问题
docker stop myapp
docker rm myapp

# 回滚到v1.0
docker run -d --name myapp -p 80:80 myapp:1.0
保留多个版本
bash 复制代码
# 同时保留多个版本的镜像
docker images
# REPOSITORY   TAG      IMAGE ID       SIZE
# myapp        3.0      abc123         200MB
# myapp        2.0      def456         195MB
# myapp        1.0      ghi789         180MB

# 快速切换版本
docker stop myapp-v3
docker run -d --name myapp-v2 -p 80:80 myapp:2.0
使用数据卷保持数据
bash 复制代码
# 升级时保持数据不丢失
docker run -d \
  --name myapp-v1 \
  -v app-data:/app/data \
  -p 80:80 \
  myapp:1.0

# 升级到v2.0,数据卷复用
docker stop myapp-v1
docker run -d \
  --name myapp-v2 \
  -v app-data:/app/data \
  -p 80:80 \
  myapp:2.0

# 如需回滚,数据依然完整
docker stop myapp-v2
docker run -d \
  --name myapp-v1-rollback \
  -v app-data:/app/data \
  -p 80:80 \
  myapp:1.0

镜像历史追踪

bash 复制代码
# 查看镜像构建历史
docker history myapp:2.0

# 查看镜像详细信息(包括构建时间、标签等)
docker image inspect myapp:2.0

# 导出镜像历史到JSON
docker image inspect myapp:2.0 --format='{{json .}}' | jq

回滚策略最佳实践

yaml 复制代码
# docker-compose.yml - 蓝绿部署配置
version: '3.8'
services:
  app-blue:
    image: myapp:${BLUE_VERSION:-1.0}
    ports:
      - "8080:80"
    environment:
      - COLOR=blue

  app-green:
    image: myapp:${GREEN_VERSION:-2.0}
    ports:
      - "8081:80"
    environment:
      - COLOR=green

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app-blue
      - app-green

切换版本:

bash 复制代码
# 当前使用blue(v1.0)
export BLUE_VERSION=1.0
export GREEN_VERSION=2.0
docker-compose up -d

# 切换到green(v2.0),通过修改nginx配置

# 如需回滚,再次切换nginx配置到blue

3.5 微服务架构的支持

单体应用 vs 微服务

单体应用

复制代码
┌─────────────────────────────┐
│      Monolithic App         │
│  ┌─────────────────────┐    │
│  │  User Module        │    │
│  │  Order Module       │    │
│  │  Payment Module     │    │
│  │  Product Module     │    │
│  └─────────────────────┘    │
│  ┌─────────────────────┐    │
│  │    Database         │    │
│  └─────────────────────┘    │
└─────────────────────────────┘

微服务架构

复制代码
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│  User    │  │  Order   │  │ Payment  │  │ Product  │
│ Service  │  │ Service  │  │ Service  │  │ Service  │
└────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘
     │             │              │              │
   ┌─┴─┐         ┌─┴─┐          ┌─┴─┐          ┌─┴─┐
   │DB │         │DB │          │DB │          │DB │
   └───┘         └───┘          └───┘          └───┘

Docker与微服务的契合

1. 服务隔离

每个微服务运行在独立容器中:

bash 复制代码
# 用户服务
docker run -d --name user-service -p 8001:80 user-service:1.0

# 订单服务
docker run -d --name order-service -p 8002:80 order-service:1.0

# 支付服务
docker run -d --name payment-service -p 8003:80 payment-service:1.0

# 商品服务
docker run -d --name product-service -p 8004:80 product-service:1.0
2. 独立部署
bash 复制代码
# 只更新订单服务,不影响其他服务
docker stop order-service
docker rm order-service
docker run -d --name order-service -p 8002:80 order-service:2.0
3. 独立扩展
bash 复制代码
# 订单服务访问量大,扩展为3个实例
docker run -d --name order-service-1 -p 8002:80 order-service:1.0
docker run -d --name order-service-2 -p 8003:80 order-service:1.0
docker run -d --name order-service-3 -p 8004:80 order-service:1.0

# 其他服务保持1个实例

Docker Compose管理微服务

yaml 复制代码
# docker-compose.yml
version: '3.8'

services:
  user-service:
    build: ./user-service
    ports:
      - "8001:80"
    environment:
      - DB_HOST=user-db
    depends_on:
      - user-db
    networks:
      - microservices

  order-service:
    build: ./order-service
    ports:
      - "8002:80"
    environment:
      - DB_HOST=order-db
      - USER_SERVICE_URL=http://user-service
    depends_on:
      - order-db
      - user-service
    networks:
      - microservices

  payment-service:
    build: ./payment-service
    ports:
      - "8003:80"
    environment:
      - DB_HOST=payment-db
      - ORDER_SERVICE_URL=http://order-service
    depends_on:
      - payment-db
      - order-service
    networks:
      - microservices

  product-service:
    build: ./product-service
    ports:
      - "8004:80"
    environment:
      - DB_HOST=product-db
    depends_on:
      - product-db
    networks:
      - microservices

  # 数据库服务
  user-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=user_db
    networks:
      - microservices

  order-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=order_db
    networks:
      - microservices

  payment-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=payment_db
    networks:
      - microservices

  product-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=product_db
    networks:
      - microservices

  # API网关
  api-gateway:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - user-service
      - order-service
      - payment-service
      - product-service
    networks:
      - microservices

networks:
  microservices:
    driver: bridge

启动所有服务:

bash 复制代码
docker-compose up -d

服务发现与通信

容器间通过服务名通信:

python 复制代码
# order-service中调用user-service
import requests

# 使用服务名作为主机名
user_data = requests.get('http://user-service/api/users/123')

Docker自动解析服务名到容器IP。

微服务监控

yaml 复制代码
# 添加监控服务
services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - microservices

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    networks:
      - microservices

3.6 小结

通过本章学习,我们掌握了Docker的五大核心功能特性:

环境一致性

  • 通过镜像封装完整运行环境
  • 一次构建,到处运行
  • 配置与代码分离

快速部署与扩展

  • 秒级启动容器
  • 快速水平扩展
  • 支持蓝绿部署和金丝雀发布
  • 自动化CI/CD集成

资源隔离与限制

  • CPU、内存、磁盘I/O限制
  • 防止资源耗尽
  • 精确的资源配额管理

版本控制与回滚

  • 镜像标签管理
  • 快速版本切换
  • 数据持久化保证安全回滚

微服务架构支持

  • 服务隔离
  • 独立部署和扩展
  • 服务发现和通信
  • 完整的微服务生态

实践建议

  1. 开发环境:使用Docker保证团队环境一致
  2. 测试环境:使用资源限制防止相互干扰
  3. 生产环境:结合编排工具(Kubernetes)管理大规模部署
  4. 监控告警:始终监控容器资源使用情况

3.7 下一步

在第4章中,我们将学习Docker的安装与配置:

  • Linux系统安装Docker
  • Docker Desktop(Windows/macOS)
  • Docker配置文件详解
  • 镜像加速器配置
  • 权限与用户组设置

掌握正确的安装和配置是后续实践的基础。


本章思考题

  1. 在你的项目中,如何利用Docker的环境一致性特性避免"在我机器上能运行"的问题?
  2. 什么场景下需要限制容器的资源使用?如何设置合理的限制值?
  3. 微服务架构中,每个服务应该如何设计镜像和配置管理?
  4. 如何设计一个安全的版本回滚策略?

相关资源

相关推荐
王飞飞不会飞4 分钟前
Mac 安装Hermes Agent 过程记录
运维·深度学习·机器学习
徐子元竟然被占了!!25 分钟前
Nginx
运维·nginx
SPC的存折1 小时前
6、Docker常用配置
运维·docker·容器
图图玩ai1 小时前
SSH 命令管理工具怎么选?从命令收藏到批量执行一次讲清
linux·nginx·docker·ai·程序员·ssh·可视化·gmssh·批量命令执行
星谐2 小时前
AutoUploadLL:自动化上传工具开发实践
运维·自动化
NineData2 小时前
NineData将亮相2026德国汉诺威工业博览会
运维·数据库·后端
CXH7283 小时前
nginx——https
运维·nginx·https
SPC的存折3 小时前
4、Docker私有仓库
运维·docker·容器
开开心心_Every3 小时前
扫描软件,部分文档文字表格识别功能可免费
运维·服务器·pdf·电脑·excel·3dsmax·houdini
陆伟峰(云固件作者)3 小时前
Linux Mint 22.3:给初学者的第一份 Linux 说明书
linux·运维·服务器