当通过 Dockerfile 上的 gradle 图像触发时,Jooq 无法找到数据库

Posted

技术标签:

【中文标题】当通过 Dockerfile 上的 gradle 图像触发时,Jooq 无法找到数据库【英文标题】:Jooq unable to find database when triggered via a gradle image on Dockerfile 【发布时间】:2020-09-20 05:08:45 【问题描述】:

我有一个 Dockerfile,它使用 gradle 构建我的 Spring Boot 应用程序,然后将其复制到容器中并触发它。看起来是这样的:

FROM gradle:5.4.1-jdk8-alpine AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM openjdk:8-jdk-alpine
EXPOSE 8080
RUN mkdir /app
COPY --from=build /home/gradle/src/build/libs/*.jar yurlapp.jar
ENTRYPOINT ["java","-jar" , "/yurlapp.jar"]

很简单,它会执行 Gradle 并将 jar 添加到 docker 容器中。到目前为止,一切都很好。提供数据库后,此 Dockerfile 将在 docker-compose.yml 中使用(应用程序需要该数据库才能工作)。这就是 docker-compose.yml 的样子:

version: '2.1'
services:
  yurldb:
    image: postgres:11
    container_name: yurldb
    networks:
      - yunet
    ports:
      - 5432:5432
    environment:
      - POSTGRES_DB=yurldb
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=somepassword
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/
      - yudata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 10s
      retries: 5
  flyway:
    image: boxfuse/flyway
    command: -url=jdbc:postgresql://yurldb:5432/yurldb -schemas=public -user=postgres -password=somepassword migrate
    networks:
      - yunet
    volumes:
      - .:/flyway/sql
    depends_on:
      yurldb:
        condition: service_healthy
  yurlapp:
    container_name: yurlapp
    image: javing/yurlapp:0.0.1
    build:
      context: .
      dockerfile: Dockerfile
    networks:
      - yunet
    ports:
      - 8080:8080
    environment:
      - DB_HOST=yurldb #the name of the DB container is used as url
    depends_on:
      yurldb:
        condition: service_healthy
      flyway:
        condition: service_healthy
networks:
  yunet:
volumes:
  yudata:

正如您所见,应用程序镜像是最后构建的,一旦数据库镜像准备好并且在 flyway 执行迁移之后。我在构建应用程序期间发生的问题。 因此,一旦 gradle 启动,它将完成它必须做的所有事情。但在某一时刻,它需要 Jooq,根据数据库上的现有表自动生成一些类。在这里出了点问题。构建爆炸并告诉我:

任务:generateSampleJooqSchemaSource 失败

FAILURE: Build failed with an exception.

* Where:
Build file '/home/gradle/src/build.gradle' line: 81

* What went wrong:
Execution failed for task ':generateSampleJooqSchemaSource'.
> jOOQ source code generation failed:

  Jun 01, 2020 7:37:39 PM org.jooq.tools.JooqLogger info
  INFO: Initialising properties  : /home/gradle/src/build/tmp/generateSampleJooqSchemaSource/config.xml
  Jun 01, 2020 7:37:39 PM org.jooq.tools.JooqLogger error
  SEVERE: Cannot read /home/gradle/src/build/tmp/generateSampleJooqSchemaSource/config.xml. Error : Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
  org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:285)
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
    at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:211)
    at org.postgresql.Driver.makeConnection(Driver.java:459)
    at org.postgresql.Driver.connect(Driver.java:261)
    at org.jooq.codegen.GenerationTool.run0(GenerationTool.java:342)
    at org.jooq.codegen.GenerationTool.run(GenerationTool.java:221)
    at org.jooq.codegen.GenerationTool.generate(GenerationTool.java:216)
    at org.jooq.codegen.GenerationTool.main(GenerationTool.java:188)
  Caused by: java.net.ConnectException: Connection refused (Connection refused)
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at org.postgresql.core.PGStream.<init>(PGStream.java:81)
    at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:93)
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:197)
    ... 8 more

它说它无法连接到数据库。这是为什么?这是我在 build.gradle 文件中的 Jooq 配置

jooq 
    sample(sourceSets.main) 
        jdbc 
            driver = 'org.postgresql.Driver'
            url = 'jdbc:postgresql://localhost:5432/yurldb'
            user = 'postgres'
            password = 'somepassword'
        
        generator 
            database() 
                name = 'org.jooq.meta.postgres.PostgresDatabase'
                inputSchema = 'public'
                includes = '.*'
            
            target 
                packageName = 'com.javing.yurl'
                directory = 'build/generated/java'
            
        
    


tasks.generateSampleJooqSchemaSource.with 
    def out = new ByteArrayOutputStream()
    javaExecSpec =  JavaExecSpec s ->
        s.standardOutput = out
        s.errorOutput = out
        s.ignoreExitValue = true
        s.jvmArgs '-Xmx512M'
    
    execResultHandler =  ExecResult r ->
        if (r.exitValue != 0) 
            throw new RuntimeException('jOOQ source code generation failed:\n\n' + out.toString())
        
    

我很困惑,我不确定我是否理解正在发生的事情。如果我要使用 docker-compose 仅​​自行启动数据库映像,然后从终端手动运行 gradle(而不是来自 docker 的 gradle),那么这些类将毫无问题地生成。所以我不知道何时使用 Dockerfile Jooq 中的 gradle 无法找到数据库。任何想法? 我是否还需要以某种方式从 Dockerfile 触发 Jooq,就像我触发 gradle 一样?谁能帮帮我,我有点卡住了。

更新 我尝试将 jooq 配置中的 url 更改为使用 yurldb 而不是 localhost 因为可能在容器内联网时,url resloves 到容器的名称,但这不起作用。会发生什么:

FAILURE: Build failed with an exception.

* Where:
Build file '/home/gradle/src/build.gradle' line: 81

* What went wrong:
Execution failed for task ':generateSampleJooqSchemaSource'.
> jOOQ source code generation failed:

  Jun 01, 2020 8:29:57 PM org.jooq.tools.JooqLogger info
  INFO: Initialising properties  : /home/gradle/src/build/tmp/generateSampleJooqSchemaSource/config.xml
  Jun 01, 2020 8:30:08 PM org.jooq.tools.JooqLogger error
  SEVERE: Cannot read /home/gradle/src/build/tmp/generateSampleJooqSchemaSource/config.xml. Error : The connection attempt failed.
  org.postgresql.util.PSQLException: The connection attempt failed.
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:297)
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
    at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:211)
    at org.postgresql.Driver.makeConnection(Driver.java:459)
    at org.postgresql.Driver.connect(Driver.java:261)
    at org.jooq.codegen.GenerationTool.run0(GenerationTool.java:342)
    at org.jooq.codegen.GenerationTool.run(GenerationTool.java:221)
    at org.jooq.codegen.GenerationTool.generate(GenerationTool.java:216)
    at org.jooq.codegen.GenerationTool.main(GenerationTool.java:188)
  Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at org.postgresql.core.PGStream.<init>(PGStream.java:81)
    at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:93)
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:197)
    ... 8 more

【问题讨论】:

【参考方案1】:

问题是您在build.gradle 中的jooq 插件的配置中将localhost 作为数据库主机。

您已在其他地方为DB_HOST 正确设置了环境变量,因此我假设您了解该服务的名称是 DNS 名称,当它们连接到公共网络时,您可以使用它来引用其他服务。你应该改变

url = 'jdbc:postgresql://localhost:5432/yurldb'

url = 'jdbc:postgresql://yurldb:5432/yurldb'

或者您可以在应用服务的环境变量中获取db的主机,然后从build.gradle读取它:

def db = System.getenv('DB_HOST')
url = "jdbc:postgresql://$db:5432/yurldb"

【讨论】:

我最初是这么想的,我试过了,但这给了我 socketTimeout(见更新)。我不知道为什么会超时,我不明白。 jooq gradle 插件可能会在完全初始化之前尝试连接到 db 容器。见this。 好的,我理解是的,他们建议增加一些延迟,以便为数据库做好准备。我会尝试的,但有一件事让我感到困惑。如果是这样,那为什么flyway不先失败呢?由于 Flyway 将在 yurlapp 服务启动之前在数据库中运行这些迁移,所以我猜它也应该失败。 你不能确定这一点。 Depends_on 仅确保容器按给定顺序启动,但不会等待它们按给定顺序完全初始化。 好的,我明白了,如果是这样的话,也许我还需要在飞路服务中添加延迟。我会玩一点,看看会发生什么。

以上是关于当通过 Dockerfile 上的 gradle 图像触发时,Jooq 无法找到数据库的主要内容,如果未能解决你的问题,请参考以下文章

Gradle项目构建docker镜像(支持Gradle多模块)

使用 Gradle/Maven 的 SpringBoot 应用程序的通用 Docker 映像和 Dockerfile

无法在 Raspberry Pi 上从 Dockerfile 安装 dlib

Docker 插件:java.io.FileNotFoundException:/src/main/docker/Dockerfile gradle-docker 失败

Dockerfile使用

构建 Dockerfile 使用非零代码 139 执行