aplication.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/springapp
spring.datasource.username=www_data
spring.datasource.password=pass
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
Dockerfile:
FROM maven:3.8.5-eclipse-temurin-17-alpine
WORKDIR app
COPY src src
COPY pom.xml pom.xml
RUN mvn clean package -DskipTests
EXPOSE 8080
CMD java -jar target/j1-0.0.1-SNAPSHOT.jar
docker-compose.yaml:
version: "3.7"
services:
springapp:
build: .
ports:
- "8080:8080"
networks:
- j0-net
environment:
- spring.datasource.url=jdbc:mysql://mysqldb:3306/springapp
depends_on:
- mysqldb
volumes:
- .m2:/root/.m2
mysqldb:
image: "mysql"
ports:
- "3306:3306"
networks:
- j0-net
environment:
MYSQL_DATABASE: springapp
MYSQL_USER: www_data
MYSQL_PASSWORD: pass
MYSQL_ROOT_PASSWORD: pass
networks:
j0-net:
When running docker compose up
for the first time. I am getting
...
#0 48.96 com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
#0 48.96
#0 48.96 The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
...
after spring boots run. Running it second time I got
j1-springapp-1 |
j1-springapp-1 | . ____ _ __ _ _
j1-springapp-1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
j1-springapp-1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
j1-springapp-1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
j1-springapp-1 | ' |____| .__|_| |_|_| |_\__, | / / / /
j1-springapp-1 | =========|_|==============|___/=/_/_/_/
j1-springapp-1 | :: Spring Boot :: (v3.2.0)
j1-springapp-1 |
j1-springapp-1 | 2023-11-26T20:42:13.536Z INFO 1 --- [ main] com.example.j1.J1Application : Starting J1Application v0.0.1-SNAPSHOT using Java 17.0.3 with PID 1 (/app/target/j1-0.0.1-SNAPSHOT.jar started by root in /app)
j1-springapp-1 | 2023-11-26T20:42:13.542Z INFO 1 --- [ main] com.example.j1.J1Application : No active profile set, falling back to 1 default profile: "default"
j1-springapp-1 | 2023-11-26T20:42:15.049Z INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
j1-springapp-1 | 2023-11-26T20:42:15.173Z INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 105 ms. Found 1 JPA repository interface.
j1-springapp-1 | 2023-11-26T20:42:16.221Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
j1-springapp-1 | 2023-11-26T20:42:16.237Z INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
j1-springapp-1 | 2023-11-26T20:42:16.237Z INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.16]
j1-springapp-1 | 2023-11-26T20:42:16.338Z INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
j1-springapp-1 | 2023-11-26T20:42:16.341Z INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2619 ms
j1-springapp-1 | 2023-11-26T20:42:16.636Z INFO 1 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
j1-springapp-1 | 2023-11-26T20:42:16.781Z INFO 1 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.3.1.Final
j1-springapp-1 | 2023-11-26T20:42:16.866Z INFO 1 --- [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
j1-springapp-1 | 2023-11-26T20:42:17.357Z INFO 1 --- [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
j1-springapp-1 | 2023-11-26T20:42:17.412Z INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
j1-springapp-1 | 2023-11-26T20:42:18.985Z ERROR 1 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
j1-springapp-1 |
j1-springapp-1 | java.sql.SQLSyntaxErrorException: Access denied for user 'www_data'@'%' to database 'springapp'
j1-springapp-1 | at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
j1-springapp-1 | at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
j1-springapp-1 | at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
...
Why? The user www_data
with password pass
is specified both in application.properties and docker-compose.yaml. So I assume the user is created and thus should have access to springapp
database. So whats going on?
Projects source: https://github.com/shepherd123456/springapp
The mysqldb
container takes a moment to start up. We have the 'depends_on-section for
springappcontainer in the
docker-compose.yaml, but this only means that we start the
mysqldbcontainer before theh
springappcontainer, not that the
mysqlservice in the
mysqldb` container is actually ready.
To fix this, we have to do two things:
mysql
service within the mysqldb
container is readyspringapp
container until the mysql
service is ready.To achieve 1., we can provide a health check (docs.docker.com
) for the mysqldb
container. Luckily, since the container ships with mysqladmin
, implementing the check means adding the following to the docker-compose.yaml
:
version: "3.7"
services:
...
mysqldb:
...
healthcheck:
test: [
"CMD",
"mysqladmin",
"-h", "127.0.0.1",
"--user=$$MYSQL_USER", # double quotes since the variable MYSQL_USER should be evaluated at container runtime
"--password=$$MYSQL_PASSWORD", # double quotes since the variable MYSQL_PASSWORD should be evaluated at container runtime
"ping"
]
interval: 10s
timeout: 1s
retries: 3
start_period: 30s
...
For 2., we can add a condition to the depends_on
(docs.docker.com
) section of springapp
in docker-compose.yml
version: "3.7"
services:
springapp:
...
depends_on:
mysqldb:
condition: service_healthy
...