Dokeryzacja projektu w Springu

0

Cześć wszystkim, mam projekt w Springu i chciałbym nauczyć się przy nim Dockera i Docker Compose. Jednak zdecydowanie robię coś nie tak.
Próbowałem już na wiele sposobów i jeśli udało mi się rozwiązać podany poniżej problem, to pojawiał się następny w postaci braku możliwości połączenia się z bazą danych (nierozpoznany host) lub musiałem mieć uruchomionego XAMPP'a żeby móc stworzyć obraz Dockera.

Obecna struktura plików projektu:
screenshot-20240308160008.png

Dockerfile:

FROM maven:3.8.3-openjdk-17 AS build
COPY src /home/app/src
COPY pom.xml /home/app
COPY src/main/resources/application-docker.properties /home/app/application.properties

RUN mvn -f /home/app/pom.xml clean package
EXPOSE 8080

ENTRYPOINT ["java","-jar","/home/app/target/spring_rest_docker.jar"]

docker-compose.yml:

version: "3.8"
services:
  spring-app:
    build: .
    restart: always
    ports:
      - '8080:8080'
    networks:
      - spring-net
    environment:
      DB_ENDPOINT: spring-mysqldb
      DB_PORT: 3306
      DB_SCHEMA: crs_database
      DB_USER: admin
      DB_PASS: root
    depends_on:
      - spring-mysqldb
    volumes:
      - .m2:/root/.m2
      - ./application-docker.properties:/home/app/application.properties

  spring-mysqldb:
    image: "mysql:8.0"
    restart: always
    ports:
      - '3306:3306'
    networks:
      - spring-net
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: crs_database
      MYSQL_USER: admin
      MYSQL_PASSWORD: root

networks:
  spring-net:

application-docker.properties

spring.datasource.url=jdbc:mysql://${DB_ENDPOINT}:${DB_PORT}/${DB_SCHEMA}?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.sql.init.mode=always
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update

spring.servlet.multipart.max-file-size=15MB
spring.servlet.multipart.max-request-size=15MB

crs.app.jwtSecret=xxxxx
crs.app.jwtExpirationMs=86400000

Przy obecnej zawartości plików i ich strukturze, otrzymuje następujące błędy:

39.35 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution [Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Failed to parse the host:port pair '${DB_ENDPOINT}:${DB_PORT}'.] [n/a]
39.35 Caused by: java.lang.NumberFormatException: For input string: "${DB_PORT}"
39.35   at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
39.35   at java.base/java.lang.Integer.parseInt(Integer.java:654)
39.35   at java.base/java.lang.Integer.parseInt(Integer.java:786)
39.35   at com.mysql.cj.conf.ConnectionUrlParser.parseHostPortPair(ConnectionUrlParser.java:499)
39.35   ... 80 more
2

Dziwną masz tą konfigurację.
Generalnie albo ustawiasz zmienne za pomocą environment w docker-compose albo robisz wszystko za pomocą profila.
Możesz po prostu w tym swoim application-docker.properties ustawić wszystkie potrzebne zmienne czyli np. zamiast jakiś dziwnych rzeczy typu :

spring.datasource.username=${DB_USER}

wrzuć tutaj po prostu username i zrób tak dla wszystkich zmiennych, usuń te swoje zmienne w environment w docker-compose i dodaj tam zmienną :

SPRING_PROFILES_ACTIVE: docker

a jak chcesz ustawiać zmiennymi to ustawiaj po ludzku czyli cala nazwa propertiesa w environment w docker-compose dla przykładu :

SPRING_DATASOURCE_USERNAME: username

0

Przekaż property springowe jako zmienną środowiskową po prostu, w dokumentacji to jest świetnie opisane, vide @Spectra .

0

Po zmianach

Struktura plików:
screenshot-20240313201949.png

Dockerfile:

FROM maven:3.8.3-openjdk-17 AS build
COPY src /home/app/src
COPY pom.xml /home/app
#COPY src/main/resources/application.properties /home/app/application.properties

RUN mvn -f /home/app/pom.xml clean package
EXPOSE 8080

ENTRYPOINT ["java","-jar","/home/app/target/spring_rest_docker.jar"]

docker-compose.yml:

version: "3.8"
services:
  spring-app:
    build: .
    restart: always
    ports:
      - '8080:8080'
    networks:
      - spring-net
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://spring-mysqldb:3306/crs_database?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
      SPRING_DATASOURCE_USERNAME: admin
      SPRING_DATASOURCE_PASSWORD: root1
      SPRING_DATASOURCE_DRIVER-CLASS-NAME: com.mysql.cj.jdbc.Driver
      SPRING_SQL_INIT_MODE: always
      SPRING_JPA_DATABASE-PLATFORM: org.hibernate.dialect.MySQLDialect
      SPRING_JPA_HIBERNATE_DDL-AUTO: update
    depends_on:
      - spring-mysqldb
    volumes:
      - .m2:/root/.m2
      - ./application-docker.properties:/home/app/application.properties

  spring-mysqldb:
    image: "mysql:8.0"
    restart: always
    ports:
      - '3306:3306'
    networks:
      - spring-net
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: crs_database
      MYSQL_USER: admin
      MYSQL_PASSWORD: root1

networks:
  spring-net:

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/crs_database
spring.datasource.username=root
spring.datasource.password=

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.sql.init.mode=always
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update

spring.servlet.multipart.max-file-size=15MB
spring.servlet.multipart.max-request-size=15MB

