CentOS 7下Docker从18.09.8升级至20.10.12实战指南
1. 升级前,先想清楚为什么和做什么
如果你正在维护一个基于 CentOS 7 的生产环境,并且 Docker 版本还停留在 18.09.8,那么考虑升级到 20.10.12 绝对是个明智的决定。我经历过好几次因为 Docker 版本过旧导致的问题,比如某些新工具链不兼容、安全漏洞无法修复,或者想用一些新特性(比如 BuildKit、cgroup v2 支持)时发现版本不支持,那种感觉就像开着一辆老爷车想上高速,心里总是不踏实。
从 18.09.8 到 20.10.12,这中间跨越了多个大版本,带来的不仅仅是版本号的提升。20.10 系列引入了很多重要的改进,比如更稳定的 containerd 作为默认运行时、对 cgroup v2 的初步支持、docker scan 镜像安全扫描功能,以及大量性能优化和 Bug 修复。对于生产环境来说,稳定性是第一位的,而 20.10.12 是一个长期支持(LTS)版本,经过了更充分的测试,能提供更可靠的服务。
但在动手之前,我们不能脑袋一热就直接开干。生产环境的升级,每一步都得走得稳。我建议你先问自己几个问题:当前服务器上跑了哪些重要的容器?有没有做数据备份?升级的窗口期有多长?有没有回滚方案?把这些想清楚了,再开始操作,心里才有底。接下来,我会带你一步步完成这次升级,把我在实际运维中踩过的坑和总结的经验都分享给你,确保过程平滑、可控。
2. 升级前的准备工作:备份与检查
升级就像给服务器做手术,术前检查必不可少。这一步做得好,能避免至少 80% 的意外情况。我吃过没做准备的亏,有一次升级后一个老容器的日志驱动不兼容,直接启动不了,差点造成线上事故。
2.1 全面备份现有容器和数据
首先,我们需要把当前正在运行的容器状态和数据都保存下来。最直接的方法就是使用 docker ps -a 命令列出所有容器,包括已停止的。然后,为每一个需要保留的容器创建镜像备份。虽然 Docker 本身不鼓励把容器当虚拟机用,但备份其数据卷和配置是必须的。
# 1. 查看所有容器,记录下 CONTAINER ID 和 NAMES
docker ps -a
# 2. 对重要的、有状态的服务容器,建议使用 docker commit 创建一个临时镜像快照(仅用于备份,非最佳实践,但紧急情况有用)
docker commit <container_id> backup-<container_name>:pre-upgrade
# 3. 更推荐的方式:备份容器的数据卷(volumes)
# 假设你的应用数据挂载在宿主机的 /opt/app/data 目录
tar -czf /backup/docker_volumes_backup_$(date +%Y%m%d).tar.gz /var/lib/docker/volumes/
# 或者备份整个 Docker 工作目录(谨慎,数据量大)
# tar -czf /backup/docker_root_dir_backup.tar.gz /var/lib/docker/
除了容器本身,Docker 的配置也至关重要。特别是如果你自定义过 /etc/docker/daemon.json 这个文件,里面可能配置了镜像加速器、日志驱动、存储驱动等。一定要把它备份出来:
cp /etc/docker/daemon.json /etc/docker/daemon.json.backup.$(date +%Y%m%d)
另外,检查一下 Docker 服务的 systemd 配置文件。在 CentOS 7 下,通常是 /usr/lib/systemd/system/docker.service。看看有没有自定义的启动参数,比如 --graph(指定 Docker 根目录)或 --storage-driver,这些信息在升级后可能需要重新配置。
2.2 检查系统环境和依赖
CentOS 7 虽然老旧,但支撑 Docker 20.10.12 是没问题的。我们还是要确认一下系统内核版本和必要的依赖包。
# 查看内核版本,建议在 3.10 以上
uname -r
# 检查 yum 仓库是否正常,更新系统基础包(非必须,但建议)
yum check-update
# 可以升级一下系统,但注意如果内核升级了可能需要重启
# yum -y update
最关键的是,确认当前 Docker 18.09.8 的运行状态,并优雅地停止所有容器。我们不希望升级过程中有容器在运行,导致文件锁冲突或数据不一致。
# 停止 Docker 服务,这将停止所有容器
systemctl stop docker
# 再次确认没有 Docker 相关进程在运行
ps aux | grep -E 'dockerd|containerd' | grep -v grep
注意:在生产环境中,停止 Docker 服务意味着所有容器服务都会中断。请务必在计划维护窗口内操作,并通知相关方。如果有些服务不能停,需要考虑搭建高可用集群,在单节点上进行滚动升级。
3. 彻底卸载旧版本 Docker
很多人觉得升级就是直接 yum update,但对于 Docker 这种核心组件,我强烈建议先彻底卸载旧版本。这是因为 Docker 的包名和结构在版本迭代中可能发生变化,直接升级有时会残留一些旧配置,引发难以排查的兼容性问题。我们采用“先破后立”的方式,更干净。
3.1 使用 yum 移除 Docker 组件
Docker 旧版本(CE)的包名通常是 docker、docker-client、docker-common 等。我们用 yum remove 命令将它们一并移除。
# 移除 Docker 旧版本及相关安装包
sudo yum remove -y docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
执行这个命令后,yum 会列出将要删除的包,并提示你确认。输入 y 继续。这里移除的是 Docker 的二进制文件和系统服务,但非常重要的一点:默认情况下,yum remove 不会删除 /var/lib/docker/ 这个目录。这个目录里存放着所有的镜像、容器、数据卷和网络配置,是我们宝贵的“数据”。保留它,我们升级后原有的镜像和容器数据(只要存储驱动兼容)就都还在。
3.2 清理残留的配置文件(可选但建议)
虽然 yum 移除了主程序,但一些旧的配置文件可能还散落在系统里。我们可以手动清理一下,避免对新版本造成干扰。主要检查两个地方:
-
旧的 systemd 服务文件:如果之前是从非常旧的版本升级上来的,可能会有残留。
# 检查是否有旧的服务文件,通常新版本会覆盖,但检查一下无妨 ls -la /etc/systemd/system/docker.service.d/ 2>/dev/null # 如果有自定义配置,请备份后再删除 -
旧的 CLI 配置文件:用户目录下的
.docker配置目录通常不影响服务,但如果你之前配置过命令行认证,可以留意。# 通常是客户端配置,升级后一般兼容 ls -la ~/.docker/
做完这些,我们的系统就处于一个“没有 Docker”但“数据全在”的状态,为安装一个全新的、干净的 Docker 20.10.12 做好了准备。
4. 配置仓库并安装 Docker 20.10.12
现在,我们开始安装新版本。CentOS 7 默认的 yum 仓库里没有 Docker CE,所以我们需要先添加 Docker 的官方 YUM 仓库。为了加速下载,我们通常使用国内镜像源,比如阿里云。
4.1 安装必要的工具并设置稳定仓库
首先,安装 yum-utils 工具包,它提供了 yum-config-manager 这个实用工具,方便我们管理 yum 仓库。
sudo yum install -y yum-utils
接下来,使用 yum-config-manager 添加 Docker 的官方稳定仓库。这里我们使用阿里云的镜像地址,速度会快很多。
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
添加成功后,你可以查看 /etc/yum.repos.d/ 目录下,应该多了一个 docker-ce.repo 文件。然后,我们更新一下 yum 的软件包索引,确保能获取到仓库中最新的软件包列表。
sudo yum makecache fast
4.2 安装指定版本 20.10.12
我们不安装最新版,而是安装指定的稳定版本 20.10.12。这样做是为了版本可控,避免引入未知的不稳定因素。
# 首先,查看仓库中可用的 Docker CE 版本,确认 20.10.12 存在
yum list docker-ce --showduplicates | sort -r | grep 20.10
# 你会看到类似这样的输出,注意版本号前的 `3:` 是 epoch,安装时需要带上
# docker-ce.x86_64 3:20.10.12-3.el7 docker-ce-stable
# docker-ce.x86_64 3:20.10.11-3.el7 docker-ce-stable
# ...
# 安装指定版本的 docker-ce, docker-ce-cli 和 containerd.io
sudo yum install -y docker-ce-20.10.12 docker-ce-cli-20.10.12 containerd.io
在安装过程中,yum 会解析依赖关系。你可能会注意到,除了这三个核心包,它还会自动安装一些新的依赖,比如 docker-ce-rootless-extras(用于 rootless 模式)、docker-scan-plugin(安全扫描插件)、fuse-overlayfs 和 slirp4netns(rootless 模式依赖)等。这是正常的,新版本的功能更丰富,依赖也更多。全程输入 y 确认安装即可。
安装完成后,不要急着启动。我们先配置 Docker 服务开机自启,这样服务器重启后 Docker 能自动运行。
sudo systemctl enable docker
5. 关键配置迁移与兼容性调整
安装完新版本,直接启动大概率会成功,但之前运行的容器可能因为配置不兼容而无法启动。这一步是升级能否平滑过渡的关键,我踩过的坑主要都在这。
5.1 处理存储驱动兼容性:overlay2 是唯一选择
Docker 18.09 默认可能还在使用 overlay 或 devicemapper 存储驱动。而从 Docker 20.10 开始,社区强烈推荐并默认使用 overlay2 驱动,它对性能、稳定性和功能的支持都是最好的。如果你的旧环境不是 overlay2,就需要迁移。
首先,检查旧的数据目录使用的是哪种驱动。虽然数据 (/var/lib/docker) 我们保留了,但驱动信息在子目录里。一个简单的判断方法是看 /var/lib/docker 下是否有 overlay2 目录。更准确的方式是回忆或查找旧的 daemon.json 配置。
如果确认需要迁移,这是一个高风险操作。对于生产环境,如果数据量不大,最安全的方法是备份镜像(docker save)和卷数据,然后彻底清理 /var/lib/docker,让 Docker 用新驱动重新开始。如果数据量庞大,必须迁移,可以参考 Docker 官方文档的存储驱动迁移指南,过程复杂且耗时。
幸运的是,从 18.09.8 开始,默认驱动很可能已经是 overlay2 了。我们可以通过恢复之前备份的 daemon.json,并明确指定驱动来确保一致。
# 恢复之前的配置(如果之前有自定义配置)
sudo cp /etc/docker/daemon.json.backup.* /etc/docker/daemon.json
# 编辑 daemon.json,确保存储驱动是 overlay2
sudo vi /etc/docker/daemon.json
在 daemon.json 中加入或确认以下内容:
{
"storage-driver": "overlay2"
}
5.2 解决常见的运行时错误:runc 与 SELinux
启动 Docker 服务后,尝试启动旧容器,你可能会遇到两个经典错误。
错误一:Unknown runtime specified docker-runc
这是因为旧版本 Docker(尤其是 CentOS 7 自带或早期安装的)在容器配置中使用了特定的运行时名称 docker-runc,而新版本 Docker 默认使用标准的 runc。我们需要批量修复容器配置文件。
# 在启动 Docker 服务后,如果容器启动报此错,执行以下命令
# 它会查找 /var/lib/docker/containers/ 下所有配置文件,将 docker-runc 替换为 runc
# 先备份容器目录(谨慎起见)
sudo cp -r /var/lib/docker/containers /var/lib/docker/containers.backup
# 执行替换操作
sudo grep -rl 'docker-runc' /var/lib/docker/containers/ | sudo xargs sed -i 's/docker-runc/runc/g'
错误二:invalid argument 关于 overlay mount 或 SELinux 标签
这个错误通常和 SELinux 有关。CentOS 7 默认启用 SELinux,而 Docker 在操作文件系统时需要正确的安全上下文。
解决方法 A(推荐,更安全):将 SELinux 设置为宽容模式(permissive),这样它只记录警告而不真正拦截。
# 编辑 SELinux 配置文件
sudo vi /etc/selinux/config
# 将 SELINUX=enforcing 改为 SELINUX=permissive
# 保存退出后,重启系统使配置生效,或者临时设置(重启失效):
sudo setenforce 0
解决方法 B:在 Docker 启动参数中禁用 SELinux 支持(不推荐用于严格安全要求的环境)。
# 编辑 docker 服务配置文件
sudo vi /etc/sysconfig/docker
# 找到 OPTIONS 行,移除 `--selinux-enabled` 参数
# 例如:OPTIONS="--selinux-enabled --log-driver=journald" 改为 OPTIONS="--log-driver=journald"
# 然后重启 docker 服务
sudo systemctl restart docker
我个人在生产环境中倾向于使用方法 A(permissive 模式),因为它既避免了访问错误,又保留了 SELinux 的审计日志,方便后续排查安全问题。
6. 验证升级结果与功能测试
配置调整完成后,现在是验收成果的时候了。我们一步一步验证,确保一切如预期。
6.1 基础验证:版本与服务状态
首先,启动 Docker 服务并检查版本。
sudo systemctl start docker
sudo systemctl status docker # 确保状态是 active (running)
docker --version
你应该看到输出:Docker version 20.10.12, build e91ed57。恭喜,核心版本升级成功了。
然后,运行一个经典的测试容器,检查 Docker 基本功能是否正常。
sudo docker run --rm hello-world
这个命令会下载一个小的测试镜像并运行,如果最后打印出 Hello from Docker! 等信息,说明 Docker 守护进程、镜像拉取、容器运行功能都正常。
6.2 数据验证:镜像与容器恢复
接下来是重头戏:检查我们原有的镜像和容器数据是否完好。
# 列出所有镜像,看看之前的镜像是否还在
docker images
# 列出所有容器(包括已停止的),检查它们的配置是否被正确读取
docker ps -a
如果 docker ps -a 能列出之前的容器,并且状态是 Exited,那就成功了一大半。尝试启动一个重要的业务容器进行测试。
docker start <你的容器名或ID>
docker logs <你的容器名或ID> # 查看启动日志,确保没有报错
如果容器启动失败,结合前面提到的 docker logs 和 docker inspect <container_id> 命令仔细查看错误信息。常见问题除了上述的 runc 和 SELinux,还可能涉及网络配置(自定义网络)、卷挂载路径等。根据错误信息逐一排查。
6.3 新特性尝鲜与性能观察
升级到 20.10.12,可以体验一些新功能。比如,试试 BuildKit 构建(需要设置环境变量 DOCKER_BUILDKIT=1),它的构建速度更快,输出更友好。也可以看看 docker scan 命令(如果安装了插件),它可以扫描镜像中的安全漏洞。
更重要的是,观察一段时间系统的稳定性。使用 docker stats 命令监控容器资源占用,检查系统日志 (journalctl -u docker) 是否有异常报错。确保你的监控系统能正常采集新版本 Docker 的指标。
7. 升级后的优化与日常维护建议
升级成功并稳定运行后,我们可以做一些优化,让 Docker 用起来更顺手、更安全。
7.1 配置镜像加速与日志策略
国内用户必备操作:配置镜像加速器,提升镜像拉取速度。修改 /etc/docker/daemon.json,加入 registry-mirrors。
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2"
}
这里同时配置了日志驱动,防止容器日志塞满磁盘。配置完成后需要重启 Docker 服务生效。
7.2 建立简单的监控与备份习惯
对于生产环境,不能只装完就了事。我建议至少做两件事:
- 日志集中收集:将 Docker 守护进程日志和容器日志统一收集到 ELK 或 Loki 等系统,方便排查问题。
- 定期备份镜像和卷:写个简单的脚本,定期将重要镜像导出 (
docker save),并将重要的绑定挂载目录或命名卷打包备份。
例如,一个每周备份的脚本雏形:
#!/bin/bash
BACKUP_DIR="/backup/docker/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
# 备份所有镜像列表
docker images --format "{{.Repository}}:{{.Tag}}" > $BACKUP_DIR/image_list.txt
# 备份指定重要镜像
docker save -o $BACKUP_DIR/myapp_image.tar myapp:latest
# 备份数据卷(假设你知道卷名)
docker run --rm -v myapp_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/myapp_data.tar.gz -C /data .
7.3 制定未来的升级计划
技术栈的更新是持续的。虽然现在升级到了 20.10.12,但 Docker 社区版(CE)的迭代很快。建议关注 Docker 官方博客和发布说明,了解新版本的特性和修复的漏洞。对于生产环境,我的经验是:紧跟最新的稳定版(Stable)或长期支持版(LTS),但不要追最新版(Edge)。每次大版本升级前,务必在测试环境充分验证。
这次从 18.09.8 到 20.10.12 的升级,核心思路就是“准备充分、彻底清理、谨慎配置、充分验证”。整个过程其实没有太多黑魔法,就是耐心和细心。尤其是处理配置兼容性和数据迁移时,多想一步,多做一次备份,就能避免很多深夜救火的悲剧。希望这份详细的指南能帮你顺利完成升级,让你的 CentOS 7 服务器重新焕发活力。如果过程中遇到其他问题,多查查 Docker 社区的 Issue 和官方文档,总能找到解决方案。
更多推荐


所有评论(0)