Docker上生产:从镜像到升级的16项设置
Linux系统 2026-11-08 20:43 0

Docker 上手十分钟,上生产却常常踩一串坑:容器重启后数据没了、日志把磁盘写满、容器里的时间比宿主机慢八小时、一个容器跑满 CPU 把整台机器拖死、升级个镜像服务断了两分钟。这些都不是 Docker 的 bug,而是默认配置面向开发环境,生产环境需要另设一遍。

下面 16 项按「镜像 → 运行 → 网络 → 存储 → 日志 → 资源 → 监控 → 升级」排,每条说清楚为什么要设、怎么设、不设会出什么问题。命令以 Docker 20.10+ 与 Compose v2 为准。

镜像层:先解决「不可复现」

  • 1. 基础镜像锁版本。FROM php:8.2-fpm 会随上游更新漂移,某天重建镜像突然跑不起来。用带小版本的 tag,或者用 digest:FROM php:8.2.13-fpm@sha256:...。
  • 2. 别用 latest。生产用 latest 等于把上线时间交给上游。内部自建镜像用「日期+commit」命名,能追溯。
  • 3. 多阶段构建。编译依赖留在 builder 阶段,最终镜像只拷产物。Node 项目从 1.2G 降到 150M 是常见的。
  • 4. 非 root 运行。USER app,配合 chown 改目录权限。容器里跑 root 的用户逃逸风险高得多,而且挂载卷写出的文件在宿主机上属于 root,后期很麻烦。
  • 5. 时区与 locale 写进镜像。ENV TZ=Asia/Shanghai + 安装 tzdata。这是「日志时间差 8 小时」的唯一根治办法,别在应用里硬编码偏移。

运行层:让容器像个正经服务

  • 6. 重启策略。生产统一 restart: unless-stopped。用 always 的话,你手动停掉的容器重启宿主后会自己起来,容易和运维意图冲突。
  • 7. 只读根文件系统。read_only: true 配合 tmpfs: /tmp,能挡住大部分「容器内被写入 webshell」的攻击。需要写目录就用卷挂出来。
  • 8. 健康检查。healthcheck 里给一个轻量的接口探测,超时 3 秒、重试 3 次。没有健康检查,编排层只知道进程在,不知道服务活没活。
  • 9. 优雅停止。应用要处理 SIGTERM,Compose 里设 stop_grace_period: 30s。默认 10 秒,队列任务或大请求会被硬杀。
  • 10. 不要在容器里跑 cron 兼职。定时任务单独一个容器或用宿主 crontab 调 docker exec。混在一起会让「重启容器」变成「重启定时任务」。

网络层:端口、DNS 与内外隔离

  • 11. 只暴露必要端口,且绑到 127.0.0.1。数据库、Redis 这类只给本机应用用的服务,映射写成 127.0.0.1:6379:6379。0.0.0.0:6379 是公网上被挖矿脚本扫到的最常见入口。
  • 12. 自定义 bridge 网络。用 networks 自建网络,容器间用服务名互访,不要靠 --link,也不要用默认 bridge。默认 bridge 下 DNS 解析不工作,是新手常见的「连不上数据库」原因。
  • 13. MTU 对齐。跨境或走隧道时,MTU 不匹配会导致大包丢失、页面卡住但 ping 正常。宿主机 ip link 看实际 MTU,Docker 用 mtu 覆盖,通常设 1400 或 1450 更稳。

存储层:数据不能跟着容器走

  • 14. 数据全部挂卷,且区分类型。命名卷(named volume)放数据库数据,绑定挂载(bind mount)放配置与代码。容器删了数据还在,这是底线。
  • 15. 备份脚本独立于容器。用宿主 cron 定时 docker exec 跑 dump,再传到异地。备份和容器放在同一块盘上等于没有备份。每月至少演练一次恢复。

还有一个细节:数据库容器的数据目录权限一旦被改错,重启会报 chown: Operation not permitted。改权限前先停容器,别在运行时动。

日志:不设上限就会写满磁盘

这是 Docker 生产环境最高频的故障,没有之一。默认 json-file 驱动不做轮转,一个话多的应用一周能写出几十 G。

  • 16. 全局配日志轮转。/etc/docker/daemon.json 里加:{"log-driver":"json-file","log-opts":{"max-size":"50m","max-file":"3"}},然后 systemctl reload docker。单个容器也可以用 logging 覆盖。
  • 对流量大的服务,直接把 driver 换成 local,压缩存储、性能更好。
  • 应用日志尽量写到 stdout,交给 Docker 收;不要既写文件又写 stdout,会双份占用。
  • 用 docker system df 每周看一眼镜像和卷占用,docker image prune 定期清无标签镜像。

资源限制:一个容器不能拖死整台机器

