Docker构建SBT应用及docker-compose下MySQL主机名解析故障排查
问题描述
使用以下docker-compose.yml配置,JDBC连接串中使用了服务名clear_mysql,但应用无法解析该主机名。
docker-compose.yml配置
version: "3.9" services: clear_api: build: context: . dockerfile: Dockerfile ports: - "8080:8080" restart: "always" depends_on: - clear_mysql - clear_redis links: - clear_mysql - clear_redis clear_mysql: image: mysql:5.7 command: --default-authentication-plugin=mysql_native_password restart: always ports: - 3306:3306 volumes: - ./docker/mysql/data:/var/lib/mysql - ./scripts/initialize.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: root clear_redis: image: "redis" restart: unless-stopped ports: - 6379:6379 volumes: - ./docker/redis_local:/data
使用的JDBC连接串
"jdbc:mysql://clear_mysql/cleardb?useSSL=false"
错误信息
#0 120.9 [error] Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure #0 120.9 [error] The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. #0 120.9 [error] at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) #0 120.9 [error] at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78) #0 120.9 [error] at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) #0 120.9 [error] at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) #0 120.9 [error] at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) #0 120.9 [error] at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61) #0 120.9 [error] at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105) #0 120.9 [error] at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151) #0 120.9 [error] at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167) #0 120.9 [error] at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:89) #0 120.9 [error] at com.mysql.cj.NativeSession.connect(NativeSession.java:120) #0 121.0 [error] at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:944) #0 121.0 [error] at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:814) #0 121.0 [error] ... 14 more #0 121.0 [error] Caused by: java.net.UnknownHostException: clear_mysql: Name does not resolve #0 121.0 [error] at java.base/java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method) #0 121.0 [error] at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(InetAddress.java:932)
更新:Dockerfile内容
FROM oarkflow/clear-sbt as api RUN apk update && apk add --no-cache curl ca-certificates unzip coreutils bash WORKDIR /api COPY ./clear-api . RUN sbt publishLocal FROM oarkflow/clear-sbt as service RUN apk update && apk add --no-cache curl ca-certificates unzip coreutils bash WORKDIR /service COPY ./clear-service . COPY --from=api /root/.ivy2/local/com.example/root/.ivy2/localcom.example RUN sbt "runMain clear.service.Local"
解决建议
1. 修正Dockerfile的启动命令
你的Dockerfile在service阶段用RUN启动应用,这会导致应用在镜像构建过程中就开始运行,而此时构建环境并未加入docker-compose的网络,自然无法解析clear_mysql主机名。
把启动命令改成CMD,让应用在容器启动后再运行:
FROM oarkflow/clear-sbt as api RUN apk update && apk add --no-cache curl ca-certificates unzip coreutils bash WORKDIR /api COPY ./clear-api . RUN sbt publishLocal FROM oarkflow/clear-sbt as service RUN apk update && apk add --no-cache curl ca-certificates unzip coreutils bash WORKDIR /service COPY ./clear-service . COPY --from=api /root/.ivy2/local/com.example/root/.ivy2/localcom.example # 替换RUN为CMD,确保容器启动时才运行应用 CMD ["sbt", "runMain", "clear.service.Local"]
2. 移除过时的links配置
docker-compose 3.x版本中,同一compose文件的服务默认会加入同一个网络,服务名可直接作为主机名解析,links属于过时配置,建议移除避免混淆。
3. 增强服务启动的依赖等待逻辑
depends_on仅保证容器启动顺序,但不保证MySQL服务完全就绪。给clear_mysql添加健康检查,让clear_api等MySQL服务可用后再启动:
修改clear_mysql配置:
clear_mysql: image: mysql:5.7 command: --default-authentication-plugin=mysql_native_password restart: always ports: - 3306:3306 volumes: - ./docker/mysql/data:/var/lib/mysql - ./scripts/initialize.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: root healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"] interval: 5s timeout: 5s retries: 5
修改clear_api的depends_on:
depends_on: clear_mysql: condition: service_healthy clear_redis: condition: service_started
4. 补全JDBC连接串信息
你的连接串缺少端口和用户名密码,补充完整可避免额外连接问题:
"jdbc:mysql://clear_mysql:3306/cleardb?useSSL=false&user=root&password=root"
内容的提问来源于stack exchange,提问作者Sujit Baniya
相关产品推荐
相关产品推荐

