ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

OpenEuler与麒麟V10上Docker安装配置实战指南

OpenEuler与麒麟V10上Docker安装配置实战指南 1. 环境准备与安装方案选型1.1 为什么在欧拉/麒麟上装 Docker 要单独写一篇先交代一个大多数新手容易踩坑的认知问题OpenEuler 和麒麟V10 虽然都是 Linux但它们跟 CentOS、Ubuntu 在用包管理器、内核参数、软件源策略上差别不小。尤其是 OpenEuler 24.03 SP4 属于较新的 LTS 版本默认软件源里的容器相关组件做了调整直接照搬 CentOS 7 那套yum install docker是装不上的——你大概率会遇到“没有可用软件包”或者版本对不上的问题。我这次是在 X86_64 架构的物理机上分别装过 OpenEuler 24.03 SP4 和麒麟V10SP1/SP2 都测过把踩过的坑和对的方案整理成一篇可复现的实操记录。适合这几类读者公司信创项目要求迁移到欧拉或麒麟需要跑容器化应用的运维和研发在 VMware 或 VirtualBox 里装好了欧拉/麒麟想在虚拟机里搭 Docker 环境做学习验证的手头有离线内网服务器想把 Docker 以及常用镜像一次性装好的实施人员。文章覆盖的内容包含在线安装、离线安装rpm 包方式、Docker 配置调优镜像加速、存储路径、cgroup 驱动、以及装完后我实测过的常见报错和解决思路。1.2 安装前必须确认的三个环境指标安装 Docker 前我建议你先检查三件事操作系统版本、架构、内核版本。命令如下# 查看系统版本 cat /etc/os-release # 查看内核版本 uname -r # 查看架构 uname -mOpenEuler 24.03 SP4 的输出里VERSION_ID24.03VERSION字段会带 SP4 字样。麒麟V10 则有两种发行版一种是基于 CentOS 兼容的“银河麒麟高级服务器操作系统 V10”另一种是基于 Ubuntu 的“银河麒麟桌面版 V10”两者安装 Docker 的方式完全不同——本文以服务器版本质是 RHEL 系为主桌面版apt 系反而可以直接参考 Ubuntu 的教程装。为什么要先确认内核因为 Docker 依赖内核的 namespace、cgroup、iptables 等特性。欧拉默认内核 5.10 以上麒麟V10 服务器版默认内核 4.19这两个内核都满足 Docker 20.10 的运行要求。唯一需要你注意的是某些厂商定制内核例如部分麒麟版本使用了华为的 openEuler 内核变体个别内核模块可能被裁剪掉后面我会提到怎么在报错时排查。1.3 在线安装dnf 源配置与安装命令OpenEuler 默认的软件源里其实已经有 docker 相关的包了只是包名叫docker或docker-engine不叫docker-ce。欧拉不直接提供 Docker CE 官方源所以在线安装最稳妥的方式是用欧拉自带的源装社区版或者自己配好 EPOL 源后安装。我推荐的操作路径是先确认dnf源可用再直接安装。# 确认 dnf 源列表 dnf repolist # 安装 docker 及相关组件 dnf install -y docker docker-cli containerd这里有个细节欧拉源里的docker包版本比较保守但胜在经过了系统适配稳定性有保障。如果你一定想装 Docker CE 最新版可以考虑在欧拉上手动引入 Docker 官方针对 RHEL 的源欧拉与 RHEL 二进制兼容大部分情况下能直接用不过我个人不太建议在生产环境这么干因为官方源没有针对欧拉做过完整测试依赖解析偶尔会出幺蛾子。麒麟V10 服务器版在线安装的逻辑也类似而且麒麟自带的源里通常已经收录了 docker 包# 麒麟V10 服务器版 yum install -y docker docker-cli containerd.io装完以后先别急着启动先把配置调好再启动否则默认配置很容易让你后面收拾烂摊子。2. Docker 核心配置详解与关键参数说明2.1 核心配置文件daemon.json 逐项说明Docker 的守护进程配置集中在/etc/docker/daemon.json这个文件默认不存在需要手动创建。很多教程只让你填一个镜像加速地址但在欧拉/麒麟上我建议你至少把下面这几项一起配好{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, data-root: /data/docker, registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ], ipv6: false }逐项解释一下exec-opts设置 cgroup 驱动为 systemd。这是最容易出问题的一项。欧拉和麒麟默认的 init 系统都是 systemd如果 Docker 的 cgroup 驱动是 cgroupfs而系统服务用的是 systemd两边管理 cgroup 的方式不一致会导致容器内资源限制失效甚至在高负载时出现“内存无法回收”的诡异问题。统一成 systemd 后Docker 和系统对 cgroup 的控制就一致了。log-driver 和 log-opts限制容器日志大小。默认情况下 Docker 不限制容器日志文件大小一个长期运行的容器可能把磁盘写满。100m × 3 的意思是单文件最大 100MB保留 3 个轮转文件也就是单容器最多约 300MB 日志。这个数值可以根据业务调整但建议一定要配别问我怎么知道的——曾见过生产环境日志把数据盘直接顶爆的案例。storage-driveroverlay2 是当前最主流的存储驱动也是 Docker 默认推荐的。欧拉 5.10 内核、麒麟 4.19 内核都原生支持 overlay2不需要额外加载模块。># 加载 br_netfilter 模块 modprobe br_netfilter # 设置开机自动加载 echo br_netfilter /etc/modules-load.d/br_netfilter.conf # 开启桥接流量经过 iptables cat /etc/sysctl.d/docker.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF # 立即生效 sysctl -p /etc/sysctl.d/docker.conf这一段命令在 CentOS 系系统的教程里经常被一笔带过因为 CentOS 默认镜像里这些参数往往是开着的。但欧拉和麒麟为了安全加固默认把ip_forward关了而且没有加载br_netfilter模块这导致很多第一次在这类系统上装 Docker 的人卡在“容器网络不通”上。实操时建议把上面的代码存成脚本一次执行因为遗漏任何一项都会造成网络异常。另外/etc/sysctl.d/docker.conf是新建文件不会覆盖系统已有的 sysctl 配置安全性上没问题。2.3 cgroup 驱动的选择逻辑关于 cgroup 驱动我再多展开一点。所谓 cgroup 驱动是 Docker 用来管理容器资源限制CPU、内存、PID 数量等的系统接口方式。Linux 内核提供两套接口cgroup v1 和 cgroup v2。欧拉 24.03 默认启用了 cgroup v2麒麟V10 内核 4.19 则默认还是 v1。Docker 在 cgroup v2 环境下如果 cgroup 驱动还是 cgroupfs 而不是 systemd会出现容器内的系统调用被拒绝的情况比如 Nginx 无法启动、Java 进程报 “cgroup memory limit” 相关错误。我之前在欧拉 24.03 上就遇到过 MySQL 容器启动后立刻 OOM 被杀的问题查了半天最后定位就是 cgroup 驱动不一致导致的。这就是为什么daemon.json里那一行exec-opts: [native.cgroupdriversystemd]如此重要。它让 Docker 使用 systemd 来管理 cgroup与宿主机保持一致从根源上避免这类诡异问题。验证当前 cgroup 驱动可以用这条命令docker info | grep -i cgroup如果输出里出现Cgroup Driver: systemd说明配置正确。如果显示cgroupfs先检查 daemon.json 是否生效再确认 Docker 是否完全重启systemctl restart docker而非systemctl reload docker后者对某些配置不生效。3. 从安装到验证的完整实操过程3.1 在线安装完整命令序列假设你已经在欧拉或麒麟服务器上拿到了 root 权限或 sudo 权限按下面的顺序操作# Step 1: 更新系统可选但建议在安装前做一次 dnf update -y # Step 2: 安装 Docker欧拉 dnf install -y docker docker-cli containerd # Step 2 备选: 安装 Docker麒麟V10服务器版 # yum install -y docker docker-cli containerd.io # Step 3: 创建配置目录并写入 daemon.json mkdir -p /etc/docker cat /etc/docker/daemon.json EOF { exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, data-root: /data/docker, registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ], ipv6: false } EOF # Step 4: 开启桥接网络相关内核参数 modprobe br_netfilter echo br_netfilter /etc/modules-load.d/br_netfilter.conf cat /etc/sysctl.d/docker.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl -p /etc/sysctl.d/docker.conf # Step 5: 启动 Docker 并设置开机自启 systemctl enable --now docker # Step 6: 验证安装 docker version docker run hello-world第 6 步的docker run hello-world会从镜像仓库拉取一个很小的测试镜像成功执行说明 Docker 守护进程正常运行能正常拉取镜像容器也能跑起来。3.2 离线安装rpm 包方案与依赖处理内网环境下没有外网源不能在线安装这是信创项目里最常见的场景。两种离线方案我分别说怎么做。方案一在有网机器上把 rpm 包全部下载下来再拷贝到内网。在能联网的欧拉/麒麟机器上执行# 创建下载目录 mkdir -p /root/docker-rpms cd /root/docker-rpms # 下载 docker 及全部依赖只下载不安装 dnf install --downloadonly --destdir/root/docker-rpms docker docker-cli containerd把整个docker-rpms目录用 U 盘或内网传输工具拷到目标服务器然后安装cd /root/docker-rpms dnf install -y ./*.rpm这个方法依赖你“下载用的机器”和“目标机器”系统版本一致。欧拉的 rpm 包放到欧拉上装没问题但是放到麒麟V10 上装可能会因为依赖库版本差异报错。跨系统复制 rpm 包我不是很推荐除非你能确认两边 glibc 等基础库版本一致。方案二利用 Docker 官方静态二进制包离线部署。这个方案更通用适合跨发行版。从 Docker 官方 GitHub Releases 页面下载docker-版本-x86_64-static-bin.tar.gz然后手动解压和注册 systemd 服务。静态编译的二进制不依赖特定发行版的库天然解决了兼容问题。具体流程# 假设已经下载好 docker-27.x.x.tgz 并上传到服务器 tar xzf docker-27.x.x.tgz cp docker/* /usr/bin/ # 创建 Docker systemd 服务文件 cat /etc/systemd/system/docker.service EOF [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com 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 TimeoutStartSec0 Delegateyes KillModeprocess Restarton-failure StartLimitBurst3 StartLimitInterval60s [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now docker静态二进制方案在欧拉和麒麟上都验证过能跑推荐给离线部署、需要跨系统交付的场景。3.3 验证 Docker 是否可用的“通关测试”装完 Docker 之后除了docker version能正常输出客户端和服务端信息外我建议你再做一次完整的“通关测试”# 1. 拉取测试镜像 docker pull hello-world # 2. 运行测试容器 docker run --rm hello-world # 3. 测试容器网络能 ping 通外网说明桥接配置正确 docker run --rm alpine ping -c 3 223.5.5.5 # 4. 测试 DNS 解析能解析域名说明 DNS 配置正确 docker run --rm alpine nslookup baidu.com # 5. 测试容器间通信 docker network create test-net docker run -d --name c1 --network test-net alpine sleep 300 docker run -it --rm --network test-net alpine sh # 在交互式 shell 里执行 ping c1能通说明容器间网络正常前三步通过说明宿主机和容器的基础网络没问题第四步通过说明容器内 DNS 配置正确第五步通过说明 bridge 网络的多容器通信正常。如果卡在第三步优先检查上一节的内核桥接参数是否生效卡在第四步优先检查镜像加速配置和/etc/docker/daemon.json里的 DNS 设置可以在daemon.json加一段dns: [223.5.5.5, 8.8.8.8]强制指定 DNS。4. 从安装到配置的高频报错排查实录4.1 报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled这个报错的含义是 Docker 守护进程在拉镜像时请求 docker.io 官方仓库失败。在欧拉/麒麟上绝大多数原因是网络问题——不是你的机器不能上网而是访问 Docker Hub 在部分网络环境下会被干扰或超时。排查路径# 1. 检查 daemon.json 里的镜像加速配置是否生效 docker info | grep -A 5 Registry Mirrors # 2. 手动测试加速地址的连通性 curl -I https://docker.m.daocloud.io如果docker info里面没有显示镜像加速地址说明 daemon.json 没有被正确读取。常见原因是 JSON 格式错误——比如多了一个逗号、引号写成了中文引号。建议用docker run hello-world前先执行docker info看一下配置项全不全。如果加速地址显示正常但仍拉取超时可以换一个可用加速地址。公共加速器经常变动保持多个备选地址是个好习惯。4.2 报错Failed to start docker.service: Unit docker.service not found这个报错出现在你用systemctl start docker时系统提示找不到 Docker 的 systemd 服务单元也就是服务文件。这个问题的根源通常是 Docker 安装不完整或者用的是静态二进制手动部署但没有创建 service 文件。处理办法是检查系统里有没有 dockerd 和 docker 命令which dockerd which docker如果命令存在但服务文件缺失用 3.2 节里面的 systemd 服务文件内容手动补上。如果命令都不存在说明安装过程本身就出了问题重新走一遍安装流程确认最后的dnf install没有任何报错。4.3 报错iptables failed: iptables --wait -t nat -A DOCKER ... Resource temporarily unavailable这个报错在内核 4.19 的麒麟V10 上比较常见。根因是 Docker 在创建 iptables 规则时系统的 nf_conntrack 模块表满导致规则写入失败。换句话说这台机器的连接跟踪表太小并发稍微一大就写不进 NAT 规则了。临时解决办法是扩大连接跟踪表的规模# 查看当前表大小 sysctl net.netfilter.nf_conntrack_max # 临时扩大 sysctl -w net.netfilter.nf_conntrack_max131072 # 持久化配置 echo net.netfilter.nf_conntrack_max131072 /etc/sysctl.d/docker.conf sysctl -p /etc/sysctl.d/docker.conf如果调大之后仍然频繁报错考虑减少 Docker 容器数量或者给宿主机增加内存。因为 nf_conntrack 表是哈希表每条连接记录都占内存太小的内存撑不起太大的表。4.4 报错docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused process_linux.go:281: applying cgroup configuration for process caused \Unit docker.service not found\**这个报错就是在 2.3 节提到的 cgroup 驱动不一致的典型症状。当daemon.json里没有配置native.cgroupdriversystemd且 Docker 检测到系统用的 systemd 时init 进程创建容器时会出现这种混乱。解决办法# 1. 确认 daemon.json 内容 cat /etc/docker/daemon.json # 2. 改完配置后必须完全重启 Docker systemctl restart docker # 3. 再次查看 cgroup 驱动 docker info | grep -i cgroup注意修改 daemon.json 后用systemctl reload docker是不够的有部分配置项必须在重启时才会被重新读取。这是我在实际使用中踩过的小坑reload只是重新加载部分运行时配置不会重新解析 daemon.json 里的所有项目。4.5 常见问题速查表我整理一份实际项目里出现频率最高的几个问题方便你按图索骥报错现象根因解决方向容器启动后访问外网不通br_netfilter 未加载或 ip_forward 未开启modprobe br_netfilter sysctl 配置拉取镜像超时镜像加速地址不可用更换/增补 registry-mirrors 地址容器被 OOM Kill日志无明显异常cgroup 驱动不一致设置 native.cgroupdriversystemd 并重启iptables 规则写入失败nf_conntrack 表满调大 nf_conntrack_maxservice 启动失败找不到单元动态二进制未创建 service补全 /etc/systemd/system/docker.service容器 root 用户创建的文件权限错乱宿主机和容器 UID/GID 映射使用 --user 指定容器运行用户执行 docker 命令提示权限不足当前用户不在 docker 组usermod -aG docker 用户名重新登录4.6 排障的通用思路别只盯着 Docker在欧拉/麒麟这类信创服务器上排障时我养成了一个习惯先排除系统层问题再排查 Docker 层问题。因为系统做了很多安全加固和内核参数调整很多“看起来是 Docker 的问题”实际根源在宿主机。比如容器时区不对、DNS 解析慢、文件句柄不足——这些 90% 都可以在daemon.json里预先规避。我建议装完 Docker 后直接把时区和限制也补上{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, data-root: /data/docker, registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ], ipv6: false, dns: [223.5.5.5, 8.8.8.8] }加了dns这一项之后容器内默认使用阿里 DNS 和谷歌 DNS规避了系统自带的 systemd-resolved 在某些内网环境里的解析抖动问题。不过如果你所在的内网有自建的 DNS 解析服务比如公司内部域名这里应该替换成内网 DNS 地址否则容器解析不到内部服务名。5. 深度使用建议与性能调优心得5.1 为 Docker 单独划分数据盘我见过太多服务器Docker 装在系统盘上跑着跑着磁盘被容器日志和镜像打满最后系统盘只读连故障排查都做不了。所以如果你在规划阶段有条件就给 Docker 单独挂一块数据盘没条件至少在装完后尽快把>systemctl stop docker mv /var/lib/docker /data/docker # 修改 daemon.json 里的># 启动容器时加上 --restart 参数 docker run -d --name myapp --restartalways myapp:latest # 给已有容器修改重启策略 docker update --restartalways myapp--restartalways的意思是无论容器因何退出包括 Docker 服务重启、宿主机重启、容器内进程崩溃Docker 都会自动把它拉起来。这在生产环境里几乎是必须的配置否则宿主机一重启所有容器都处于 Exited 状态需要人工介入。我在欧拉上实测过配置了--restartalways的容器在宿主机重启后会自动恢复未配置的则全部停留在退出状态。这条经验对运维来说能省不少事。5.3 配置容器资源限制避免一台容器拖垮宿主机很多刚从虚拟机过渡到容器的工程师会忽略资源限制。虚拟机有 vCPU 和内存限制撑着容器没有限制的话可以直接把宿主机 CPU 和内存吃满影响同一台上的其他容器。我用 Docker 跑业务容器时都会在docker run时加上资源限制参数docker run -d \ --name myapp \ --memory1g \ --memory-swap1g \ --cpus1.0 \ --restartalways \ myapp:latest--memory1g限制容器最多使用 1GB 内存--memory-swap1g把 swap 也禁掉避免容器内存超限后使用 swap 导致性能骤降--cpus1.0限制容器最多使用 1 个 CPU 核。这几个参数加完之后即使容器内有内存泄漏最多也只是把容器干掉不会牵连宿主机上的其他服务。结合 2.1 节的daemon.json里配置native.cgroupdriversystemd容器资源限制在欧拉/麒麟上能够正确生效这也是我前面反复强调 cgroup 驱动一致性的原因——如果不一致就算你加了--memory参数内核也不一定会严格执行。5.4 docker compose 安装与用法如果是多容器编排直接装docker-compose-plugin比单独装 python 版 compose 要省心得多。欧拉/麒麟的源里通常有现成的包# 欧拉/麒麟 安装 compose 插件 dnf install -y docker-compose-plugin装完以后用docker compose version验证。新版 Docker Compose 已经集成到 docker CLI 里不再需要docker-compose命令前缀加横杠。拿一个最简单的例子说明 Compose 的实际价值。假设你要部署 Nginx MySQL 两个服务不写 Compose 文件的话要执行两次docker run还要手动创建网络、设置端口映射、配置环境变量。用 Compose 把这些都固化在一个docker-compose.yml文件里后续启动销毁只需两条命令services: web: image: nginx:latest container_name: nginx-web ports: - 80:80 restart: always mysql: image: mysql:8.0 container_name: mysql-db environment: - MYSQL_ROOT_PASSWORDyourpassword volumes: - /data/mysql:/var/lib/mysql ports: - 3306:3306 restart: always然后docker compose up -d启动docker compose down批量停掉。这种方式尤其在信创项目交付时好使——可以把整个部署过程向量化避免在客户现场对着命令行手抖。5.5 镜像仓库选择与私有化方案内网或政务网环境里拉取 Docker Hub 镜像基本不可行即使配置了加速器也可能被安全策略拦掉。这种情况下在服务器上搭建一个私有镜像仓库是刚需。轻量级方案是跑一个 registry 容器docker run -d \ --name registry \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ --restartalways \ registry:2然后用docker tag和docker push把镜像推到私有仓库其他机器通过docker pull 服务器IP:5000/镜像名拉取。唯一的条件是所有客户端机器的 Docker 必须配置insecure-registries才能用 HTTP 协议访问私有仓库{ insecure-registries: [192.168.1.100:5000] }关于私有仓库加 HTTPS 证书、配置用户认证这些进阶内容等有需要的时候可以再展开一篇专门讲这里先给一个能跑的交付方案。6. 写在最后一些实际的体会在欧拉和麒麟上装 Docker难度其实并不高真正折腾人的是那些和 CentOS 默认行为不一致的小差异。比如br_netfilter内核模块默认没加载、ip_forward默认关闭、cgroup 驱动需要显式改成 systemd这些点不提前处理装完 Docker 之后几乎一定会遇到网络不通的诡异现象。我个人在几次信创项目交付中养成了一个固定套路不管目标系统是欧拉还是麒麟装 Docker 前先把内核参数检查一遍装完立刻把 daemon.json 完整配置写好再启动最后跑一遍网络通关测试。这样一套流程下来几乎不会出幺蛾子。再说一个很多人会忽略的小技巧装完 Docker 后顺手把docker命令的自动补全也配好。欧拉/麒麟的 bash-completion 包通常已经装了只需要把 Docker 的补全脚本放到对应目录dnf install -y bash-completion mkdir -p /etc/bash_completion.d curl -L https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker -o /etc/bash_completion.d/docker重新登录终端后输入docker run按 Tab 就能补全参数。现场排障时少打几个字符优势不大但少记几个参数名就不会出错这种细节积累多了做事效率自然就上来了。最后提醒一句欧拉和麒麟都在快速迭代中不同版本的源和内核参数可能有细微差异如果跟着这篇文章操作时遇到问题优先检查系统版本和源是否匹配再逐项对照 daemon.json 的内核参数大概率能在十分钟内定位到问题。
返回列表