Docker cgroup v2 永久修复方案
问题背景
在 Linux 系统中使用 Docker 时,特别是较新版本的系统(如 Ubuntu 22.04+)默认使用 cgroup v2,可能会导致 Docker 容器无法正常启动。这是因为 Docker 需要特定的 cgroup 挂载配置才能正常工作。看了一下网上的解决方法都为临时方案,重启系统后会失效,这里提供一个永久解决的方法。
解决方案
这里提供一个完整的修复脚本,包含以下功能:
- 自动检测 cgroup 版本
- 创建 systemd 服务确保永久挂载
- 立即挂载所需 cgroup
- 配置 Docker 使用正确的 cgroup 驱动
- 重启 Docker 及相关服务
修复脚本
#!/bin/bash
# Docker cgroup 永久修复脚本(仅针对 cgroup v2)
# 确保系统启动时自动挂载所需的 cgroup
# 检测 root 权限
if [ "$(id -u)" -ne 0 ]; then
echo "请使用 root 权限运行此脚本 (sudo $0)"
exit 1
fi
# 检测 cgroup 版本
detect_cgroup_version() {
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
echo "v2"
else
echo "v1"
fi
}
CGROUP_VERSION=$(detect_cgroup_version)
echo "检测到 cgroup 版本: $CGROUP_VERSION"
# 如果是 cgroup v1,直接退出
if [ "$CGROUP_VERSION" = "v1" ]; then
echo "当前系统使用 cgroup v1,无需执行此修复脚本。"
echo "如果 Docker 运行有问题,请检查是否已正确挂载 cgroup 子系统。"
exit 0
fi
# 1. 创建 systemd 服务确保永久挂载
create_systemd_service() {
echo "创建 systemd 服务确保永久挂载..."
SERVICE_FILE="/etc/systemd/system/docker-cgroup-mount.service"
cat > "$SERVICE_FILE" <<'EOF'
[Unit]
Description=Mount cgroups for Docker
Before=docker.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/bash -c "mkdir -p /sys/fs/cgroup/systemd"
ExecStart=/bin/bash -c "mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd || true"
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable docker-cgroup-mount.service
systemctl start docker-cgroup-mount.service
echo "Systemd 服务已创建并启用"
}
# 2. 立即挂载 cgroup(不等待重启)
mount_cgroups_now() {
echo "立即挂载 cgroups..."
mkdir -p /sys/fs/cgroup/systemd
if ! mountpoint -q /sys/fs/cgroup/systemd; then
mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd || {
echo "挂载失败,尝试替代方案..."
# 备用挂载方法
umount /sys/fs/cgroup 2>/dev/null || true
mount -t tmpfs cgroup_root /sys/fs/cgroup
mkdir -p /sys/fs/cgroup/systemd
mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
}
fi
echo "当前 cgroup 挂载状态:"
mount | grep cgroup
}
# 3. 配置 Docker 使用正确的 cgroup 驱动
configure_docker() {
echo "配置 Docker 使用 systemd cgroup 驱动..."
DOCKER_CONF="/etc/docker/daemon.json"
# 创建或修改 Docker 配置
if [ -f "$DOCKER_CONF" ]; then
# 备份现有配置
cp "$DOCKER_CONF" "${DOCKER_CONF}.bak-$(date +%Y%m%d%H%M%S)"
# 确保配置格式正确
if ! grep -q '"exec-opts"' "$DOCKER_CONF"; then
sed -i '2i\ "exec-opts": ["native.cgroupdriver=systemd"],' "$DOCKER_CONF"
fi
else
# 创建新配置
cat > "$DOCKER_CONF" <<'EOF'
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
fi
echo "Docker 配置文件内容:"
cat "$DOCKER_CONF"
}
# 4. 重启 Docker 服务
restart_docker() {
echo "重启 Docker 服务..."
systemctl daemon-reload
systemctl restart docker
# 检查状态
if ! systemctl is-active --quiet docker; then
echo "Docker 启动失败,查看日志:"
journalctl -u docker --since "5 minutes ago" | tail -n 30
exit 1
fi
echo "Docker 状态:"
systemctl status docker --no-pager -l | head -10
}
# 主执行流程(仅 cgroup v2 执行)
mount_cgroups_now
create_systemd_service
configure_docker
restart_docker
# 这里可以添加重启服务的命令
echo -e "\n修复完成!"
文章评论