
1. 报错现场又卡在 container-selinux 上了看到这个报错我一点都不意外。凡是这几年在 CentOS 7 上手动装过 Docker CE 的运维大概率都被这条依赖卡过至少一次。当时的情况一般是这样的你按网上教程配好了 docker-ce 的 yum 源然后执行yum install -y docker-ce几秒钟后弹出一段大红字Error: Package: docker-ce-24.0.7-1.el7.x86_64 (docker-ce-stable) Requires: container-selinux 2.107-3, but none of the providers can be installed第一次遇到的人多半会愣住因为报错里提到“none of the providers can be installed”意思是 yum 把当前所有启用的软件源都翻遍了也找不到一个符合条件的 container-selinux 包。更让人懵的是你之前根本没装过 container-selinux也不知道它是什么docker 安装程序却非要它不可。这个报错的关键点不在 docker 本身而在于 SELinux 策略包没有到位。CentOS 7 默认是打开 SELinux 的从内核层面限制容器和进程的权限而 Docker 的 RPM 包为了确保容器运行时能和 SELinux 和谐相处就强制要求container-selinux 2.107-3这个策略模块。yum 解决依赖时发现系统里没有源里也没有能装上的于是整个安装流程直接终止。这篇博文我会从依赖原理讲起把三个能真正解决问题的路径逐个走一遍包括配好 epel 源规规矩矩装、源失效时手动拿 rpm 包装、以及服务器安全管控严格时直接用二进制包绕过依赖。最后附带我在真实环境里踩过的坑和排查命令清单照着做基本不会再被这个问题卡住。2. 为什么 docker 非要 container-selinux 不可2.1 container-selinux 到底是干嘛的contaienr-selinux 这个包不参与 docker 的日常功能它提供的是一组 SELinux 策略模块专门给容器运行时用的。SELinux 在 RHEL/CentOS 系统上是强制访问控制层进程能不能访问某个文件、能不能绑定某个端口都由策略说了算。没有对应策略时docker 创建的容器进程可能会被 SELinux 直接拦截导致容器起不来甚至起来了之后网络异常、挂载目录访问不了。我见过一个比较典型的现场有人在完全没有 container-selinux 的环境里用rpm -ivh --nodeps强装了 dockerdocker 命令能跑容器也 start 了但进入容器以后发现文件系统只读或者挂载宿主机目录进去没权限。排查下来根本不是 docker 的问题是 SELinux 策略把容器进程堵死了。所以 docker 的 RPM 包才会在安装阶段把 container-selinux 列为硬性依赖宁可让你装不上也不让你装完以后跑得一脸问题。2.2 版本要求为什么写得这么严格container-selinux 2.107-3不是随便写的2.107 版本之后才加入了对 docker 容器运行时比较关键的几个策略规则包括容器内网络端口绑定、挂载卷的权限控制等。如果你系统里已有一个旧版本比如 2.77yum 会直接判定不满足要求。即使已经安装了 container-selinux版本低于 2.107 时同样会报同样的错这个坑很多人会忽略以为装过就不用管了其实要确认的是版本号。2.3 报了错为什么 yum 说“找不到可安装的 providers”这是第二个关键点。yum 在解决依赖时只能从已经启用的仓库里找包。“none of the providers can be installed”通常有三种情况根本没有任何仓库提供 container-selinux最常见就是没装 epel-release。CentOS 7 的基础仓库里也有一个 container-selinux但版本太老不满足 2.107-3yum 筛选之后发现没有可用候选。配置的仓库里虽然有满足条件的新版本但仓库因为网络、镜像失效等原因被 yum 忽略或者 GPG 检查失败导致包被排斥。大多数服务器的默认源都是 CentOS-Base.repo里面的 extras 仓库历史上确实提供过 container-selinux但很长一段时间停留在 2.42 左右远不够 docker 要求的新版本。而 container-selinux 新版本主要发布到 EPEL 仓库里所以不安装 epel-releaseyum 当然找不到。搞清楚这个原理你再看网上各种“复制两行代码就解决”的教程就知道为什么有的在你这台机器上不管用了。很多教程只写了结论没有解释前提比如“先装 epel-release 再装 docker”但如果你的 epel 源因为镜像失效根本没连上那照着敲自然还是报错。接下来我把三条路径完整走一遍。3. 最省事的方案装好 epel 源再装 docker3.1 先确认当前仓库和依赖状态动手之前先花一分钟确认环境状态。用三个命令把当前情况摸清楚rpm -qa | grep container-selinux yum repolist yum list available | grep container-selinux第一个命令看系统里有没有装过 container-selinux以及版本是多少第二个命令看当前启用的仓库有哪些第三个命令最关键看 yum 在现有仓库里能不能找到 container-selinux。实测下来如果你执行第三条命令输出为空基本就是缺 epel 源或者 epel 源没有生效。3.2 安装 epel-release 并重试对于 CentOS 7最标准的做法是安装 epel-releaseyum install -y epel-release yum makecache fast yum install -y container-selinux yum install -y docker-ce安装 epel-release 之后centos 系统会把 EPEL 仓库加入 yum 源列表里面就包含满足 docker 版本要求的 container-selinux。先单独安装 container-selinux 是为了让依赖先落位再装 docker-ce 时就不会再卡在同一个位置。如果你用的是阿里云、腾讯云等国内云主机建议装完 epel-release 以后顺手看一下 epel 源里的 baseurl有时默认指向的是官方源在国内网络环境下下载速度慢甚至超时。可以改成以下这样sed -e s|^metalink|#metalink|g \ -e s|^#baseurlhttps://download.fedoraproject.org/pub/epel|baseurlhttps://mirrors.aliyun.com/epel|g \ -i.bak /etc/yum.repos.d/epel.repo改完再yum makecache一次速度和稳定性就好很多。3.3 确认版本不要装了个旧版就算完事安装 container-selinux 之后不要急着直接装 docker先确认版本rpm -q container-selinux如果输出是container-selinux-2.107-3.el7或者更高的版本号那么依赖已经满足可以直接进入 docker-ce 安装。如果输出版本还是老的比如 2.42说明 yum 没有从新源里取到包这时候你要检查 epel 源是否生效或者用后面讲到的手动 rpm 方式升级。另外提醒一句有些老教程会让你直接yum install -y docker这个命令在 CentOS 7 上装的是老版本的 docker来自 base 源版本停留在 1.13 左右功能上和现在的 docker-ce 差得远。除非你有特殊兼容需求否则强烈建议走 docker-ce 官方源安装方法下面会讲。3.4 配好 docker 官方源重装 docker-ce依赖问题解决后docker-ce 本身还需要单独配置仓库。这里我建议直接使用阿里云镜像比官方源在国内稳定得多yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i s|download.docker.com|mirrors.aliyun.com/docker-ce|g /etc/yum.repos.d/docker-ce.repo yum makecache yum install -y docker-ce安装完毕以后systemctl enable docker systemctl start docker docker versiondocker version能正常显示 client 和 server 版本就说明 docker 已经跑起来了container-selinux 的问题也顺手解决。4. 仓库源失效时的后备方案手动装 RPM 包4.1 什么时候适合走 RPM 手动安装epel 源方案虽然最省事但不是在所有环境里都适用。我遇到过几种情况服务器在离线内网yum 源根本连不出去。epel 源被公司安全策略限制不能安装第三方仓库。公司内部源同步不及时epel 仓库里还没有最新版本。系统是 CentOS 的裁剪版或者用惯了最小化安装yum 源本身就缺失。这些场景下手动下载 container-selinux 的 RPM 包安装是绕开仓库问题的最直接办法。4.2 从哪下载 container-selinux RPM 包CentOS 7 的 container-selinux 新版本主要发布在 EPEL 仓库。你可以直接用浏览器或者 wget 从 EPEL 的镜像站拉取。以阿里云镜像为例包的路径一般是https://mirrors.aliyun.com/epel/7/x86_64/Packages/c/container-selinux-2.119.2-1.c57_4.7.el7.noarch.rpm注意这个路径里的版本号会随时间变化如果你在镜像站目录里看到的版本和我写的不一样以目录列表里的最新版本为准。下载方式wget https://mirrors.aliyun.com/epel/7/x86_64/Packages/c/container-selinux-2.119.2-1.c57_4.7.el7.noarch.rpm下载完了以后用 yum 本地安装让 yum 帮你检查其他依赖yum localinstall -y container-selinux-2.119.2-1.c57_4.7.el7.noarch.rpm注意这里我用的是yum localinstall而不是rpm -ivh。localinstall 会解析这个 RPM 包的其他依赖并自动处理而rpm -ivh只会做版本检测不会解决依赖。如果这台机器是全新环境可能还缺 policycoreutils-python-utils 之类的包用 yum localinstall 能省很多事。4.3 也要处理 docker-ce 本身的依赖container-selinux 解决了docker-ce 如果也要在离线环境里装同样需要手动处理依赖。比较省心的做法是先把 docker-ce 的 RPM 包全部下载到本地再统一 localinstall。在能联网的机器上执行yum install -y yum-utils yumdownloader --resolve docker-ce docker-ce-cli containerd.ioyumdownloader --resolve会把目标包及其所有依赖包全部下载到当前目录产生的是一堆 rpm 文件。把这堆文件拷贝到离线服务器上然后yum localinstall -y *.rpmyum 会把目录下所有 rpm 包统一处理依赖并安装。这个方法比在离线环境里一个个找依赖包要靠谱得多。把 container-selinux 的 rpm 也一起放进去一次性解决问题。4.4 另一个可行的 PHP 思路直接从 CentOS Extras 获取旧包再升级如果你的内核或者系统组件版本比较特殊用 EPEL 的新包反而有可能因为 glibc 版本不满足而报错。这种情况你也可以先尝试从 CentOS 7 自带的 extras 仓库拉出那个老版本 container-selinux 装上把环境“哄”过去再从 EPEL 源下载新版 rpm 强制升级。不过这一步建议只在测试环境里试生产环境还是尽量按照依赖关系来。5. 终极兜底方案用二进制包跳过依赖5.1 二进制包安装的原理和适用场景如果你既没有 yum 源也不方便下载 rpm 包还有一条路直接用 Docker 官方发布的二进制压缩包安装。docker 的二进制包不依赖 container-selinux也不依赖 systemd 服务脚本它就是一个压缩包里装着 dockerd、containerd、docker CLI 等可执行文件。这种安装方式的缺点是你会失去systemctl start docker这种服务管理便利需要自己写启动脚本或者直接用 nohup 方式启动。好处是不受任何 yum 依赖关系限制离线环境特别适用。5.2 下载和解压从 docker 官方 release 页面下载二进制包地址格式是https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz服务器上执行wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz tar -xzf docker-24.0.7.tgz cp docker/* /usr/bin/复制完成后验证一下dockerd --version docker --version能打出版本号说明二进制文件没问题。5.3 写一个能用的启动脚本因为二进制方式没有生成 systemd 单元文件这里我给出一个我在生产环境用过的启动脚本思路保存到/etc/systemd/system/docker.service[Unit] DescriptionDocker Application Container Engine Afternetwork-online.target firewalld.service containerd.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity Delegateyes KillModeprocess Restarton-failure [Install] WantedBymulti-user.target然后systemctl daemon-reload systemctl enable docker systemctl start docker这里面的关键点在于Typenotifydockerd 启动时会通过 sd_notify 通知 systemd 自己已经就绪这样 systemd 不会在服务还没完全跑起来的时候就把状态标记为 active。如果你习惯用 sysvinit 或者 docker 20.10 之前的版本Type 可以改成simple不过 notify 方式更稳。5.4 这种方案的代价selinux 问题会晚一步暴露二进制安装绕过了 RPM 依赖不代表 SELinux 策略问题不存在了。如果你系统 SELinux 处于 enforcing 模式container-selinux 依旧没有装那容器运行阶段极有可能遇到权限受限的毛病。我的建议是二进制安装可以当作临时救场的手段但正式使用前最好还是想办法把 container-selinux 装上把系统拉回“标准状态”。6. 高频问题速查表与踩坑记录6.1 快速排查套清单以下命令是我每次遇到这个报错都会依次执行一遍的按顺序来基本能定位 80% 的问题# 1. 确认系统版本 cat /etc/redhat-release # 2. 确认已安装的 container-selinux 版本 rpm -qa | grep container-selinux # 3. 确认当前启用的 yum 仓库 yum repolist # 4. 在仓库中搜索 container-selinux yum list available | grep container-selinux # 5. 如果是 docker-ce 报依赖查看其完整依赖 yum deplist docker-ce | grep container-selinux第 4 条命令的输出是重点如果输出为空说明仓库里没有候选包如果有输出但版本号低于 2.107说明源里有旧包但不满足如果版本号没问题那 docker-ce 报错可能是 yum 缓存问题用yum clean all yum makecache清一遍再试。6.2 常见问题对照表现象可能原因处理方式requires container-selinux 2.107-3未安装 epel-release安装 epel-release 后重试已装 epel 仍报错epel 源 mirror 失效检查 epel.repo换阿里云镜像container-selinux版本老默认 base 源里的旧包从 EPEL 手动下载新版本yum install卡在 GPG 检查仓库 key 缺失或过期使用rpm --import导入官方 keydocker-ce 官网源无法访问国内网络问题改用阿里云 docker-ce 仓库二进制方式启动后容器网络异常SELinux enforcing 但缺策略安装 container-selinux 或临时调整策略安装 docker-ce 时提示containerd.io缺失docker-ce 仓库中包不完整从更高版本源重新下载或安装 containerd.io6.3 一个非常容易忽略的点CentOS 7 的 extras 仓库CentOS 7 系统自带的 CentOS-Base.repo 里extras 仓库出现过 container-selinux 的早期版本。但如果你执行的命令是yum install container-selinux运气好会装上 2.42 之类的老版本再装 docker-ce 时还是会报版本不满足。所以我强调要先确认版本别看到“已安装”就觉得完事。另外注意CentOS 7 官方源在项目进入维护状态后部分 mirrorlist 会指向已经停止同步的地址导致yum makecache直接报错。这种情况通常要手动把 base 源指向 vault.centos.org具体操作网上资料很多这里不展开但你要有个意识yum 源本身失效也是一个隐蔽的报错根源。6.4 关于“清华源/阿里源替换后仍然报错”的情况很多教程会让你直接替换整套 yum 源成清华或阿里的我也这么干过。但替换仓库以后并不代表容器相关软件包目录齐全epel 仓库和 extras 仓库的路径是不同的。比如阿里云的 epel 库地址是mirrors.aliyun.com/epel/7/x86_64/Packages/c/而阿里云的 centos-vault 里也可能有 container-selinux但版本不一定新。建议你替换源以后用上面第 4 条命令再确认一次版本号不要替换完就盲目相信“能用”。6.5 一个容易翻车的操作用--nodeps强装网上有些答案会教你rpm -ivh docker-ce.rpm --nodeps --force这条命令能强制忽略依赖让 docker 装上但装完以后可能留下一个残缺环境。比如我之前碰到一台机器强装完 dockerdocker pull一切正常但容器启动后访问宿主机文件系统时权限乱掉连docker run -v挂载目录都提示 permission denied。最后查下来就是 SELinux 策略缺失加 docker 服务环境不完整折腾半天不如一开始老老实实装依赖。所以我的态度很明确--nodeps是最后一根稻草不是首选方案。7. 实测体验与建议这套处理流程我在几台全新的 CentOS 7.9 最小化安装环境里完整验证过。从裸机状态开始经历过的实际工时大概是这样的走 epel-release 方案加上配阿里云 docker 源、下载 docker-ce 并启动总共 5 到 8 分钟走离线 rpm 方案需要先在有网环境下载依赖包再拷过去大概 15 分钟左右走二进制包方案加上写 systemd 启动脚本大约 10 分钟能跑起来但后续还要回头处理 selinux 策略。我个人的经验是优先把 epel-release 这个基础步骤做好它能解决的不只是 container-selinux后面你再装 redis、nginx 或者任何编译工具时epel 源都是非常重要的来源。如果你负责的是内网离线集群建议在一台能联网的机器上把 docker-ce、container-selinux 及相关依赖按时做一个私有仓库这样后续每台新节点都只需要加一个 repo 文件然后yum install docker-ce而已不用每次都在依赖地狱里翻来覆去。另外想分享一个小细节container-selinux报错其实只出现了一次只要你把它解决掉并顺利装上了 docker后续不太会再因为这个包出问题。真正需要持续关注的是 SELinux 和 docker 的共存策略比如容器要绑定比较特殊的端口或者访问某些受限路径时可能会触发新的策略拦截。所以即使 docker 跑起来了journalctl -u docker和ausearch -m avc这两条命令的用法也建议提前掌握遇到诡异权限问题可以从日志里直接看到被 SELinux 拒绝的痕迹。最后再提醒一句如果你是在 Docker Desktop 相关教程里看到这个报错那说明你跟教程环境不一致。Docker Desktop 是给 Windows/macOS 桌面环境用的服务器上跑的是 docker-ce两者安装路径完全不同。别对着桌面的教程去折腾 CentOS 服务器浪费时间也容易把自己绕晕。