Microservice can not connect to MySQL running in Docker container - java

I am trying to run my Java microservice locally on MacOs and connect to MySQL db running in Docker container but I get an error:
java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
My docker-compose.yml looks like it:
version: "3.1"
services:
mysql:
image: mysql
container_name: mysql_v.0.1
command: --default-authentication-plugin=mysql_native_password
restart: always
env_file:
- .mysql-dev-env
ports:
- 33060:33060
However I am able to connect to mysql and create dbs trough docker itself with:
docker exec -it mysql_v.0.1
mysql -u root -p
Microservice has such application.dev.yml config:
db:
pool.size.maximum: 30
connection.idle.minimum: 10
widget:
url: jdbc:mysql://localhost:33060/dev_widget_platform?characterEncoding=UTF-8&useUnicode=yes&autoReconnect=true
user: root
password: pass
I am trying to connect to db via MySQL Workbench it has no success too.
Seems like I need to apply some network trick but i am new to docker and MySQl.

Unless you're using SSL locally, add this to the end of your connection string
&useSSL=false
So it becomes
url: jdbc:mysql://localhost:33060/dev_widget_platform?characterEncoding=UTF-8&useUnicode=yes&autoReconnect=true&useSSL=false

Related

Error creating a docker-compose connecting a java and a mysql containers

I am trying to connect the container of my springboot application with the container of a mysql image using docker-compose, however when I run docker-compose up my terminal starts a loop where it starts the spring application, try to connect with the MySQL container, fails and keep trying. The error that I get is com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failures
docker-compose file:
version: '3.8'
services:
mysqldb:
image: mysql
platform: linux/x86_64
env_file: ./.env
restart: always
environment:
- MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- MYSQL_DATABASE=$MYSQLDB_DATABASE
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- db:/var/lib/mysql
app:
depends_on:
- mysqldb
build: .
restart: always
env_file: ./.env
ports:
- $APP_LOCAL_PORT:$APP_DOCKER_PORT
environment:
- DB_HOST=mysqldb
- DB_USER=$MYSQLDB_USER
- DB_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- DB_NAME=$MYSQLDB_DATABASE
- DB_PORT=$MYSQLDB_DOCKER_PORT
stdin_open: true
tty: true
volumes:
db:
.env:
MYSQLDB_USER=root
MYSQLDB_ROOT_PASSWORD=12345678
MYSQLDB_DATABASE=dronefeederdb
MYSQLDB_LOCAL_PORT=3306
MYSQLDB_DOCKER_PORT=3306
APP_LOCAL_PORT=8080
APP_DOCKER_PORT=8080
Application.yaml:
server:
port: 8080
spring:
datasource:
username: ${DB_USER}
password: ${DB_PASSWORD}
url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
jpa:
hibernate:
ddl-auto: update
show-sql: true
open-in-view: false
#https://ia-tec-development.medium.com/lombok-e-spring-data-jpa-142398897733
security.user:
name: dronefeeder
password: dronefeeder
#https://www.baeldung.com/spring-boot-security-autoconfiguration
resilience4j.circuitbreaker:
configs:
default:
waitDurationInOpenState: 10s
failureRateThreshold: 10
#instances:
#estudantes:
#baseConfig: default
Dockerfile:
FROM openjdk:11.0-jdk as build-image
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
FROM openjdk:11.0-jre
COPY --from=build-image /app/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
Repository link:
https://github.com/julia-baptista/dronefeeder/tree/docker-configuration
I believe the issue is your application's use of localhost for the SQL URL in the Application.yaml property file. Since your app runs on a container by itself it tries to look at localhost of the container, while your SQL server is in another container, with its own localhost. Localhost in docker container do not refer to the host, they refer to the localhost within the container itself. If you want to access the host machine, this is an excellent answer From inside of a Docker container, how do I connect to the localhost of the machine?
url: jdbc:mysql://localhost:3306/dronefeederdb
localhost should not be used, you need to use the sql continainer url.
The fastest option is to use host.docker.internal instead of localhost. But it's not the best.
Another quick option is to run the two containers on the same docker network. Define that in your compose file the same way as the volumes. Then set each container to that network. See Networking in Compose. Then you can set your SQL url to use the SQL container name instead of localhost. So this..
url: jdbc:mysql://localhost:3306/dronefeederdb becomes url: jdbc:mysql://mysql/dronefeederdb
Neither option is robust, since you're hardcoding the container name in the application property file. A better solution is to have an environment variable in your webApp image that can accept the URL to the SQL server. Then you can provide the SQL location when running the container, or in your compose file (Environment variables in Compose). This way the SQL server can be anywhere.
Update:
There were a couple of issues in the compose and env files that caused mySQL container to fail startup. Thus the webApp was not able to connect.
Credentials
MYSQL_USER was set to root. mySql already creates the user root. You cannot create it again. I changed that to foo. See the Environment Variables section in the official docker image readme for more.
MYSQL_PASSWORD was not set. This is the password for the user your app will use. I set this to pass!123
The apps DB_PASSWORD was set to user root. That would have been ok if sql had started and it was using the root user I guess. But I changed that to the non-root user since were setting DB_USER=foo
Network was not defined
The two containers need to be on the same "docker network" if they are to run together in docker in the same machine. There's more to this which is beyond my experience. But in this case it needs to be on the same network for app to access mysqldb by its container name. I created dronefeederNet and added each container to it.
Files:
.env
MYSQLDB_USER=foo
MYSQLDB_PASSWORD=pass!123
MYSQLDB_ROOT_PASSWORD=12345678
MYSQLDB_DATABASE=dronefeederdb
MYSQLDB_LOCAL_PORT=3307
MYSQLDB_DOCKER_PORT=3306
APP_LOCAL_PORT=8081
APP_DOCKER_PORT=8080
docker-compose.yml
version: '3.8'
services:
mysqldb:
image: mysql
platform: linux/x86_64
env_file: ./.env
restart: always
environment:
- MYSQL_USER=$MYSQLDB_USER
- MYSQL_PASSWORD=$MYSQLDB_PASSWORD
- MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- MYSQL_DATABASE=$MYSQLDB_DATABASE
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- db:/var/lib/mysql
networks:
- dronefeederNet
app:
depends_on:
- mysqldb
build: .
restart: always
env_file: ./.env
ports:
- $APP_LOCAL_PORT:$APP_DOCKER_PORT
environment:
- DB_HOST=mysqldb
- DB_USER=$MYSQLDB_USER
- DB_PASSWORD=$MYSQLDB_PASSWORD
- DB_NAME=$MYSQLDB_DATABASE
- DB_PORT=$MYSQLDB_DOCKER_PORT
stdin_open: true
tty: true
networks:
- dronefeederNet
volumes:
db:
networks:
dronefeederNet:
Give this a try and I hope it runs. I was able to start it up ok.
You need to add in the app definition block a depends on: sentence, to make docker compose to not boot the application until the database is up.
Check this documentation: Docker Compose Startup Order

