Docker: Springboot容器无法连接到PostgreSQL容器

huangapple go评论75阅读模式
英文:

Docker: Springboot container cannot connect to PostgreSql Container

问题

以下是翻译好的内容:

我正在构建一个使用docker-compose的Spring Boot应用程序,该应用程序使用PostgreSQL。当我使用docker-compose up --build运行容器时,我的Spring Boot应用程序无法启动,因为它找不到PostgreSQL容器的主机名。

Spring Boot Dockerfile

FROM maven:3.6.3-openjdk-14-slim AS build  
COPY src /usr/src/app/src  
COPY pom.xml /usr/src/app  
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:14-slim
COPY --from=build /usr/src/app/target/server-0.0.1-SNAPSHOT.jar /usr/app/server-0.0.1-SNAPSHOT.jar
EXPOSE 9000  
ENTRYPOINT ["java","-jar","/usr/app/server-0.0.1-SNAPSHOT.jar"]

docker-compose.yml

version: '3'

services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_db
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - db-network
    restart: always

  server:
    build: './server'
    depends_on:
      - db
    restart: always
    ports:
      - "9000:9000"
    networks:
      - db-network
    volumes:
      - ./server:/server

networks:
  db-network:

volumes:
  db-data:

application.properties

spring.datasource.url=jdbc:postgresql://db:5432/my_db
spring.datasource.username=postgres
spring.datasource.password=postgres

错误输出

Caused by: java.net.UnknownHostException: db

我猜测是因为在Spring Boot Dockerfile的构建阶段之前,docker-compose的虚拟网络尚未创建。有没有解决这个问题的想法?

英文:

I am building a Spring Boot application which uses PostgreSQL with docker-compose.
When I run my containers using docker-compose up --build, my Spring Boot application fails to start because it does not find the PostgreSQL container's hostname.

Spring Boot Dockerfile

FROM maven:3.6.3-openjdk-14-slim AS build  
COPY src /usr/src/app/src  
COPY pom.xml /usr/src/app  
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:14-slim
COPY --from=build /usr/src/app/target/server-0.0.1-SNAPSHOT.jar /usr/app/server-0.0.1-SNAPSHOT.jar
EXPOSE 9000  
ENTRYPOINT ["java","-jar","/usr/app/server-0.0.1-SNAPSHOT.jar"]

docker-compose.yml

version: '3'

services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_db
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - db-network
    restart: always

  server:
    build: './server'
    depends_on:
      - db
    restart: always
    ports:
      - "9000:9000"
    networks:
      - db-network
    volumes:
      - ./server:/server


networks:
  db-network:

volumes:
  db-data:

application.properties

spring.datasource.url=jdbc:postgresql://db:5432/my_db
spring.datasource.username=postgres
spring.datasource.password=postgres

Error output

Caused by: java.net.UnknownHostException: db

My guess is that docker-compose's virtual network isn't created yet during the build stage of the Spring Boot Dockerfile.
Any idea on how to solve this issue ?

答案1

得分: 1

大量信息在这里:https://docs.docker.com/compose/networking/

> 在 Web 容器内部,连接到数据库的连接字符串如下所示:
> postgres://db:5432,而从主机上,连接字符串如下所示:
> postgres://{DOCKER_IP}:8001。

这是在说明 db:5432 可以在 docker-compose.yaml 中使用,并且 IP 地址将被传递(而不是 "db"),但在应用程序代码中外部使用它将无法工作。然而,您可以从 docker-compose.yaml 中作为应用程序输入变量传递 db,然后您的应用程序可以在配置文件中填入它。然后,这将使您能够连接。

像这样将配置外部化是相当常见的做法,所以应该是一个相对简单的修复。

例如:

Docker-compose.yaml

version: '3'

services:
  db:
    container_name: db
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_db
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - db-network
    restart: always

  server:
    build: './server'
    depends_on:
      - db
    environment:
      DB_HOST: db
      DB_PORT: 5432
      DB_DATABASE: my_db
      DB_USER: postgres
      DB_PASSWORD: postgres
    restart: always
    ports:
      - "9000:9000"
    networks:
      - db-network
    volumes:
      - ./server:/server

networks:
  db-network:

volumes:
  db-data:

然后在 src/main/java/resources/application.properties 下创建一个 application.properties 文件

spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
英文:

Lots of info here: https://docs.docker.com/compose/networking/

> Within the web container, your connection string to db would look like
> postgres://db:5432, and from the host machine, the connection string
> would look like postgres://{DOCKER_IP}:8001.

What this is saying is db:5432 is fine to use within docker-compose.yaml and the IP address will be passed (not "db"), but using it externally within your application code isn't going to work. You could however pass from docker-compose.yaml db as an application input variable, which your application could fill in in the configuration file. This would enable you then to connect.

Externalising configuration like this is fairly common practice so should be a relatively easy fix.

eg:

Docker-compose.yaml

version: '3'

services:
  db:
    container_name: db
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_db
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - db-network
    restart: always

  server:
    build: './server'
    depends_on:
      - db
    environment:
      DB_HOST: db # untested, but there should be a way to pass this in
      DB_PORT: 5432
      DB_DATABASE: my_db
      DB_USER: postgres
      DB_PASSWORD: postgres
    restart: always
    ports:
      - "9000:9000"
    networks:
      - db-network
    volumes:
      - ./server:/server


networks:
  db-network:

volumes:
  db-data:

Then have an application.properties file located under src/main/java/resources/application.properties

spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

答案2

得分: 1

This post完全解决了我的问题。
原来Maven在构建.jar文件时尝试与数据库建立连接。我所需做的就是在Dockerfile中添加这行内容:RUN mvn -f /usr/src/app/pom.xml clean package -DskipTests

英文:

This post completely solved my issue.
It turns out that maven was trying to establish the connection to the database while building the .jar file. All I had to do is modify my Dockerfile with this line RUN mvn -f /usr/src/app/pom.xml clean package -DskipTests.

答案3

得分: 0

在构建图像时请注意,服务在数据库未运行之前将无法访问数据库。只有在图像构建完成并容器运行之后,服务才能访问数据库。因此,在尝试将主机传递给 db 时,它在构建阶段尚不可用。只有在数据库容器启动后才可用。

英文:

Please do note while building the images the service will not have access to the database as it is not yet running . Only after the images are built and the containers are running do the services have access . So when you try to pass a host as db , it is not yet available in the build stage . It is available only once the db container starts running .

huangapple
  • 本文由 发表于 2020年10月27日 19:49:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/64553851.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定