Can't dockerize a web app: java.net.ConnectException

I have a web app that uses MySQL. I was hoping to “dockerize” it so that I learn to use Docker and at the same time make my app more “shareable” (anyone could check it out without downloading and setting up a MySQL server). Here’s my attempt:

Step 1. Write Dockerfile

In the project root I created a file called Dockerfile with the following content:

FROM amazoncorretto:17-alpine-jdk

WORKDIR /app

COPY target/spring_bootstrap-0.0.1-SNAPSHOT.jar .

EXPOSE 8080

CMD ["java", "-jar", "spring_bootstrap-0.0.1-SNAPSHOT.jar"]

Step 2. Write docker-compose.yml

I need to have both JDK and a MySQL server components in my container. As I understand, I need a docker-compose.yml file. Here’s what it looks like:

version: '3'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - db
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3307/users_db?useSSL=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: pp_user
      SPRING_DATASOURCE_PASSWORD: pp_user

  db:
    image: mysql:latest
    ports:
      - "3307:3306"
    environment:
      MYSQL_DATABASE: users_db
      MYSQL_USER: pp_user
      MYSQL_PASSWORD: pp_user
      MYSQL_ROOT_PASSWORD: root_password

You might be wondering why it’s 3307. It’s because for some reason 3306 was already occupied (I have no idea why, MySQL server doesn’t seem to be running outside the Docker container)

Step 3. Remove datasource properties from application.properties

# connection properties
#spring.datasource.url=jdbc:mysql://localhost:3306/users_db?useSSL=false&serverTimezone=UTC
#spring.datasource.username=pp_user
#spring.datasource.password=pp_user

Step 4. Clean and package so that I have an up-to-date jar

Step 5. Navigate to the project directory and run docker-compose up

The command produced colossal log output. My MySQL server got up and running, but the project itself failed

the Docker Desktop screenshot showing that MySQL is running, the app has "exited"

This was the killer. Not very informative to me, though

bootstrap_fetch-app-1  | Caused by: java.net.ConnectException: Connection refused
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:547) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
bootstrap_fetch-app-1  |        at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:153) ~[mysql-connector-j-8.0.32.jar!/:8.0.32]
bootstrap_fetch-app-1  |        at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:63) ~[mysql-connector-j-8.0.32.jar!/:8.0.32]
bootstrap_fetch-app-1  |        ... 51 common frames omitted
bootstrap_fetch-app-1  |
bootstrap_fetch-app-1 exited with code 1

What may be the problem? Please let me know if you need more details

Just because you forward a host port to the container you still need to use the original port from another container when you connect internally using the container name. In the connection string you need port 3306 and not 3307. The host port is only for connecting from the host or from another machine if that host port is accessible remotely.

1 Like

Thank you for your feedback! You were right

My problem had to do with these mistakes

1. Not including the properties

I had to reference the docker-compose.yml properties in my application.properties file

spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}

2. Specifying a wrong port

Even though the host port was 3307, I still needed to specify 3306 in my property

# the correct version

version: '3'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - db
    environment:
      # note the change in the following line
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/users_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: pp_user
      SPRING_DATASOURCE_PASSWORD: pp_user

  db:
    image: mysql:latest
    ports:
      - "3307:3306"
    environment:
      MYSQL_DATABASE: users_db
      MYSQL_USER: pp_user
      MYSQL_PASSWORD: pp_user
      MYSQL_ROOT_PASSWORD: root_password

If you want to access the database running inside the Docker container and check that the data is actually modified, you can install MySQL Shell (I used MySQL Installer), run it, and execute something like this

MySQL Shell 8.0.34 
Copyright (c) 2016, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.                                           
Other names may be trademarks of their respective owners.                                                                                                                                                                               
Type '\help' or '\?' for help; '\quit' to exit.                                                                           
MySQL  JS > \connect --mysql -h localhost -P 3307 -u pp_user -p                                                        
Creating a Classic session to 'pp_user@localhost:3307'                                                                  
Please provide the password for 'pp_user@localhost:3307': *******                                                       
Save password for 'pp_user@localhost:3307'? [Y]es/[N]o/Ne[v]er (default No): Y                                          
Fetching schema names for auto-completion... Press ^C to stop.                                                          
Your MySQL connection id is 44                                                                                          
Server version: 8.1.0 MySQL Community Server - GPL                                                                      
No default schema selected; type \use <schema> to set one.                                                               
MySQL  localhost:3307 ssl  JS > \sql                                                                                   
Switching to SQL mode... Commands end with ;                                                                            
Fetching global names for auto-completion... Press ^C to stop.                                                          
Error during auto-completion cache update: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation                                                                                                                 
MySQL  localhost:3307 ssl  SQL > select * from users_db.users;