crs.app.jwtSecret=xxxxx
crs.app.jwtExpirationMs=86400000

Występuje błąd z połączeniem:

 The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
40.56   at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
40.56   at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
40.56   at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:815)
40.56   at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:438)
40.56   at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241)
40.56   at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:189)
40.56   at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
40.56   at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359)
40.56   at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201)
40.56   at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470)
40.56   at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
40.56   at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100)
40.56   at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
40.56   at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
40.56   at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:428)
40.56   at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:46)
40.56   ... 63 more
40.56 Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
40.56
40.56 The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
40.56   at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
40.56   at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
40.56   at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
40.56   at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:104)
40.56   at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:149)
40.56   at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:165)
40.56   at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:88)
40.56   at com.mysql.cj.NativeSession.connect(NativeSession.java:120)
40.56   at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:935)
40.56   at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:805)
40.56   ... 76 more
40.56 Caused by: java.net.ConnectException: Connection refused
40.56   at java.base/sun.nio.ch.Net.pollConnect(Native Method)
40.56   at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
40.56   at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:542)
40.56   at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:597)
40.56   at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
40.56   at java.base/java.net.Socket.connect(Socket.java:633)
40.56   at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:153)
40.56   at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:62)
0

nie brakuje ci na zaleznosci do bazy danych sprawdzenia czy jest juz "gotowa" zeby obsluzyc springa?

0
Ziemiak napisał(a):

nie brakuje ci na zaleznosci do bazy danych sprawdzenia czy jest juz "gotowa" zeby obsluzyc springa?

service_started ? https://docs.docker.com/compose/startup-order/

0

A w application.properties nie powinna być nazwa usługi zamiast localhost

0
bbzzyyczczeek napisał(a):

A w application.properties nie powinna być nazwa usługi zamiast localhost

Może źle myślę, ale skoro daje environment z docker-compose, to application.properties nie powinno być brane pod uwagę.

Podmieniłem na nazwę usługi czyli spring-mysqldb oraz nawet do docker-compose dodałem container_name - efekt?
"Caused by: java.net.UnknownHostException: spring-mysqldb"

Kontener z bazą danych na pewno wstaje, bo poprzez Workbench na luzie wchodzę. Jeśli odpalam oddzielnie, to się wysypuje jak wcześniej

0

A pokaż co tam masz po stronie sieci pokonfigurowane (zakładam, że to jakis linux):

docker network ls

docker inspect <network name>

ip l

route

sudo systemctl status ufw

sudo systemctl status firewalld
0

konflikt może być spowodowany tym, że kontener i apka lecą po tym samym hoscie (localhost) i przez to jest blokada. Spróbuj wymusić innego hosta np. 0.0.0.0

dodaj do Dockerfile coś a'la: ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 <- tylko nie wiem co tam do springa potrzeba

1
trojanus__ napisał(a):

konflikt może być spowodowany tym, że kontener i apka lecą po tym samym hoscie (localhost) i przez to jest blokada. Spróbuj wymusić innego hosta np. 0.0.0.0

dodaj do Dockerfile coś a'la: ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 <- tylko nie wiem co tam do springa potrzeba

Niestety nie działa. Postaram się wieczorem wrzucić aktualną wersję na GitHuba i podesłać tutaj link do repozytorium

0
bbzzyyczczeek napisał(a):

https://discord.com/channels/747549818938851384/1163774974591512686/threads/1218356773455663175
Zobacz tutaj

Problem musiał leżeć w samym Dockerfile w takim razie, bo tylko to zmieniłem i działa

0

@bbzzyyczczeek: czy mogę prosić o repost do rozwiązania? ten link mnie na manowce prowadzi, a jestem ciekaw jakie to rozwiązanie :)

taki screen mam z Discorda 😀

screenshot-20240321233442.png

0
trojanus__ napisał(a):

@bbzzyyczczeek: czy mogę prosić o repost do rozwiązania? ten link mnie na manowce prowadzi, a jestem ciekaw jakie to rozwiązanie :)

taki screen mam z Discorda 😀

screenshot-20240321233442.png

Screenshot_20240321_234232_Discord.jpgScreenshot_20240321_234240_Discord.jpg

Podejrzewam, że link prowadzi Cie na manowce dlatego, że na tym serwerze Discord musisz ustawić sobie odpowiednie role (np. Java) i wtedy będziesz miał dostęp do tego kanału. Ja korzystałem z tego serwera już wcześniej, więc obyło się bez problemów

0

to jaka była odpowiedź na zagadkę?

taka o?

version: "3.8"
services:
  spring-app:
    build: .
    restart: always
    ports:
      - '8080:8080'
//ciach ciach?///////////networks:
//ciach ciach?///////////- spring-net
    environment:
      DB_ENDPOINT: spring-mysqldb
      DB_PORT: 3306
      DB_SCHEMA: crs_database
      DB_USER: admin
      DB_PASS: root
    depends_on:
      - spring-mysqldb
    volumes:
      - .m2:/root/.m2
      - ./application-docker.properties:/home/app/application.properties

  spring-mysqldb:
    image: "mysql:8.0"
    restart: always
    ports:
      - '3306:3306'
//ciach ciach?///////////networks:
//ciach ciach?///////////- spring-net
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: crs_database
      MYSQL_USER: admin
      MYSQL_PASSWORD: root

//ciach ciach?///////////networks:
//ciach ciach?///////////spring-net:

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.