尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

x86架构下Docker离线安装与中间件部署实战指南

x86架构下Docker离线安装与中间件部署实战指南 干过几次内网交付项目之后我对“docker离线安装”这几个字真的又爱又恨。爱的是一旦把离线环境打通后面部署中间件简直行云流水恨的是第一次操作时光是把docker装起来就可能卡在依赖、架构、内核版本这些不起眼的细节上。这篇文章就把我在x86系统架构服务器上做docker离线安装和中间件部署的完整过程写出来。适用场景很明确服务器没有外网只能通过U盘、内网yum源、或者局域网文件共享来传递安装包但你又需要快速跑起MySQL、Redis、Nginx这类基础设施中间件。整个流程我在CentOS 7.9和Rocky Linux 8.x上都验证过理论上兼容大多数x86_64的Linux发行版。如果你接下来要做内网交付、机房设备初始化和离线环境项目这篇文章的步骤可以直接抄作业包括我踩过的坑也会原封不动分享出来。1. 离线安装前的方案选型与前置检查1.1 先用一条命令确认架构和内核对不对开始装docker之前我强烈建议先花两分钟确认三件事系统架构、发行版版本、内核版本。别小看这一步很多离线安装失败根本原因就是架构不对或者内核太老。uname -m cat /etc/os-release uname -runame -m输出x86_64就说明是x86系统架构的64位机器这也是docker官方rpm包和二进制包的默认目标。如果是i386、i686这种32位架构那docker基本不用想了官方早就停止支持了。/etc/os-release会告诉你具体是CentOS 7还是Rocky Linux 8这决定了应该去下载哪个rpm包集合。uname -r则是内核版本CentOS 7默认的3.10内核虽然比较老但docker 20.10及以前版本还能跑新版本对内核要求会更高一些。1.2 三种离线安装方案该怎么选离线安装docker主要有三条路我根据使用频率排个序第一种Yum/Apt离线仓库方式。在有网环境下把docker和依赖包全部下载成rpm或者deb文件然后拷贝到内网机器上用本地repo源安装。这种方法最符合运维人员习惯后续如果有其他机器搭一个内网yum源就能批量安装。缺点是需要提前把依赖关系摸清楚否则会陷入“缺一个包装一个包”的循环。第二种官方静态二进制方式。从docker官网下载docker-版本号.tgz压缩包里面包含dockerd、docker、containerd这些二进制文件解压后放到/usr/bin目录再用systemd管理。这种方式最干净不依赖系统包管理器适合批量服务器部署也适合那种包管理器损坏的极端情况。缺点是需要自己写systemd service文件对不熟悉systemd的人稍微有点门槛。第三种直接搬运行已经做好的操作系统镜像。比如用打包好的虚拟机模板或者轻量系统镜像docker提前预制在镜像里。这种方式对单机部署很快但如果是几十台机器传输镜像的时间成本和定制化成本反而更高。我自己的习惯是单台机器试运行用第一种yum/apt批量生产环境用第二种静态二进制第三种基本不推荐。2. 离线安装Docker与Docker Compose全流程2.1 在有网环境准备docker的rpm安装包这一步需要在能连外网的机器上提前下载。以CentOS/RHEL系列为例我推荐用yumdownloader和createrepo来做一个本地离线包目录。先说第一种方式直接下载指定rpm包# 安装yum-utils工具 yum install -y yum-utils # 创建目录存放docker相关rpm包 mkdir -p /root/docker-offline-packages cd /root/docker-offline-packages # 下载docker和依赖组件 yumdownloader --resolve docker-ce docker-ce-cli containerd.io docker-compose-pluginyumdownloader --resolve会把docker-ce所需的全部依赖包一次性下载到当前目录包括container-selinux、libseccomp等。下载完后检查一下目录里的rpm文件数量正常应该在10个左右。如果你需要在内网批量安装更推荐把这些rpm包做成一个本地yum源。方法也很简单把rpm文件放到一个目录用createrepo生成元数据然后在离线机器的/etc/yum.repos.d/下新建一个repo文件指向这个目录createrepo /root/docker-offline-packagesrepo文件内容大致如下[docker-offline] nameDocker Offline Repository baseurlfile:///root/docker-offline-packages enabled1 gpgcheck0这样在离线机器上执行yum install -y docker-ce就能自动解析依赖并安装。这个方法最适合内网有多台服务器的情况因为只要把这些rpm包同步到每台机器或者放在一台内网文件服务器上用HTTP暴露出来所有机器都能用同一个源。对于Ubuntu/Debian系统逻辑类似用apt-get download或者apt-get install --download-only -y docker.io来缓存deb包然后在内网执行dpkg -i *.deb即可。2.2 内网机器安装docker并配置开机启动拿到rpm包之后内网安装就很快了。如果只是临时安装一两台直接rpm -ivh *.rpm如果遇到报错提示某个包已存在就用rpm -Uvh *.rpm升级安装。rpm安装能自动处理依赖但前提是当前目录下的rpm包必须齐全。我记得有一次在CentOS 7.9上装docker时卡在了container-selinux这个包上因为系统自带的selinux策略版本过低docker引用的container-selinux版本装不上。这种情况不要硬扛最快的方法是查一下docker-ce这个rpm包到底依赖哪些版本然后从阿里云开源镜像站下载对应版本的container-selinux。装完之后立即设置开机启动并启动服务systemctl enable --now docker docker versiondocker version如果能看到Client和Server两段信息说明docker已经正常运行了。如果只看到Client没有Server多半是dockerd启动失败这时候要用journalctl -u docker看日志绝大多数是和iptables、cgroup、存储驱动相关的问题后面我会单独写一节排查。2.3 离线安装docker-compose的正确姿势docker-compose在大规模中间件编排时非常好用离线环境下安装它也需要提前准备。compose有两种形式老一代的docker-compose独立二进制和新版本的docker compose插件。新版本插件会作为docker的一个子命令出现如果你已经通过yum方式安装了docker-compose-plugin那docker compose version直接就能用不需要额外操作。如果用的是独立二进制下载时注意选择docker-compose-linux-x86_64这个文件我通常会放到/usr/local/bin/docker-composecp docker-compose-linux-x86_64 /usr/local/bin/docker-compose chmod x /usr/local/bin/docker-compose docker-compose --version这里有个容易踩的坑docker-compose二进制文件依赖于glibc版本如果内网系统太老比如CentOS 7自带的glibc 2.17部分高版本docker-compose会直接抛 version GLIBC_2.28 not found。遇到这种情况就别想升级系统了老老实实下载一个旧一点的docker-compose版本比如1.29.x。3. 中间件镜像的离线获取、传输与导入3.1 在有网机器上拉取镜像并打标签docker本体搞定后真正的重头戏是中间件镜像的离线搬运。这里有一个核心原则在有网机器上拉取镜像导出成tar文件传到内网再导入。我平时会在有网环境准备一台“镜像中转机”把需要的镜像一次性拉齐全docker pull nginx:1.24.0 docker pull mysql:8.0.36 docker pull redis:7.2.4如果需要部署harbor也可以把goharbor/harbor-*相关镜像一并拉下来。如果内网机器比较多建议先对所有镜像打上将来要用的tag比如内网registry地址前缀这样在内网导入后就能直接被docker-compose或私有仓库使用。3.2 镜像导出、压缩、分卷一整套操作镜像拉好后用docker save导出为tar包。很多人会把docker save和docker export搞混这里说明一下save保存的是镜像层完整保留历史元数据、环境变量、入口点适合镜像迁移export导出的是容器文件系统会把历史层合并成一个扁平层会导致镜像丢失堆栈历史不适合镜像分发。我们要的是前者。mkdir -p /root/images docker save -o /root/images/nginx-1.24.0.tar nginx:1.24.0 docker save -o /root/images/mysql-8.0.36.tar mysql:8.0.36 docker save -o /root/images/redis-7.2.4.tar redis:7.2.4镜像文件通常不小MySQL 8.0 的镜像大概600MB左右传输和存储都挺占空间的。为了更安全地搬运我会进一步压缩并分卷gzip /root/images/mysql-8.0.36.tar split -b 100M -d /root/images/mysql-8.0.36.tar.gz /root/images/mysql-8.0.36.tar.gz.partsplit -b 100M -d会把大文件按100MB切分成多个part文件适合用U盘或者FTP传输时规避单文件大小限制。到了内网机器后先合并再解压cat /root/images/mysql-8.0.36.tar.gz.part* /root/images/mysql-8.0.36.tar.gz gzip -d /root/images/mysql-8.0.36.tar.gz压缩传输这个细节看似不起眼但在离线环境中非常实用。我第一次做离线传输时没压缩一张16GB的U盘装两个镜像就满了后来改成压缩之后同样容量能装下的镜像数量翻了好几倍。3.3 内网导入镜像并验证可用性镜像包到了内网机器上之后导入动作很简单docker load -i /root/images/nginx-1.24.0.tar docker load -i /root/images/mysql-8.0.36.tar docker load -i /root/images/redis-7.2.4.tar导入完成后查看镜像列表docker images这里我特别想提醒一个细节docker load导入后显示的镜像名和tag来自你docker save之前打的tag。所以如果当时拉下来的是原始名称导入后也就是原始名称如果内网要用特定名称建议在有网机器上先docker tag好再save。还有一个容易被忽视的问题镜像导入后是否能在当前机器上启动取决于镜像的架构。如果你在一台ARM Mac或者ARM服务器上执行了docker pull导出的镜像也是ARM架构的传到x86系统机器上根本跑不起来。这也是为什么标题里特别强调x86系统架构——在x86服务器上准备镜像时先在Windows或者Linux x86机器上执行或者用docker manifest inspect确认镜像支持linux/amd64。4. 中间件容器化部署实操4.1 用docker快速部署Nginx并挂载配置Nginx是很多应用的前置入口也是我在内网第一个部署的中间件。部署方式很简单重点在目录设计上。先创建Nginx的数据目录mkdir -p /data/nginx/{conf,html,logs}然后准备一份基础nginx.conf建议最少包含worker_processes、events、http三个核心块。我们用容器跑Nginx时最重要的是把宿主机目录挂载到容器里的/etc/nginx/conf.d、/usr/share/nginx/html和/var/log/nginx这样以后改配置、放页面、看日志都不用进入容器。启动命令docker run -d \ --name nginx \ --restartalways \ -p 80:80 \ -v /data/nginx/conf:/etc/nginx/conf.d:ro \ -v /data/nginx/html:/usr/share/nginx/html \ -v /data/nginx/logs:/var/log/nginx \ -e TZAsia/Shanghai \ nginx:1.24.0--restartalways这个参数我在内网环境特别强调因为生产环境机器重启是常事如果docker容器没有设置自动重启宕机恢复后服务就全断了。-e TZAsia/Shanghai是为了时区Nginx镜像默认UTC时间日志和实际北京时间差8小时排查问题时很容易被误导。启动后验证docker ps curl -I http://127.0.0.1如果curl返回200说明Nginx已经正常提供服务。以后修改配置只需编辑宿主机/data/nginx/conf/下的文件然后执行docker exec nginx nginx -s reload让配置生效即可。4.2 MySQL 8.0数据持久化与初始化配置MySQL在内网是绝对的刚需。用docker部署MySQL时最核心的就是数据持久化和字符集配置。数据持久化没啥可讨价还价的必须挂载volume否则容器一删数据就全没了。mkdir -p /data/mysql/{data,conf,logs} docker run -d \ --name mysql \ --restartalways \ -e MYSQL_ROOT_PASSWORDStrongPassw0rd \ -e TZAsia/Shanghai \ -p 3306:3306 \ -v /data/mysql/data:/var/lib/mysql \ -v /data/mysql/conf:/etc/mysql/conf.d \ -v /data/mysql/logs:/var/log/mysql \ mysql:8.0.36关于初始化密码有两点经验。第一MYSQL_ROOT_PASSWORD这个环境变量只在首次初始化数据目录时生效如果目录里已经有了旧数据改这个变量不会覆盖密码。第二如果忘记初始化密码最稳妥的方法是挂一个临时配置文件来跳过权限认证进入容器后修改密码再恢复配置文件新版本MySQL 8支持在配置里加skip-grant-tables然后重启来实现。初始化等待时间通常需要30秒到1分钟因为MySQL第一次启动时要建系统表。内网机器性能一般稍安勿躁。验证方式docker exec -it mysql mysql -uroot -p进入MySQL后建议顺手把默认认证插件调整为mysql_native_password或者使用caching_sha2_password这取决于你的客户端工具是否支持新认证方式。老旧的业务系统如果连不上MySQL 8大概率是认证插件问题ALTER USER root% IDENTIFIED WITH mysql_native_password BY StrongPassw0rd; FLUSH PRIVILEGES;另外我还会在/data/mysql/conf/下创建一个my.cnf文件设置默认字符集为utf8mb4确保中文数据不出乱码。这在很多业务系统上是刚性需求。4.3 Redis主从模式部署与持久化配置Redis部署也不难难点通常在主从和持久化上。内网环境里我一般会部署一主一从既能满足高可用要求又不会给机器太大负担。先创建数据目录mkdir -p /data/redis/{master,slave,conf}主节点部署docker run -d \ --name redis-master \ --restartalways \ -p 6379:6379 \ -v /data/redis/master:/data \ -v /data/redis/conf/redis-master.conf:/etc/redis/redis.conf \ redis:7.2.4 \ redis-server /etc/redis/redis.conf从节点通过replicaof命令挂到主节点在redis-slave.conf里配置replicaof 10.0.0.10 6379然后启动从节点docker run -d \ --name redis-slave \ --restartalways \ -p 6380:6379 \ -v /data/redis/slave:/data \ -v /data/redis/conf/redis-slave.conf:/etc/redis/redis.conf \ redis:7.2.4 \ redis-server /etc/redis/redis.conf这里有个关键点Redis持久化推荐同时开启RDB和AOF。RDB做快照恢复快AOF记录每个写操作丢数据少。对应配置appendonly yes appendfsync everysec save 900 1 save 300 10 save 60 10000我遇到过的坑是Redis容器默认以redis用户运行挂载到宿主机目录后目录属主如果不匹配Redis写入时会报权限错误。解决办法非常直接chown -R 999:999 /data/redis如果排查半天还是启动失败直接看容器日志docker logs redis-master5. 内网多机器分发部署私有镜像仓库5.1 用registry镜像搭建局域网私有仓库当你需要在多台内网机器上部署中间件时每台机器都手动docker load镜像包传文件效率实在太低了。更好的做法是在局域网里搭一个私有镜像仓库把镜像推送上去其他机器直接docker pull即可。最简单的方式就是跑一个官方registry容器mkdir -p /data/registry docker run -d \ --name registry \ --restartalways \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ registry:2registry启动后在有镜像的内网机器上先给镜像打上私有仓库地址的tagdocker tag nginx:1.24.0 192.168.1.10:5000/nginx:1.24.0 docker push 192.168.1.10:5000/nginx:1.24.0其他机器需要用到这个镜像时只需配置/etc/docker/daemon.json添加insecure-registries: [192.168.1.10:5000]然后重启docker就可以直接docker pull了。insecure-registries这个配置是必须的因为私有仓库默认走HTTP而docker默认要求HTTPS不把这个地址加入白名单pull时一定会报证书错误。5.2 批量推送镜像到私有仓库的脚本思路如果你要推送的镜像列表很长一条一条docker tag加docker push确实浪费时间。我用一个非常简单的shell循环处理for image in nginx:1.24.0 mysql:8.0.36 redis:7.2.4; do docker tag $image 192.168.1.10:5000/$image docker push 192.168.1.10:5000/$image done推送完成后可以在registry容器里查看仓库列表curl http://192.168.1.10:5000/v2/_catalog这个方法虽然简单但能省下大量人工操作。其实想过用harbor它带有Web管理界面和RBAC权限控制适合团队规模较大的场景。如果只是三五台机器registry完全够用。若选择harbor离线安装也不复杂核心是把harbor的离线安装包harbor-offline-installer-xxx.tgz传到内网把里面的docker镜像load到本机然后执行install.sh脚本即可。6. 离线环境常见问题与排查技巧实录6.1 rpm依赖缺失和版本冲突怎么破离线环境最常见的报错就是类似libcgroup is needed by docker-ce-...、container-selinux is needed by docker-ce-...这种。别慌思路就两个一是把依赖包找到并下载下来一起装二是修改安装方式。找依赖包最简单的方法是在有网环境的机器上执行yum deplist docker-ce它会列出所有依赖包和具体版本。然后逐个yumdownloader下载。如果下载的数量太多我更推荐在一个干净的有网机器上用yum install --downloadonly --downloaddir/tmp/dockerdeps docker-ce一把梭下载全部依赖。另一个很实用的思路是放弃rpm包方式改用静态二进制。静态包里自带dockerd、containerd、runc等关键组件不依赖系统包管理器对离线环境特别友好。我遇到过一台内核较新的Rocky Linux 9rpm包始终装不上换成二进制包反而一路绿灯。6.2 Docker启动失败iptables、cgroup和存储驱动启动docker时报Failed to start Docker Application Container Engine是比较头疼的问题。排查时第一看定位的日志journalctl -u docker --no-pager -n 50常见的三个原因按出现频率排序iptables相关报错。docker默认要操作iptables如果系统禁用了iptables或者使用nftables可能会起不来。可以尝试临时用iptables -L -n看是否正常如果iptables命令本身报错需要先把iptables服务装好或启用。cgroup版本不匹配。Docker默认使用cgroupfs如果系统开启了cgroup v2而docker版本较老也可能启动失败。新版本docker通常能自动适配但是如果一直失败可以在/etc/docker/daemon.json中显式指定cgroupdriver: systemd或cgroupdriver: cgroupfs实测下来CentOS 7上systemd更稳Ubuntu 20.04以上用systemd也一致。存储驱动 overlay2 不可用。如果文件系统不支持overlay2docker会退回到vfs虽然能启动但是磁盘占用巨大性能也差。可以用docker info查看Storage Driver那行如果显示vfs建议格式化相关分区为xfs或者ext4重新加载后重启docker。解决方案基本都可以用调整/etc/docker/daemon.json加上重启docker来解决。这个文件在内网环境下尤其重要它的作用不只是给registry配白名单还包括配置>
返回列表