ARTICLE DETAIL

资讯详情

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

离线环境Docker与中间件部署实操指南

离线环境Docker与中间件部署实操指南 1. 为什么说离线安装docker都是被逼出来的干了几年运维和开发我越来越觉得离线安装这四个字背后全是故事。但凡网络畅通、镜像源可用谁愿意对着U盘和安装包折腾半天但现实就是很多生产环境、内网隔离区、涉密机房、客户现场别说访问Docker Hub了连一个普通的yum源都得走审批流程。这时候把docker以及mysql、redis、nacos、nginx这类中间件一次性离线带进去就成了最刚需的能力。这篇文章想讲的不是官网那份离线安装文档的复读而是我在x86架构服务器上实际操作下来的完整链路——从联网机器上准备安装包、处理依赖、传输镜像到目标机器上装好docker、启动registry、拉取中间件镜像并跑起来再到中间遇到的各类坑的排查思路。适合谁看一线运维、要交付项目的实施工程师、还有自己买了服务器但网络受限的个人开发者。进正题之前先交代一个总原则离线安装的复杂程度永远比在线安装高一档因为在线安装有包管理器帮你解决依赖离线安装则要求你自己把依赖链看得明明白白。x86架构相对arm要省心不少不用交叉编译、不用考虑架构转换但依旧有不少细节容易翻车。下面我会把整套流程按可复现的顺序摊开来讲。2. 联网环境准备离线安装包的获取策略与版本锁定既然是离线安装第一步当然是在一台能联网的、和目标机器相同操作系统的x86机器上把需要的rpm包、二进制文件、镜像文件全部捞下来。这一步看似简单其实暗藏三个关键决策。2.1 系统版本与内核版本必须先对齐docker对内核和操作系统版本有硬性要求。我踩过的一个比较典型的坑是在CentOS 7.9上装了docker 23.0的rpm包启动一切正常但运行容器时一直报operation not permitted排查到最后才发现是内核3.10太老对cgroup v2 namespace的支持不完整。所以第一步不是下载docker而是确认目标机器系统版本和内核版本cat /etc/redhat-release uname -r如果是CentOS 7系列内核3.10.x建议使用docker 20.10.x版本这个版本对旧内核兼容性最好如果是CentOS 8或Rocky 8/9内核4.18以上可以用docker 23.0或24.0如果是Ubuntu 20.04/22.04直接下载对应的deb包或者用官方静态二进制包会少很多麻烦。2.2 用yumdownloader或repotrack完整拉取依赖在联网机器上如果系统是CentOS/RHEL系我习惯的做法是先配置好docker官方源然后使用yumdownloader或repotrack把docker及其所有依赖一次性拉下来# 配置docker官方源联网机器上执行 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 方式一yumdownloader 只下载指定rpm不解决依赖 mkdir -p /opt/docker-offline-rpm cd /opt/docker-offline-rpm yumdownloader --resolve docker-ce docker-ce-cli containerd.io docker-compose-plugin # 方式二repotrack 连依赖一并跟踪下载推荐 repotrack docker-ce docker-ce-cli containerd.io docker-compose-plugin这里我特意推荐repotrack因为它会把所有被依赖的rpm比如container-selinux、libseccomp、fuse-overlayfs等全部下载到当前目录。用yumdownloader加--resolve也能解决一部分依赖但偶尔有遗漏。如果你们公司有内网yum源用yum install --downloadonly --downloaddir/opt/docker-offline-rpm docker-ce也是一个方案。下载完之后重要的是检查rpm包是否齐全。怎么检查用一个笨但有效的办法把所有rpm包拷贝到一个临时目录用rpm -Uvh *.rpm做一次试安装如果不报依赖缺失就说明包齐了。试安装可以用--test参数只做检查不实际安装。2.3 静态二进制包方案是另一个硬核选择如果你的目标系统比较冷门或者不想被rpm依赖折磨docker官方还提供静态二进制压缩包。下载地址是https://download.docker.com/linux/static/stable/x86_64/选择对应版本的docker-xx.xx.xx.tgz解压后里面的docker、dockerd、containerd、runc等二进制文件都是编译好的直接拷贝到/usr/bin目录下就能用。这种方式的优点是不依赖任何系统库和包管理器适合各种精简系统、容器化操作系统。但缺点是需要自行编写systemd服务文件来管理docker守护进程工作量多了一步。我个人建议能走rpm/deb包就优先走包管理器方案只有包管理器方案走不通时再用静态二进制包。原因很简单systemd服务写得不规范会导致开机自启失败、日志权限错乱等连锁问题。2.4 别忘了docker compose的离线安装现在的应用部署基本离不开docker compose特别是做中间件多组件编排的时候。docker compose在CentOS上对应的是docker-compose-plugin这个包联网环境下通过yum安装。但注意docker compose v2是作为docker的一个插件运行的它的二进制文件必须放在/usr/libexec/docker/cli-plugins/目录下并命名为docker-compose。如果repotrack已经把docker-compose-plugin拉下来了直接rpm安装即可。如果没有去GitHub releases下载docker-compose-linux-x86_64二进制文件改名为docker-compose放到指定目录记得加执行权限chmod x /usr/libexec/docker/cli-plugins/docker-compose docker compose version这个坑很多新手会踩下载了docker-compose但docker死活不认最后发现是放错了目录或者权限不够。3. 离线安装docker引擎从rpm包到可用镜像的全过程包准备好了接下来的活就是把这些东西搬到目标机器上然后装好。这部分看起来就是敲几条命令但实际操作中有不少值得展开的地方。3.1 rpm包安装顺序与依赖处理进入目标机器后把整个目录传到目标机器上——U盘、scp、内网FTP都行。然后执行安装cd /opt/docker-offline-rpm rpm -Uvh *.rpm这里有个细节如果目录里rpm包很多直接rpm -Uvh *.rpm可能会因为依赖包顺序问题报错。我遇到过一次非常典型的container-selinux必须先于docker-ce安装但按字母排序后它反而排在后面导致安装失败。解决办法很简单优先安装依赖包再安装主包rpm -ivh container-selinux-*.rpm libseccomp-*.rpm rpm -ivh containerd.io-*.rpm docker-ce-cli-*.rpm docker-ce-*.rpm或者干脆用yum localinstall *.rpm让yum自己算依赖顺序。但前提是rpm包真的是完整的没有缺漏。安装完成后先别急着启动做一个重要动作配置镜像加速器或私有仓库地址因为离线环境下默认的Docker Hub肯定访问不了不提前配置的话虽然不影响docker引擎启动但后续所有镜像拉取都得手动load反而更麻烦。编辑/etc/docker/daemon.json{ registry-mirrors: [http://192.168.1.100:8080], insecure-registries: [192.168.1.100:8080], data-root: /data/docker, log-opts: { max-size: 50m, max-file: 5 } }这里解释一下几个配置的作用insecure-registries是让docker允许通过HTTP方式访问私有仓库这对内网环境至关重要因为大部分企业的私有仓库并没有配HTTPS证书>systemctl daemon-reload systemctl enable docker systemctl start docker docker infodocker info输出里重点看两行Storage Driver是不是overlay2Cgroup Version是不是2。如果Storage Driver显示的是vfs说明系统内核或文件系统不支持overlay2这时候容器性能会明显下降建议检查内核模块是否加载了overlaymodprobe overlay lsmod | grep overlay如果加载不了overlay模块大概率是内核太老或者没有安装对应内核模块包解决办法是找同版本内核的kernel-modules-extra包或者考虑升级内核。这是离线环境下比较尴尬但必须面对的问题。3.3 systemd不受管控时的应急启动方案有一种场景我很想单独提一下目标机器不是标准systemd系统或者出于某些原因无法使用systemctl管理服务。这时候可以直接用dockerd命令后台拉起nohup dockerd --iptablesfalse --ip-masqfalse --data-root/data/docker /var/log/dockerd.log 21 --iptablesfalse是关闭docker对iptables的自动管理这在网络环境比较特殊的内网很有用因为docker默认会修改宿主机的iptables规则有时候会导致防火墙策略冲突。但注意关闭iptables管理也意味着容器网络隔离和端口映射的NAT规则需要你手动配置适合对网络原理比较熟悉的人。普通场景建议还是让systemd正常管理让docker自动处理网络。4. 中间件镜像的获取与离线导入save/load与registry的完整套路docker引擎装好之后真正的大头来了——中间件的镜像怎么搞进去。这里的难点不是能不能搞而是怎么搞才高效、怎么搞才不容易出错。4.1 单机场景docker save和docker load够用了单个镜像的直接搬运是最简单的方式。在联网机器上先从Docker Hub拉取镜像然后打包docker pull mysql:8.0 docker save -o mysql-8.0.tar mysql:8.0文件传到目标机器后load进去docker load -i mysql-8.0.tar这条链路看起来简单但有三个容易忽略的深层问题第一save和export的区别。save是针对镜像的保留完整的镜像层级和元数据export是针对容器的把容器的文件系统导出成tar包。如果误用了docker export导入后变成的是不带历史commit记录的扁平文件系统无法作为镜像直接run必须再通过docker import处理而且启动命令、环境变量全部丢失。我见过有人因为在脚本里把export和save搞混折腾了一整天。第二多架构镜像问题。在x86机器上docker pull默认拉取的是linux/amd64的镜像——这也是我们需要的。但如果目标机器是arm或者ppc64le而打包机器是x86拉取到的镜像平台就不匹配。标题里明确了x86系统架构但如果你手头有一台macOS ARM笔记本做生产环境打包那就要小心了Mac M系列上docker pull默认拉取的是arm64镜像打包出来的tar传到x86服务器上load虽然会成功但运行时会报exec format error。如果确实需要在Mac上为x86打包要使用docker pull --platform linux/amd64参数。这一点看我们标题是x86架构反而省了很多事。第三镜像里有没有内置的启动脚本对环境有硬依赖。有些中间件镜像内置了健康检查或初始化逻辑会在启动时尝试访问外网或特定域名离线环境下会卡住或报错。这个后面在具体中间件实操部分再说。4.2 批量场景本地registry仓库才是正解如果你需要维护的机器很多或者中间件数量达到十几个镜像一个一个save/load就太低效了。这时候应该搭建一个离线镜像仓库。思路是这样的在联网机器上把所有镜像pull下来推送到一个私有registry然后把这个registry的存储目录整体打包搬运到内网。先在联网机器上启动registry容器docker run -d --name registry-offline \ -p 8080:5000 \ -v /data/registry-data:/var/lib/registry \ --restartalways \ registry:2然后给所有需要的镜像重新打tag推送到这个本地registrydocker tag mysql:8.0 192.168.1.100:8080/mysql:8.0 docker push 192.168.1.100:8080/mysql:8.0所有镜像推送完后把/data/registry-data整个目录打包压缩传到内网机器上同样启动一个registry容器并挂载这个目录。这样内网所有机器就都能通过docker pull 内网registry地址/镜像名:tag来拉取镜像了和在线环境体验一致。这里提一个实际经验registry镜像仓库的存储目录里包含的是镜像的层级和索引数据跨机器拷贝时不要直接在宿主机上复制文件更安全的做法是在registry容器运行时用docker cp或者直接在数据目录做一个tar。我犯过一次错误直接scp数据目录到另一台机器结果容器启动后registry一直报blob丢失因为拷贝过程中有几个blob文件没拷全最后只能重新push。所以批量搬运时务必打包成一整个tar文件再传不要用rsync逐文件同步的方式除非你能保证网络传输零丢包。4.3 镜像仓库的垃圾回收与磁盘占用registry跑久了之后你会发现在内网机器上反复push和删除镜像数据目录会越来越大因为registry默认不会自动回收被删掉镜像的blob层。离线仓库空间有限的话需要手动执行垃圾回收docker exec registry-offline sh -c registry garbage-collect /etc/docker/registry/config.yml这个命令会在容器的标准输出里打印回收日志。注意执行垃圾回收前最好把registry停掉否则并发写操作可能导致数据损坏。另外垃圾回收之后之前被删除镜像的tar包再load进来可能会报错但这个报错不影响正常push新镜像。总体建议是批量导入前先规划好镜像清单尽量不要反复清理和导入减少不必要的风险。5. 以mysql、redis、nacos为例离线中间件部署的完整标记镜像到了目标机器上接下来的核心就是怎么把这些中间件在离线环境里跑好。这里我挑三个最有代表性的mysql有状态、需要持久化、redis有密码和持久化配置、nacos依赖外部存储配置较复杂的中间件。把这三个搞明白其他中间件基本是同理可证的。5.1 mysql 8.0离线部署挂载目录与参数调优mysql是中间件里最常用也最容易出问题的。离线部署和在线部署在docker层面其实没什么区别主要风险在于初始化时会不会尝试连接外网、时区配置、字符集、数据持久化位置。先看部署命令mkdir -p /data/mysql/conf /data/mysql/data docker run -d \ --name mysql8 \ --restartalways \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDMyStr0ngPassw0rd \ -e TZAsia/Shanghai \ -v /data/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf \ -v /data/mysql/data:/var/lib/mysql \ -v /etc/localtime:/etc/localtime:ro \ mysql:8.0我把my.cnf的内容放到了宿主机上这样改配置不需要进容器。一个比较稳妥的MySQL配置模板[mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_general_ci lower_case_table_names1 max_connections500 innodb_buffer_pool_size2G innodb_flush_log_at_trx_commit1 default-time-zone08:00 socket/var/run/mysqld/mysqld.socklower_case_table_names1是让表名不区分大小写这在从Windows环境迁移数据到Linux时特别重要因为Windows上表名默认不区分大小写而Linux上默认区分。如果初始化后再改这个参数mysql会直接拒绝启动必须在初始化前设置好。离线部署最容易忽视的一个参数就是默认时区问题不加default-time-zone08:00的话所有时间字段会比北京时间早8个小时。还有一个很关键的初始化参数-e MYSQL_ROOT_PASSWORD只是设置root密码如果你还需要初始化其他数据库可以加MYSQL_DATABASEappdb和MYSQL_USERappuser等环境变量——官方镜像的entrypoint脚本会自动处理。容器启动后验证连接docker logs mysql8 docker exec -it mysql8 mysql -uroot -p日志里看到ready for connections字样说明启动成功。如果发现启动失败最常见的原因是数据目录里已经有过一份备用的数据或者配置文件的权限不正确。解决方法清空/data/mysql/data目录或者用chown -R mysql:mysql /data/mysql修正权限再重来。5.2 redis 6/7离线部署AOF与RDB双保险redis部署起来比mysql简单但坑少不等于不用注意。redis的离线部署主要注意三点密码、持久化策略、内存优化参数。docker run -d \ --name redis \ --restartalways \ -p 6379:6379 \ -v /data/redis/data:/data \ -v /data/redis/conf/redis.conf:/etc/redis/redis.conf \ redis:7 redis-server /etc/redis/redis.confredis.conf模板细项requirepass YourRedisPassword appendonly yes appendfsync everysec save 900 1 save 300 10 maxmemory 4gb maxmemory-policy allkeys-lruappendonly yes开启AOF持久化配合RDB快照可以最大程度降低数据丢失风险。appendfsync everysec是性价比最高的配置表示每秒同步一次性能损失很小但最多丢1秒数据。maxmemory-policy allkeys-lru是内存淘汰策略当redis内存达到4GB上限时会自动淘汰最久未使用的key这个在业务量不可控的环境里非常有用不然内存打满redis会直接拒绝写入。这里说一个我在离线环境下的心得redis容器跑起来之后从宿主机访问要记得检查iptables和云安全组规则特别是如果docker的网络模式用了--network host端口映射规则和bridge模式完全不同。我自己遇到过Redis能连但所有操作都超时的情况最后发现是防火墙对6379端口的半开连接状态做了限制。5.3 nacos 2.x离线部署从单机到集群的规划nacos在微服务架构里几乎成了标配它的部署比前两个复杂不少——因为nacos可以内嵌derby存储也可以外接mysql存储。离线环境下我强烈建议直接用外接mysql模式这样数据持久化和后续集群扩展都靠谱得多。先确定nacos镜像的版本和配置方式。用nacos/nacos-server:v2.3.2举例docker run -d \ --name nacos \ --restartalways \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -e MODEstandalone \ -e SPRING_DATASOURCE_PLATFORMmysql \ -e MYSQL_SERVICE_HOST192.168.1.10 \ -e MYSQL_SERVICE_PORT3306 \ -e MYSQL_SERVICE_DB_NAMEnacos_config \ -e MYSQL_SERVICE_USERnacos \ -e MYSQL_SERVICE_PASSWORDYourMysqlPass \ -e JVM_XMS512m \ -e JVM_XMX512m \ nacos/nacos-server:v2.3.2在启动nacos之前先要到nacos的GitHub仓库下载对应版本的nacos-mysql.sql初始化脚本在你自己部署的mysql上执行建表。很多人在这一步翻车直接用官方docker镜像自带的初始化脚本但脚本版本和nacos版本不匹配导致nacos启动后配置写入失败。另外一个容易被忽略的点是端口。nacos 2.x版本和1.x不同除了8848主端口还开放了9848和9849两个gRPC端口。在离线环境的防火墙和负载均衡配置里这三个端口都得放通否则服务注册和各微服务之间的通信会时好时坏表现很诡异——刚开始能连上过几秒就断特别像是网络问题但其实是端口没开放。nacos的集群部署就复杂一些需要保证每个节点都能访问同一个mysql并且节点之前能够互相通信。离线环境里集群部署的建议是先把单机模式调通、配上mysql存储再扩展成集群不要一上来就搞三节点排查问题的难度会成倍上升。5.4 其他常见中间件的部署速查表中间件的类型实在太多我不可能在一个文章里全部展开。下面这个表格是我在多个离线项目中沉淀下来的速查清单照着做基本不会有大问题中间件端口持久化目录关键环境变量容易忽略的点nginx80/443/etc/nginx /usr/share/nginx/html无需要挂载log目录防日志膨胀rabbitmq5672/15672/var/lib/rabbitmqRABBITMQ_DEFAULT_USER/PASS插件启用需rabbitmq-plugins命令集群需erlang cookie一致elasticsearch9200/9300/usr/share/elasticsearch/datadiscovery.typesingle-node需要设置vm.max_map_count262144minio9000/9001/dataMINIO_ROOT_USER/PASSWORD控制台和API端口不要搞混zookeeper2181/2888/3888/dataZOO_MY_ID, ZOO_SERVERS数据目录权限必须是zookeeper用户kafka9092/var/lib/kafka/dataKAFKA_ZOOKEEPER_CONNECTadvertised.listeners配置不对会报leader不存在的错拿elasticsearch说一个真实的坑在x86的CentOS上离线部署elasticsearch容器刚启动就会被kill掉docker logs里看不到任何报错看systemd日志才发现是vm.max_map_count内核参数太小导致的。解决办法是执行sysctl -w vm.max_map_count262144 echo vm.max_map_count262144 /etc/sysctl.conf这个参数是elasticsearch的运行基石不调大概率会出问题但很少有人第一时间想到。6. 离线环境特有的坑与排查链路从启动失败到数据损坏每一个做离线环境的人都应该为意外状态做好准备。在线环境遇到的问题在离线环境也会遇到而离线环境还会额外叠加包不齐全架构不匹配依赖冲突这些层次的问题。这一节我想把几个真正让我印象深刻的坑完整讲清楚——不是列几条注意事项那么简单而是把排查的链路一起写出来方便你以后照着复现排查思路。6.1 依赖缺失导致的dockerd启动失败怎么一步步定位现象执行systemctl start docker后docker没有起来systemctl status docker显示进程启动失败。排查第一步看journal日志journalctl -u docker --no-pager | tail -n 50如果看到类似error creating overlay mount to /var/lib/docker/overlay2/...或者operation not permitted的行多半是内核不兼容或者缺少overlay模块如果看到failed to load listeners: no listeners found则是网络配置问题。一个非常典型的离线安装问题iptables v1.8.4 (nf_tables): unknown option --wait。这通常是iptables版本不兼容导致。docker 20.10以上的版本默认需要iptables支持--wait参数但CentOS 7自带的iptables 1.4.21不支持。解决办法是升级iptablesyum install -y iptables或者把docker切换到--iptablesfalse模式凑合运行。但注意关闭iptables之后docker端口映射不会生效所以如果你的应用恰好依赖-p映射端口这个方法就失灵了。排查链路的核心逻辑是先看进程是否活着再看网络和存储子系统是否正常最后看i节点和磁盘空间。磁盘空间在离线环境尤其容易被忽视——因为镜像被打成tar包在宿主机上占了一份load进docker又占了一份如果忘了删除tar包磁盘很快就会满。6.2 镜像load成功但运行时exec format error的根因这个问题的排查过程我印象极深。那是一个内网项目我从一台办公用的Mac上打好镜像tar包传到x86服务器上loaddocker images能看到镜像但docker run直接报standard_init_linux.go:228: exec user process caused: exec format error第一反应是问自己镜像是不是arm64架构的用docker inspect查看镜像的平台信息docker inspect 镜像ID | grep Architecture果然显示的是arm64。原因很简单Mac M1/M2上docker pull默认拉取arm64镜像。解决办法是重新在Mac上执行带平台参数的pulldocker pull --platform linux/amd64 mysql:8.0 docker build --platform linux/amd64 -t my-image:tag .但这里面有个更隐蔽的问题如果你是直接用Dockerfile build的自定义镜像即使pull基础镜像时指定了--platform linux/amd64build过程中如果某些RUN命令执行了不兼容x86的二进制一样会报错。所以稳妥做法是所有打包操作尽量在一台x86的Linux机器上完成不要用ARM Mac捣腾——除非你加CI用docker buildx做多平台构建。6.3 容器数据目录权限问题一种看起来像没权限其实不是的报错中间件容器跑不起来最常见的一类报错是chown: changing ownership of /var/lib/mysql: Operation not permitted或者mkdir: cannot create directory /var/lib/postgresql/data: Permission denied。很多人的第一反应是给宿主机目录疯狂chmod 777但这样往往无效。真正的原因是容器内的进程是以某个非root用户运行的比如mysql用户、postgres用户而宿主机挂载进去的目录宿主机属主是root容器内那个用户没有写权限。正确做法是找到镜像内用户对应的UID/GID然后把宿主机目录属主改掉# 先查一般是mysql的uid docker inspect mysql:8.0 | grep -A 5 User # 或者直接看镜像的Dockerfile里声明的用户 chown -R 999:999 /data/mysqlmysql官方镜像的mysql用户通常是999postgres是999redis是999。但不同版本可能有差异别写死用docker inspect查最稳妥。这一步看着简单但在离线交付的场景里因为常驻U盘上的包都是提前做好的现场往往没有外网去查文档所以一定要把排查链路记熟。6.4 镜像源连接失败的假网络故障还有一个我反复见到的场景离线环境内网里明明配置了私有registrydocker pull却一直报connection refused。排查链路是这样的先在目标机器上直接测试registry端口通不通telnet 192.168.1.100 8080如果不通查防火墙和网络端口通了但还是连不上检查daemon.json里的insecure-registries是否包含了这个地址和端口确认配置没写错后systemctl restart docker——注意daemon.json的修改不执行restart是不会生效的SIGHUP信号有时候不够如果还是不行看看registry容器的日志docker logs registry-offline确认它是否真的在监听。这个排查链路本身没什么高深的但有几个步骤容易跳过第二步很多人改了daemon.json但忘了重启docker或者是以为只需reload就行第五步也是我自己的经验——registry容器经常因为没用--restartalways系统重启后根本没起来而宿主机的端口却是监听的被其他进程占用了排查起来非常迷惑。6.5 离线安装后常见的网络与存储混淆点在离线环境里还有一个概念性认知要建立docker的网络隔离并不代表容器可以访问宿主机所在内网的所有服务。比如容器里运行的应用需要连接宿主机上的某个数据库直接用localhost是连不通的因为在bridge网络模式下容器里的localhost指向的是容器自身。正确做法使用--network host模式运行容器让容器直接共享宿主机网络栈在容器里用localhost就能访问宿主机服务或者使用--add-host host.docker.internal:host-gateway参数在容器内通过host.docker.internal访问宿主机或者在docker compose里使用extra_hosts配置。这个坑在离线中间件场景里特别常见因为很多人会把mysql跑在宿主机上、应用跑在容器里然后在配置里写了localhost:3306结果应用一直报数据库连接失败。光这一条我在实际交付过程中就看同事排查了小半天。7. 一次交付场景的完整实操复盘说了这么多理论、命令和坑我觉得有必要把整个流程串起来做一个真实场景的推演——这样你才好在自己的项目里直接照猫画虎。假设目标环境是一台Rocky 8.4的x86服务器内网隔离不通外网。需要离线交付的内容是docker引擎 mysql 8.0 redis 7 nginx nacos。整个操作步骤可以归纳为五步走第一步在联网的CentOS/Rocky机器上准备rpm包和镜像tar包。mkdir -p /opt/delivery/{rpm,images} cd /opt/delivery/rpm repotrack docker-ce docker-ce-cli containerd.io docker-compose-plugin cd /opt/delivery/images docker pull mysql:8.0 docker pull redis:7 docker pull nginx:1.24 docker pull nacos/nacos-server:v2.3.2 docker pull registry:2 docker save -o mysql-8.0.tar mysql:8.0 docker save -o redis-7.tar redis:7 docker save -o nginx-1.24.tar nginx:1.24 docker save -o nacos-2.3.2.tar nacos/nacos-server:v2.3.2 docker save -o registry-2.tar registry:2第二步把rpm包和镜像tar包传到内网目标机器上。这里我一般先传rpm包把docker引擎装好、确定能正常拉镜像之后再传镜像tar包。没必要在全新环境里一股脑全传过去出了问题还要一个个排除。第三步内网机器装docker并配置私有仓库。cd /opt/delivery/rpm yum localinstall -y *.rpm cat /etc/docker/daemon.json EOF { insecure-registries: [192.168.1.100:5000], data-root: /data/docker, log-opts: { max-size: 50m, max-file: 5 } } EOF systemctl enable docker systemctl start docker docker load -i registry-2.tar docker run -d --name registry --restartalways -p 5000:5000 -v /data/registry:/var/lib/registry registry:2第四步把剩余镜像load进来推送到私有仓库。这一步有两个操作路径如果机器数量少直接docker load -i然后docker run即可如果机器数量多就load registry后把其余镜像load进这台机器再tag、push到registry让其他机器从registry拉取。docker load -i mysql-8.0.tar docker tag mysql:8.0 192.168.1.100:5000/mysql:8.0 docker push 192.168.1.100:5000/mysql:8.0 # redis、nginx、nacos依此类推第五步所有机器配置daemon.json指向私有仓库通过拉取镜像启动中间件。docker pull 192.168.1.100:5000/mysql:8.0 docker pull 192.168.1.100:5000/redis:7 ...最后验证一次完整链路在另一台机器上执行docker pull 192.168.1.100:5000/mysql:8.0然后docker run确认能正常访问。这个从零到全部可用的信号明确之后交付才算真正完成。这套流程我一共用过很多次每次的核心原则都一样先小范围验证再批量复制先保证链路再追求速度。离线环境的试错代价比在线环境高得多一次容器启动失败牵涉的可能是现场的整套交付流程延期。8. 一些离线部署的补充建议与个人经验文章写到这里核心内容基本都覆盖了。最后我再挑几条零零散散但非常影响实际操作体验的经验来讲这些不在官方文档里但都来自真实项目中的一手体会。关于传输工具如果目标机器只能通过跳板机访问scp传大文件容易断建议用rsync配合断点续传或者把大tar包分卷再传。我遇到过传了半个小时的mysql镜像包突然断掉重新scp又要半小时最后用split按1GB分块传输配合rsync --partial才解决。关于清单管理在离线交付时我强烈建议在U盘或打包目录里维护一个manifest.txt把所有文件的版本、大小、校验值记录清楚。进到内网环境没外网可查如果哪个文件损坏了你只能靠这份清单判断。每次都用sha256sum校验重要文件不要嫌麻烦。关于版本固定离线系统的软件版本一旦装上基本不会频繁升级。所以决定版本时一定要慎之又慎把需求方要的中间件特性、已知安全漏洞、数据库兼容性都摸清楚再定版本。在离线环境里做版本回退的代价比在在线环境高得多——因为旧版本的rpm包和镜像你可能并没有存下来。关于演练离线部署不是看文档就能掌握的技能。强烈建议在家里或测试环境里完整走一遍从联网机器准备包到离线机器启动中间件的流程。第一次可能会花掉半天时间但一旦走通这个能力体系就建立了以后的交付效率会有质的提升。我最早也是在一台闲置的x86服务器上反复练习才慢慢积累了处理各类意外状况的经验。这套东西说下来其实没有太多花哨的技巧核心就是细心、耐心、有条理。离线和在线的差别无非是可用的资源从无限变成了有限而你的应对策略也从缺什么装什么变成了装什么带什么。理解了这一点整个离线部署的思维模式就有了。希望这篇内容对你的实际操作能有实实在在的帮助。如果后面在离线部署中间件的过程中遇到具体问题欢迎在评论区把报错信息发出来我们一起研究。
返回列表