ARTICLE DETAIL

资讯详情

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

银河麒麟V10离线部署Docker:PostgreSQL、Redis与Nginx实战指南

银河麒麟V10离线部署Docker:PostgreSQL、Redis与Nginx实战指南 前阵子接了个内网项目一堆银河麒麟V10的服务器外网一概不通但业务系统急需PostgreSQL存数据、Redis做缓存和分布式锁、Nginx做入口代理。这套东西放在能联网的机器上十分钟就能拉起来一到离线环境就麻烦大了——没有镜像仓库、没有在线Yum源、连启动报错都只能靠经验猜。我花了一周左右把整套离线部署流程彻底跑顺包括Docker引擎安装、镜像搬运、三个服务的编排与初始化以及一堆只有离线环境才碰得到的坑。这篇就把完整过程复现一遍给准备在麒麟系统上做Docker离线部署的朋友做个参考。如果你是运维、实施工程师或者项目上被分到“把环境搞定”这个活的研发同学这篇文章应该能直接帮你省下两三天踩坑时间。里面所有操作我都尽量拆到了“照着敲就能跑”的程度但也希望你别只复制命令稍微看下每步背后的原因后面出问题才知道往哪个方向查。1. 项目背景与整体思路拆解1.1 这个场景难在哪为什么非要用Docker先说结论在麒麟系统上离线部署这三件套Docker基本是最优解。原因是这三样东西的生态依赖太复杂了。比如PostgreSQL要依赖一堆系统库Nginx编译装要gcc、pcre、zlib那一套Redis稍微好点但也要编译工具链。在联网机器上这都不是事Yum源一配全自动搞定可一旦离线每个依赖都要手动找rpm包版本稍微不对就是连环报错。换了Docker之后这些问题全部收敛到了“镜像”这一个载体上。镜像就是整个运行环境的快照包括操作系统基础层、软件本体、依赖库、默认配置全在里面。你只需要在能联网的机器上把镜像准备好搬到内网加载就能得到完全一致的运行环境跟你目标机器上装了什么东西、缺哪个库统统无关。这对麒麟这种不同版本之间差异比较大的系统特别友好——我这次就同时碰到了银河麒麟V10和另一个变体系统底层内核和基础软件都不一样但用Docker之后部署步骤完全一致。还有一个实际的考虑以后升级和回滚会容易得多。你要换PostgreSQL小版本直接在镜像层面操作旧容器一停新容器一起数据卷还挂在宿主机上回滚不过是换回旧镜像再启动的事。比在系统里编译安装、手动管理目录清爽一个量级。1.2 离线部署的整体方案镜像搬运路线离线环境的基本套路就四个字外面备好里面加载。核心是两条数据链第一条是Docker引擎本身的安装包。麒麟系统上通常没有现成的docker-ce你要在联网机器上下载对应架构的rpm包docker-ce、docker-ce-cli、containerd.io、docker-compose-plugin等然后拷进去离线安装。第二条是业务镜像。在联网机器上执行docker pull再用docker save打成tar包压缩后传给内网机器最后docker load加载回本地镜像库。如果内网已经有机房级镜像仓库Harbor、Registry这类可以省掉第二段的人工拷贝直接从内网仓库拉取。但很多项目现场一开始什么都没有所以从tar包起步是最稳妥的也最不依赖外部条件。整个过程我会在后文逐步展开先给出最终的网络拓扑你就明白了一台联网的“制备机”负责下载Docker rpm包、拉取镜像、打tar包、压缩。一台或几台内网“目标机”负责加载tar包、安装Docker、通过Compose启动服务。两者之间靠U盘、移动硬盘或者内网文件传输通道搬数据。1.3 目录规划与端口规划离线环境最怕装完了才发现磁盘不够、数据目录没规划。所以动手之前先把目录定死后面所有挂载都围绕它走。我这次的服务数据统一放在/data下三个组件各占一个子目录/data/postgresPostgreSQL数据目录和初始化脚本目录/data/redisRedis持久化目录/data/nginxNginx配置、证书、日志、站点文件目录端口规划上PostgreSQL占5432、Redis占6379、Nginx对外占80/443另外预留一个8080给内部服务测试用。这些端口在麒麟系统的防火墙里需要预先放行否则容器起来了外面照样访问不了。还有一个容易忽略的点检查磁盘剩余空间。PostgreSQL镜像本身70多MB但数据文件日积月累可能几十个GBRedis的AOF也会持续增长Nginx日志如果不限制大小几个月下来能吃掉大量磁盘。我习惯在部署前执行df -h看一眼并给数据目录留足余量至少20GB可用空间以上再往下走。2. 部署前的环境准备2.1 麒麟系统基础环境检查拿到一台新机器先别急着装花五分钟做一轮基础检查能避开后面至少一半的坑。第一件事是看系统和架构cat /etc/os-release uname -a arch麒麟系统目前常见的版本以 V10 为主CPU 架构可能是 x86_64也可能是飞腾、鲲鹏这类 ARM 架构。这个非常关键因为后面所有东西都要匹配架构Docker 的 rpm 有 x86 和 arm 之分镜像也有amd64和arm64之分二进制形式的 docker-compose 同样要选对平台。如果架构选错轻则提示 “exec format error”重则容器直接起不来。接下来看磁盘、内存和防火墙df -h free -h systemctl status firewalld如果防火墙是开启的先准备好要放行的端口。麒麟系统通常用 firewalldfirewall-cmd --permanent --add-port5432/tcp firewall-cmd --permanent --add-port6379/tcp firewall-cmd --permanent --add-port80/tcp firewall-cmd --permanent --add-port443/tcp firewall-cmd --reload注意如果是在内网且安全策略允许也可以直接关闭防火墙但生产环境不建议这么干。放行具体端口更稳妥也方便后面排查问题。最后检查时间。内网机器经常出现时间不准的问题而时间偏差会直接影响客户端调用、日志分析甚至某些鉴权逻辑。先看date -R如果时间不对而且内网有NTP服务器顺手配置一下chrony或ntpdate。离线环境经常没有外部时间源所以我会让目标机指向内网NTP服务器保证集群内时间基本一致。2.2 离线安装Docker引擎这一步是很多离线部署卡住的第一关。麒麟系统上最常见的安装方式有两种如果现场有内网Yum源并且源里同步了docker-ce相关的包可以直接用yum install docker-ce docker-ce-cli containerd.io安装省心很多。没有内网源的话就用rpm包离线安装。在联网制备机上用yumdownloader或直接去镜像站把docker-ce、docker-ce-cli、containerd.io、docker-compose-plugin这几个包及其依赖全部下载下来拷入内网。依赖包比较多、手动物理拷贝容易漏我的做法是在制备机上建立目录统一存放然后打包分发。到达目标机后先尝试rpm -ivh docker-ce-*.rpm docker-ce-cli-*.rpm containerd.io-*.rpm如果报依赖缺失就继续找缺失的依赖包。也可以在制备机的联网环境里先创建一个完整的rpm目录再用如下一条命令交互式安装让rpm自己解析目录内的依赖顺序rpm -ivh --replacepkgs --replacefiles *.rpm装完Docker之后先别急着启动把守护进程的关键配置写进/etc/docker/daemon.json。离线环境虽然没有镜像加速可配但下面两个参数很实用{ data-root: /data/docker, log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }>systemctl daemon-reload systemctl enable --now docker docker infodocker info能看到Storage Driver、Docker Root Dir确认配置生效即可。如果启动失败别瞎猜直接看日志journalctl -u docker -n 502.3 镜像的离线获取与传递Docker引擎装好之后下一步就是三个镜像的获取。这步在制备机上完成。按照我这次项目的实际体积给出一个推荐的镜像清单服务镜像名版本说明PostgreSQLpostgres14-alpine体积小、够稳定兼容性也广Redisredis7-alpine官方镜像支持主从和哨兵Nginxnginxstable-alpine稳定版rpm包仓库里比较新选alpine后缀的基础镜像有两个好处一是体积小一个镜像几十MBtar包拷起来轻松二是攻击面小离线环境里系统组件越少越省心。当然如果业务依赖某些PostgreSQL扩展或Nginx编译模块就要考虑换更大的镜像或者自己构建这个不在今天的讨论范围。在制备机上依次执行docker pull postgres:14-alpine docker pull redis:7-alpine docker pull nginx:stable-alpine然后打tar包docker save -o pg.tar postgres:14-alpine docker save -o redis.tar redis:7-alpine docker save -o nginx.tar nginx:stable-alpine这里必须强调一下save和export的区别。docker save保存的是整个镜像的完整分层结构load可以无损还原docker export则只能导出容器的文件系统历史分层、环境变量、默认命令全都丢了不适合镜像迁移。我见过有人用export倒腾镜像结果容器起不来还找不出原因最后发现是这一步就错了。tar包传输前我习惯用gzip压缩一下gzip pg.tar传文件前先算个校验值比如md5sum pg.tar.gz到目标机上再算一次对比。内网拷贝偶尔会遇到文件损坏的问题提前校验能少走很多弯路。到达目标机后统一加载docker load -i pg.tar.gz docker load -i redis.tar.gz docker load -i nginx.tar.gz用docker images确认三个镜像都在列表里就说明搬运工作完成了。2.4 docker-compose准备有了镜像之后还要准备容器编排工具。docker-compose能把你手动敲的一大堆docker run参数收敛成一个yaml文件三个服务统一启停升级回滚也方便。项目规模稍微大一点这一步几乎不可省。在制备机上下载对应架构的docker-compose二进制文件在Docker官方GitHub Releases页面能找到有linux-x86_64和linux-aarch64等不同版本拷到目标机后安装mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose chmod x /usr/local/bin/docker-compose docker-compose version如果目标机是ARM架构记得下载docker-compose-linux-aarch64那个文件。如果麒麟系统的Python环境不完整尽量不要用老式的pip install docker-compose方式直接二进制最省事。到此环境层面的准备全部完成下面开始逐个服务部署。3. PostgreSQL离线部署与初始化3.1 镜像选择与docker-compose配置PostgreSQL我选了14-alpine版本不新但足够稳很多业务系统都在用。具体版本号可以根据项目要求调整但基础镜像尽量用postgres官方镜像、alpine变体图的就是体积小、行为一致。写一个完整的docker-compose.yml把三个服务都放进去先看PostgreSQL这段version: 3.8 services: postgres: image: postgres:14-alpine container_name: postgres restart: always environment: POSTGRES_USER: appuser POSTGRES_PASSWORD: 你的强密码 POSTGRES_DB: appdb TZ: Asia/Shanghai PGTZ: Asia/Shanghai ports: - 5432:5432 volumes: - /data/postgres/data:/var/lib/postgresql/data - /data/postgres/init:/docker-entrypoint-initdb.d command: - postgres - -c - shared_buffers256MB - -c - max_connections200 healthcheck: test: [CMD-SHELL, pg_isready -U appuser -d appdb] interval: 10s timeout: 5s retries: 5POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB是官方镜像的初始化入口首次启动数据目录为空时镜像会按这些环境变量自动创建用户、密码和数据库。注意这个初始化只在数据目录为空时执行如果后面你想改数据库密码改环境变量重新创建容器是不会生效的得进去用SQL改。/docker-entrypoint-initdb.d目录里如果放了.sql、.sh文件首次初始化时也会按文件名顺序执行。我习惯把建表、初始化数据这些脚本放在这个目录这样整个库的初始化完全自动化不用容器起来之后再手动导入。3.2 数据持久化与备份恢复PostgreSQL挂了卷之后数据就在宿主机/data/postgres/data下。这样容器删了、镜像换了数据都还在是生产环境的基本要求。关于备份恢复容器化之后反而更简单了。日常逻辑备份用pg_dumpdocker exec postgres pg_dump -U appuser -d appdb -F c -f /tmp/appdb.dump docker cp postgres:/tmp/appdb.dump ./恢复时反过来docker cp appdb.dump postgres:/tmp/ docker exec postgres pg_restore -U appuser -d appdb /tmp/appdb.dump这里我有两点经验想分享。第一备份文件别直接放在容器里用docker cp及时拷出来落盘到宿主机否则容器一删备份全没。第二如果是从老环境迁数据除了导数据还要核对字符集和排序规则。很多旧库用的是en_US.utf8中文环境下面如果有中文排序需求初始化时要注意LC_COLLATE、LC_CTYPE的设置这属于建库之后很难无痛修改的参数宁可一开始就定好。3.3 远程连接与常见坑容器起来后直接在本机连一下docker exec -it postgres psql -U appuser -d appdb能进去说明容器内部没问题。但外部客户端连接时经常会遇到“能ping通却连不上数据库”的情况。两个常见原因一是PostgreSQL默认的pg_hba.conf不一定允许来自宿主机以外的连接。官方镜像默认配置里通常只信任容器网络内的连接你需要额外加一条规则。进到容器数据目录下改echo host all all 0.0.0.0/0 scram-sha-256 /data/postgres/data/pg_hba.conf然后重载配置docker exec postgres pg_ctl reload二是在麒麟系统上如果开了防火墙5432端口要提前放行。这个前面已经说过了。还有个小坑如果你是首次部署发现初始化的用户连不上大概率是环境变量没生效。删除容器、清空数据卷、重新修正compose后再启动一次即可不要手动去改postgres系统表容易把库搞坏。4. Redis离线部署与配置细节4.1 Redis容器创建与基础配置Redis相对简单但要注意的点一个不少。我用的镜像默认没有配置文件所有参数都通过命令行传进去这样反而直观每个参数都写在了明面上。redis: image: redis:7-alpine container_name: redis restart: always command: - redis-server - --requirepass - 你的Redis密码 - --appendonly - yes - --maxmemory - 1gb - --maxmemory-policy - allkeys-lru - --bind - 0.0.0.0 - --protected-mode - yes ports: - 6379:6379 volumes: - /data/redis/data:/data healthcheck: test: [CMD, redis-cli, -a, 你的Redis密码, ping] interval: 10s timeout: 5s retries: 5参数逐个解释一下。requirepass是必须的别嫌麻烦Redis不带密码裸奔内网也容易出问题。appendonly yes开启AOF持久化重启数据不丢。maxmemory和maxmemory-policy一起用给Redis设一个内存上限超过之后用allkeys-lru策略淘汰不常用的key这是最常见的缓存配置。还有一个细节protected-mode默认就是yes但如果你Redis没设密码且绑定了0.0.0.0它反而会拒绝外部连接这是保护机制。设置了密码之后可以正常对外提供服务。容器起来后用带密码的方式验证redis-cli -h 127.0.0.1 -p 6379 -a 你的Redis密码 ping返回PONG就说明通了。4.2 内存策略与生产调优很多人部署Redis就是图个省事密码一设、端口一开就完事。但跑到线上最先爆的就是内存和缓存策略。内存上限这步很关键。如果不设maxmemoryRedis会用尽宿主机可用内存一旦业务量上来整个机器都可能被拖垮。有了上限和淘汰策略Redis才能在内存满时自我约束优先保留热点key。淘汰策略也不是通用的这里给个快速选型参考场景推荐策略说明纯缓存允许丢数据allkeys-lru最常用按访问时间淘汰缓存部分持久数据volatile-lru只淘汰设置了过期时间的key需要严格保证主数据不丢noeviction内存满直接报错不淘汰任何key如果你把Redis既当缓存又当分布式锁存储用那要小心。锁的key如果被LRU淘汰掉了其他节点会认为锁已释放可能同时进入临界区。这种场景最好给锁的key设置较长的过期时间或者把锁key标记为volatile-lru策略下的持久key不设过期时间就不参与淘汰。关于分布式锁很多项目都在用Redis实现方式就是一条命令SET lock:order:123 unique_value NX PX 30000NX保证只有key不存在时才能设置成功PX 30000设置30秒过期防止持有锁的进程挂掉后死锁。释放锁时不能简单用DEL因为可能把别人新拿到的锁删了要用Lua脚本保证原子性if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end把获取锁时的unique_value带进去验证只有值匹配才删除这样才是安全的。4.3 Redis连接超时等常见问题热搜关键词里有一条“redis command timed out”这几乎是接入Redis后必遇的报错。我总结过原因90%出在三个地方一是网络和防火墙层面。客户端到Redis之间的网段不通、防火墙拦截或者Redis绑定的地址不对都会导致连接超时。先redis-cli -h 服务器IP -p 6379 ping验证链路。二是客户端配置不当。很多Java项目用Spring Boot默认的Lettuce连接池如果连接池太小高并发下线程等不到连接就会报超时。可以在配置文件里调大连接池并设置合理的读取超时spring: redis: timeout: 3000ms lettuce: pool: max-active: 50 max-idle: 20 min-idle: 5三是Redis本身阻塞。内存不够触发大量淘汰、AOF重写、慢查询堆积都会让Redis响应延迟。用redis-cli --latency测一下再用SLOWLOG GET 10看一下慢命令基本能定位。缓存治理方面日常被问到最多的三个问题我顺手也说一下缓存穿透缓存里没有、数据库也没有请求全部打到DB可以在接口层做参数校验或者把空值也缓存起来但过期时间要短缓存击穿某个热点key刚好过期大量请求同时打到DB可以在缓存重建过程加互斥锁缓存雪崩大量key同时过期导致DB压力暴增解决办法很简单给key的过期时间加一个随机延时让过期时间分散开。5. Nginx离线部署与配置实战5.1 容器化部署与配置挂载Nginx的容器化部署核心是配置目录的挂载。官方镜像默认配置在/etc/nginx下主配置是nginx.conf站点配置在/etc/nginx/conf.d。替换配置时我强烈建议你在宿主机维护一套配置只挂载目录而不直接改容器内部文件这样升级镜像、重建容器时配置不会丢失。nginx: image: nginx:stable-alpine container_name: nginx restart: always ports: - 80:80 - 443:443 - 8080:8080 volumes: - /data/nginx/conf.d:/etc/nginx/conf.d - /data/nginx/certs:/etc/nginx/certs - /data/nginx/logs:/var/log/nginx - /data/nginx/www:/usr/share/nginx/html挂载目录建好之后先把宿主机目录结构准备好再启动容器。一个坑是文件权限。如果宿主机某个文件权限是root容器内Nginx worker以nginx用户运行可能读不了表现为页面403或日志报权限错误。这时把需要Nginx读取的文件权限设为644目录设为755即可。如果麒麟系统开了SELinux还可能需要给挂载目录打chcon -Rt svirt_sandbox_file_t /data/nginx标签。启动后验证docker exec -it nginx nginx -t docker logs nginx | tail -20日志目录挂载好后访问日志和错误日志都会写在宿主机排查问题非常方便。5.2 反向代理、负载均衡与SSLNginx最常见的用途就是反向代理。下面这个配置是典型的“前端入口代理后端服务”场景upstream backend_app { server 192.168.10.11:8080; server 192.168.10.12:8080; } server { listen 80; server_name app.example.com; location / { proxy_pass http://backend_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }upstream定义一组后端服务器Nginx默认按轮询策略分发请求两台机器就轮流接天然实现负载均衡。proxy_set_header这些头很重要后端程序要拿客户端真实IP就靠它们少了的话所有请求在业务日志里都是Nginx容器的IP排查问题会非常痛苦。HTTPS配置也不复杂但有几个坑很典型server { listen 443 ssl; server_name app.example.com; ssl_certificate /etc/nginx/certs/app.example.com.pem; ssl_certificate_key /etc/nginx/certs/app.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; }热搜词里那条net::ERR_CERT_COMMON_NAME_INVALID我见到过无数次。这个错误本质是证书里的域名和你浏览器访问的域名对不上。自签证书必须把CN或SAN字段设置成实际访问的域名或IP。尤其要访问IP时证书里必须包含IP类型的SAN只写CN是不行的。如果现场没有正规证书用openssl临时生成一张自签证书做测试没问题但生产环境还是建议走正规证书或者内网CA。修改Nginx配置一定要养成先检查再reload的习惯docker exec nginx nginx -t docker exec nginx nginx -s reload5.3 location工作流与多站点多端口Nginx的location匹配规则是很多人的薄弱点但非常值得搞懂因为排错时它直接决定请求走到了哪个服务。优先级从高到低大概是精确匹配^~前缀匹配命中后不再检查正则~或~*正则匹配按配置文件中的顺序普通前缀匹配举几个实际例子# 健康检查精确匹配不会与其他规则混淆 location /health { return 200 ok; } # API接口全部走这组后端 location ^~ /api/ { proxy_pass http://backend_api; } # 静态资源后缀匹配正则带浏览器缓存 location ~* \.(js|css|png|jpg)$ { expires 7d; add_header Cache-Control public; }如果开发环境需要在本地通过“自定义域名多端口”的方式调试多个站点Nginx容器化也很好办。在conf.d下建多个配置文件每个文件里一个或多个serverlisten 8080server_name dev1.locallisten 8081server_name dev2.local然后在开发机的hosts文件里把dev1.local、dev2.local指到服务器IP浏览器直接访问http://dev1.local:8080就能调到对应站点。这个方案不仅适用于容器里的Nginx本地虚拟机或者开发机上的Nginx同样适用是排查前端跨域、后端环境切换的一把好手。6. 常见问题排查与避坑实录6.1 系统重启后服务如何自恢复这应该是离线部署最容易被忽略的点了。部署完一切正常结果机房断电重启之后三个容器一个都没起来原因是启动策略没配置。compose里restart: always就干这个用的容器非主动停止时Docker会在重启后自动拉起它。如果你手头已经有一些docker run启动的存量容器不想重新编排也可以这样补救docker update --restart always 容器名另外提醒一句Docker服务本身也要设开机自启。前面安装时执行过systemctl enable docker如果当时没做重启后Docker服务没起来容器自然也不会启动。可以检查一下systemctl is-enabled docker6.2 容器日志膨胀与数据目录迁移Nginx访问日志、PostgreSQL慢查询日志跑上几个月非常可观。之前我在daemon.json里配置了max-size100m、max-file3这是Docker层面统一限制容器日志文件的轮转只针对容器stdout日志不影响应用自己写到挂载目录的日志文件。所以分类处理容器标准输出日志靠Docker的log-opts限制挂载目录里的应用日志由应用自行轮转。Nginx官方镜像自带logrotate不太方便启用最简单方案是定期用crontab把旧的访问日志压缩归档或者按天分割。PostgreSQL的日志默认写到pg_log目录同样需要关注。如果某天磁盘真的满了先定位大目录du -sh /var/lib/docker du -sh /data/*找到占用大户后再决定是清理日志还是迁移数据目录。迁移Docker根目录比较折腾所以我才建议一上来就把>ss -tlnp | grep 5432 netstat -tlnp | grep 5432如果端口被占了要么停掉旧服务要么把容器的宿主机端口映射换成一个不冲突的端口。改端口记得把防火墙规则一起带上。SELinux是个玄学问题。之前提过如果麒麟系统开了SELinux挂载目录的上下文不对容器内可能读不到宿主机文件表现为“明明挂在容器里有文件应用却看不到”。遇到这种情况要么给目录打正确标签chcon -Rt svirt_sandbox_file_t /data/nginx要么临时把SELinux设为宽容模式确认是不是它的问题setenforce 0但setenforce 0重启后会恢复要彻底关闭得改/etc/selinux/config。非必要不建议关先确认根因再说。时间同步的问题前面提过这里再强调一次。离线内网环境没有NTP外网源一定要让目标机指向内网的NTP服务器。很多调用方报“时间戳不合法”或者认证失败最后都是两边时间差了几分钟导致的。6.4 关于Docker启动失败和相关报错的快速判断有两条热搜词让我印象很深都是和Docker Desktop启动失败相关的报错类似“virtualization support not detected”这样。这里我要澄清一下Docker Desktop是给桌面系统用的带虚拟化组件的工具和我们在麒麟服务器上用的CLI版Docker完全是两回事。服务器上装的docker-ce直接跑在Linux内核上不需要单独开启嵌套虚拟化。如果你是在麒麟桌面系统上尝试装Docker Desktop之类的东西那才需要去检查BIOS/固件里是否开启了虚拟化虚拟机里还要开CPU嵌套虚拟化。如果是docker-ce本身启动失败排查路径很固定systemctl status docker journalctl -u docker -n 50 docker info 21看日志里有没有配置文件报错、网络冲突、磁盘空间不足等线索。我遇到过最常见的一种是daemon.json格式出问题导致Docker起不来比如结尾多逗号、配置项写错。改完记得systemctl daemon-reload再重启。还有一个很多人忽略的问题镜像加载后启动容器时报“no space left on device”。这不一定是真的磁盘满了也可能是inode耗尽了。用df -i /看一下inode使用率如果100%即使还有空闲磁盘也写不进文件。清理大量小日志文件或临时文件可以释放inode。下面把这段时间踩过的典型问题整理成速查表方便大家直接对号入座现象可能原因处理方式容器启动后立即退出数据目录权限、配置错误docker logs 容器名看报错docker命令提示找不到daemon服务未启动systemctl start docker宿主机访问不到PostgreSQL防火墙未放行、pg_hba.conf未配放行5432端口追加host规则redis-cli ping报NOAUTH密码未带redis-cli -a 密码 pingNginx配置改后reload报错语法错误nginx -t先检查浏览器访问报证书不匹配证书CN/SAN与域名不符重新生成匹配证书容器重启后数据丢失未挂载数据卷compose里补volumes镜像加载后无法运行架构不匹配确认镜像平台与CPU架构一致日志把磁盘写满未限制日志大小daemon.json配置log-opts系统重启后容器不启动restart策略未设置docker update --restart always最后再分享一个我这次部署下来最大的体会离线环境其实不可怕可怕的是没有一套固定的物料准备清单。如果你也经常做这类部署建议把“制备机准备的包、镜像清单、校验值、目标机的操作步骤”整理成一个标准文档每次按文档走能少踩一半的坑。我后面就打算把Compose文件里的参数继续模板化再补一个一键初始化的脚本让下次交付时直接把文档丢给现场就能跑起来。
返回列表