第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. 如何设计一个安全的版本回滚策略?

相关资源

相关推荐
2601_949146538 小时前
Shell语音通知接口使用指南:运维自动化中的语音告警集成方案
运维·自动化
儒雅的晴天8 小时前
大模型幻觉问题
运维·服务器
Gofarlic_OMS9 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
通信大师9 小时前
深度解析PCC策略计费控制:核心网产品与应用价值
运维·服务器·网络·5g
dixiuapp9 小时前
智能工单系统如何选,实现自动化与预测性维护
运维·自动化
Elastic 中国社区官方博客9 小时前
如何防御你的 RAG 系统免受上下文投毒攻击
大数据·运维·人工智能·elasticsearch·搜索引擎·ai·全文检索
小锋学长生活大爆炸10 小时前
【教程】免Root在Termux上安装Docker
运维·docker·容器
进击切图仔10 小时前
常用 Docker 命令备份
运维·docker·容器
NotStrandedYet10 小时前
《国产系统运维笔记》第8期:挑战国产化流媒体部署——银河麒麟+龙芯架构编译SRS实战全记录
运维·kylin·国产化·银河麒麟·龙芯·信创运维·srs编译安装
默|笙11 小时前
【Linux】fd_重定向本质
linux·运维·服务器