Docker MySQL - can't connect from Spring Boot app to MySQL database

16,330

Solution 1

Try this docker-compose.yml:

version: '3'
services:
  workaround-mysql:
    container_name: workaround-mysql
    image: mysql
    environment:
      MYSQL_DATABASE: workaround
      MYSQL_USER: springuser
      MYSQL_PASSWORD: admin
      MYSQL_ROOT_PASSWORD: admin
      MYSQL_ROOT_HOST: '%'
    ports:
      - "3308:3306"
    restart: always
  workaround:
    depends_on: 
      - workaround-mysql
    restart: always
    # will build ./docker/workaround/Dockerfile
    build: ./docker/workaround
    working_dir: /workaround
    volumes:
      - ./:/workaround
      - ~/.m2:/root/.m2
    expose:
      - "8080"
    command: "mvn clean spring-boot:run"

And update your application.properties to use the next JDBC connection url:

spring.datasource.url=jdbc:mysql://workaround-mysql:3306/workaround?serverTimezone=UTC&max_allowed_packet=15728640

It should work when both containers in the same docker-compose file, because docker-compose creates default network for containers, so they can resolve each other by name.

Solution 2

What you haven't tried so far is running both containers on the same Docker network.

First, forget about IP addressing - using it should be avoided by all means.

Second, launch both compose instances with the same Docker network.

Third, do not expose ports - inside bridge network all ports are accessible to running containers.

  1. Create global network

     docker network create foo
    
  2. Modify both compose files so that they use this network instead of creating each one its own:

     version: '3.5'
     services:
    
     ....
    
     networks:
       default:
         external: true
         name: foo
    
  3. Remove expose directives from compose files - inside one network all ports are exposed by default

  4. Modify connection strings to use default 3306 port instead of 3308

  5. Enjoy

Solution 3

In order for the service to connect with MySql through docker it has to be in same network, look into Docker network

But for better solution I would suggest you to write a single docker compose file for MySql and Spring boot.The reason is it will easily be linked when you do that.No need any other configuration.

version: "3"
services:
  mysql-service:
    image: mysql
    ports:
      - "3306:3306"
    environment:
      - MYSQL_DATABASE=db
      - MYSQL_USER=root
      - MYSQL_PASSWORD=pass
      - MYSQL_ROOT_PASSWORD=pass
  spring-service:
    image: springservce:latest
    ports:
      - "8080:8080"
    depends_on:
      - mysql-service

Share:
16,330

Related videos on Youtube

Tomas Bisciak
Author by

Tomas Bisciak

Java programmer ,CS bachelors degree from the University of Ss. Cyril and Methodius in Trnava. Constantly trying to improve my skills :) I welcome edits to my answers/questions.

Updated on September 27, 2022

