资讯动态

x86架构下Docker离线安装与中间件容器化部署实操指南

发布时间:2026/10/13 4:04:17 来源:尧图企业网站定制
1. 离线部署的整体思路与方案选型1.1 为什么需要离线安装docker先聊一个我经常被问到的问题好好的服务器为什么非要离线装docker答案其实很现实——很多项目环境是物理隔离的内网比如政务云、金融机房、电力专网甚至是某些企业内部研发网。在这些网络环境里服务器能上电、能跑业务但访问不了外网更别说直接连docker hub拉镜像了。有的环境甚至yum源都是内网定制的外网源根本不通。另一个场景是交付。我给客户做过一套模拟项目X的交付现场环境要求把整套中间件MySQL、Redis、消息队列在两小时内跑起来。客户机房能给的就是几台裸机没有外网没有现成的镜像源甚至没有一台能临时当镜像仓库的机器。这个时候你如果在现场才去装docker、才去想办法拉镜像那交付时间就彻底失控了。所以离线安装不是说“图省事”而是很多企业级环境的硬性要求。把这套流程吃透你在任何内网环境都能快速把容器运行时搞定再配合离线镜像包把中间件整套拉起来这是运维和交付人员必须具备的基本功。还有一个容易被忽略的点x86系统架构。标题特别强调了这一点因为不同CPU架构拉取的镜像是不通用的。你在一台ARM服务器上导出的镜像扔到x86服务器上直接跑大概率会报“exec format error”。我这篇文章讲的所有内容默认都是x86_64体系也就是Intel或者AMD的CPU。你如果现场用的是ARM架构比如鲲鹏、飞腾那拉镜像的时候要选对应架构的tag导出导入的流程一样但镜像本身不能混用。1.2 三种主流方案对比离线装docker我实际操作下来主要有三条路方案Arpm包离线安装。在有网的机器上用yumdownloader或者直接手动下载docker相关的rpm包拷贝到目标机器上用rpm -ivh或者yum localinstall离线安装。这个方案最直接适合那种目标机器上什么都没有、连yum源都不通的场景。方案B内网yum源。如果现场已经有一套定制的内网yum仓库可以把docker的rpm包扔进去然后目标机器配置指向内网源正常yum install。这个方案对机器多、需要批量装的情况更友好但前提是你得有权限往yum源里放东西而且得先有一套能用的内网源基础设施。方案C静态二进制解压。官方其实提供docker二进制压缩包下载后解压把可执行文件扔到/usr/bin配置systemd服务托管。这个方案很干净不依赖rpm包管理器适合那种系统版本特别老、或者你不想污染系统rpm库的场景。我个人的建议是如果机器数量少1到10台直接rpm包离线安装维护成本最低卸载也干净。如果机器数量多几十台往上优先内网yum源批量操作省心。静态二进制方案适合特殊系统或者你想把docker目录整个定制化的场景。方案没有绝对的好坏核心是看现场条件限制。你到了现场再临时纠结方案那是最要命的。1.3 选择离线版本号的注意点离线安装有一个特别容易踩的坑版本选择。很多人在有网环境装docker直接curl -fsSL https://get.docker.com | sh装完是啥版本就是啥版本也无所谓。但离线环境不一样你带进去什么版本现场就是什么版本想升级还得重新拷包进网。我的经验是选择centos 7或者RHEL 7.9兼容的docker 20.10.x版本或者直接选docker 24.x系列。20.10这个系列在国内很多企业的存量环境里验证过稳定性和兼容性都很好不管是老内核3.10还是新内核5.x表现都可控。docker 24.x对containerd的版本要求更高如果你现场系统特别老比如centos 7.2有些依赖可能需要额外处理。还有一个更稳妥的做法连docker-compose或者现在的docker compose插件一起带进去。部署中间件不可能全靠裸docker run编排才是常态我后面会详细讲。我本人在现场通常带的是一整套rpm目录包括docker-ce主程序docker-ce-cli命令行工具containerd.io容器运行时docker-compose-plugincompose v2插件这样四件套齐了后续部署中间件的时候就不用再纠结缺组件。2. 基础环境准备与检查清单2.1 操作系统与内核版本确认到了现场第一件事不是急着拷安装包而是先把目标机器的底细摸清楚。我在一次现场交付中遇到过这种事客户说机器系统是centos 7结果上去一看是centos 7.2内核3.10.0-327。这个内核版本配合docker高版本会出现overlay2存储驱动不支持的情况虽然docker会自动回退到vfs但性能惨不忍睹。最后是让客户帮忙升级了内核补丁折腾了大半天。所以进机房第一件事执行这几条命令cat /etc/os-release uname -r arch重点确认三点系统是什么发行版、内核是多少、CPU架构是不是x86_64。docker官方对centos系统的建议是内核版本不低于3.10但如果用overlay2驱动3.10.0-514对应centos 7.3以下的版本会有兼容性问题。怎么判断当前内核是否支持overlay2最简单的方法cat /proc/filesystems | grep overlay有输出就说明内核支持没输出就只能用vfs性能打折但能用。系统版本太老的情况下比如centos 6.x那docker 20.10装起来会很别扭我建议直接和客户沟通先升级系统否则你后续排查问题会被系统底子拖死。2.2 磁盘分区与存储规划磁盘问题是我遇到的最多“现场翻车”原因之一。docker装完后默认的数据目录是/var/lib/docker容器日志、镜像层、容器可写层全在这里。如果你现场服务器的根分区只有50G而你要部署MySQL数据、ES索引、Kafka日志那这个分区一天就能被打满。先看磁盘情况df -h lsblk如果/var/lib/docker所在分区空间不够有两个处理思路一是挂数据盘。在安装之前先把新磁盘格式化、挂载到某个路径比如/data然后配置docker使用/data/docker作为数据目录。这个操作在docker的配置文件中直接指定不用重新安装。二是如果docker已经装了数据目录也可以迁移。我的建议是最好在装完docker之后、拉镜像之前就把目录改好否则镜像和容器数据迁移会额外增加一步而且容易漏网。磁盘规划还有一个容易被忽略的点inode耗尽。这个我不会在这里展开后面常见问题环节细说。2.3 基础依赖与软件包准备docker的rpm包依赖还是比较多的。离线安装最烦的就是缺依赖现场没网缺一个就得想办法传一次。20.10版本的常见依赖包括container-selinuxcontainerd.iodocker-ce-cliiptables、libtool、libseccomp等系统基础库我的习惯是在有网的机器上用一个干净环境执行yumdownloader --resolve --destdir/tmp/docker_offline docker-ce docker-ce-cli containerd.io把docker本体和所有依赖全部下载到本地目录。--resolve参数会自动解析依赖连带依赖包一起下载这个比手动yum install --downloadonly更直观而且不会把无关的包卷进来。不过要注意不同系统版本和不同yum源环境依赖包列表可能不一样。严格来说最靠谱的获取方式是在一台和现场同版本系统的机器上执行下载这样依赖的版本才能完全对上。软件包准备好了之后不要马上拷进去就装。现场确认一下目标机器的selinux状态getenforcedocker和selinux的关系非常微妙。CentOS 7默认selinux是enforcing这时候装docker20.10以上版本一般没问题但容器里某些操作会被selinux拦特别是挂载目录、访问设备节点这些场景。我个人见到过太多“容器起不来查半天是selinux拦了”的情况了。如果现场业务对selinux没硬性要求我一般建议临时改为permissivesetenforce 0然后修改/etc/selinux/config改成disabled。但如果客户安全策略要求selinux必须开启那就保持enforcing尽量不要动遇到权限问题再针对性处理。3. docker离线安装实操3.1 离线包的拷贝与校验把rpm包从本机拷到目标机器的方式最常见的是U盘拷贝或者scp。如果现场只有Windows跳板机那一般是先传到跳板机再通过跳板机传到Linux服务器。我自己的习惯是拷贝完成之后做一次校验防止传输过程中文件损坏。方法很简单在有网机器下载完成后记录所有rpm包的sha256值sha256sum /tmp/docker_offline/*.rpm /tmp/docker_offline/checksum.txt把校验文件一起拷到现场目标机器上执行sha256sum -c checksum.txt看到每个文件都显示OK再进行安装。这一步看起来很“多余”但实际救过我一命——有一次U盘拷贝的文件在传输过程中损坏直接rpm安装报错还很难排查。有了校验30秒就能定位是文件问题还是系统问题。3.2 rpm包安装与启动验证安装命令很简单但有讲究。最稳妥的安装方式是cd /tmp/docker_offline rpm -ivh *.rpmrpm -ivh会逐个安装遇到依赖缺漏会明确报错。如果报错提示缺了某个依赖说明你下载依赖的时候漏包了。这时候去有网的机器补下载再传进来重新执行安装。还有一种更省事的方式yum localinstall *.rpm这个命令会利用本地的rpm缓存自动解决依赖顺序不用手动排安装顺序体验好很多。但前提是你现场机器能正常使用yum命令不需要外网本地localinstall本来就不走网络。安装完成之后先不要急着启动把配置改好了再启动省得反复重启服务。配置docker服务自启动然后设置数据目录。先创建配置目录mkdir -p /etc/docker然后编辑daemon.json我下面单独讲。配置完成后再执行systemctl enable docker systemctl start docker systemctl status docker查看docker版本验证docker version docker info注意docker version会同时显示Client和Server两部分信息。如果只有Client信息而没有Server信息说明docker服务没起来或者daemon启动失败了。这时候journalctl -u docker查日志看具体报错。3.3 docker核心配置daemon.json详解daemon.json是docker守护进程的配置文件很多问题排查到最后都回到这里。我总结了一份在离线/内网环境下比较实用的配置{ data-root: /data/docker, exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, registry-mirrors: [], insecure-registries: [10.0.0.10:5000], iptables: true, ip-forward: true, bridge: none }每项背后的逻辑我说下>docker pull mysql:8.0.32 docker pull redis:7.0.11 docker pull nginx:1.24.0 docker pull rabbitmq:3.11-management docker pull eclipse-mosquitto:2.0 docker pull elasticsearch:7.17.12 docker pull kibana:7.17.12 docker pull bitnami/kafka:3.5.0这里我不推荐拉latest标签。离线环境没有网络latest标签的镜像内容会随时间漂移而且如果现场需要复现latest的不确定性太大。指定精确版本号保证可复现性这是我交付时的基本原则。拉完之后导出为tar包docker save -o images_middleware.tar mysql:8.0.32 redis:7.0.11 nginx:1.24.0注意docker save和docker export是两个完全不同的命令。save是把镜像打包包含所有层可以重新导入成为镜像export是把容器打包把容器的文件系统导出来导入之后没有历史层信息。离线分发镜像必须用save不要用export。打包完之后检查一下tar包大小。一个MySQL镜像大概500MB左右ES接近1GB全套中间件打包下来可能有几个GB。拷贝的时候要考虑传输方式和时间用U盘没问题但走慢速跳板机传输的话时间成本要提前估算。4.2 镜像导入现场离线导入到了现场之后把tar包拷贝进去执行导入docker load -i images_middleware.tar加载过程中会看到每一层逐步加载的日志。加载完成后验证镜像是否正确docker images这里会显示所有镜像的仓库名、标签和大小。如果导入之后发现镜像名带none说明在save的时候没有指定正确的仓库名或者镜像本身是旧的构建方式。问题不大可以通过docker tag重新打标签。还有一种情况tar包损坏导致load失败。load失败会直接报错错误信息通常会提示archive/tar: invalid tar header之类的。这种情况下只能重新拷贝一遍基本就是传输导致的问题。4.3 搭建私有镜像仓库Harbor如果现场机器比较多或者后续还有版本更新需求我不建议每台机器都手动load镜像包而是建议搭一套私有镜像仓库。Harbor是业界最常用的方案功能完整、有Web界面、支持项目权限控制。离线环境下搭Harbor的思路是在有网的机器上拉取Harbor的离线安装包Harbor官方提供离线安装包压缩包约1GB左右传到现场。然后现场准备一台机器作为镜像仓库服务器安装docker和docker-composeHarbor的部署依赖docker compose。Harbor的安装过程几行命令tar -xzf harbor-offline-installer-v2.10.0.tgz cd harbor cp harbor.yml.tmpl harbor.yml编辑harbor.yml重点改几个配置hostname改成这台机器在局域网内的访问地址比如10.0.0.10。port默认是80端口如果想换成其他端口比如5000就改对应配置。harbor_admin_password管理员初始密码必须改这是安全底线。然后启动安装./install.sh看到✔----Harbor has been installed and started successfully.----的日志就说明装好了。访问http://10.0.0.10能打开Harbor的Web管理界面。接下来把中间件镜像推到Harbordocker tag mysql:8.0.32 10.0.0.10/library/mysql:8.0.32 docker push 10.0.0.10/library/mysql:8.0.32这里描述一下关键点Harbor默认创建library项目这也是docker官方默认项目名。推镜像的时候镜像名的前缀必须包含仓库地址docker才能识别推送到哪个仓库。所有需要跑中间件的服务器配置daemon.json里的insecure-registries加入Harbor的地址然后就可以直接docker pull 10.0.0.10/library/mysql:8.0.32这样比每台机器load镜像包方便太多。但说实话如果就三五台机器手动load完全够用。Harbor适合规模稍大、有版本迭代需求的场景。4.4 内网节点配置拉取私有仓库镜像这里有一个细节很多人第一次配置的时候会卡住。在内网节点的daemon.json里加insecure-registries之后一定要重启docker才能生效systemctl daemon-reload systemctl restart docker然后才能正常pull私有仓库的镜像。如果重启之后仍然报错提示certificate signed by unknown authority或者http: server gave HTTP response to HTTPS client基本就是两个原因忘了加insecure-registries或者在改配置之前已经启动过docker没重启。节点访问不到仓库地址网络不通。用curl http://10.0.0.10/v2/测试一下如果能返回一个JSON响应说明网络通。为什么http: server gave HTTP response to HTTPS client这个错误这么经典因为docker客户端默认用HTTPS访问仓库而私有仓库只提供HTTP服务的时候握手协议对不上就会报这个错。加了insecure-registries之后docker客户端会放行对该地址的非HTTPS连接。5. 中间件容器化部署实操5.1 快速部署MySQL 8实战中间件部署是标题里最实在的部分。我拿MySQL 8举例完整跑一遍。单机小规模场景下直接docker run比compose更轻快。但如果要持久化目录、密码、字符集、备份恢复都做好管理建议还是用compose。先看目录结构规划/opt/mysql/ ├── conf/ │ └── my.cnf ├── data/ └── docker-compose.ymlmy.cnf内容按常见的生产配置给出[mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_general_ci default-time-zone08:00 max_connections500 innodb_buffer_pool_size2G slow_query_log1 slow_query_log_file/var/log/mysql/slow.log long_query_time2character-set-server指定utf8mb4这是为了支持完整的Unicode字符包括emoji也是当前主流推荐。max_connections和innodb_buffer_pool_size需要根据机器内存调整如果机器是16G内存2G的buffer pool是基准值。docker-compose.ymlversion: 3.8 services: mysql: image: 10.0.0.10/library/mysql:8.0.32 container_name: mysql8 restart: always ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: YourStrongPassword TZ: Asia/Shanghai volumes: - /opt/mysql/data:/var/lib/mysql - /opt/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf注意几个细节容器内MySQL默认数据目录是/var/lib/mysql把宿主机/opt/mysql/data挂载进去数据会持久化在宿主机。即使容器删除重建数据还在。TZ: Asia/Shanghai必须配置。MySQL容器基础镜像默认时区是UTC如果你不设置数据库记录的now()时间会比北京时间晚8小时。虽然Java应用可以通过连接串指定时区但数据库直接返回的时间不对经常导致各种排查困扰。这个我踩过太多次。启动cd /opt/mysql docker compose up -d查看启动状态docker logs mysql8 --tail 50看到ready for connections的日志就说明启动成功了。验证连接docker exec -it mysql8 mysql -uroot -p然后执行select version(); select now();确认版本和时区都正常。MySQL部署里最容易被坑的一个点是容器初始化完成后会创建一个匿名卷如果你第一次启动时没挂载数据目录之后想补挂载数据不会自动迁移。所以数据目录的挂载必须第一次启动之前就配好。5.2 Redis部署与密码认证Redis的容器化部署相对简单但有几个细节会影响后续使用的稳定性。我还是用compose方式version: 3.8 services: redis: image: 10.0.0.10/library/redis:7.0.11 container_name: redis7 restart: always ports: - 6379:6379 command: [redis-server, --appendonly, yes, --requirepass, YourRedisPassword] volumes: - /opt/redis/data:/data关键点--appendonly yes开启AOF持久化Redis默认是RDB快照持久化AOF记录每次写操作数据安全性更高。生产环境建议AOF和RDB都开启但容器化部署一般配置AOF即可。--requirepass设置访问密码。虽然Redis通常只在内网访问但内网不等于安全之前有过多次Redis未授权访问提权的安全事件密码必须设。启动cd /opt/redis docker compose up -d测试连接docker exec -it redis7 redis-cli -a YourRedisPassword ping返回PONG说明正常。Redis容器有一个体验不太好的点默认没有配置文件所有配置都通过command参数传。如果配置项特别多比如设置maxmemory、设置持久化策略command会变得很长。这种情况下建议把redis.conf写好挂载进容器command里只写redis-server /etc/redis/redis.conf。两种方式效果一样看个人习惯。5.3 用Nginx做内网反向代理Nginx容器部署和前面的思路有些不同。Nginx本身是一个反向代理服务它的主要价值在于路由各种中间件暴露的HTTP接口比如让团队统一通过一台Nginx访问不同的中间件服务。配置Nginx容器version: 3.8 services: nginx: image: 10.0.0.10/library/nginx:1.24.0 container_name: nginx restart: always ports: - 80:80 - 443:443 volumes: - /opt/nginx/conf.d:/etc/nginx/conf.d:ro - /opt/nginx/logs:/var/log/nginxconf.d目录挂载自定义配置文件实现反向代理。比如把某台机器上的ES服务代理到统一入口server { listen 80; server_name es.internal; location / { proxy_pass http://192.168.1.20:9200; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }配置好之后执行nginx -s reload容器内执行reload还是直接在宿主机执行其实你如果配置了volume挂载直接在宿主机编辑配置文件然后在宿主机上执行docker exec nginx nginx -s reloadNginx容器重启成本低但生产环境频繁停止重启会影响在途连接。用reload方式是平滑重载不中断服务这是Nginx的特性也是我推荐这种方式的原因。5.4 消息队列和搜索组件部署要点RabbitMQ、Kafka、Elasticsearch这类组件容器化部署的思路类似但细节差异很大。RabbitMQ直接跑带management插件的镜像可以省去后续装插件的步骤services: rabbitmq: image: 10.0.0.10/library/rabbitmq:3.11-management container_name: rabbitmq ports: - 5672:5672 - 15672:15672 environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: StrongPassword15672是Web管理界面5672是AMQP协议端口。基础镜像不带management的也可以进去rabbitmq-plugins enable rabbitmq_management手动开启但直接选management镜像更省事。Kafka的容器化部署要注意一点Kafka天然依赖zookeeper除非你用的是KRaft模式新版Kafka可以不用zookeeper。如果中间件场景里已经有zookeeper容器Kafka可以直接配置连接。用bitnami的kafka镜像时它通常会带一个内置的zookeeper服务或者让你额外起一个zookeeper容器。services: zookeeper: image: 10.0.0.10/library/bitnami/zookeeper:3.9 ports: - 2181:2181 environment: ALLOW_ANONYMOUS_LOGIN: yes kafka: image: 10.0.0.10/library/bitnami/kafka:3.5.0 ports: - 9092:9092 environment: KAFKA_CFG_ZOOKEEPER_CONNECT: zookeeper:2181 ALLOW_PLAINTEXT_LISTENER: yes KAFKA_CFG_LISTENERS: PLAINTEXT://:9092 KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092Kafka有好几个监听器配置看起来完全一样但含义不同listeners是Kafka进程实际监听的地址advertised.listeners是告诉客户端应该连接哪个地址。如果两者不匹配客户端会连接失败。这是Kafka容器化部署最常见的坑没有之一。ES的话核心注意点是ES容器默认以elasticsearch用户运行挂载数据目录的权限必须匹配。宿主机创建/opt/es/data之后要执行chown -R 1000:1000 /opt/es/data把属主改成uid 1000否则ES容器启动时会报目录权限错误。另外ES容器启动时如果报vm.max_map_count太低需要在宿主机执行sysctl -w vm.max_map_count262144这个参数是Linux内核控制单个进程能拥有的内存映射区域数上限ES这个软件对它的要求比较高。这个配置修改之后重启系统就丢了要写进/etc/sysctl.conf持久化。6. 常见问题与排查技巧6.1 容器启动后无法访问排查思路这个问题出现频率最高。容器起来了docker ps能看到状态是Up但外部访问不通。我通常按这个顺序排查第一步确认端口映射是否正确docker port 容器名看到类似3306/tcp - 0.0.0.0:3306的输出说明映射没问题。第二步确认容器内服务是否真的在监听端口docker exec 容器名 netstat -tlnp如果没有netstat命令可以docker exec 容器名 ss -tlnp。第三步宿主机上直接访问端口curl http://localhost:3306curl能通但外部机器不通那就是防火墙问题了。在宿主机上执行systemctl status firewalld如果开着可能需要开放端口firewall-cmd --zonepublic --add-port3306/tcp --permanent firewall-cmd --reload或者干脆停掉防火墙如果是内网环境且安全策略允许的话systemctl stop firewalld第四步如果宿主机上curl都不通基本是容器内服务没起来。看日志docker logs 容器名 --tail 100从这里基本能定位问题。6.2 容器时间与宿主机时间不一致容器默认时区通常和宿主机一致因为共享内核时钟但时区设置不一定一致。很多官方镜像默认时区是UTC导致日志时间、定时任务时间都与北京时间差8小时。解决办法我在部署MySQL的时候已经提过有TZ环境变量的就设置TZ: Asia/Shanghai。但有些中间件镜像不识别TZ环境变量那就得挂载宿主机的时区文件volumes: - /etc/localtime:/etc/localtime:ro这个挂载把宿主机的/etc/localtime映射进容器容器内所有读时间的程序都会用宿主机的时区设置。还有一个更底层的方式启动命令里加-e TZAsia/Shanghai之外如果容器内的/etc/timezone文件没有内容有的程序会读取这个文件。可以挂载volumes: - /etc/timezone:/etc/timezone:ro但/etc/timezone文件不是所有Linux版本都有centos和ubuntu的位置不一样建议先实测一下。6.3 磁盘空间被日志占满容器日志是磁盘杀手。如果你没限制日志大小一个长期运行的容器container日志文件可以到几十个GB。这个问题我们之前配过daemon.json的log-opts限制那只对之后创建的容器生效已经存在的容器仍然用旧配置。现场遇到日志占满的处理办法先查哪个容器占的空间大du -sh /var/lib/docker/containers/* | sort -rh | head -10找到对应容器后清空日志文件。这里注意不要直接删日志文件正确的做法是truncate -s 0 /var/lib/docker/containers/容器ID/*-json.log用truncate清空而不是rm删除是因为容器持有这个日志文件的文件句柄直接删掉文件不会释放磁盘空间句柄还在只有清空内容才能立即释放。这个技巧在线上用过很多次非常管用。更彻底的做法是所有新容器都建议加一个logging: options: max-size: 100m max-file: 3在compose文件的每个服务下都配这个双保险。6.4 镜像导入慢或导入失败docker load导入几个GB的镜像包时有时候会显得非常慢甚至看起来像是卡死了。这种情况多数不是docker的问题而是磁盘IO瓶颈。如果导入到网络存储或者机械硬盘几个GB的文件解压会花很长时间。判断是否卡死的办法是iostat看磁盘IO是否持续在忙如果busy率很高说明还在干活耐心等。另一个问题是导入时空间不足。docker load会把镜像所有层解压到数据目录临时需要的空间大致是镜像包大小的2倍。所以确保/var/lib/docker所在分区有足够空间。导入失败还有一种情况是版本兼容问题。用旧版本docker导入新版本docker save的镜像有可能失败。比如docker 19.03导入docker 24.x保存的镜像个别格式可能不兼容。如果你现场docker版本偏老建议在有网机器上save的时候加上--platform linux/amd64参数明确架构并且尽量找和现场docker版本接近的机器做save。6.5 inode耗尽一个容易被忽略的坑前面提过inode问题这里单独说下。docker容器在运行过程中会创建大量文件临时文件、层文件、日志、容器内部文件改动。如果数据目录所在文件系统的inode耗尽即使磁盘空间还有剩余也没法创建新文件。检查inode使用率df -i如果/var/lib/docker所在分区的IUse%接近100%说明inode已经紧张。inode耗尽可能导致各种诡异现象容器文件系统操作报错、docker pull镜像没反应、容器删除也删不掉。现场遇到这种问题除了清理无用容器和悬空镜像外最根本的办法是保证数据目录所在分区格式化的时候指定了足够的inodemkfs.ext4 -i 1024 /dev/sdb1-i 1024表示每1024字节分配一个inode比默认的4096/8192要高很多能容纳更多小文件。这种方式适合数据目录这种会产生大量小文件的场景。7. 实用运维经验与交接建议7.1 镜像清单与版本台账离线环境最大的风险是“不知道现场到底装了啥”。我在交付的时候一定会做一份镜像与版本台账包含以下信息镜像名和tag每个镜像对应的中间件版本部署在哪台机器数据目录挂载位置端口映射情况启动命令或compose文件位置这份台账不光是给客户看的也是给自己留的。隔了几个月再去现场排查问题如果没有台账光靠docker ps反推容器配置效率太低。台账用简单的Markdown表格维护即可不需要上什么专业工具。7.2 备份与恢复虽然容器化部署简化了安装过程但数据备份不能省。MySQL数据备份用mysqldump或者物理备份都行看数据量。我这里更推荐在容器外执行docker exec mysql8 sh -c exec mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --all-databases /backup/mysql_backup.sqlRedis持久化文件直接备份/opt/redis/data目录下的appendonly.aof文件。Kafka的话如果需要备份消息数据直接备份日志目录。但Kafka本身一般用于流式处理消息过一段时间会被消费掉或过期清理备份策略需要业务方参与确定。7.3 与客户/团队的交接说明最后说一句我在多次交付中总结出来的经验离线部署docker和中间件技术难度其实没有特别高真正的价值在于流程和规范。交付的时候给客户一份环境说明文档包含docker和compose版本私有仓库地址和访问方法所有中间件的连接方式IP、端口、账号、密码由客户方保管数据目录位置和备份策略常见问题的应急处理办法这份文档比技术本身更重要。我见过太多人只顾着把docker跑起来结果三个月后客户换了个运维啥都看不懂又得重新排查。项目交接的最终交付物一定是一份能让人独立接手的文档而不只是一堆运行中的容器。至于后续扩展比如把编排方案切换到更完整的容器管理平台、增加监控告警体系、实现中间件配置的自动化巡检这些都是在打好离线容器基础之后的自然演进方向等基础稳定了再逐步推进也不迟。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