默认情况下,任何容器都能吃满宿主机的 CPU 和内存。生产必须设上限:

参数作用建议
--memory内存硬上限,超了 OOM Kill按应用实测峰值 ×1.5 设
--memory-swap内存+swap 总上限与 memory 相同,等于禁用 swap
--cpusCPU 配额(折算成核数)0.5–2 之间按业务设
--pids-limit进程/线程数上限200–500,防 fork 炸弹
--ulimit nofile句柄数65535

设了 --memory 之后要观察 OOM 计数:docker inspect --format '{{.State.OOMKilled}}' 容器名。如果频繁为 true,说明上限太低或应用有内存泄漏,别直接调大掩盖问题。

监控:三个指标就够定位

  • 容器状态与重启次数:重启次数突增说明容器在反复崩溃,docker events 能看到原因。
  • 资源使用率:docker stats 的 MEM% 与 CPU%,或接 cAdvisor + Prometheus。关注「接近上限」而不是「当前多少」。
  • 健康检查结果:docker ps 的 STATUS 列会显示 unhealthy,这是最早的业务异常信号。

日志侧建议统一收集(Loki + Promtail 或 ELK),至少要能按容器名 grep 到最近一小时的错误,否则出事只能靠猜。

升级:怎么做到不断服

单机场景下,最实用的做法是「双容器 + 反代切换」:

  • 起 app_v1 与 app_v2,Nginx upstream 指向其中一个。
  • 部署新版时先起 v2,健康检查通过后改 upstream 指向 v2,nginx -s reload。
  • 观察 10 分钟无 5xx 再停 v1。回滚只需把 upstream 改回去,十秒完成。

数据库变更要单独处理:迁移脚本必须向后兼容(先加字段不改旧字段、双写过渡),否则回滚代码时数据库对不上。这一点比容器编排更重要。

一个可直接用的 Compose 骨架

把上面这些落成配置,大致是这样(节选关键项):

  • services.app.image: registry/app:20261108-a1b2c3(锁版本)
  • restart: unless-stopped、read_only: true、tmpfs: ["/tmp"]
  • logging.options.max-size: 50m / max-file: 3
  • deploy.resources.limits: cpus 1.0 / memory 1g、pids_limit: 300
  • healthcheck: test curl -f http://localhost/health、interval 15s、retries 3
  • stop_grace_period: 30s、networks: [backend]
  • 数据库服务只写 127.0.0.1:3306:3306,卷用命名卷,不暴露公网

常见问题

Q:改完 daemon.json 日志轮转,旧日志还在?
轮转只对新建的容器生效。已有容器要重建(docker compose up -d --force-recreate)才会应用新配置。旧的 json 日志文件需要手动清理,注意先停容器再删,否则空间不释放。

Q:容器里时间不对,改了 TZ 还是差 8 小时?
宿主机时间本身可能就有偏差。先 date 看宿主机,再 docker exec 容器 date 对比。宿主机对但容器不对,通常是镜像没装 tzdata;宿主机本身就不对,用 chrony 或 ntpdate 校时。

Q:容器一直在重启,怎么查原因?
docker logs --tail 100 容器名 看退出前最后几行;docker inspect --format '{{.State.ExitCode}}' 看退出码(137 是被杀,1 是应用异常)。看不到日志就临时改成 command: sleep 3600 进去手动跑。

Q:单机 Docker 需要上 Kubernetes 吗?
业务规模在两三台机器以内、团队没有专职运维,Compose + 反代足够,上 K8s 的维护成本远高于收益。等出现「多节点调度」「弹性扩缩」「灰度发布」的真实需求再考虑。

Q:容器被入侵了怎么判断?
三个迹象:镜像里出现不认识的进程(docker top)、CPU 长期 100% 但业务量正常(挖矿)、对外出现异常连接(ss -tnp)。发现后先断网再取证,别直接删容器。

小结

16 项里如果只做四件:锁镜像版本、日志加轮转、资源设上限、数据挂卷并异地备份。这四件能挡住生产环境 80% 的事故。剩下的按需补,尤其是「只读文件系统 + 非 root」这两项安全设置,越早做越省事。

再补一个习惯:任何一次变更前,先用 docker compose config 校验配置,再在测试环境跑一遍。Docker 的问题大多是配置问题,而配置问题几乎都能靠「先看一遍生效后的最终配置」提前发现。

相关阅读:服务器性能自测脚本合集、服务器迁移不丢数据的完整清单、中小企业上云第一步、买服务器前必须测的 5 个指标。

本站深度稿系列:从0搭一个扛得住流量的站:LNMP调优清单、Linux磁盘与IO排查:四类故障的定位路径、Windows服务器加固20项:从账号到离线备份。

Powered by ©智简魔方