Comments

  • Tomas Bisciak
    Tomas Bisciak over 1 year

    What I'm trying to do is, connect from my spring-boot app to mysql database in Docker. Each in their own container.

    But I must be having something wrong because I can't do it.

    To keep it simple :

    application-properties :

    # URL for the mysql db
    spring.datasource.url=jdbc:mysql://workaround-mysql:3308/workaround?serverTimezone=UTC&max_allowed_packet=15728640
    # User name in mysql
    spring.datasource.username=springuser
    # Password for mysql
    spring.datasource.password=admin
    #Port at which application runs
    server.port=8080
    

    docker-compose for MySQL:

    version: '3'
    services:
      workaround-mysql:
        container_name: workaround-mysql
        image: mysql
        environment:
          MYSQL_DATABASE: workaround
          MYSQL_USER: springuser
          MYSQL_PASSWORD: admin
          MYSQL_ROOT_PASSWORD: admin
          MYSQL_ROOT_HOST: '%'
        ports:
          - "3308:3306"
        restart: always
    

    So pretty simple right ? Database I start with docker-compose up:

    enter image description here

    All seems to be working fine so far.

    Now that I have db started, to the application, this is its docker-compose.yml:

    version: '3'
    services:
    
      workaround:
        restart: always
        # will build ./docker/workaround/Dockerfile
        build: ./docker/workaround
        working_dir: /workaround
        volumes:
          - ./:/workaround
          - ~/.m2:/root/.m2
        expose:
          - "8080"
        command: "mvn clean spring-boot:run"
    

    For its Dockerfile I use Linux Alpine and Java.

    FROM alpine:3.9
    ....add java...
    RUN apk update
    RUN apk add dos2unix --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/community/ --allow-untrusted
    RUN apk add bash
    RUN apk add maven
    

    Super simple. Now let's start the application :

    enter image description here

    enter image description here

    enter image description here

    Unknown host, so let's try the IP then :

        docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' workaround-mysql
    
    # URL for the mysql db
    spring.datasource.url=jdbc:mysql://172.20.0.2:3308/workaround?serverTimezone=UTC&max_allowed_packet=15728640
    

    Now I get timeout:

    enter image description here

    As you can see I get error. What is wrong with my setup and how to fix this? Either I have unknown host exception or Refused to connect or connection timeout.

    I have tried:

    Notes:

    • I run this all on one computer I use port 3308 because I have local MySQL db at 3306.

    • Here is docker ps -a

    enter image description here

    @Vusal ANSWER output :

    enter image description here

    Only thing different from code in answer I did wait for database to be ready 30 seconds

    command: /bin/bash -c "sleep 30;mvn clean spring-boot:run;"
    
    • Tomas Bisciak
      Tomas Bisciak almost 5 years
      @M.Deinum Still getting error Connection refused even when they are on same network
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    I will try it out
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Will try it out
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Bud if i remove use of 3308 I will clash with 3306 that i have running locally already (mysql database) that i test with from intellij ? Right?
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    services.workaround-mysql.networks.default contains unsupported option: 'external' and services.workaround-mysql.networks.default contains unsupported option: 'name'
  • grapes
    grapes almost 5 years
    Put version: '3.5' or later at the top of yaml files
  • grapes
    grapes almost 5 years
    "Bud if i remove use of 3308 I will clash with 3306 that i have running locally already (mysql database) that i test with from intellij ? Right?" No, you wont. 3306 will exist only inside network foo and will NOT be available outside. As far as I understood, you connect to db from another container, not from host. If I am wrong and you also need to connect from host, you will need to expose ports
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Ok so after I have used code you send me , I have Caused by: java.net.ConnectException: Connection refused (Connection refused) I already had that before when i tried this approach. No success, Will update question with full output
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Updated question with output to your answer.
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Tried version 3.5 and 3.7 still getting unsupported option on external keyword (when i do docker-compose build)
  • grapes
    grapes almost 5 years
    docker-compose --version?
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    docker-compose version 1.23.2, build 1110ad01
  • Avi
    Avi almost 5 years
    The jdbc url in application.properties should be something like this "url=jdbc:mysql://mysql-service:3306/db" (In docke-compse.yml, I have mentioned my service name as 'mysql-service' and DB name as 'db' that's why have used the same value in the URL ).Same goes for username and password
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    I will test since i still used that 3308 , I will change it to 3306 and see if it changes from connection refused
  • Avi
    Avi almost 5 years
    @TomasBisciak, for you reference github.com/aviu95/user_mgt look into the code
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    Yes i made it work! Your answer was pretty close to what accepted answer is . Pretty much same, so thank you so much also!!
  • grapes
    grapes almost 5 years
    I've double checked this syntax, can you verify you have no misspellings and correct tabulation? Note - networks directive is GLOBAL, not related to any particular service
  • Tomas Bisciak
    Tomas Bisciak almost 5 years
    My fault didnt have it global ;) I have put it under service so that might be the case .Either way problem is solved by info in your answer will probably be used to further refine what i have now :D awesome