云服务器Docker容器化部署避坑指南:从Overlay2到cgroup v2的深度调优

0. 问题背景

很多人把Docker当虚拟机用,直接在云服务器上 yum install docker 就跑起来。结果磁盘无故暴涨、容器OOM悄无声息、网络延迟抖成心电图。踩坑两年后总结:默认配置只适合“能跑”,远不是“稳跑”

本文涉及的真实环境为 轻云互联 的4C8G云服务器,系统 CentOS 7.9 + 内核 5.10(升级过)。所有操作均为一线血泪验证。

1. 存储驱动:干掉Overlay,拥抱Overlay2

先确认当前驱动:

docker info | grep "Storage Driver"

大多数云镜像还在用 overlay(不是overlay2),这会导致容器删除后空间不释放,最终占满云盘。Overlay2才是现代推荐方案,而且需要内核支持 overlay2 + lowerdir 多层级。

切换到Overlay2的方式:

systemctl stop docker
vim /etc/docker/daemon.json
{
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
systemctl start docker
docker info | grep "Storage Driver"  # 确认显示 overlay2

如果内核版本低于4.0,override_kernel_check 会强制启用,但建议升级内核。轻云互联的镜像模板支持一键升级到5.x。

2. cgroup v2:别再让内存计入错误片

Docker依赖cgroup做资源隔离。CentOS7默认cgroup v1,但cgroup v2对内存回收更精准,尤其memory.highmemory.low 的配合能避免OOM Killer胡乱杀人。

启用cgroup v2(需内核4.5+):

grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
reboot
cat /proc/cmdline | grep cgroup  # 应有 unified_cgroup_hierarchy=1
docker info | grep "Cgroup"      # 显示 Cgroup Driver: cgroupfs 或 systemd

注意:cgroup v2下Docker必须用 cgroupfs 驱动而非 systemd(除非你装了最新的runc>=1.1),否则容器启动失败。修改daemon.json:

{
  "exec-opts": ["native.cgroupdriver=cgroupfs"]
}

重启后检查:docker info | grep "Cgroup Driver"

3. 资源限制:别让 --memory 白设

很多人写 docker run -m 512m,但系统内存压力时容器依然被OOM甚至宿主机严重swap。关键参数:

docker run -d --name nginx_demo \
  --memory="256m" \
  --memory-reservation="128m" \
  --memory-swap="256m" \       # swap总上限,等于memory表示不额外使用swap
  --cpu-period="100000" \
  --cpu-quota="50000" \        # 限制0.5核
  --kernel-memory="64m" \      # 限制内核内存
  nginx:alpine

真实排错:之前给PHP容器设 -m 512m --memory-swap -1(无上限),结果云服务器内存被吃光,Swap飙升到IO瓶颈。正确做法:--memory-swap 等于 --memory 彻底禁用swap,或设为2倍(如果业务需要换出)。

另外,云服务器上 /proc/sys/vm/swappiness 最好设成1(仍然使用swap,但极低概率),避免容器突发内存占用时系统频繁换页:

echo 1 > /proc/sys/vm/swappiness
sysctl -w vm.swappiness=1

4. 网络性能:bridge模式下的损耗该省则省

Docker默认bridge走NAT,性能损耗约5%-10% L3转发。对于高IO应用(如Redis、数据库),建议用host网络macvlan

host网络示例(直接共享宿主机网络栈,无额外封装):

docker run --network host -d nginx:alpine

缺点:端口冲突、无容器隔离。如果安全要求高,上macvlan:

docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 mynet
docker run --network mynet --ip 192.168.1.100 -d nginx

注意:macvlan需要主机开启ip_forward,并且容器IP落在同一子网,云服务商的安全组要放行。

5. 日志管理:慎用json-file,避免磁盘爆满

默认json-file日志不自动轮转,一周跑满20G云盘。推荐改用journaldlocal

{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

local驱动是Docker 20.10+专属,性能优于json-file且自动压缩。

6. 安全加固:用户命名空间映射

容器内root默认对应宿主机root,一旦逃逸直接拿root。打开用户映射:

usermod --add-subuids 100000-165535 --add-subgids 100000-165535 dockremap
systemctl restart docker
docker info | grep "Userns"  # 显示 Userns: exclusions

此时启动容器都自动使用remapped用户,容器内root在宿主机上是一个普通用户。

7. 实战:一键部署优化后的Nginx+PHP

在轻云互联云服务器上,用上面所有调优参数写一个完整的docker-compose.yml:

version: '3.8'
services:
  web:
    image: nginx:1.25-alpine
    network_mode: host
    mem_limit: 256m
    mem_reservation: 128m
    cpus: 0.5
    logging:
      driver: local
      options:
        max-size: "10m"
        max-file: "3"
    volumes:
      - /opt/www:/usr/share/nginx/html:ro
    security_opt:
      - no-new-privileges:true
  php:
    image: php:8.2-fpm-alpine
    network_mode: host
    mem_limit: 512m
    cpus: 0.5
    user: "1000:1000"
    environment:
      - PHP_OPCACHE_ENABLE=1
    volumes:
      - /opt/www:/var/www/html

启动前确保内核参数已调优:

echo "vm.swappiness=1" >> /etc/sysctl.conf
sysctl -p

运行 docker-compose up -d 后,使用 docker stats 观察资源使用,应稳定在设定范围内。如果遇到OOM,优先检查是否没设置 --memory-swap 导致swap吃掉内存。

8. 终极检查脚本

部署完成后建议跑一遍验证:

#!/bin/bash
echo "=== Storage Driver ==="
docker info 2>/dev/null | grep "Storage Driver"
echo "=== Cgroup Driver ==="
docker info 2>/dev/null | grep "Cgroup Driver"
echo "=== Kernel Memory & cgroup v2 ==="
cat /proc/cmdline | grep -o "unified_cgroup_hierarchy=1" || echo "No cgroup v2"
echo "=== Log Driver ==="
docker info 2>/dev/null | grep "Logging Driver"
echo "=== User Namespaces ==="
docker info 2>/dev/null | grep "Userns"
echo "=== Swappiness ==="
cat /proc/sys/vm/swappiness

全部参数都正常后,这台云服务器的Docker性能可媲美轻量级KVM。