ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RHEL9 安装 Docker CE 全流程:从环境准备到生产级容器部署

RHEL9 安装 Docker CE 全流程:从环境准备到生产级容器部署 1. RHEL9 上装 Docker先得把这几件事想明白最近接手了一台 RHEL9 的服务器环境是全新的任务是在上面把 Docker 跑起来。RHEL9 这个版本跟以前的 RHEL 系列有一个很大的不同它默认不再把 Docker 作为容器运行时推荐系统自带的容器工具是 Podman官方源里也没有 docker 包。所以想在上面快速上手 Docker不能像 CentOS 7 时代那样直接yum install docker得走一套自己的流程。先说清楚概念Red Hat 从 RHEL 8 开始就把 Podman 作为默认容器管理工具到了 RHEL 9 更是彻底把 docker 包从官方 yum 源里移除了。如果你直接用yum install docker会提示没有可用软件包这是正常现象。Podman 是兼容 Docker CLI 命令的很多指令写法几乎一样但如果你有现成的 docker-compose 文件、依赖 Docker API 的构建工具链、或者团队统一用 Docker 生态那还是老老实实装 Docker CE 靠谱。再说一个容易踩的概念坑Docker 和 Docker Desktop 是两个不同的东西。Docker Desktop 是带图形界面、适合 Windows 和 macOS 的桌面版内部靠虚拟机跑 Linux 容器而 RHEL9 服务器上要装的是 Docker Engine也就是纯命令行版本。我在热搜词里看到一堆 docker desktop failed to start because virtualisation support wasnt detected 的搜索这说明好多人把这两者混为一谈了。Docker Desktop 启动失败多半是宿主机没开虚拟化那是在 Windows 上的事跟 RHEL9 装 Docker Engine 是两码事别在服务器上尝试装 Desktop 版。在开始之前建议先确认三件事系统是 RHEL9 的哪个小版本cat /etc/redhat-release网络能不能访问 Docker 官方仓库机器是不是 x86_64 架构。RHEL9 的三个小版本我都试过9.0 到 9.3 的安装流程基本一致差异不大。如果你用的是 CentOS Stream 9流程也通用因为 CentOS Stream 9 跟 RHEL9 的包管理方式几乎完全一致。2. RHEL9 安装 Docker 的完整流程2.1 配置 Docker 官方 yum 源RHEL9 默认没有 Docker 源需要手工添加。先检查系统是否有yum-utils一般 RHEL9 全新安装可能没带直接装上sudo dnf install -y yum-utils然后添加 Docker 官方仓库。注意这里我建议优先使用官方源因为版本最完整、更新最及时。命令如下sudo yum-config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo这一步执行后/etc/yum.repos.d/目录下会出现一个docker-ce.repo文件。这个仓库配置了 stable、test、nightly 三个子仓库默认取 stable。我习惯先执行一次dnf makecache把仓库缓存刷新一下然后在安装前先yum list docker-ce --showduplicates看看有哪些版本可选确认源生效。补充说明Docker 官方源对 RHEL 的支援其实是通过rhel这个路径提供的同时也兼容 CentOS 的 repo 配置。如果你在 RHEL 上遇到 404 或者找不到包的情况可以检查一下/etc/yum.repos.d/docker-ce.repo里 baseurl 的路径是否命中了正确的发行版标识。2.2 安装 docker-ce 及相关组件RHEL9 上安装 Docker 时最常踩的坑是缺少 container-selinux 依赖。这个包默认不在 RHEL9 的标准源里而在 AppStream 或者 extras 源中。我的做法是先把系统已有的源全部启用sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin如果安装过程中报错Problem: package docker-ce-... requires container-selinux ...别慌这属于 RHEL 的软件源层级问题。先执行sudo dnf module enable container-tools:3.0再装。RHEL9 的 AppStream 里带了一个 container-tools 模块启用之后依赖会自动解决。装完确认版本docker --version正常会输出类似Docker version 24.0.7, build afdd53b的信息。RHEL9 配合 Docker 24.x 版本实测跑得很稳。如果系统提示 docker-compose-plugin 不在仓库里那多半是添加的 repo 不是官方源或者是 RHEL 订阅没有正确注册导致第三方源被禁用。2.3 启动服务并验证安装结果安装完成后先别急着拉镜像。Docker 引擎的核心服务叫docker.service同时需要containerd.service配合运行。我把启动顺序固定成这样sudo systemctl daemon-reload sudo systemctl enable --now containerd sudo systemctl enable --now docker--now参数的意思是立即启动并设置开机自启。很多教程只写systemctl start docker结果重启服务器后 Docker 没跟着起来又要手动折腾一次。在服务器场景下开机自启是刚需建议一步到位。验证服务状态sudo systemctl status docker sudo docker run hello-world跑hello-world容器是检验引擎是否正常工作的最直接方法。它能验证 Docker daemon 能否拉取镜像、创建临时容器、打印日志。我在新机器上一定会做这一步而不是干看docker version。2.4 配置镜像加速源RHEL9 服务器在国内网络环境下直接拉 Docker Hub 镜像经常慢得让人怀疑人生。镜像加速源就是解决这个问题的关键。修改 Docker 的 daemon 配置文件/etc/docker/daemon.json把 registry-mirrors 字段加进去{ registry-mirrors: [ https://docker.m.daocloud.io, https://docker.1panel.live ] }写完后重启 Dockersudo systemctl daemon-reload sudo systemctl restart docker这里有一个细节值得注意配置 mirror 后 Docker 并不会立刻清除已有的缓存索引所以配置完重启后第一次拉镜像可能还是会走原来的路径拉一次小镜像测试一下即可。加速源本质上是一个上游 registry 的缓存代理它拉取的镜像跟官方是完全一致的指纹校验通过即可放心使用。实操心得加速源不是越多越好建议保留一到两个响应快的就好。我在实际使用中发现某些公共加速源会不定期变更地址写太多不仅影响配置解析还可能因为第一个源超时而白白等待很久。加速源的选择标准只有一个——稳定、可访问、能拉到你需要的镜像。3. 镜像与容器的核心操作要点3.1 镜像管理高频命令Docker 的日常使用中镜像管理占了大头。这里把高频命令整理成节奏感比较清晰的顺序# 搜索镜像 docker search nginx # 拉取镜像 docker pull nginx:latest docker pull mysql:8.0 # 查看本地镜像 docker images # 删除镜像先删容器再删镜像 docker rmi nginx:latest # 清理悬空镜像 docker image prune有几个细节新手特别容易忽略。第一docker rmi删除镜像时如果还有容器在用这个镜像会报错提示冲突必须先删容器或者docker rm -f 容器ID强制删除。第二docker image prune只会清理没有被任何容器引用的悬空镜像不会误删正在使用的镜像可以放心执行。第三RHEL9 上如果磁盘是 XFS 格式默认就是Docker 的存储驱动会自动选择 overlay2不需要手动配置但可以通过docker info确认。3.2 容器生命周期管理容器管理是 Docker 操作的另一半。拿 Nginx 举例一个非常标准的运行命令是docker run -d --name my-nginx -p 8080:80 nginx:latest拆开来看-d是后台运行--name给容器起名字-p 8080:80把宿主机的 8080 端口映射到容器内的 80 端口。跑起来之后可以用docker ps查看状态docker logs my-nginx看日志docker exec -it my-nginx bash进容器内部排查问题。容器启动策略这块--restart参数很重要。我在生产环境跑 MySQL、Redis 这类核心服务时固定加--restartalways这样即使机器重启或容器进程异常退出Docker 也会自动把容器拉起来。不加这个参数宕机一次你就得手动docker start一次半夜被叫起来非常难受。3.3 数据卷与端口映射的底层逻辑Docker 容器默认是无状态的容器一删里面的数据就全没了。解决这个问题靠数据卷volume。推荐用具名卷来管理docker volume create mysql-data docker run -d --name mysql-test \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDyour_password \ mysql:8.0比如 MySQL 的官方镜像把数据放在/var/lib/mysql通过-v mysql-data:/var/lib/mysql把具名卷挂载到这个目录后续就算容器误删数据还在卷里重新run一个相同的容器挂载同名的卷数据就回来了。宿主机的目录挂载类似-v /host/path:/container/path的形式适合需要直接查看和修改文件的场景。端口映射设计的建议是宿主端口尽量保持高位且唯一避免跟系统常用端口冲突。比如 MySQL 用 13306 映射到容器内 3306Redis 用 16379 映射 6379。这样在一台多服务的服务器上端口一目了然也便于防火墙规则管理。4. 实战基于容器跑起 MySQL 8.0 和 Redis 主从4.1 部署 MySQL 8.0 并配置远程访问MySQL 8.0 是使用频率最高的容器化数据库之一。我的部署流程是docker run -d \ --name mysql8 \ --restartalways \ -p 13306:3306 \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDRoot123456 \ -e TZAsia/Shanghai \ mysql:8.0--restartalways保证 MySQL 随开机自启TZ设置时区防止容器内时间跟宿主机不一致MYSQL_ROOT_PASSWORD是初始化 root 密码的环境变量。跑起来后验证一下容器状态和日志docker ps | grep mysql8 docker logs mysql8 | tail -20容器内部正常启动后宿主机直接用 mysql 客户端连接测试mysql -h 127.0.0.1 -P 13306 -u root -p这里有一个高频问题容器启动正常、映射端口也对但客户端连不上去报Host xxx is not allowed to connect to this MySQL server。原因是 MySQL 8.0 默认 root 只允许 localhost 登录。解决方法是进容器里改授权docker exec -it mysql8 mysql -u root -pCREATE USER app% IDENTIFIED BY App123456; GRANT ALL PRIVILEGES ON *.* TO app% WITH GRANT OPTION; FLUSH PRIVILEGES;建议不要直接给 root 开放远程权限而是创建一个专用的应用账户权限范围按需控制。RHEL9 的防火墙默认是 firewalld如果外部机器连不上还需要检查防火墙是否放行了对应端口sudo firewall-cmd --permanent --add-port13306/tcp sudo firewall-cmd --reload4.2 搭建 Redis 主从复制集群Redis 主从在容器环境下搭建很轻松。先在同一个自定义网络里创建两个容器主节点docker run -d \ --name redis-master \ --restartalways \ -p 16379:6379 \ redis:7 redis-server --requirepass Master123从节点需要指定主节点的地址和认证信息。容器之间跨容器通信时用容器名而不是 IP 更灵活因为容器重建后 IP 会变docker run -d \ --name redis-slave \ --restartalways \ -p 16380:6379 \ redis:7 redis-server \ --replicaof redis-master 6379 \ --masterauth Master123 \ --requirepass Slave123验证主从同步状态docker exec -it redis-slave redis-cli -a Slave123 info replication看到role:slave、master_link_status:up就说明主从关系建立成功了。这里最容易出问题的点是主从容器之间的网络隔离——如果你的容器不在同一个 network--replicaof redis-master 6379里的redis-master根本解析不了。实操心得搭建 Redis 主从前建议手动先创建 Docker 网络docker network create redis-net然后两个容器都加上--network redis-net这样容器名解析才可靠。我在不创建网络的情况下跑过容器之间用 IP 也可以但 IP 会漂移维护成本高何必给自己找麻烦。4.3 用 docker-compose 编排多容器服务到了多容器的场景直接用docker run一条条命令敲太容易出错也不便于维护。docker compose是标准解法。RHEL9 上安装 Docker 时我们已经装好了docker-compose-plugin直接支持docker compose子命令不用单独装 Python 版的 docker-compose。以 MySQL Redis 主从为例docker-compose.yml可以这样写version: 3.8 services: mysql8: image: mysql:8.0 container_name: mysql8 restart: always ports: - 13306:3306 environment: - MYSQL_ROOT_PASSWORDRoot123456 - TZAsia/Shanghai volumes: - mysql-data:/var/lib/mysql redis-master: image: redis:7 container_name: redis-master restart: always ports: - 16379:6379 command: redis-server --requirepass Master123 redis-slave: image: redis:7 container_name: redis-slave restart: always ports: - 16380:6379 command: redis-server --replicaof redis-master 6379 --masterauth Master123 --requirepass Slave123 depends_on: - redis-master volumes: mysql-data:启动命令docker compose up -ddepends_on的作用是让从节点等主节点先启动但它只保证启动顺序不保证主节点内 Redis 服务就绪。实际操作中如果从节点先报错连不上等主节点就绪后再docker compose restart redis-slave即可。这个编排文件的好处是整个服务栈可以用一条命令启停迁移服务器时也只需要把这个 yml 文件带过去几分钟就能在新的 RHEL9 上复现。5. RHEL9 上 Docker 常见问题排查5.1 服务启动失败与 virtualization support 检查在 RHEL9 服务器上systemctl start docker执行后服务直接失败systemctl status docker显示Active: failed。日志里常见的报错有两类一类是 containerd 没起来导致 docker 无法连接 containerd socket另一类是 iptables 相关的问题Docker 要往 NAT 表里写规则系统内核模块没加载或者 firewalld 冲突就会报错。先按顺序排查# 查看 docker 服务详细日志 sudo journalctl -u docker --no-pager -n 50 # 检查 containerd 状态 sudo systemctl status containerd # 检查 iptables 模块 sudo lsmod | grep iptables sudo sysctl net.bridge.bridge-nf-call-iptablesnet.bridge.bridge-nf-call-iptables这个内核参数如果输出 0需要改成 1 并持久化echo net.bridge.bridge-nf-call-iptables1 | sudo tee -a /etc/sysctl.conf sudo sysctl -p还有一个要提醒的是热搜词里那个 virtualization support not detected 的错误那是 Docker Desktop 在 Windows 或 macOS 上启动时检测不到虚拟化扩展的报错跟 RHEL9 的 Docker Engine 没有关系。RHEL9 服务器如果遇到内核模块加载失败通常是没装iproute-tc或者内核版本太老升级系统补丁即可。5.2 Permission denied 权限问题安装完 Docker用普通用户执行docker ps报错permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock这是 Docker 的 socket 文件归 root 所有普通用户没有访问权限。解决方法是把用户加入 docker 组sudo groupadd docker sudo usermod -aG docker $USER newgrp dockernewgrp docker能让当前会话立即生效不用重新登录。加组之后如果还是报权限问题先看 socket 文件权限ls -l /var/run/docker.sock正常情况下应该是srw-rw---- root docker。如果这个文件不存在说明 docker daemon 没有启动先执行sudo systemctl start docker。我在新服务器上建议装完 Docker 后立刻做用户组授权省的后面每次敲命令都加 sudo而且不加 sudo 的命令在脚本里更容易踩坑。5.3 容器网络不通与 DNS 问题容器跑起来后宿主机能访问但容器访问外部网络超时这是典型的网络问题。先分两层排查第一层是容器内部能不能解析域名第二层是能不能访问外网 IP。# 进入容器内部测试 docker exec -it my-nginx bash # 测试 DNS ping baidu.com # 如果域名解析失败检查 DNS 配置 cat /etc/resolv.conf容器内/etc/resolv.conf的 DNS 默认继承宿主机配置。RHEL9 如果启用了 systemd-resolved容器内可能会拿到一个 127.0.0.53 的 DNS 地址而这个地址在容器网络里根本不通。解决方法是改 daemon.json 指定默认 DNS{ dns: [223.5.5.5, 8.8.8.8] }然后重启 Docker重建容器才生效。容器网络还有一个常见场景是不同容器之间互相 ping 不通。这个我在前面已经提过——自定义 bridge 网络 容器名互访是标准做法默认的 bridge 网络不支持容器名解析。跨主机容器互通是另一个话题一般用 Swarm 或 Kubernetes 来解决初期用不上不用急着搞。单机场景下把 docker network 玩明白基本够用。5.4 镜像下载慢的解决办法RHEL9 服务器上拉镜像慢原因无非两种网络链路问题或者 Docker Hub 本身访问不稳。前面第 2.4 节配置过加速源这里再补充两个后续手段。一个是给docker pull加超时重试可以在 pull 命令失败后反复执行几次实测偶尔能成功。另一个手段是设置代理镜像。有些官方镜像在 Docker Hub 上地址特殊可以改用镜像的完整路径docker pull docker.m.daocloud.io/library/mysql:8.0然后打标签改成标准名称docker tag docker.m.daocloud.io/library/mysql:8.0 mysql:8.0 docker rmi docker.m.daocloud.io/library/mysql:8.0这个方法的本质是利用加速源的域名直接拉取避免了 daemon.json 配置可能失效的问题。我遇到某些加速源不稳定时就用这个方式兜底。另外拉取镜像前先确认本地是不是已经有同名不同 tag 的镜像有时候你需要的镜像之前已经拉过了只是 tag 不同可以直接打 tag 复用省得重新下载几百兆。6. 实操心得与避坑指南6.1 我在 RHEL9 上踩过的坑这段时间在 RHEL9 上折腾 Docker踩过几个印象深刻的坑写出来给大家省点时间。第一个是container-selinux 依赖的坑。RHEL9 的最小化安装只带基础源Docker 安装到一半报依赖缺失是常事。解决办法是先dnf install container-selinux再装 docker-ce。如果这一步还是不行检查系统有没有正确启用 AppStream 仓库sudo subscription-manager repos --list-enabled dnf repolist第二个是firewalld 跟 Docker 的端口冲突。RHEL9 默认开着 firewalldDocker 的 iptables 规则跟 firewalld 的端口管理是两套体系。如果你改了 firewalld 规则后发现 Docker 端口映射失效先别怀疑 Docker试着重启 firewalld 和 docker 的服务顺序sudo systemctl restart docker sudo firewall-cmd --reload第三种常见情况是RHEL9 上不想用 sudo 跑 docker。按照 5.2 节的方法加入 docker 组后如果用的还是 SSH 登录会话一定要重新登录一次让组权限生效单纯newgrp docker只在当前 shell 生效新开的 SSH 会话还是旧权限。第四个是日志暴增把磁盘撑满。容器默认的日志驱动是 json-file日志文件无限增长。我的建议是启动容器时加上日志轮转参数docker run -d \ --log-opt max-size10m \ --log-opt max-file3 \ nginx:latest或者在 daemon.json 里统一配置{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }生产环境不管跑什么容器这个日志限制都建议加上。我在一台跑了二十多个容器的 N100 小主机上试过不加日志限制一周不到磁盘就告警了加完之后磁盘占用非常稳定。6.2 生产环境建议在 RHEL9 上跑 Docker 到生产环境级别有几个建议要重点拎出来说。先把 Docker 的 daemon.json 一次性配置到位{ registry-mirrors: [ https://docker.m.daocloud.io, https://docker.1panel.live ], dns: [223.5.5.5, 8.8.8.8], data-root: /var/lib/docker, log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }>{ data-root: /data/docker }改完>docker image prune -f docker container prune -f docker volume prune -f加上这行巡检逻辑后我的服务器磁盘从没因为 Docker 资源堆积出过问题。最后想说的是RHEL9 的容器化选型不一定非要 Docker。如果你是纯 Red Hat 生态的系统管理员Podman 其实已经足够日常使用了。但如果你跟我一样手里有一堆 docker-compose 编排文件、依赖 Docker Hub 镜像生态、或者团队成员已经习惯了 Docker 的工作流那在 RHEL9 上部署 Docker CE 完全可行只要按照上面这套流程走从安装到生产可用基本可以控制在半小时以内。这也正是我把整个实操过程记下来的原因——工具选型从来不是死板的关键是搞清楚自己的业务诉求再选择顺手的那一个。
返回列表