Communication link failure in Spring boot + Mysql + docker compose

I have a docker compose.yaml file:

version: "3.8"
services:
  mysqldb:
    image: mysql:latest
    container_name: mysql_db
    environment:
      MYSQL_DATABASE: "playground_database"
      MYSQL_USER: "myadmin"
      MYSQL_PASSWORD: "mypassword"
      MYSQL_ROOT_PASSWORD: "mypassword"
    ports:
      - '3306:3306'
    expose:
      - '3306'
    volumes:
      - my-db:/var/lib/mysql
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "myadmin", "-p${MYSQL_PASSWORD}"]
      timeout: 20s
      retries: 10
  rest:
    container_name: rest_playground
    build:
      dockerfile: Dockerfile
    image: spring-boot-playground:latest
    ports:
      - 8080:8080
    environment:
      - DATASOURCE_HOST=mysqldb:3306
      - DATASOURCE_USER=myadmin
      - DATASOURCE_PASSWORD=mypassword
      - DATASOURCE_DB=playground_database
      - SPRING_DATA_SOURCE_URL=jdbc:mysql://mysqldb:3306/playground_database?autoReconnect=true&useSSL=false&createDatabaseIfNotExist=true
    depends_on:
      mysqldb:
        condition: service_healthy
volumes:
  my-db:

While the myysql_db container status is healthy, I am getting:

			"Log": [
				{
					"Start": "2024-01-26T13:51:37.015756294Z",
					"End": "2024-01-26T13:51:37.07978236Z",
					"ExitCode": 0,
					"Output": "Enter password: \u0007mysqladmin: connect to server at 'localhost' failed\nerror: 'Access denied for user 'myadmin'@'localhost' (using password: NO)'\n"
				}
			]

And:

rest_playground  | Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

The database ping never passes, so, the service cannot run. Kindly help out.

You can not use localhost/127.0.0.1 inside a container to connect to another, as that is the localhost within the container, not localhost of the node/host.

Use the service name from docker-compose.yml instead, Docker provides an internal DNS service to resolve that to the container ip.

Thank you for your help. So, within the healthcheck object in docker-compose.yaml, I have renamed localhost to MySQL server service, mysqladmin i.e

healthcheck: test: [ "CMD", "mysqladmin", "ping", "-h", "mysqldb", "-u", "myadmin", "-p${MYSQL_PASSWORD}"]

However, I have the following exception,

"Output": "Enter password: \u0007mysqladmin: connect to server at 'mysqldb' failed\nerror: 'Access denied for user 'myadmin'@'172.18.0.2' (using password: NO)'\n"

If this was not your suggestion to resolve the issue, kindly advise further.

Using localhost in healtchecks that checks the processes in the container is possible, but I don’t see how you set the variable in the healtcheck. The one that you set for the container will not be available there for two reasons.

  1. The variable will be interpreted when the yaml is parsed so it will be empty unless you have an env variable on the host or in a dot env file.
  2. CMD will not run a shell so you won’t have environment variables even if you pass the variable correctly. CMD-SHELL would run the commands in the container’s default shell: Services top-level elements | Docker Docs

The error message is pretty clear by the way: “using password: NO”. Since you intended to pass a password, that should have been suspicious.

If you want the variable to be passed to the shell (using CMD-SHELL), you can use a double dollar like this:

test: [ "CMD-SHELL", "mysqladmin", "ping", "-h", "localhost", "-u", "myadmin", "-p$${MYSQL_PASSWORD}"]

If you use a recent version of Docker Compose and you didn’t set a variable on the host or in a dot env file, you should have gotten a warning saying the environment variable is not set.

@bluepuma77, @rimelek . I appreciate your help. So, this configuration sort of worked. I added database configs from application.properties into the environment properties of the service container in JSON format.

version: "3.8"
services:
  rest:
    container_name: rest_playground
    build:
      dockerfile: Dockerfile
    image: spring-boot-playground:latest
    ports:
      - 8080:8080
    environment:
      SPRING_APPLICATION_JSON: '{
        "spring.datasource.url": "jdbc:mysql://mysqldb:3306/playground_database?useSSL=false&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true",
        "spring.datasource.username": "myadmin",
        "spring.datasource.password": "mypassword",
        "spring.jpa.properties.hibernate.dialect" : "org.hibernate.dialect.MySQL8Dialect",
        "spring.jpa.hibernate.ddl-auto" : "create"
      }'
    depends_on:
      mysqldb:
        condition: service_healthy
    networks:
      - playground-network
  mysqldb:
    image: mysql:latest
    container_name: mysqldb
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=playground_database
    ports:
      - '3306:3306'
    expose:
      - '3306'
    volumes:
      - my-db:/var/lib/mysql
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "mysqldb", "-u", "root", "-p$${MYSQL_ROOT_PASSWORD}"]
      timeout: 20s
      retries: 10
    networks:
      - playground-network
volumes:
  my-db:
networks:
  playground-network: