You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker镜像构建时连接PostgreSQL生成JOOQ对象失败求助

问题描述

我正在开发一个副业项目,想用docker-compose完成本地部署,预期流程是:

  1. 部署带有init.sql文件的PostgreSQL容器;
  2. 在镜像构建阶段生成应用所需的JOOQ代码;
  3. 将生成的代码复制到镜像并运行应用。

但不管怎么配置,构建容器始终连不上PostgreSQL容器来生成代码,试过links、网络配置都没用。

当前配置

Docker Compose 配置

services:
  database:
    container_name: database
    hostname: database
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      - PGUSER=user
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=db
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
      interval: 2s
      timeout: 5s
      retries: 5
    networks: 
      - mynet

  server:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      database:
        condition: service_healthy
    ports:
      - "8080:8080"
    networks:
      - mynet

networks:
  mynet:
    driver: bridge

Dockerfile 配置

FROM maven:3.9.7-amazoncorretto-17 AS build
COPY models models

RUN mvn clean package -f models/pom.xml -Plocal

pom.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.abl.rjmdb</groupId>
    <artifactId>models</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jooq.version>3.19.8</jooq.version>
        <postgresql.version>42.7.3</postgresql.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq</artifactId>
            <version>${jooq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-meta</artifactId>
            <version>${jooq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-codegen</artifactId>
            <version>${jooq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>${postgresql.version}</version>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>local</id>
            <properties>
                <database.driver>org.postgresql.Driver</database.driver>
                <database.url>jdbc:postgresql://database:5432/db</database.url>
                <database.user>user</database.user>
                <database.password>password</database.password>
                <database.schema>public</database.schema>
            </properties>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.jooq</groupId>
                        <artifactId>jooq-codegen-maven</artifactId>
                        <version>${jooq.version}</version>

                        <executions>
                            <execution>
                                <phase>generate-sources</phase>
                                <goals>
                                    <goal>generate</goal>
                                </goals>
                            </execution>
                        </executions>

                        <configuration>
                            <jdbc>
                                <driver>${database.driver}</driver>
                                <url>${database.url}</url>
                                <user>${database.user}</user>
                                <password>${database.password}</password>
                            </jdbc>
                            <generator>
                                <database>
                                    <includes>.*</includes>
                                    <inputSchema>${database.schema}</inputSchema>
                                </database>
                                <target>
                                    <packageName>com.abl.rjmdb.model.jooq</packageName>
                                    <directory>${project.build.directory}/generated-sources/jooq</directory>
                                </target>
                            </generator>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

</project>

遇到的错误

  • 用database作为主机时:

11.96 [ERROR] Failed to execute goal org.jooq:jooq-codegen-maven:3.19.8:generate (default) on project models: Error running jOOQ code generation tool: The connection attempt failed. Unknown host database -> [Help 1]

  • 用127.0.0.1作为主机时:

Failed to execute goal org.jooq:jooq-codegen-maven:3.19.8:generate (default) on project models: Error running jOOQ code generation tool: Connection to 127.0.0.1:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. Connection refused

  • 用docker inspect <container name>获取的IP地址时:

Failed to execute goal org.jooq:jooq-codegen-maven:3.19.8:generate (default) on project models: Error running jOOQ code generation tool: Connection to 172.17.0.2:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. Connection refused

我已经确认PostgreSQL容器正常运行,而且从主机可以连接上。想请教两个问题:

  1. 该如何解决这个连接问题?
  2. 在Docker镜像内生成JOOQ代码是不是不属于最佳实践?

解决方案

问题根源

Docker Compose的depends_on只会控制服务启动顺序,但镜像构建阶段(docker build)是在Compose网络之外执行的,所以构建容器根本访问不到PostgreSQL服务所在的Compose网络,这就是为什么用database主机名找不到、用localhost或容器IP也连不上的原因。

解决方法

方法1:使用主机网络进行构建(本地开发场景)

修改Docker Compose中server的构建配置,让构建过程使用主机网络,这样就能直接访问本地已启动的PostgreSQL容器:

server:
  build:
    context: .
    dockerfile: Dockerfile
    network: host  # 新增配置,让构建容器使用主机网络
  depends_on:
    database:
      condition: service_healthy
  ports:
    - "8080:8080"
  networks:
    - mynet

同时修改pom.xml中的数据库URL为主机能访问的地址:

<database.url>jdbc:postgresql://localhost:5432/db</database.url>

这样构建时,Maven容器会使用主机网络,直接访问主机映射的5432端口,就能连接到PostgreSQL容器。

方法2:多阶段构建+临时数据库(通用隔离方案)

如果不想依赖外部数据库,可以在Dockerfile的构建阶段临时启动一个PostgreSQL容器来生成JOOQ代码,构建过程完全自给自足:

FROM maven:3.9.7-amazoncorretto-17 AS build
COPY models models
COPY init.sql /tmp/init.sql

# 安装PostgreSQL服务和客户端
RUN apt-get update && apt-get install -y postgresql postgresql-client

# 临时启动数据库、执行初始化脚本、生成JOOQ代码
RUN service postgresql start && \
    su postgres -c "createdb db" && \
    su postgres -c "createuser user -s" && \
    su postgres -c "psql -d db -f /tmp/init.sql" && \
    su postgres -c "psql -d db -c \"ALTER USER user WITH PASSWORD 'password';\"" && \
    mvn clean package -f models/pom.xml -Plocal -Ddatabase.url=jdbc:postgresql://localhost:5432/db -Ddatabase.user=user -Ddatabase.password=password && \
    service postgresql stop

这种方式不需要依赖外部服务,适合CI/CD环境使用。

关于镜像内生成JOOQ代码的最佳实践

在镜像构建阶段生成JOOQ代码不是最佳实践,原因如下:

  1. 构建效率低:每次构建都要连接数据库、生成代码,增加构建时间;
  2. 构建依赖外部服务:容易出现像你遇到的网络连接问题,构建过程不具备隔离性;
  3. 可重复性差:如果数据库结构变更,没有版本控制的话,生成的代码可能不一致。

推荐的最佳实践:

  • 在本地或者CI/CD环境中,先连接数据库生成JOOQ代码,把生成的代码提交到版本控制系统;
  • 镜像构建时直接使用已生成的代码,不需要再连接数据库,这样构建过程更快、更可靠,也不会依赖外部服务。

内容的提问来源于stack exchange,提问作者AmitBL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 20:44:53