7

这就是我的意思。如何编写 docker-compose.yaml 文件,以便在“构建”其中一个服务时,它首先运行另一个服务?

我会尝试更具体。我正在尝试使用数据库库 JOOQ 构建 Java 应用程序,它希望在构建时连接到数据库以生成与数据库表对应的 Java 类。我想要 Dockerfile(s) 和 docker-compose.yaml 文件的某种组合,以便以下大致按以下顺序发生。

  1. 启动“数据库”服务(在我的情况下,使用 postgres 图像)。
  2. 在我的开发存储库中使用 SQL 脚本初始化数据库。
  3. 我的“web”服务的构建阶段运行,它使用同一个 repo 中的 Dockerfile,它调用 Gradle 构建,它告诉 JOOQ 连接到在步骤 1 中启动的数据库服务。这会生成 Java 文件,编译它们,然后用于构建容器的所有其他内容。
  4. “web”服务启动,连接到步骤 1 中启动的数据库服务。

这是我正在使用的 docker-compose.yaml 文件

version: '3.7' 
services:
  postgres:
    image: postgres:10.5-alpine
    restart: always
    ports:
      - "6432:5432"
    environment:
      POSTGRES_DB: flashtools
      POSTGRES_USER: flashtools
      POSTGRES_PASSWORD: flashtools
    volumes:
      - ./src/main/scripts/01_init.sql:/docker-entrypoint- 
initdb.d/01_init.sql
  web:
    build: .
    network_mode: host
    depends_on:
      - postgres
    ports:
      - "8080:8080"

我会用更多细节来充实这一点,但希望我所问的非常简单。

4

2 回答 2

2

我有同样的问题并以一种hacky方式解决了它......

在我的例子中,Web 服务是 Haskell,它使用命令构建stack build,然后使用stack exec APP_NAME. 还有一个速记如stack build --exec APP_NAME.

还有一个选项可以仅使用 构建依赖项stack build --only-dependencies,因此 Docker 构建会缓存它们。

所以我像这样改变了我的 Dockerfile:

COPY ./package.yaml /app/package.yaml        # Copying the package file
RUN stack build --only-dependencies          # Build dependencies only

COPY . /app                                  # Copying the rest of the files

EXPOSE 3000

CMD ["stack", "build", "--exec", "APP_NAME"] # Build the application itself

因此最终构建仅在服务启动时运行。

我不太了解Java,但我想那里也一定有类似的选择。

还需要对depends_on部分进行一些黑客攻击: https ://docs.docker.com/compose/startup-order/

于 2019-05-30T07:55:18.577 回答
0

在我的例子中,Web 服务入口点是一个类似node server.js.

如果数据库在调用时已经可用,它将正常工作,但使用 docker-compose 时情况并非如此。

一种解决方法是在您的代码中编写代码,server.js以便在数据库准备好之前重试。

在我的server.js

connectDB()
.then(db => {
    /* Use db here...*/

    app.listen(3000);
});

async function connectDB() {
    var retry = 5;
    while (retry-- > 0 && !(dbReady()) {
        await sleep(1000);
    }
    return useDB();
}

function dbReady() {
    /* returns true iff DB available */
}

async function useDB() {
    /* returns DB instance */
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
于 2021-01-24T04:33:59.093 回答