1. 先别急着装Docker:2026年CentOS版本选择背后的逻辑
2026年1月,我在一台旧的CentOS 7.9服务器上重新部署Docker时,发现yum源已经彻底失效了——CentOS 7早在2024年6月就停止了维护,官方镜像源全部移到vault仓库,直接执行yum install docker得到的是一连串404。这个时间节点上谈"CentOS部署Docker",第一个要解决的问题其实不是Docker本身,而是"你到底该用哪个CentOS"。
如果你手头是生产环境,我建议先想清楚一个事实:CentOS 7的生命周期已经终结,CentOS 8也早停了,现在还在维护的是CentOS Stream 8/9,以及它背后的上游RHEL。很多人一听到"Stream"就犹豫,担心它是测试版不稳定——其实这个理解有点偏差。Stream是滚动发行的,处在RHEL版本的前瞻位置,简单说它比传统CentOS更频繁地接收更新,但API和核心行为与RHEL保持兼容。对于跑Docker这类容器场景,用Stream 9完全够用;如果必须用传统CentOS 7,那就得自己配置vault源,并且接受它不再有安全补丁的现实。
再说下载镜像的问题。常见获取CentOS安装镜像的地方有官方镜像站和各高校镜像站,下载时注意区分DVD版(完整安装,体积大)和Minimal版(精简安装,适合服务器)。如果你只是要部署Docker,Minimal版就够了,装完再自己补工具链,干净利落。有一个容易忽略的点:CentOS 8 Stream下载时还要留意架构,x86_64和aarch64是两个不同的文件,在ARM服务器上装了x86的镜像会直接引导失败。
版本选型这一步,我把关键判断整理成了一张表:
| 场景 | 推荐版本 | 理由 |
|---|---|---|
| 新装服务器(x86) | CentOS Stream 9 | 正常维护中,兼容RHEL 9生态,Docker官方支持 |
| 新装服务器(ARM) | CentOS Stream 9 aarch64 | 能拿到完整软件包支持 |
| 存量CentOS 7机器 | CentOS 7.9 + vault源 | 不建议长期使用,但过渡期可保住现有业务 |
| 追求最短路径 | Rocky Linux / AlmaLinux 9 | 与CentOS完全兼容,社区活跃度高 |
我个人在2026年初这个节点上的建议是:新环境优先考虑Rocky Linux或AlmaLinux,它们就是CentOS的"继承者",二进制兼容性几乎无感知;如果公司规范强制用CentOS品牌,再选Stream 9。选好系统版本后,装Docker的过程才会顺畅。
2. 系统初始化三板斧:内核、源、残留清理
Docker对内核有硬性要求,别小看这一步。CentOS 7默认的内核是3.10.x,而Docker的官方支持矩阵里,3.10虽然能用,但很多新特性(比如OverlayFS的部分模式、cgroup v2)会受限。CentOS Stream 9默认内核是5.14,跑Docker就没这些烦恼。所以安装前先执行:
uname -r如果内核版本过低(比如3.10),我又不想动生产环境,那就先确认是否满足Docker的最低内核要求(3.10),再继续。但如果你是Stream 9或者Rocky 9,这个检查基本就是走过场。
接下来是关键:配置yum源。如果是CentOS 7且原官方源已失效,需要切换到vault源。所谓vault,就是CentOS把已停止维护的版本打包归档的仓库,地址类似vault.centos.org/7.9.2009/。切换的具体操作是把/etc/yum.repos.d/下的repo文件里的mirrorlist和baseurl替换成vault路径,同时把gpgcheck保持为1,验证密钥也要加上。这一步骤做完后,yum makecache如果不再报404,源就算通了。
对于Stream 9,源的配置就简单得多,它的源还在正常维护期,直接:
sudo dnf install -y epel-release sudo dnf makecacheEPEL(Extra Packages for Enterprise Linux)源不是必须的,但强烈建议装。Docker依赖的有些包(比如container-selinux)可能不在默认源里,EPEL能补齐这些缺口。我见过很多人在安装时报"没有可用软件包container-selinux",十有八九就是EPEL没装或者版本不对。
最后一步清理:如果机器之前装过旧版Docker(名字可能是docker、docker-engine、docker.io),一定要先卸载干净。残留的dockerd进程和旧配置文件会导致新版安装后行为诡异,我遇到过一次端口占用排查了三个小时,最后发现是旧版容器的iptables规则没清掉。卸载命令:
sudo dnf remove docker docker-engine docker.io containerd runc卸载后检查/var/lib/docker目录是否还在。如果里面有旧数据但你想保留,就备份走;如果不要了,直接删掉,免得新Docker启动时尝试恢复不兼容的镜像层。
3. Docker引擎安装:yum源配置和两个容易忽略的细节
干净的系统上装Docker,官方推荐的方式是配置Docker的yum源后安装docker-ce。这里我用的镜像是阿里云的Docker镜像源,国内访问速度快,同步也及时。配置命令:
sudo dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo如果你用的是CentOS 7而不是Stream,需要手动把repo文件里的$releasever替换成7,否则releasever会解析到一个不存在的版本号路径。这个坑我踩过不止一次,输出总是"404 Not Found",跟网络一点关系都没有。
接着安装:
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里有一个细节很多人会漏掉:docker-compose-plugin一定要装。别小看Compose,单容器场景用不到,但只要开始编排多容器(比如MySQL主从、Web应用加Redis),没有Compose会痛苦得多。顺带说一句,docker-buildx-plugin是用来构建跨平台镜像的,CI/CD场景用得上,装机的时候顺手装掉,免得后面缺。
启动和验证:
sudo systemctl enable --now docker sudo systemctl status docker docker version如果状态显示active (running),再用docker info看基本信息。我个人的经验是,初次安装后先跑一个hello-world验证引擎本身没问题:
docker run --rm hello-world这一步能确认两个核心链路:第一,dockerd守护进程正常响应;第二,默认网络和镜像拉取能力正常。如果hello-world卡住,多半是接下来要讲的镜像加速问题,而不是引擎故障。
还需注意,当前用户如果要免sudo直接跑docker命令,需要加入docker组:
sudo usermod -aG docker $USER newgrp docker这一点在生产环境很有用,但在多租户服务器上要谨慎——docker组里的用户理论上可以挂载宿主机文件系统并提权,不是完全隔离的。我一般只在单用途的Docker主机上加,公共服务器就不做这个操作。
4. 镜像加速与网络连通:为什么"docker pull"总是卡住
装好Docker后第一个真实的拦住大家的问题是:docker pull拉公共镜像仓库的镜像时,速度慢得像便秘,甚至直接超时。这不是Docker本身的问题,是网络链路到公共镜像仓库的延迟。解决办法是配置镜像加速器——把镜像拉取请求先发到国内节点,再由国内节点从源站同步。
配置方法在/etc/docker/daemon.json里写入:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] }然后:
sudo systemctl daemon-reload sudo systemctl restart docker重启后执行docker info,看Registry Mirrors字段是否出现了上述地址。这一步有个常见陷阱:daemon.json本身不存在时,直接新建即可,但一定要确保格式合法(JSON不允许注释和尾逗号),而且多个镜像加速器之间只有逗号,没有多余空格带来的解析错误。我遇到过写完daemon.json后dockerd起不来的情况,排查命令是:
sudo journalctl -u docker --since "5 minutes ago" | grep -i error看到"invalid character"之类的关键词,基本就是JSON写得有问题。
配置加速器只能解决镜像层下载的延迟,容器运行时的网络连接(比如容器里访问外部API)走的是另一条链路。如果容器docker run启动后,容器内ping外网不通,先检查宿主机本身能不能联网、防火墙是否放行。CentOS 7默认firewalld会拦截容器流量,遇到这种情况,我是这样处理的:
sudo firewall-cmd --permanent --zone=trusted --add-interface=docker0 sudo firewall-cmd --reload把docker0网卡划入trusted区域,让容器出网流量直接通行。在CentOS Stream 9上firewalld的行为略有变化,但这条命令仍然有效。要注意的是,这样放行是粗粒度的,如果容器里跑着敏感服务,最好还是用-p端口映射加白名单替代,而不是全trusted。
网络和加速配置完之后,验证方式还是那句老话:拉一个常用镜像试试。我一般拉alpine:latest,镜像小、拉取快,能快速判断整个链路是否通畅。
5. 实战部署MySQL 8.0:存储、配置、端口映射的最稳姿势
热词里"docker安装mysql主从"、"docker安装mysql8.0并使用"出现频率极高,说明很多人在跑业务的第一站就是数据库容器化。这一节我拿MySQL 8.0做例子,把从拉镜像到可访问的全流程走一遍,顺便把最容易出问题的点拆开讲。
拉镜像:
docker pull mysql:8.0这里要注意,MySQL的Docker镜像默认时区是UTC,且数据目录在容器内部,一旦容器删除,数据就没了。所以跑数据库容器,第一原则就是挂载宿主机目录。创建数据目录和配置文件目录:
sudo mkdir -p /data/mysql/conf /data/mysql/data配置文件可以提前放一份到宿主机:
[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci default-time-zone=+08:00接着启动容器:
docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=YourStrongPass@2026 \ -v /data/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf \ -v /data/mysql/data:/var/lib/mysql \ --restart=unless-stopped \ mysql:8.0各参数的含义和取舍:
-p 3306:3306:宿主机3306映射到容器3306。如果不加,容器外无法通过宿主机IP连接。生产环境建议只映射到内网IP,比如-p 192.168.1.10:3306:3306,而不是0.0.0.0,避免数据库暴露到公网。-e MYSQL_ROOT_PASSWORD:初始化时设置root密码。第一次启动时有效,之后改密码要进容器或通过SQL执行。-v挂载:配置文件和数据的持久化都在这里。没有这一步,容器删了等于删库。--restart=unless-stopped:服务器重启或dockerd重启后,容器自动拉起,减少运维事故。
启动之后检查:
docker ps docker logs mysql8 --tail 20日志里出现ready for connections就说明初始化成功。然后可以用宿主机上的mysql客户端连接:
mysql -h 127.0.0.1 -P 3306 -u root -p如果宿主机没有mysql客户端,用容器内的:
docker exec -it mysql8 mysql -u root -p这一节的关键点,你以为就这些?还有一个隐形的坑:MySQL 8.0默认认证插件是caching_sha2_password,老版本的应用(比如PHP 5.6时代的mysqli扩展)连不上,会报"Authentication plugin 'caching_sha2_password' cannot be loaded"。解决办法是在容器里创建兼容账号:
CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; GRANT ALL PRIVILEGES ON *.* TO 'app'@'%';如果业务代码升级到新版驱动,则不需要这个兼容处理。这是数据库容器化最常见的兼容性陷阱,提前知道能省一大半排查时间。
6. 主从复制场景:用Docker Compose编排还是两条命令硬跑?
回到热搜词里的"docker安装redis主从"和"docker安装mysql主从",多容器协作的需求现在是真不少。我以Redis主从为例,说说用纯docker run和用Compose的差别,以及我的选择。
Redis主从的部署思路:一个主节点负责写,一个从节点负责复制。用两条docker run命令也能完成,比如:
docker run -d --name redis-master -p 6379:6379 redis:7 redis-server --appendonly yes docker run -d --name redis-slave -p 6380:6379 --link redis-master redis:7 redis-server --replicaof redis-master 6379注意这里用了--link,这是个老化的参数,在Docker的官方文档里已经标记为legacy,新的网络模型推荐用自定义网络。而且两条命令在重启后如果顺序错了,从节点可能连不上主节点。所以我更推荐用Compose:
services: redis-master: image: redis:7 container_name: redis-master command: ["redis-server", "--appendonly", "yes"] ports: - "6379:6379" volumes: - redis-master-data:/data redis-slave: image: redis:7 container_name: redis-slave command: ["redis-server", "--replicaof", "redis-master", "6379"] ports: - "6380:6379" depends_on: - redis-master volumes: redis-master-data:在项目目录下保存为docker-compose.yml,然后:
docker compose up -ddepends_on保证了启动顺序:主节点先起来,从节点再启动。自定义网络让容器之间可以用服务名互相访问,这就比--link优雅得多。检查主从状态:
docker exec -it redis-slave redis-cli -p 6379 info replication看到role:slave和master_link_status:up就说明复制链路正常。
部署MySQL主从的流程更繁琐一点(要改binlog配置、初始化复制账号、获取binlog坐标),但思路完全一样。我的建议是:只要涉及两个及以上容器的编排,别犹豫,直接用Compose。它最大的价值不是省那几行命令,而是把容器的启动依赖、网络关系、数据卷定义固化成一个版本可追踪的文件,这比"运维靠记忆敲docker run"可靠一个量级。
7. 部署后必查:进程异常退出、磁盘爆满、时区配置的排查套路
容器跑起来了,不代表就万事大吉。我把部署后最容易出的三类问题列出来,每一类都附上排查套路。
第一类:容器不断重启。症状是docker ps里状态显示Restarting,或者STATUS一栏出现"(n)"的计数值。先用:
docker logs 容器名 --tail 50看退出原因。如果是MySQL类数据库,日志里通常直接写明了错误(比如目录权限、配置项不合法);如果是应用容器,可能是启动命令的参数不对。还有一种常见情况是容器里进程以PID 1运行时,接收不到信号导致退出异常,这属于Docker信号处理的经典问题,解决办法是给应用加init: true(在Compose里)或者安装tini作为PID 1包装进程。
第二类:磁盘被撑爆。容器日志、镜像层、数据卷都有可能膨胀。先看整体占用:
sudo du -sh /var/lib/docker sudo journalctl -u docker --disk-usage日志无限增长是所有容器服务的通病,我给dockerd加上日志限制最省心:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }这样单个容器的日志文件超过10MB就滚动,最多保留3个文件。对生产环境来说,这个配置能避免很多"存储悄悄跑满"的夜半惊魂。
第三类:时区和locale问题。CentOS宿主机的时区是Asia/Shanghai,但容器默认UTC,跑定时任务会差8小时。在docker run里加:
-e TZ=Asia/Shanghai或者Compose里写相同环境变量,重启容器即可。有些基础镜像还缺中文locale,运行Java应用时会出现乱码,需要安装对应的language pack,这个在CentOS Stream 9上装起来比较简单,但一定要记得在Dockerfile里做,不要等容器起了再手动执行,因为容器重启就没了。
8. 2026年的CentOS与Docker生态:一些个人的判断和习惯
到2026年,其实有一个趋势非常明确:CentOS 7和8的存量运维模式正在迅速萎缩,取而代之的是CentOS Stream、Rocky Linux、AlmaLinux这些继承者。Docker本身也在稳步迭代,containerd作为底层运行时越来越成熟,buildkit成为默认构建引擎,Compose v2基本取代了老版docker-compose命令。这些变化在实践中意味着什么?我简单说几个体会。
第一,写博文和教程时经常看到的旧命令,比如docker-compose(带横杠)在很多新系统上已经不会自动安装了,取而代之的是docker compose(空格分隔)。我在新服务器上装完docker-compose-plugin后,直接输出docker compose version验证的是空格版本。如果你在执行自动化脚本,这个命令差异一定会踩到。
第二,Docker Hub的限流政策越来越严格,匿名用户拉取镜像受限,生产环境一定要配置registry mirror或者私有镜像仓库。如果公司有自建的Harbor,把daemon.json里的registry-mirrors换成内网地址,拉取速度和安全可控性都会上一个台阶。
第三,安全基线要提前定。Docker的默认配置偏宽松——root容器、特权模式、挂载宿主目录、暴露端口,每一样都是风险。我在团队里定的规矩是:非必要不加--privileged;容器内应用尽量以非root用户运行;数据卷挂载只给最小范围;生产环境不用默认网桥,用用户自定义的bridge网络。这些东西写进CI脚本里,比事后补救便宜得多。
回到开头那个场景,那天我在CentOS 7.9上折腾vault源的时候,其实挺感叹的——同一个操作系统,在它生命周期不同阶段接触到的生态完全不一样。如果你恰好也在2026年的节点上做CentOS部署Docker这件事,记住我最核心的三个建议:第一个,新环境别再用CentOS 7,除非你有明确的存量约束;第二个,装完Docker先解决加速器和日志大小限制,这两个是长期的体验基础;第三个,多容器场景直接用Compose,别让启动顺序靠运气。做完这三件事,你的Docker环境大概率能稳定跑很久。