ARTICLE DETAIL

资讯详情

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

Kylin Server离线安装Docker全流程:依赖准备、部署验证与镜像分发

Kylin Server离线安装Docker全流程:依赖准备、部署验证与镜像分发 1. 离线安装Docker到底在解决什么问题接到一台刚拆封的Kylin Server服务器第一反应是先装Docker。结果一看内网环境没有外网yum源也连不出去标准的yum install docker这条路直接断了。这种场景其实非常普遍物理隔离的园区、安全要求严格的生产网、临时搭建的离线测试环境在没有外部网络的情况下软件分发只能靠介质拷贝。这篇文章就是记录我在Kylin Server上离线安装Docker的完整过程——从联网侧怎么下载离线包到目标机器怎么安装配置再到怎么把镜像灌进去最后把踩过的坑一并列出来。适合所有在国产Linux服务器上做运维、做交付、做私有化部署的同学参考。离线安装不是新鲜事但坑不少。安装包要选对架构依赖要收齐还得分清楚Docker各组件谁是主谁是次。最常用的方案有两种一种是用yumdownloader收集rpm包再本地安装另一种是下载Docker官方静态二进制包直接解压到系统里。两种我都试过。RPM方式对系统改动更规范卸载升级都走标准流程二进制方式更简单粗暴能绕过一大部分依赖地狱前提是你要对systemd和服务管理足够熟悉。这篇博文会把两条路线的完整操作都写出来每个关键步骤我都尽量解释背后的原因这样你换到别的国产Linux发行版时也能自己应变。1.1 什么场景必须走离线离线这个词听起来很古老但实际需求一点都不少。我在项目里遇到过三类典型场景。第一类是物理隔离网络。机器放在独立机房或者专用内网段没有互联网出口系统装完就不让连外网所有软件只能靠U盘、光盘或者内网文件传输送进去。第二类是有严格的软件下载审批流程。运维规定安装包必须先经过介质审查禁止直接从公网下载安装所以即使机器能访问外网流程上也不允许走在线安装。第三类是临时环境或边缘项目。没有配置内网软件源又不想为装一个Docker专门去搭建一套yum仓库离线包装进去是最快的方式。不管哪种场景操作套路都一样在一台可以联网的下载机上把Docker本体和所有依赖准备齐全再运到目标机器上安装。只要准备工作做得严谨目标机器上的安装过程其实不超过十分钟。据我观察很多人在这一步卡住不是命令不会敲而是下载阶段丢三落四导致在目标机器上反复试错。1.2 动手前先摸清Kylin的底细别急着下载先搞清楚目标机器是什么版本、什么架构。这一步漏了后面基本百分百要返工。登录Kylin Server先跑两条命令cat /etc/os-release uname -m我在Kylin V10 SP2上看到的信息整体走的是RHEL/CentOS 8那一套体系所以用yum、dnf管理包都是可以的。uname -m输出x86_64就是AMD64架构输出aarch64就是ARM架构这两个架构的Docker安装包完全不同绝对不能混用。还有一条命令经常被忽略uname -rDocker要求内核版本至少3.8以上推荐3.10以上。Kylin V10默认内核一般都在4.19或更新这个要求基本都能满足但我确实见过有人在老内核上强行装Docker启动时报“unsupported kernel”。确认一下没坏处顺便看看内核模块是否完整。提示如果/etc/os-release信息不完整可以再看/etc/redhat-release。Kylin的rpm体系兼容性大致可以参考CentOS的发布版本来判断但不要完全照搬CentOS的源部分依赖版本会有差异。2. 联网侧准备把Docker离线包完整打出来离线安装的成败七成在联网侧的准备工作。很多人失败不是因为命令错而是依赖没下载全或者包拷过去才发现架构不对。联网下载机最好选一个和目标Kylin同架构的CentOS/RHEL系Linux这样rpm依赖关系最接近打包传过去才不会出幺蛾子。2.1 先选方案RPM包还是静态二进制RPM包方案的优势在于用yum localinstall安装时系统会把Docker当成标准软件包来管理之后的卸载、升级、依赖追踪都交给rpm数据库对长期运维更友好。缺点是依赖数量偏多任何一个依赖没收全本地安装就会报错。静态二进制包方案的优势是几乎没有系统库依赖把docker、dockerd、containerd这些可执行文件直接拷贝到/usr/local/bin就能用。缺点是systemd服务文件得自己写升级维护得自己管文件跟系统的关系比较“野”不太适合不熟悉Linux服务机制的人。我的建议是正式生产环境优先走RPM快速验证、镜像打包、或者RPM依赖死活解不开的时候走二进制。这篇文章两条路线都写清楚你可以根据实际情况选。2.2 用yumdownloader拉取全套RPM包首选RPM方式下载。在联网机器上先加Docker官方源sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum makecache然后创建工作目录用yumdownloader收集Docker本体和依赖mkdir -p /tmp/docker-offline cd /tmp/docker-offline yumdownloader --resolve docker-ce docker-ce-cli containerd.io docker-compose-pluginyumdownloader的--resolve参数会自动解析依赖并一并下载这是离线安装最关键的一步。如果去掉这个参数它只会下载你指定的包依赖不会跟着下来。我在第一次操作时就把--resolve忘了结果拷到内网后一装就报几十个依赖缺失最后还是回下载机重新补包。docker-compose-plugin装好后你在目标机器上就能直接使用docker compose命令不用再单独装Python那套老版docker-compose。如果不打算用Compose这个包可以去掉少几个文件更省事。下载完成后检查文件大小并打包ls -lh /tmp/docker-offline tar czf docker-offline-rpms.tar.gz *.rpm把这个tar包和校验信息一起带走。2.3 静态二进制包下载如果不想碰rpm依赖或者目标机器的yum环境实在太碎用官方静态包是更省心的选择。到Docker官网Release页面找对应架构的稳定版本以x86_64为例直接在联网服务器上执行curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz -o docker-24.0.7.tgz tar xzf docker-24.0.7.tgz解压后会得到docker目录里面包含docker、dockerd、docker-proxy、containerd、containerd-shim-runc-v2、ctr、runc、docker-init这些二进制。这个包对系统几乎没有额外依赖只要内核满足要求就能直接跑。注意静态包里的docker和dockerd是配套版本。有些教程只把docker命令拷贝过去dockerd还是老版本结果client和server版本不匹配执行docker version会出现“cannot communicate with the Docker daemon”之类的误导性报错。2.4 离线包的完整性校验这里分享一个教训。我第一次离线部署时只按文件大小估摸着tar包没损坏就拷过去了结果解压时一个rpm包损坏内网机器上反复重试也浪费了不少时间。小文件问题不大但rpm包总共几十上百MBU盘拷贝或者内网FTP传输中断是常有的事。正确做法是在下载机生成校验值sha256sum /tmp/docker-offline/docker-offline-rpms.tar.gz目标机器收到后也跑一下sha256sum两边输出一致再开始安装。这个步骤只要几十秒但能避免一场半夜加班。3. 目标机器安装两种落地方式的完整操作终于到了目标机器。先别急着解压花两分钟做系统检查我遇到过的很多安装失败都是因为缺了这一步。3.1 安装前系统检查按照前面说的方法确认版本和架构后再看三样东西。第一防火墙状态。Kylin默认可能启用firewalld它跟Docker的iptables策略偶尔会冲突。如果不想在装完容器后莫名网络不通先确认规则sudo systemctl status firewalld我不建议一上来就关防火墙生产环境安全要求高。更稳妥的办法是先按原计划安装Docker起来后需要哪些端口再加白名单遇到具体网络问题再单独排查。如果你现在只是在测试环境验证部署临时关闭防火墙也没有问题。第二内核模块。overlay2存储驱动和容器网络都依赖内核模块sudo modprobe overlay sudo modprobe br_netfilter lsmod | grep overlay lsmod | grep br_netfilter如果模块加载失败说明内核包里可能没带相关模块要去确认是否安装了对应的kernel-modules包。第三网络转发参数。容器要正常通信需要开启IPv4转发并让桥接流量经过iptables处理sudo sysctl -w net.ipv4.ip_forward1 sudo sysctl -w net.bridge.bridge-nf-call-iptables1这些参数临时生效后还要写进/etc/sysctl.conf或者在/etc/sysctl.d/下建一个专门文件保证重启后还能保留。3.2 方式一rpm本地安装把打包好的rpm文件传到目标机器后进入目录执行cd /path/to/rpms sudo yum localinstall -y ./docker-ce-*.rpm ./docker-ce-cli-*.rpm ./containerd.io-*.rpm ./docker-compose-plugin-*.rpmyum localinstall会自动处理当前目录下所有rpm之间的依赖关系。这里有个小细节通配符前面要带./避免把当前目录之外的同名文件也匹配进去。安装完成后执行sudo systemctl daemon-reload sudo systemctl enable --now docker sudo docker versiondocker version会同时显示Client和Server版本如果Server段有信息说明daemon已经起来了这一步就算成功了。RPM方式最常遇到的报错是本地rpm之间的版本冲突比如containerd.io想要的libseccomp版本比系统自带的更高。这时不要用rpm -ivh --nodeps硬装那会把依赖关系搞乱后续一升级就炸。正确做法是把缺失的依赖rpm也下载进来再localinstall一次或者临时把麒麟系统的本地源挂上去让yum自己解析。3.3 方式二二进制包手动部署二进制方式不需要装rpm。把tar包解压后将可执行文件放到/usr/local/binsudo tar xzf docker-24.0.7.tgz --strip-components1 -C /usr/local/bin \ docker/docker docker/dockerd docker/containerd docker/containerd-shim-runc-v2 \ docker/ctr docker/runc docker/docker-init docker/docker-proxy顺便把符号链接做一下因为后续很多脚本工具习惯直接调用docker命令sudo ln -s /usr/local/bin/docker /usr/bin/docker sudo ln -s /usr/local/bin/dockerd /usr/bin/dockerd二进制包不会自动写systemd服务需要自己创建/etc/systemd/system/docker.service。我用的是官方推荐的基础版本稍作调整[Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service containerd.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/local/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID LimitNOFILE1048576 LimitNPROCinfinity LimitCOREinfinity TimeoutStartSec0 Delegateyes KillModeprocess Restarton-failure StartLimitBurst3 StartLimitInterval60s [Install] WantedBymulti-user.target注意这里我没有加Requiresdocker.socket那一套需要额外的socket unit文件配合。如果没有完整创建反而会导致systemd启动失败所以精简掉更稳妥。写完之后执行sudo systemctl daemon-reload sudo systemctl start docker sudo systemctl enable docker sudo docker version如果docker version正常返回Server信息手动部署就成功了。提示手动部署模式下后续升级Docker时直接替换/usr/local/bin下的二进制文件然后重启docker服务即可systemd服务文件不用改动。3.4 写一份最稳妥的daemon.json无论用哪种方式安装都建议在启动前把/etc/docker/daemon.json写好。{ data-root: /var/lib/docker, exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, registry-mirrors: [https://your_internal_mirror.example.com] }我单独讲几个关键字段。>sudo systemctl restart docker4. 启动服务与验证让Docker真正跑起来安装成功不等于能跑业务。我习惯用一套完整验证确认Docker真的可用而不是只看docker version有输出就觉得万事大吉。4.1 用systemd启动并设置开机自启两种安装方式我都建议统一用systemd管理sudo systemctl daemon-reload sudo systemctl start docker sudo systemctl enable dockerenable放在start前后都行但我建议每次执行完start后都显式enable一次避免机器重启后Docker没起来应用全部跟着挂掉。RPM方式在安装阶段可能已经把enable做掉了但多执行一次也无妨。查看服务状态和日志sudo systemctl status docker --no-pager sudo journalctl -u docker --no-pager -n 200服务状态是active (running)后再看日志尾部有没有ERROR或WARN。Docker daemon的日志默认打到journald里用journalctl查起来最直接。4.2 离线验证跑一个本地镜像测试离线环境没法docker pull hello-world所以验证方式要换成导入本地镜像。如果你手里正好有一台联网机器可以在那边先准备docker pull nginx:latest docker save -o /tmp/nginx.tar nginx:latest然后把nginx.tar拷到内网机器docker load -i nginx.tar docker run -d --name test-nginx -p 80:80 nginx:latest curl http://127.0.0.1:80能返回nginx默认页面说明Docker从安装到运行容器这条链路全部通了。如果没有现成镜像退而求其次至少要让docker info和docker ps能正常输出。docker ps输出空列表但没有报错说明containerd和runc这些底层组件都正常。4.3 常用验证命令速查这里是我每次部署完都会过一遍的命令集。sudo docker version # 客户端和服务端版本 sudo docker info # 详细配置、存储驱动、网络模式等 sudo docker ps -a # 容器列表 sudo docker images # 本地镜像列表 sudo docker network ls # 网络列表 sudo systemctl status docker # systemd服务状态命令输出要结合场景看。比如docker info里Storage Driver如果显示overlay2说明驱动正常如果显示vfs说明overlay2模块没加载或者挂载有问题容器性能会明显下降这个细节稍后讲坑的时候会再展开。5. 离线环境下的镜像搬运与分发装好Docker后下一个真正的痛点通常是镜像从哪来。内网机器不能docker pull只能靠手动把镜像灌进去。这里分享我从单镜像到批量仓库的三套做法。5.1 docker save/load单镜像搬运最基础的方式是save和load。在联网机器上docker pull mysql:8.0 docker save -o mysql-8.0.tar mysql:8.0 ls -lh mysql-8.0.tar到内网机器docker load -i mysql-8.0.tar docker images | grep mysqlsave导出的是包含完整镜像层和元数据的格式load之后镜像ID和tag保持不变适合保存镜像后直接运行。它和export/import有本质区别后面我会单独提醒。注意tar文件大小。一个mysql镜像可能上GBU盘拷贝时要当心FAT32格式的单文件4GB上限镜像一大就会直接报错。建议用exFAT或NTFS格式的移动设备或者用split分割成多个文件再合并。5.2 用registry镜像搭一个离线仓库如果镜像数量很多或者要在多个内网节点上分发一个个save/load太累了。更专业的做法是在内网搭一台registry仓库。先从联网机器拿镜像docker pull registry:2 docker save -o registry-2.tar registry:2把registry-2.tar load到内网其中一台机器然后运行mkdir -p /data/registry docker run -d \ --name registry \ --restartalways \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ registry:2这台机器就是内网镜像仓库。生产环境建议在registry前面加TLS和账号密码这里只讲最简配置。之后其他机器想拉镜像在daemon.json里加一行insecure-registries把仓库地址填进去{ insecure-registries: [registry.internal.example.com:5000] }重启Docker后从联网侧把镜像推到内网仓库再在内网节点拉取# 联网机器上先重新tag docker tag nginx:latest registry.internal.example.com:5000/nginx:latest docker push registry.internal.example.com:5000/nginx:latest # 内网节点上 docker pull registry.internal.example.com:5000/nginx:latest这种做法比save/load更接近生产环境。多台节点只要配置好仓库地址就能按需拉取镜像不用每个包都物理拷贝一遍。我在交付项目时基本都用这个模式省下的时间非常可观。5.3 镜像导入导出的三个细节第一个细节是save和export的区别。docker save保留完整镜像历史层和元数据docker export导出的是容器当前文件系统docker import再导入时会丢失原有镜像的CMD、ENV等配置。按镜像分发一定用save/load不要用export/import。第二个细节是多镜像可以一次打包。docker save -o app-bundle.tar app:1.0 app:1.1 redis:7 mysql:8内网一次load就能全部导入节省反复拷贝的时间。第三个细节是tar包完整性校验。镜像tar通常很大在联网机器上生成sha256校验值内网load之前先校验能避免大部分损坏问题。方法跟前面rpm包校验一样不再重复。6. 排坑实录这些坑我基本都踩过离线安装Docker最大的问题往往不在Docker本身而在于环境差异。我把实际遇到的坑按频率排序写在下面你遇到类似报错时可以直接对照。6.1 yum本地安装时依赖打架现象yum localinstall执行到一半报缺少libseccomp 2.4.1或者libcgroup、slirp4netns找不到。原因Docker rpm依赖的库版本比Kylin系统默认的rpm高或者docker-ce源里依赖包没下载完整。我遇到过最典型的是containerd.io要求libseccomp高版本而系统源里只有低版本。排查思路先把报错缺的包名记下来回联网机器用yumdownloader把缺的依赖也拉下来再打包传进去。最省事的方法是把联网机器上配置好的docker-ce repo和缓存目录一并打包到目标机器上挂载成本地yum源让yum自己解析依赖这样就不用来回补包了。如果只是个别依赖包装不上而且你实际检查过版本差距非常小可以用rpm -Uvh --nodeps试一下但我强烈不推荐。这个操作会让rpm数据库认为依赖已满足实际缺的库文件还在过几天某个软件升级时会出现莫名其妙的链接错误排查成本远高于当时手动补齐依赖。6.2 overlay2内核模块与iptables问题现象docker info显示Storage Driver是vfs容器启动慢、磁盘占用大或者启动容器后宿主机访问容器端口超时。原因overlay2需要内核overlayfs支持。模块没加载或内核配置里没编进去Docker会自动降级到vfs。网络不通多数是br_netfilter模块没加载或者net.bridge.bridge-nf-call-iptables参数为0。解决方法sudo modprobe overlay sudo modprobe br_netfilter sudo sysctl -w net.bridge.bridge-nf-call-iptables1然后写进启动文件确保重启后生效echo overlay /etc/modules-load.d/containerd.conf echo br_netfilter /etc/modules-load.d/containerd.conf echo net.bridge.bridge-nf-call-iptables 1 /etc/sysctl.d/99-bridge.conf sysctl --system重启Docker后再看Storage Driver一般就会变成overlay2。6.3 dockerd启动失败常见原因现象systemctl start docker后journalctl日志里直接报failed to start daemon。原因五花八门按我遇到的概率排序。第一/etc/docker/daemon.json格式错误。比如JSON里多个逗号、引号不配Docker解析直接失败。这是最常见的一种。用python -m json.tool /etc/docker/daemon.json能快速验证格式。第二数据目录所在磁盘空间不足。/var/lib/docker默认在根分区根分区快满时dockerd启动会报no space left on device。df -h确认磁盘容量后把data-root指到有空间的分区记得提前把新目录创建好并给足权限。第三端口占用。默认Docker不监听TCP端口但如果改过配置或者系统里已经有进程占用了2375、2376也会导致启动失败。ss -lntp可以看端口占用。第四SELinux策略阻挡。Kylin默认SELinux可能处于enforcing状态Docker与SELinux的交互偶尔会出问题。不是所有环境都建议关闭SELinux但在测试环境可以先setenforce 0验证确认是这个原因后再考虑调整策略而不是一关了之。处理思路就一条优先看journalctl -u docker里的原始报错不要停留在systemctl status的模糊提示上。原生日志会告诉你是配置、磁盘、权限还是网络问题直接对症下药。6.4 容器网络不通的排查思路如果你启动容器后从宿主机访问容器端口不通按这个顺序查。第一步确认端口映射。docker ps看PORTS列左边是宿主机端口右边是容器端口。映射没出来说明run命令里的-p参数写错了。第二步确认容器进程活着。docker logs test-nginx看应用日志如果nginx根本没起来curl当然连不上。第三步确认防火墙规则。firewall-cmd --list-all看有没有放行对应端口。Docker会自动往iptables里加规则但如果你手写了firewalld规则且优先级比较高也可能出现覆盖和冲突。第四步确认docker0网桥。ip addr show docker0看网桥是否存在。不存在说明daemon网络初始化失败回到模块加载那一步查。第五步确认宿主机路由。ip route看默认路由是不是走到正确的网卡。内网多网卡机器经常出现容器流量走了错误网关的情况这种问题在单网卡环境很少见。这套排查流程我用过很多次基本能在十分钟内定位问题。记住一点容器网络不通大多数情况下不是容器里的业务问题而是宿主机的网络转发或者防火墙策略问题。7. 写在最后几点长期实用的建议离线安装Docker这件事装完只是开始。结合我多次部署的体会给你留几个建议。第一离线准备工作一定要脚本化。把下载、打包、校验的步骤写成shell脚本放到U盘里下次换机器直接跑不用再靠记忆复制粘贴。脚本里把架构判断、仓库地址、版本号都变量化换个环境改几个变量就能复用非常省心。第二daemon.json在装完第一阶段就写好。日志限制、cgroupdriver、storage-driver这些配置一旦上线后再改会影响调度和已有容器能早写就早写。等你真的遇到日志爆盘再回头补配置往往已经晚了。第三内网镜像仓库值得一开始就搭。哪怕只有两台机器registry带来的便利也远超投入。后面加节点、换版本、同步镜像都会受益。我用registry方案之后基本不再依赖U盘一张张拷镜像tar内网拉取的速度和稳定性都比介质拷贝强得多。最后分享一个小技巧每次离线部署后我都会把环境信息记录下来包括Kylin版本、内核版本、Docker版本、daemon.json内容、容器启动参数整理成一份部署记录。几个月后机器真正出问题时这份记录能省去大量重建认知的时间。别迷信自己的记忆力也别信任一堆没有说明的tar包。把部署过程沉淀成文档下一次不管是升级、排障还是交接你都会轻松很多。
返回列表