docker compose 中 depends_on 仅控制启动顺序,不确保依赖服务端口就绪;java 应用需配合健康检查、重试机制、显式 jvm 内存参数及 dns 优化才能稳定运行。

docker-compose.yml 里 depends_on 不保证服务已就绪
Java 应用启动慢,常因数据库或 Redis 还没 ready 就急着连,直接报 Connection refused 或 java.net.ConnectException。但 depends_on 只控制容器启动顺序,不等目标容器的端口监听成功。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 改用健康检查 +
condition: service_healthy,在依赖服务的depends_on中显式声明 - Java 客户端侧加重试逻辑(如 Spring Boot 的
@Retryable或 HikariCP 的connection-init-sql+initialization-fail-timeout) - 临时调试可用
sh -c 'until nc -z db 5432; do sleep 2; done'放在 Java 服务的command前(仅限开发环境)
Java 进程在容器里被 OOM Killer 杀掉,但 docker stats 显示内存远未超限
根本原因是 JVM 默认堆大小未限制,容器内 Java 进程会按宿主机内存估算堆上限(比如宿主机 64G,JVM 可能自动设 -Xmx16g),而 Docker 内存限制(mem_limit)只管 RSS,JVM 堆外内存(Metaspace、Direct Buffer、线程栈)也会吃掉大量内存,触发 OOM Killer。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 必须显式设置 JVM 参数:
-Xmx512m -XX:MaxMetaspaceSize=256m -XX:+UseContainerSupport(JDK 8u191+ / JDK 10+ 自动识别 cgroup) - Docker Compose 中配
mem_limit和mem_reservation,避免突发内存争抢 - 验证是否生效:进容器执行
java -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxMetaspaceSize"
多个 Java 服务共用同一网络,spring.profiles.active 配置被覆盖或读错
常见于用 environment 字段传配置时,YAML 缩进错误或值未加引号,导致布尔/数字被 YAML 解析为其他类型(如 dev 变成布尔值 true),或环境变量名冲突(如两个服务都设了 SPRING_PROFILES_ACTIVE)。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 所有 profile 值用单引号包裹:
SPRING_PROFILES_ACTIVE: 'integration' - 优先用
env_file管理各服务独立配置,避免environment块堆积 - Java 启动时加
-Dspring.debug=true,查日志确认实际激活的 profile 是否符合预期 - 网络内服务发现若用 hostname,确保
container_name和spring.application.name不同名,否则 Eureka / Nacos 注册可能混乱
本地构建镜像后,docker-compose up 启动慢,Java 类加载卡在 sun.misc.URLClassPath
本质是容器内 DNS 解析异常,JVM 在类加载时尝试反向解析 JAR 包来源 URL 的 host,而默认 Docker DNS(8.8.8.8 或宿主机 DNS)在私有网络或离线环境下不可达,造成秒级阻塞。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 在
docker-compose.yml的 Java 服务下加dns配置,指向可靠 DNS(如114.114.114.114)或宿主机网关 - 启动参数加
-Dsun.net.inetaddr.ttl=30 -Dnetworkaddress.cache.ttl=30降低 DNS 缓存失败影响 - 更彻底方案:构建镜像时在
Dockerfile中写入/etc/java-*/security/java.security,设networkaddress.cache.ttl=30
真正麻烦的是 JVM 的容器适配细节——它不像 Node 或 Python 那样默认“懂” cgroup,很多行为要靠参数硬掰。参数漏一个,就可能在测试环境跑得好好的,一上 CI 就挂。










