What is the alternative to condition form of depends_on in docker-compose Version 3?

DockerDocker Compose

Docker Problem Overview


docker-compose 2.1 offers the nice feature to specify a condition with depends_on. The current docker-compose documentation states: > Version 3 no longer supports the condition form of depends_on.

Unfortunately the documentation does not explain, why the condition form was removed and is lacking any specific recommondation on how to implement that behaviour using V3 upwards.

Docker Solutions


Solution 1 - Docker

There's been a move away from specifying container dependencies in compose. They're only valid at startup time and don't work when dependent containers are restarted at run time. Instead, each container should include mechanism to retry to reconnect to dependent services when the connection is dropped. Many libraries to connect to databases or REST API services have configurable built-in retries. I'd look into that. It is needed for production code anyway.

Solution 2 - Docker

From 1.27.0, 2.x and 3.x are merged with COMPOSE_SPEC schema.

version is now optional. So, you can just remove it and specify a condition as before:

services:
  web:
    build: .
    depends_on:
      redis:
        condition: service_healthy
  redis:
    image: redis
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 1s
      timeout: 3s
      retries: 30

Solution 3 - Docker

There are some external tools that let you mimic this behaviour. For example, with the dockerize tool you can wrap your CMD or ENTRYPOINT with dockerize -wait and that will prevent running your application until specified services are ready.

If your docker-compose file used to look like this:

version: '2.1'
services:
  kafka:
    image: spotify/kafka
    healthcheck:
      test: nc -z localhost 9092
  webapp:
     image: foo/bar # your image
     healthcheck:
       test: curl -f http://localhost:8080
  tests:
     image: bar/foo # your image
     command: YOUR_TEST_COMMAND
     depends_on:
       kafka:
         condition: service_healthy
       webapp:
         condition: service_healthy

then you can use dockerize in your v3 compose file like this:

version: '3.0'
services:
  kafka:
    image: spotify/kafka
  webapp:
     image: foo/bar # your image
  tests:
     image: bar/foo # your image
     command: dockerize -wait tcp://kafka:9092 -wait web://webapp:8080 YOUR_TEST_COMMAND

Solution 4 - Docker

Just thought I'd add my solution for when running postgres and an application via docker-compose where I need the application to wait for the init sql script to complete before starting.

dockerize seems to wait for the db port to be available (port 5432) which is the equivilant of depends_on which can be used in docker 3:

version: '3'

services:
  app:
    container_name: back-end
    depends_on:
      - postgres
  postgres:
    image: postgres:10-alpine
    container_name: postgres
    ports:
      - "5432:5432"
    volumes:
      - ./docker-init:/docker-entrypoint-initdb.d/

The Problem:

If you have a large init script the app will start before that completes as the depends_on only waits for the db port.

Although I do agree that the solution should be implemented in the application logic, the problem we have is only for when we want to run tests and prepopulate the database with test data so it made more sense to implement a solution outside the code as I tend not like introducing code "to make tests work"

The Solution:

Implement a healthcheck on the postgres container. For me that meant checking the command of pid 1 is postgres as it will be running a different command on pid 1 while the init db scripts are running

Write a script on the application side which will wait for postgres to become healthy. The script looks like this:

#!/bin/bash
function check {
  STATUS=\`curl -s --unix-socket /var/run/docker.sock http:/v1.24/containers/postgres/json | python -c 'import sys, json; print json.load('sys.stdin')["State"]["Health"]["Status"]'\`

  if [ "$STATUS" = "healthy" ]; then
    return 0
  fi
  return 1
}

until check; do
  echo "Waiting for postgres to be ready"
  sleep 5
done

echo "Postgres ready"

Then the docker-compose should mount the directories of the scripts so that we don't edit the Dockerfile for the application and if we're using a custom postgres image, this way we can continue to use the docker files for your published images.

We're also overriding the entry point defined in the docker file of the app so that we can run the wait script before the app starts

version: '3'

services:
  app:
    container_name: back-end
    entrypoint: ["/bin/sh","-c","/opt/app/wait/wait-for-postgres.sh && <YOUR_APP_START_SCRIPT>"]
    depends_on:
      - postgres
    volumes:
      - //var/run/docker.sock:/var/run/docker.sock
      - ./docker-scripts/wait-for-postgres:/opt/app/wait
  postgres:
    image: postgres:10-alpine
    container_name: postgres
    ports:
      - "5432:5432"
    volumes:
      - ./docker-init:/docker-entrypoint-initdb.d/
      - ./docker-scripts/postgres-healthcheck:/var/lib
    healthcheck:
      test: /var/lib/healthcheck.sh
      interval: 5s
      timeout: 5s
      retries: 10

Solution 5 - Docker

Instead of depending on another container to start, consider deliberately exiting from your containerized application if a connection error is received while trying to access a container that may not be in a ready state. Such a strategy used together with an appropriate restart policy for your containers will restart your application container until the connection is available or a different condition is met.

Alternatively, there are some good utilities like wait-for-it to use if you prefer to wait for a specific amount of time. Here's a good example of using wait-for-it with an mssql container

Solution 6 - Docker

I reached this page because one container would not wait for the one depending upon and I had to run a docker system prune to get it working. There was an orphaned container error that prompted me to run the prune.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionm oView Question on Stackoverflow
Solution 1 - DockerBernardView Answer on Stackoverflow
Solution 2 - DockerquantaView Answer on Stackoverflow
Solution 3 - DockerJakub KukulView Answer on Stackoverflow
Solution 4 - DockerMujiView Answer on Stackoverflow
Solution 5 - DockergoonerifyView Answer on Stackoverflow
Solution 6 - DockerobotezatView Answer on Stackoverflow