Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start service only when other service had completed?

Using compose I want to start a service only after another service has exited with code 0.

I have mutiple needs for this functionality. The basic need is where I have:

  • database service
  • database migration service
  • application service

The database service will start an empty database. My app needs it's schema setup in the database so I have a second service which will do this when it is run. When it is done this service will exit successfully - I can see this in my docker compose log file:

webservices_kong-migration_1 exited with code 0

I do not want the application service to start until after the database migration has completed.

I have the following in my docker-compose file for the application service:

depends_on:
  kong-database:
    condition: service_healthy
  kong-migration:
    condition: service_started

I know this is wrong because I can see in my docker-compose log that the application is started after the migration has started but before it has completed, causing the application to fail.

(I have been taking https://github.com/Kong/docker-kong/blob/master/compose/docker-compose.yml as an example)

Does docker-compose have functionality to do this or should I be considering another method?

like image 407
Robert3452 Avatar asked Jan 04 '18 09:01

Robert3452


4 Answers

This is a supplement to @zooblin 's answer

Since docker-compose version 1.29, we can do it by condition: service_completed_successfully

In your scene, database service start will cost some time, so the migration scripts should be executed after database fully started.

And the application service should start after migration scripts executed successfully.

the docker-compose.yaml may be like following(here we use cassandra as exmaple, for other database, you can just modify healthcheck commands):

version: '3.8'
services:
  applicaion-service:
    image: your-applicaion-service:0.0.1
    depends_on:
      cassandra-init-keyspace:
        condition: service_completed_successfully


  cassandra:
    image: cassandra:4.0.1
    ports:
      - "9042:9042"
    healthcheck:
      test: ["CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces"]
      interval: 15s
      timeout: 10s
      retries: 10

  cassandra-init-keyspace:
    image: cassandra:4.0.1
    depends_on:
      cassandra:
        condition: service_healthy
    volumes:
      - ./src/main/resources/cassandra/init.cql:/init.cql
    command: /bin/bash -c "echo loading cassandra keyspace && cqlsh cassandra -f /init.cql"
like image 126
counter2015 Avatar answered Oct 27 '22 10:10

counter2015


Docker compose haven't any out-of-the-box solutions.
But exists a number of good implementations for solving this problem.

One of the better solutions is using service discovery as Consul and Autopilot model implemented in Joyent Containerpilot.

This model allows implementing dependencies between services even in docker swarm cluster where service dependency does not exist at all.

Containerpilot jobs model allow creating simple scripts to keep started services in the right order.

like image 22
ozlevka Avatar answered Oct 27 '22 08:10

ozlevka


docker-compose version 1.29 comes with build in functionality: service_completed_successfully. According to spec:

service_completed_successfully - specifies that a dependency is expected to run to successful completion before starting a dependent service.

depends_on:
  <service-name>:
    condition: service_completed_successfully
like image 7
zooblin Avatar answered Oct 27 '22 10:10

zooblin


For those who are looking for an answer, there're still no out-of-the-box solutions for this.

A workaround solution consists in using a wrapper script : https://docs.docker.com/compose/startup-order/

In Robert's case, you can imagine a script that loops and waits until the database service can no more be pinged (until the services has stopped).

like image 5
Zak Avatar answered Oct 27 '22 09:10

Zak