Search code examples
databasepostgresqldockerdocker-composejooq

How can one make a Docker Compose service build depend on another service?


Here's what I mean. How can I write a docker-compose.yaml file so that when one of the services is "built", it first runs another service?

I'll try to be even more specific. I'm trying to build a Java application using the database library JOOQ, which wants to connect to a database at build time in order to generate Java classes that correspond to database tables. I would like some combination of Dockerfile(s) and docker-compose.yaml file, such that the following happens in roughly the following order.

  1. A "database" service is started (in my case, using a postgres image).
  2. The database is initialized with SQL scripts in my development repo.
  3. The build phase of my "web" service runs, which uses a Dockerfile in the same repo, which invokes the Gradle build, which tells JOOQ to connect to the database service started in step 1. This generates Java files, compiles them, and does everything else for building the container.
  4. The "web" service is started, connecting to the database service started in step 1.

Here's the docker-compose.yaml file I'm working with

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"

I'll flesh this out with more details, but hopefully what I'm asking is pretty straightforward.


Solution

  • This should now (technically) be possible:

    since 2021-04-06 in version 1.29.0 (release note link)

    Using the service_completed_successfully condition (which is a "Long Form" depends_on option):

    Long syntax:

    The long form syntax enables the configuration of additional fields that can't be expressed in the short form.

    • condition: condition under which dependency is considered satisfied
      • service_completed_successfully: specifies that a dependency is expected to run to successful completion before starting a dependent service.

    (source - emphasis added)

    Long Syntax Example:

    depends_on:
      service_name:
        condition: service_completed_successfully
    

    Update your docker-compose.yml file:

    You'll need to make the following changes:

    • bump your compose version up to 3.8
    • add the new service_completed_successfully condition to your depends_on
    version: "3.8"
    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:
            condition: service_completed_successfully
        ports:
          - "8080:8080"
    

    You might also need to use a multi-stage Dockerfile:

    (multi-stage build info)

    Multi-stage builds are typically used to slim down your final Docker image, but it can also be used to run scripts and create "artifacts" needed before finishing your build.

    It's hard to suggest this without seeing your exact Dockerfile, but I thought it was worth mentioning that you may need to also use this.