ARTICLE DETAIL

资讯详情

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

Kylin Server V10离线安装Docker全流程:依赖解析与排障实践

Kylin Server V10离线安装Docker全流程:依赖解析与排障实践 上个月帮客户部署一套容器化的内网交付环境机器清一色是Kylin Server V10Halberd机房跟外部网络物理隔离。业务要求在这些机器上装好Docker并且装完得能稳稳当当跑起来。听起来就六个字“离线安装Docker”实际做的时候才发现问题全藏在细节里rpm依赖缺一串、x86和ARM的包不能混用、iptables版本对不上、SELinux插一脚、firewalld再搅和一把。这篇文章就把我这次完整走通过的路程记录下来从环境确认到包准备从安装配置到排障再到离线镜像搬运每一步的理由和替代方案都尽量讲清楚。适合正在做内网交付、准备在Kylin Server上跑容器化应用的运维和交付同学参考。1. 离线安装Docker真正的坎不只是拷rpm包很多人第一反应是找台能联网的机器把Docker的rpm下载下来传到目标机器上rpm -ivh一把梭。这个流程在CentOS上可能一次就过但放到Kylin Server上很少这么顺利。原因很简单Docker的rpm包依赖链比想象中长至少涉及containerd、runc、container-selinux、iptables、libseccomp这些组件。如果离线包里没带全安装器会直接甩一句Requires: xxx is needed by docker-ce然后戛然而止。1.1 为什么不能直接拷二进制文件Docker说到底是dockerd这个daemon加上一堆客户端工具理论上下载官方发布的二进制tarball解压放到/usr/bin就能跑。我在CentOS上也这么干过确实能起来。但在Kylin Server上二进制方式会带来三个麻烦systemd的service文件得自己写开机自启、日志处理全要手动维护交付时不规范。runc、containerd、docker-ce三者之间的版本匹配关系容易搞乱网上很多教程还是旧版组合跑新镜像时接口不兼容。项目交付时审计要装机记录拷二进制这种方式显得太“野”rpm安装则能通过rpm -qa清晰追溯到每个包的版本和来源。所以离线安装Docker走rpm路线是更规范也更稳的选择。既然决定用rpm就必须正视依赖链。这也是为什么很多人拿着一个docker-ce的rpm跑到内网装卡在container-selinux、iptables这些依赖上动弹不得。1.2 Kylin Server与CentOS源的兼容性判断Kylin对外宣称兼容RHEL生态但它不是CentOSyum源里的包版本、repo文件内容都有自己的一套。判断能不能用某个源的包最靠谱的指标是glibc版本。rpm -q glibc看到版本是2.28及以上的就优先考虑el8系列RHEL 8 / CentOS 8的Docker包。如果Kylin版本比较老glibc低于2.28那就退回el7的包。我这次碰到的Kylin Server V10版本glibc是2.28所以直接选el8的Docker rpm包一次装上没问题。还有个细节得注意Kylin V10的repo文件里$releasever可能被解析成7或者10而Docker官方仓库的路径是/linux/centos/$releasever/里面根本没有10这个目录。配置yum源的时候如果不管这个变量执行yum install docker-ce会报404。处理方式就是在repo文件里手动把$releasever替换成8。1.3 出发前必须确认的三条命令在联网机器上开始下载包之前先在目标机器上把这三条命令的输出记下来它们决定了你在联网机器上要下什么包。cat /etc/kylin-release arch rpm -q glibccat /etc/kylin-release拿到系统具体版本比如V10 SP1还是SP2arch决定下载x86_64还是aarch64的包rpm -q glibc决定该选el7还是el8的包。三者的组合判断如下表系统版本机器架构glibc版本推荐的rpm目录V10 SP1x86_642.28centos/8/x86_64V10 SP1aarch642.28centos/8/aarch64老版本V10x86_642.17centos/7/x86_64备选这个判断表看起来简单但能帮你少传几十个没用的包。架构选错是最直接的坑——x86_64的rpm包传到aarch64机器上安装直接报wrong ELF class根本装不进去。2. 备料环节需要下载哪些rpm以及怎么一次拉齐确认完环境和架构下一步是去联网机器上把包备齐。这一步的关键不是“下载docker-ce这一个包”而是把整条依赖链一次性拉下来。2.1 Docker rpm家族有哪些成员以docker-ce 24.0.x版本为例离线包里至少要包含下面几个成员docker-ce主程序提供dockerd daemon。docker-ce-clidocker命令行工具没有它你没法敲任何docker命令。containerd.io容器运行时新版docker-ce默认用它来管理容器生命周期。docker-buildx-plugin构建镜像用的Buildx插件现在官方默认带。docker-compose-plugindocker compose插件有了它才支持docker compose命令。container-selinuxSELinux策略包Kylin如果开了SELinux没有这个包docker容器启动会报权限错误。除了上面几个还有一批系统级依赖比如iptables、libnfnetlink、libnetfilter_conntrack、libseccomp、policycoreutils-python-utils等。这些通常来自系统基础源而不是Docker源离线打包时很容易漏掉。2.2 用yumdownloader一次拉全依赖如果联网机器本身是CentOS 8或者同架构的机器配置好docker-ce的yum源之后可以用yumdownloader这个工具把依赖递归解析出来。# 安装工具 yum install -y yum-utils # 配置docker-ce源注意将$releasever替换成8 curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i s/\$releasever/8/g /etc/yum.repos.d/docker-ce.repo # 指定目录一次性下载 mkdir -p /opt/docker-rpm yumdownloader --resolve --destdir/opt/docker-rpm \ docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin container-selinux--resolve选项会递归解析依赖把缺的包一并下载到指定目录。这个命令跑完/opt/docker-rpm里通常会多出十几个包其中就有iptables相关组件。2.3 没有yum-utils时的手工下载方案有些内网交付的联网跳板机很干净连yum-utils都不愿意装。这时候就得手工下载。以阿里云Docker镜像源为例路径是https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/Packages/浏览器打开这个目录能看到所有稳定版包列表。把需要的包下载到本地再按文件名挑出对应架构的版本即可。mkdir -p /opt/docker-rpm cd /opt/docker-rpm wget https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/Packages/docker-ce-24.0.9-1.el8.x86_64.rpm wget https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/Packages/docker-ce-cli-24.0.9-1.el8.x86_64.rpm注意手工下载容易漏的是依赖包。比如container-selinux需要policycoreutils-python-utils如果跳板机能联网建议还是先配好源让yumdownloader帮你把这些边角料包一并收集。2.4 一份可复用的离线包清单下面是这次实际用过的一份包目录版本号以仓库实时列表为准但包名结构是通用的包名说明docker-ce-24.0.9-1.el8.x86_64.rpmDocker主程序docker-ce-cli-24.0.9-1.el8.x86_64.rpmDocker命令行containerd.io-1.6.28-3.1.el8.x86_64.rpm容器运行时docker-buildx-plugin-0.14.1-1.el8.x86_64.rpmBuildx插件docker-compose-plugin-2.28.1-1.el8.x86_64.rpmCompose插件container-selinux-2.229.0-1.el8.noarch.rpmSELinux策略libnetfilter_conntrack-*.rpm依赖包libnfnetlink-*.rpm依赖包iptables-*.rpmDocker网络依赖版本要满足要求下载时永远记住一句话宁可多带不要少带。离线环境里缺一个依赖包就意味着要重新找机器下载、重新刻盘或者走审批流程传递文件时间成本高得吓人。3. 目标机器的完整安装流程从上传rpm到开机自启包备齐了接下来就是上目标机器操作。这一步如果按部就班来非常快全程十分钟内能搞定。3.1 上传包后的第一件事先体检先把整个rpm目录用U盘、scp或者内部文件传输通道拷贝到目标机器统一放到/opt/docker-rpm。上传后不要急着安装先做两件事cd /opt/docker-rpm ls -lh rpm -qip docker-ce-24.0.9-1.el8.x86_64.rpmls -lh看文件大小防止传输过程中产生半截文件。如果一个包的大小和源端差太多别用重新传。rpm -qip查看包的元信息确认架构是x86_64还是aarch64确认Source是el8还是el7。这一步能拦截掉百分之九十的架构错误和下载错误。3.2 安装顺序先把依赖喂饱不建议直接rpm -ivh *.rpm一股脑装虽然rpm会自动跳过已安装的包但遇到依赖缺口时它会停下来而且报错信息不直观。更稳的做法是分两步走# 第一步解决selinux和系统依赖 yum localinstall -y container-selinux-*.noarch.rpm policycoreutils-python-utils-*.rpm 2/dev/null rpm -Uvh libseccomp-*.rpm libnfnetlink-*.rpm libnetfilter_conntrack-*.rpm iptables-*.rpm 2/dev/null # 第二步安装docker本体和组件 rpm -Uvh containerd.io-*.rpm docker-ce-cli-*.rpm docker-ce-*.rpm rpm -Uvh docker-buildx-plugin-*.rpm docker-compose-plugin-*.rpm为什么要先装container-selinux因为docker-ce的rpm包在metalink里明确写了Requires: container-selinux 2:2.95不满足这个依赖docker-ce是装不进去的。而container-selinux又依赖policycoreutils-python-utils所以这两个包得排在最前面。如果报runc版本不满足containerd.io的要求别慌。目标机器上通常自带runc但版本可能偏老比如1.0.0-rc95这种而新版containerd.io要求runc 1.1.0。解决办法是去Kylin基础源或者EPEL源里找对应架构的runc 1.1.x包一起带进来升级。3.3 配置daemon.json比默认配置多走一步装完rpm包后/etc/docker/目录还不存在需要手动创建并写入daemon.json。这份配置我建议一开始就写好不要用默认配置跑否则后面迁移数据目录、限制日志都要重启服务麻烦。mkdir -p /etc/docker /data/docker cat /etc/docker/daemon.json EOF { data-root: /data/docker, exec-opts: [native.cgroupdriversystemd], storage-driver: overlay2, log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, iptables: true } EOF这里解释几个关键项。>systemctl daemon-reload systemctl enable --now docker systemctl status dockersystemctl status看到Active: active (running)之后再用两条命令验证docker version docker info内网环境没有hello-world镜像所以不能靠docker run hello-world来验证。只要docker version里Client和Server两端都有版本信息就说明daemon正常启动了。docker info可以再看一眼存储驱动是否是overlay2、Cgroup驱动是不是systemd。4. 装完必翻车的四个细节权限、防火墙、存储和日志Docker装完并不等于万事大吉下面这几个问题我几乎每次都能碰到一两个提前处理能省下大量排障时间。4.1 docker组为什么普通用户执行docker会失败rpm安装完成后Docker会自动创建docker组但当前登录的普通用户并不在这个组里。普通用户执行docker ps会看到Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock原因是/var/run/docker.sock的权限属于root:docker普通用户没权限访问。解决办法是把用户加进docker组然后重新登录usermod -aG docker kylinuser注意重新登录的意思是退出当前SSH会话再重新连接单纯newgrp docker开一个新shell也可以但更彻底的做法是退出重连。不生效的话检查id kylinuser看是否已经包含docker组。4.2 firewalld和iptables的隐形冲突这是离线安装后最闹心的问题。表现现象是容器起来了docker port能看到映射但外部访问不通。原因通常是Docker会直接操作iptables规则来配置端口映射而Kylin自带的firewalld在nftables框架下管理网络过滤两边互不认识产生规则冲突。处理办法分情况。如果是生产环境且防火墙必须开着那就不要停firewalld而是把需要对外提供服务的端口在firewalld里放行firewall-cmd --permanent --add-port8080/tcp firewall-cmd --reload如果是测试验证环境可以直接停掉firewalld再重启一次Dockersystemctl stop firewalld systemctl restart docker重启Docker之后用iptables -t nat -L -n | grep DOCKER检查NAT表里有没有Docker的端口映射规则。有说明端口转发链路正常。4.3 overlay2存储驱动检查Docker默认会优先用VFS、overlayfs等驱动但在Kylin Server上如果内核模块没加载存储驱动会自动降级为VFS。VFS的性能非常差跑几个容器后磁盘占用会暴涨数倍。检查当前驱动docker info | grep -A2 Storage Driver如果输出是overlay2那就没问题。如果显示vfs多半是br_netfilter模块没加载或者/etc/modules-load.d/里没配开机加载。需要手动加载modprobe br_netfilter echo modprobe br_netfilter /etc/rc.local chmod x /etc/rc.local sysctl -w net.bridge.bridge-nf-call-iptables1这个操作同时也能解决一部分容器间通信、端口映射不通的问题因为br_netfilter是Docker网桥流量经过iptables过滤的前提。4.4 日志分区被占满数据目录改到/data/docker之后如果忘了限制日志容器产生的json日志文件会直接灌到/data/docker/containers目录下。一个调试阶段打日志频繁的容器一天写几个G跟玩一样。这里有个容易忽略的点daemon.json里的max-size和max-file只对之后创建的新容器生效已经跑起来的容器不会自动回收日志。所以部署容器时要先确认日志参数生效再启动容器。如果已经在跑容器日志文件又很大只能重建这个容器来让限制生效或者手动清空/var/lib/docker/containers/id/*.log。5. 离线的镜像怎样进来save/load、内网Registry和composeDocker装好了接下来最大的问题是镜像从哪里来内网没有外网访问能力镜像搬运就成了一件绕不开的事。5.1 单机场景docker save / docker load如果只有一两台机器docker save加docker load是最直接的方案。在联网机器上把镜像导出成tar包传到目标机器再导入。# 联网机器上 docker pull nginx:1.24 docker save nginx:1.24 | gzip nginx-1.24.tar.gz # 目标机器上 docker load -i nginx-1.24.tar.gz这里有几个实践经验。第一导出和导入的机器架构必须一致。x86_64的机器上拉下来的镜像是amd64架构的传到aarch64机器上跑不起来。所以备料阶段就要确定目标机器是ARM还是x86然后在同架构的联网机器上拉镜像。第二多个镜像不要打成一个tar。一次导入一个大tar如果中间某个镜像失效整个导入可能失败而且排查定位都费劲。单镜像单文件传一个导一个虽然文件多一点但稳。第三大镜像建议先gzip再传压缩率通常能到30%到50%能省不少传输时间。5.2 多机场景内网Registry才是正解机器一多比如十台以上save/load的工作量就会变得非常大。这时候更合理的方案是内网搭一个镜像仓库。在内网一台存储足够的机器上部署Registry或者Harbor然后把目标机器的daemon.json里加上insecure-registries字段{ insecure-registries: [registry.internal:5000] }之后在联网机器上docker pull镜像docker save导出传到Registry所在机器上docker load再改tag并docker push到内网Registry。所有内网机器再从Registry拉取镜像。docker tag nginx:1.24 registry.internal:5000/nginx:1.24 docker push registry.internal:5000/nginx:1.24这个方案的优点是镜像统一管控版本升级时只push一次内网机器pull就行不用再逐台搬运tar包。5.3 compose插件和后续升级离线环境下装docker-compose现在不用再去GitHub上单独下载那个二进制了。只要在备料阶段把docker-compose-plugin这个rpm包一起带上安装后就能直接用docker compose version能输出版本号说明compose插件已经生效。后续升级Docker也一样把新版docker-ce及相关rpm包带进内网rpm -Uvh覆盖安装即可正在运行的容器不受影响只要在窗口期内重启一下dockerd就行。5.4 一个小经验每次做离线交付我都会在目标机器上把docker version的输出和一份安装记录存档同时在联网机器上把整个rpm目录和验证过的daemon.json模板打包存成一套“交付套件”。下次再遇到Kylin Server V10的机器一小时内就能装完。装完第一时间docker info截图存档这个动作能让后期的故障排查省很多事。
返回列表