Dokeryzacja projektu w Springu

Dokeryzacja projektu w Springu
MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
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:

Kopiuj
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:

Kopiuj
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

Kopiuj
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:

Kopiuj
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]
Kopiuj
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
SP
  • Rejestracja:prawie 5 lat
  • Ostatnio:około 13 godzin
  • Postów:30
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

KE
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 2 godziny
  • Postów:678
0

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

MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
0

Po zmianach

Struktura plików:
screenshot-20240313201949.png

Dockerfile:

Kopiuj
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:

Kopiuj
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

Kopiuj
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:

Kopiuj
 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)
KE
No toś zagiął teraz - wszystko wygląda okej... dziwne.
SP
Odpal najpierw bazę, zobacz czy kontener wstał i jest OK i dopiero wtedy odpal ten serwis swój i zobacz czy działa.
KE
A, może tak :) za dużo w k8s siedzę i myślałem że domyślnie jest restart=always.
ZI
  • Rejestracja:ponad 8 lat
  • Ostatnio:5 dni
  • Postów:230
0

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

flinst-one
a czy to nie robi "depends_on" ?
ZI
Baza wstala ale nie jest jeszcze w stanie mozliwym do obslugi ruchu (dla dockera wstal kontener ale z perspektywy bazy sie jeszcze podnosi) to puszcza springa ktory chce sie dobic do tej bazy i dostaje wyjatek
ZI
Jak chcesz sprawdzic czy to to to podniesc sobie osobno baze i potem springa i zobacz czy sie dogadaja
flinst-one
  • Rejestracja:około 5 lat
  • Ostatnio:około godziny
  • Postów:327
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/

BB
  • Rejestracja:ponad 2 lata
  • Ostatnio:około 2 miesiące
  • Postów:66
0

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

MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
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

SP
Ty chyba kolego nie zrozumiałeś tego co napisałem. Odpal najpierw bazę, zobacz za pomocą docker logs czy wstała, możesz tym swoim Workbenchem czy czymkolwiek sprawdzić, puścić jakiegoś zwykłego selecta czy odpowiada a potem, odpal kontener z aplikacją. I wywal ten wolumen z application.properties w docker-compose nie potrzebny.
MV
Doskonale zrozumiałem. Uruchomiłem bazę, sprawdziłem Logs, a następnie poprzez Workbench połączyłem się z serwerem bazy i nawet dodałem tabelę. Więc baza działa. Gdy zakomentowałem zawartość całe environment od kontenera z aplikacją w docker-compose. Otrzymuje błąd: 44.52 Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure 44.52 The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. Caused by: java.net.UnknownHostException: spring-mysqldb
KE
Teraz myślę, że jakby był problem z kolejnością wstawania serwisów, to byłoby "connection refused" a nie "unknown host". Jakby DNS nie działał w sieci dockerowej.
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:4 dni
  • Postów:2370
0

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

Kopiuj
docker network ls

docker inspect <network name>

ip l

route

sudo systemctl status ufw

sudo systemctl status firewalld
TR
  • Rejestracja:ponad rok
  • Ostatnio:około 4 godziny
  • Postów:49
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

edytowany 2x, ostatnio: trojanus__
MV
A generalnie np. samo dodanie properties: spring.docker.compose.enabled, spring.docker.compose.file, spring.docker.compose.host - coś zmieni?
TR
kiedyś miałem podobny problem, wystawienie na hoscie 0.0.0.0 mi pomogło. Nie mogę teraz znaleźć konkretnego projektu w którym to robiłem, nie pamiętam czy było to w springu, czy innym frameworku. Ogólnie konflikt może być między wystawionym hostem Springa i kontenerem dockera.
MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
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

BB
  • Rejestracja:ponad 2 lata
  • Ostatnio:około 2 miesiące
  • Postów:66
MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
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

TR
  • Rejestracja:ponad rok
  • Ostatnio:około 4 godziny
  • Postów:49
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

MV
  • Rejestracja:prawie 2 lata
  • Ostatnio:9 miesięcy
  • Postów:19
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

TR
no, spoczko, dzięki, przepiszę sobie ;)
marian pazdzioch
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 11 godzin
  • Postów:735
0

to jaka była odpowiedź na zagadkę?

taka o?

Kopiuj
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:
MA
Ktoś wyjaśni? Można bez problemu tworzyć sieci i w serwisach je kojarzyć, to że docker robi to automatycznie to swoją drogą, niczemu nie szkodzi

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.