写在前面
本文是 Docker 系列收官篇。前面的内容让容器"能跑",这篇讲让容器"在生产环境跑得稳、跑得安全":日志、监控、健康检查、资源限制、优雅关闭、安全加固,以及 Docker vs K8s 的选择。
一、生产环境清单
1
2
3
4
5
6
7
8
9
10
| 一个生产级容器应用应该有:
✓ 健康检查(让编排器知道是否健康)
✓ 资源限制(防止单容器吃光资源)
✓ 日志方案(收集、聚合)
✓ 监控(指标、告警)
✓ 重启策略(崩溃自动恢复)
✓ 优雅关闭(处理完请求再停)
✓ 非 root 用户
✓ 镜像扫描(无漏洞)
✓ 密钥管理(密钥不进镜像)
|
二、健康检查
1
2
3
| # Dockerfile 里定义健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
|
1
2
3
4
5
6
7
8
9
| # docker-compose.yml
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s # 启动宽限期
|
1
2
3
4
5
| 状态:starting → healthy → unhealthy
健康检查失败 → unhealthy
编排器(Docker Swarm / K8s)根据状态决定是否重启/摘流量
应用要提供 /health 端点(检查自身 + 依赖)
|
三、资源限制
1
2
3
4
5
6
7
8
9
10
11
| # docker-compose.yml
services:
app:
deploy:
resources:
limits:
cpus: "1.5" # 最多 1.5 核
memory: 512M # 最多 512M 内存
reservations: # 保底
cpus: "0.5"
memory: 128M
|
1
2
3
4
5
| # docker run 限制
docker run --cpus="1.5" --memory="512m" --memory-swap="1g" myapp
# OOM:容器内存超限会被内核 OOM Kill(重启)
# CPU 限流:超 cpu 配额会被节流(慢,但不杀)
|
1
2
3
4
| 为什么要限制:
不限制 → 一个容器内存泄漏/死循环,吃光宿主机
→ 影响其他容器("吵闹的邻居")
限制 → 隔离资源,单容器故障不扩散
|
四、重启策略
1
2
3
4
5
| docker run --restart=no # 不重启(默认)
docker run --restart=on-failure # 非正常退出才重启
docker run --restart=on-failure:5 # 最多重启 5 次
docker run --restart=always # 总是重启(包括手动 stop?stop 例外)
docker run --restart=unless-stopped # 总是重启,除非手动停止(推荐)
|
1
2
3
4
| unless-stopped 最常用:
崩溃 → 自动重启
手动 stop → 不重启
宿主机重启 → 容器跟着起来
|
五、优雅关闭
容器收到停止信号(SIGTERM),应处理完当前请求再退出:
1
2
| # 应用要监听 SIGTERM
# .NET/Java/Go 等运行时会处理,但要正确配置
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| docker stop 默认:
1. 发 SIGTERM
2. 等待 10 秒(grace period)
3. 没退出就 SIGKILL(强杀,可能丢数据)
docker stop -t 30 web # 等 30 秒
应用要做:
✓ 监听 SIGTERM
✓ 停止接收新请求
✓ 处理完已有请求
✓ 释放资源(关闭连接、刷盘)
✓ 退出
否则:强杀 → 请求中断、数据丢失
|
六、日志管理
1
2
3
4
5
6
7
| Docker 日志两种:
1. 容器 stdout/stderr(应用日志)
docker logs web
日志驱动(logging driver)决定怎么处理
2. 容器内文件日志
要挂载出来或用 agent 收集
|
1
2
3
4
5
6
7
8
| # 配置日志驱动 + 日志轮转(防日志撑爆磁盘)
services:
app:
logging:
driver: json-file
options:
max-size: "10m" # 单文件最大 10M
max-file: "3" # 保留 3 个
|
1
2
3
4
5
6
7
8
| 日志驱动:
json-file(默认)— 存文件
fluentd / syslog / journald — 转发到日志系统
none — 不存
生产方案:
应用日志输出到 stdout → Docker 收集 → 转发到 ELK/Loki
(容器十二要素应用原则:日志当事件流,输出到 stdout)
|
七、监控
1
2
3
| # 内置:实时资源占用
docker stats
# CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
|
1
2
3
4
5
6
7
8
9
10
| 生产监控栈:
cAdvisor — 采集容器指标(CPU/内存/网络/磁盘)
Prometheus — 存储时序指标
Grafana — 可视化看板
Node Exporter — 宿主机指标
应用内部指标 → Prometheus client 暴露 /metrics
容器指标 → cAdvisor
日志 → ELK/Loki
告警 → Alertmanager
|
八、安全加固
8.1 最小权限
1
2
3
4
5
6
7
8
9
10
11
12
| services:
app:
user: "1000:1000" # 非 root 运行
read_only: true # 根文件系统只读
tmpfs:
- /tmp # 需要写的目录用 tmpfs
cap_drop:
- ALL # 丢弃所有 Linux capabilities
cap_add:
- NET_BIND_SERVICE # 只加需要的
security_opt:
- no-new-privileges # 禁止提权
|
8.2 镜像安全
1
2
3
4
5
6
| ✓ 用可信基础镜像(官方、固定版本 tag)
✓ 镜像扫描:docker scout / trivy / clair
扫描已知漏洞(CVE)
✓ 用 distroless/scratch(减小攻击面)
✓ 多阶段构建(不带源码/构建工具)
✓ 不用 root
|
8.3 密钥管理
1
2
3
4
5
6
7
| ❌ 密钥写进镜像 / 环境变量明文(会泄露)
✓ Docker Secret(Swarm)/ K8s Secret
✓ 挂载文件(只读,不进镜像、不进 env)
✓ 外部密钥管理(Vault、云 KMS)
环境变量也不安全(inspect 能看到、子进程能读)
生产用 Secret 文件挂载或外部 KMS
|
8.4 更强的隔离
1
2
3
4
5
6
7
| 默认容器共享宿主机内核 → 内核漏洞可能逃逸
更强隔离方案:
gVisor — 用户态内核,拦截系统调用(Google)
Kata Containers — 轻量虚拟机跑容器(VM 级隔离)
Firecracker — 微 VM(AWS,极快启动)
多租户、高安全场景用这些替代默认 runc
|
九、Docker vs Kubernetes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| Docker / Docker Compose:
✓ 单机
✓ 简单、上手快
✓ 本地开发、CI、小项目
✗ 不能跨机器、故障自愈弱、无滚动更新
Kubernetes:
✓ 多机集群、自动调度
✓ 自愈(容器挂了自动重启/迁移)
✓ 滚动更新、回滚
✓ 服务发现、负载均衡、扩缩容
✓ 配置/密钥管理
✗ 复杂、运维成本高
选择:
单机 / 小项目 / 本地 → Docker Compose
多机 / 生产 / 微服务 → Kubernetes
中间过渡 → Docker Swarm(简单,但已式微)
生产正规军:Docker 打镜像 → K8s 编排运行
(Docker 是构建/打包工具,K8s 是运行/编排平台)
|
十、CI/CD 集成
1
2
3
4
5
6
7
8
9
10
11
| 典型流程(结合本站 GitHub Actions 自动部署文章):
开发者 push 代码
→ GitHub Actions 触发
→ docker build 构建镜像
→ docker push 到镜像仓库
→ 服务器 docker pull + docker compose up -d
(或 K8s kubectl apply)
Docker 让"构建一次,到处运行"成为可能
是 CI/CD 流水线的核心组件
|
十一、小结
- 生产清单:健康检查、资源限制、重启策略、日志、监控、优雅关闭、安全
- 健康检查:HEALTHCHECK + /health 端点
- 资源限制:limits/reservations,防止"吵闹邻居"
- 优雅关闭:监听 SIGTERM,处理完请求再退出
- 日志:输出 stdout,日志驱动转发,轮转防爆盘
- 监控:cAdvisor + Prometheus + Grafana
- 安全:非 root、只读根、cap_drop、镜像扫描、密钥管理、gVisor
- Docker vs K8s:Docker 打包构建,K8s 编排运行
系列总结
Docker 五篇完结:
- 基础与原理:容器 vs 虚拟机、namespace/cgroups/UnionFS
- Dockerfile:多阶段构建、镜像瘦身、安全
- Compose:多服务编排、服务发现、依赖管理
- 网络与存储:bridge 自定义网络、Volume/Bind/tmpfs、无状态原则
- 生产实践:健康检查、资源限制、日志监控、安全加固、Docker vs K8s
核心心法:容器让应用与运行环境解耦——一次构建,到处运行。Docker 负责打包和单机,K8s 负责多机编排。理解容器的隔离(namespace)、限制(cgroups)、分层(UnionFS),就理解了云原生的根基。