dockerdocker-composedeployment

how to fix "communications link failure the last packet sent successfully to the server was 0 milliseconds ago"


Hello I am trying to deploy a Spring Boot application using docker-compose. However, while running the file with the docker-compose up -d command, the following error occurred. I have created a project directory inside my EC2 instance, and a docker-compose.yml file exists within that directory. They say it's an issue with the MySQL connection, but I can't figure out what's wrong. The Spring Boot app container is running fine, and I want to deploy my application.

ERROR 1 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. 2025-01-04T21:16:36.993+09:00 WARN 1 --- [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata

org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.] [n/a] at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:100) ~[hibernate-core-6.6.4.Final.jar!/:6.6.4.Final] . . . Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

Below are the docker-compose.yml and application.yml files I have written. The actual values have been replaced with 'test'.

//docker-compose.yml

version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: testdb
      MYSQL_ROOT_PASSWORD: testpassword
    volumes:
      - mysql-vl:/var/lib/mysql
    networks:
      - test-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

  redis:
    image: redis:latest
    container_name: redis
    ports:
      - "6379:6379"
    volumes:
      - redis-vl:/data
    networks:
      - test-network

  app:
    image: test/myimage:latest
    container_name: test
    ports:
      - "8080:8080"
    environment:
      DB_URL: mysql
      REDIS_HOST: redis
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - test-network
    environment:
      DB_URL: mysql
      REDIS_HOST: redis

volumes:
  mysql-vl:
    driver: local
  redis-vl:
    driver: local

networks:
  test-network:
    driver: bridge
//application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: testpassword
    url: jdbc:mysql://${DB_URL:localhost}:3306/testdb?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      show_sql: true
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
  data:
    redis:
      port: 6379
      host: ${REDIS_HOST:localhost}

jwt:
  secret-key: secretkey
  access-exp: 7200000
  refresh-exp: 604800000

When I run it afterward, the Redis and MySQL containers start without any issues. Please help me figure out what the problem might be. Please help me!!!!


Solution

  • The DB_URL environment variable is set to mysql, and your application.yml uses it to construct the JDBC URL. This should work because Docker Compose services in the same network can communicate using their service names. However, ensure that The mysql service is running and healthy. The DB_URL environment variable is correctly passed to the container running your Spring Boot app.Add the following environment section to your docker-compose.yml for the app service:

    environment:
      DB_URL: mysql
      REDIS_HOST: redis
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydb?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: password
    

    Update your application.yml to rely on these environment variables directly:

    spring:
      datasource:
        url: ${SPRING_DATASOURCE_URL}
        username: ${SPRING_DATASOURCE_USERNAME}
        password: ${SPRING_DATASOURCE_PASSWORD}
        driver-class-name: com.mysql.cj.jdbc.Driver
    

    The MySQL container may not be ready to accept connections when your Spring Boot application starts, even if the health check passes. Add a startup delay to your application to ensure the database is fully ready before trying to connect. Modify the depends_on section in the docker-compose.yml file to include a condition for MySQL's readiness:

    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    

    Alternatively, you can also use a retry mechanism in your Spring Boot application or an entrypoint script to wait until MySQL is accessible.

    The health check for MySQL in your docker-compose.yml checks if MySQL is alive but does not confirm that it is ready to accept connections. Replace the health check with one that waits for MySQL to be fully initialized:

    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost --silent"]
      interval: 10s
      timeout: 20s
      retries: 10