Spring boot client doesn't register to Spring admin on docker

Hello to all developers.
I have a problem and I have been struggling with it for a few days but I can not solve it.
The problem is I have two dockerized Spring application, one of them is admin and another is client. When I run these two out of Docker, the client registers with the admin without any problem, and I can see the client from the admin dashboard. But when I try to run these two as two containers in Docker with a Docker network, the client application gives this error:
de.codecentric.boot.admin.client.registration.DefaultApplicationRegistrator: Failed to register application as Application(name=spring client, managementUrl=http://545ade59e8dc:8585/actuator, healthUrl=http://545ade59e8dc:8585/actuator/health, serviceUrl=http://545ade59e8dc:8585/) at spring-boot-admin ([http://localhost:8080/instances]): I/O error on POST request for "http://localhost:8080/instances": Connection refused; nested exception is java.net.ConnectException: Connection refused. Further attempts are logged on DEBUG level
The admin application's docker-compose.yml file:
version: '3.3'
networks:
spring-admin-network:
driver: bridge
services:
spring-admin:
build:
context: .
args:
JAR_FILE: "./target/spring-admin-1.0.0.jar"
image: spring-admin
container_name: spring-admin
ports:
- "127.0.0.1:8080:8585"
networks:
- spring-admin-network
And the client application's docker-compose.yml file:
version: '3.3'
networks:
spring-admin-network:
driver: bridge
services:
repo-reporter:
build:
context: .
args:
JAR_FILE: "./target/spring-client-1.0.0.jar"
image: spring-client
container_name: spring-client
ports:
- "127.0.0.1:8081:8585"
networks:
- spring-admin-network
And application.properies for admin application:
spring.application.name=spring-admin
server.port=8585
spring.security.user.name=admin
spring.security.user.password=admin
And application.properies for client application:
spring.application.name=spring-client
server.port=8585
server.compression.enabled=true
server.http2.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
spring.boot.admin.client.url=http://localhost:8080
spring.boot.admin.client.username=admin
spring.boot.admin.client.password=admin
spring.boot.admin.client.instance.metadata.user.name=${spring.security.user.name}
spring.boot.admin.client.instance.metadata.user.password=${spring.security.user.password}
The commands I execute:
docker network create spring-admin-network
...Some hash...
cd /spring-admin
docker-compose build
...Successfully built...
docker-compose up -d
...Creating network "springadmin_spring-admin-network" with driver "bridge"
Creating spring-admin ... done...
cd ../spring-client
docker-compose build
...Successfully built...
docker-compose up -d
...Creating network "springclient_spring-admin-network" with driver "bridge"
Creating spring-client ... done...
docker logs -f spring-client
.
.
.
de.codecentric.boot.admin.client.registration.DefaultApplicationRegistrator: Failed to register application as Application(name=spring client, managementUrl=http://545ade59e8dc:8585/actuator, healthUrl=http://545ade59e8dc:8585/actuator/health, serviceUrl=http://545ade59e8dc:8585/) at spring-boot-admin ([http://localhost:8080/instances]): I/O error on POST request for "http://localhost:8080/instances": Connection refused; nested exception is java.net.ConnectException: Connection refused. Further attempts are logged on DEBUG level
Thanks in advance.
Docker creates a new docker network when you build and run the docker-compose file. as an example
xxx_spring-admin-network (for admin application)
yyy_spring-admin-network (for client application)
you can check by
docker network ls
First and foremost, you should set up a Docker network.
docker network create spring-admin-network
then make a docker-compose.yml change Both files should point to an existent network.
version: '3.3'
networks:
spring-admin-network:
external: true
...

Postgres container connection refused

Docker-compose with 2 containers. 1st is a Postgres database and 2nd is a Java Spring Boot application. For running, I use further docker-compose config file:
docker-compose.yml
version: "3.7"
services:
db-service:
image: postgres
restart: always
volumes:
- /home/ec2-user/dbdata:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 1
POSTGRES_DB: auth
ports:
- 5432:5432
auth-service:
build: .
restart: always
depends_on:
- db-service
links:
- db-service
ports:
- 80:80
I suppose to use /home/ec2-user/dbdata to containing database data and after all, data is created. successfully. And log of postgres container is:
PostgreSQL init process complete; ready for start
2021-01-07 01:36:16.786 UTC
[1] LOG: starting PostgreSQL 13.1 (Debian 13.1-1.pgdg100+1) on
x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
2021-01-07 01:36:16.786 UTC [1] LOG: listening on
IPv4 address "0.0.0.0", port 5432 2021-01-07
01:36:16.786 UTC [1] LOG: listening on IPv6 address "::", port 5432
2021-01-07 01:36:16.790 UTC [1] LOG: listening on
Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2021-01-07 01:36:16.795 UTC [76] LOG: database system was shut down
at 2021-01-07 01:36:16 UTC 2021-01-07 01:36:16.800
UTC [1] LOG: database system is ready to accept connections
But Java app throws an error:
org.postgresql.util.PSQLException: Connection to 127.0.0.1:5432
refused. Check that the hostname and port are correct and that the
postmaster is accepting TCP/IP connections.
But in port mapping is 5432:5432.
And data source properties into Java app is:
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/auth
spring.datasource.username=postgres
spring.datasource.password=1
What is can be the reason for this error?
It's not working because the java app is pointed to 127.0.0.1 which is local to the java container and postgres is not running in that container.
In your properties file change this line:
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/auth
to
spring.datasource.url=jdbc:postgresql://db-service:5432/auth
Using db-service as the host comes from the name of the service in your docker-compose.yml file. See the docker compose networking page for more information.
Another option, since both containers are linked (as per docker-compose file) is to use localhost (instead of 127.0.0.1) as the DB host in the connection string -> spring.datasource.url=jdbc:postgresql://localhost:5432/auth

Not able to connect to MySQL with Docker container name but can connect with localhost

I am not able to connect to MySQL using Docker container name in connection string but can connect with localhost.
docker-compose:
mysql-docker-container:
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=test
- MYSQL_PASSWORD=test
ports:
- 3306:3306
volumes:
- /data/mysql
app:
image: app
build:
context: ./
dockerfile: Dockerfile
depends_on:
- mysql-docker-container
links:
- mysql-docker-container:mysql-docker-container
ports:
- 9090:9090
volumes:
- /data/p2c-app
environment:
- DATABASE_HOST=mysql-docker-container
- DATABASE_USER=testuser
- DATABASE_PASWORD=testuser
- DATABASE_NAME=test
- DATABASE_PORT=3306
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&allowPublicKeyRetrieval=true
Above works, but I want with container name like below - I am getting CONNECTION REFUSED
spring.datasource.url=jdbc:mysql://mysql-docker-container:3306/test?useSSL=false&allowPublicKeyRetrieval=true
What am I doing wrong?
You can update /etc/hosts if localhost connection works.
127.0.0.1 localhost mysql-docker-container
To check whether mysql-docker-container is reachable from the app container you can open a tty and ping.
docker exec -it app_container_name bash
ping mysql-docker-container
Everything is ok.
It seems the database service is up but the mysql is in the startup process.
And the app service starts up then and can not reach to the database.
There are some workarounds for this situation.
But the simple one is that you add below to app service.
restart: on-failure
And note that depends_on section just means in docker container context not in underlying services.

Docker Compose - Flyway - Unable to obtain Jdbc connection from DataSource

I'm traying to deploy a microserivice and a flyway service with Docker Compose in Ubuntu. The docker-compose.yml looks like this:
version: '2'
services:
mysqldb:
image: mysql:5.6.26
environment:
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: base
ports:
- "3306:3306"
flyway-service-i:
image: mialk/flyway-service
volumes:
- "../resources/db/migration:/migrations/ro"
depends_on:
- mysqldb
links:
- mysqldb
command: migrate -url=jdbc:mysql://mysqldb:3306/base -user=user -password=password -baselineOnMigrate=true - locations='filesystem:/migrations'
service1:
image: my/service
ports:
- "8080:8080"
links:
- mysqldb
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysqldb:3306/base
- SPRING_DATASOURCE_USERNAME=user
- SPRING_DATASOURCE_PASSWORD=password
But when I run the command: sudo docker-compose up, I have this message:
flyway-service-i_1 | ERROR: Unable to obtain Jdbc connection from DataSource (jdbc:mysql://mysqldb:3306/base) for user 'user': Host '172.18.0.4' is not allowed to connect to this MySQL server
Each time that I run the command, I get a different host, e.g:
ERROR: Unable to obtain Jdbc connection from DataSource (jdbc:mysql://mysqldb:3306/base) for user 'user': Host '172.18.0.6' is not allowed to connect to this MySQL server
The data base was created in that way:
CREATE DATABASE base CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON base.* To 'user'#'localhost';
The ifconfig command shows that Docker has the IP 172.17.0.1.
I don't know why flyway can't connect to the data base, and why the host changes en each call,can you help me please?
Thanks! :)
Issue
In this line
GRANT ALL PRIVILEGES ON base.* To 'user'#'localhost';
you grant priviledges to user on localhost but your service1 and flyaway-service-1 services are running in their own separate containers and therefore are not running on localhost (with respect to the mysqldb container). If these services were running inside the mysqldb container then maybe they could be running on localhost.
Possible Resolution?
You may want to try using the hostname of the services/containers you're granting access to instead of localhost?
ie :
GRANT ALL PRIVILEGES ON base.* To 'user'#'service1';
Docker Networks instead of Container Links
Also, I would suggest using Docker's new networking feature instead of the legacy container linking method. See rationale behind docker compose "links" order

Categories

Resources