跳至正文

Docker部署个破服务,踩了11个坑才跑起来,差点把电脑砸了!

事情是这样的。上周接了个活,要把一个老项目用Docker部署到客户服务器上。本来以为就写个Dockerfile、配个docker-compose.yml,半小时搞定。结果从下午2点搞到凌晨3点,中间至少骂了十句脏话。

先说说环境。项目是Spring Boot 2.3 + Redis + MySQL,本地跑得好好的,一上Docker就各种幺蛾子。服务器是CentOS 7.9,Docker版本20.10.17,docker-compose版本1.29.2。

第一个坑,Dockerfile里写了个FROM openjdk:8-jre-alpine。本地build没问题,push到私有仓库也正常。远程服务器一pull,报错:exec format error。查了半天,发现alpine版本用的是musl libc,和服务器内核有兼容问题。解决办法:换成FROM openjdk:8-jre-slim,底层是Debian,稳得很。

第二个坑,镜像拉下来了,docker run直接卡死。看了下日志,说数据库连不上。我明明在application.yml里配了jdbc:mysql://localhost:3306/db,但容器里的localhost是容器自己,不是宿主机。改成宿主机IP?不行,万一IP变了呢。最后用docker-compose加了个service name,jdbc:mysql://mysql:3306/db,容器间通信靠网络别名。

第三个坑,Redis也一样。配了spring.redis.host=redis,启动后应用报Connection refused。排查发现Redis容器启动比应用慢,应用先启动连不上就挂了。解决方案:在docker-compose.yml里加depends_on,但depends_on只保证启动顺序,不保证服务就绪。又加了healthcheck,应用里再配个重试机制,才算搞定。

第四个坑,文件权限。项目有个上传目录,映射到宿主机/data/uploads。容器里uid是1000,宿主机目录所有者是root,应用写文件直接Permission denied。改chmod 777?不安全。最后在Dockerfile里RUN adduser -D appuser,然后USER appuser,宿主机目录也chown appuser:appuser。

第五个坑,时区。容器默认UTC,项目里一堆时间戳全对不上。Dockerfile里加RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,再ENV TZ=Asia/Shanghai。注意alpine镜像没有tzdata,得先apk add tzdata。

第六个坑,日志。项目用Logback,日志文件写/var/log/app.log。容器里这个目录没挂载出来,容器重启日志全丢。改成挂载宿主机目录,又发现Logback的滚动策略和容器重启时机冲突,日志文件被锁住。最后把日志直接输出到控制台,docker logs看,生产环境用ELK收。

第七个坑,健康检查。Kubernetes没上,就靠docker-compose的restart: always。结果应用OOM了,容器还在跑,但接口全挂。加了个healthcheck,curl -f http://localhost:8080/actuator/health,失败三次就重启。注意Spring Boot 2.3的actuator默认不暴露health端点,得在application.yml里配management.endpoints.web.exposure.include=health。

第八个坑,网络。项目里有个定时任务,要调用外部API。容器里DNS解析有问题,域名解析超时。查了/etc/resolv.conf,发现Docker默认用8.8.8.8,但客户内网必须用内部DNS。在docker-compose.yml里配dns: 192.168.1.1,搞定。

第九个坑,镜像大小。初始Dockerfile没用多阶段构建,一个镜像1.2G,传到客户服务器慢得要死。重构:第一阶段用maven:3.6-jdk-8编译,第二阶段只COPY jar包和运行环境,镜像降到180M。

第十个坑,环境变量。项目里有些配置是硬编码的,比如短信API密钥。当时图省事直接写在application.yml里,推代码时差点泄漏。改成用环境变量注入,Dockerfile里不写,docker-compose.yml里配environment,或者用.env文件。注意Spring Boot读取环境变量的优先级。

第十一个坑,网络代理。客户服务器在内网,不能直接访问Docker Hub。我提前把镜像push到私有仓库,但docker-compose pull还是报错。查了Docker daemon配置,需要加HTTP_PROXY和HTTPS_PROXY。在/etc/systemd/system/docker.service.d/proxy.conf里配好,重启dockerd。

搞完这11个坑,项目终于跑起来了。第二天客户说访问不了,过去一看,防火墙没开端口。这个不算Docker的坑,但够我喝一壶的。

总结一下经验:Docker部署不是写个Dockerfile就完事了。网络、权限、时区、日志、健康检查、镜像大小、环境变量,每一个都能卡你半天。最好在开发环境就模拟生产环境的Docker配置,别等到上线才测试。还有,docker-compose的depends_on别信,healthcheck才是亲爹。最后,日志别往文件写,容器挂了啥都查不到。

坑踩完了,写出来给兄弟们避雷。下次再部署类似项目,先把这个清单翻出来,一个一个对。


📎 延伸阅读

看完这篇,如果你想:

  • 直接拿工具 → 回复”13“,我把跨境获客工具包发给你
  • 系统学习 → 点击菜单”AI训练营”,从0开始跑通AI变现

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注