27

I'm working with a docker service using docker-compose, and I have a service that depends on anther.

I've used the depends_on key, but the service with the dependency launches prior to the depending service being completely up.

version: '3'

services:
  KeyManager:
    image: cjrutherford/keymanager
    deploy:
      replicas: 1
    ports:
      - '3220:3220'
    networks:
      - privnet
  YellowDiamond:
    image: cjrutherford/server
    depends_on:
      - KeyManager
    deploy:
      replicas: 1
    ports:
      - '3000:3000'
    networks:
      - privnet
      - web
networks:
  privnet:
    internal: true
  web:

Both of these are node applications, and the keymanager is required to be running to accept requests before the server launches. Can I add a timeout? or send a trigger in the app? it's just launching way too early to get the key from the manager.

Chris Rutherford
  • 1,592
  • 3
  • 22
  • 58
  • Not a perfect solution, but this maybe can give you some hints: https://github.com/dadarek/docker-wait-for-dependencies – rckrd Apr 03 '19 at 19:09
  • 1
    **See Also**: [Docker Compose wait for container X before starting Y](https://stackoverflow.com/q/31746182/1366033) – KyleMit Nov 19 '20 at 23:14

3 Answers3

21

You are probably looking for docker compose healthcheck and the Long Syntax form of depends_on.

The behavior for this feature has changed between docker-copmose versions, so here is the updated way to do so (this docker-compose file works as is):

services:
  db:
    image: postgres
    environment:
      - POSTGRES_USER=king
      - POSTGRES_DB=kong
      - POSTGRES_HOST_AUTH_METHOD=trust
    healthcheck:
      test: pg_isready -U postgres

  web:
    image: alpine
    depends_on: 
      db:
        condition: service_healthy

Then run docker-compose run web, and it will wait for the database before starting.

There is also a more detailed form of the healthcheck directive:

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]
  interval: 10s
  timeout: 5s
  retries: 5

Notes:

  1. This requires docker-compose 1.27.0 or higher
  2. In order for this to work, the compose file must not contain version directive (reference)
DannyB
  • 12,810
  • 5
  • 55
  • 65
  • 4
    this has been changed again for version 3 in docker-compose 1.27.0, condition form is supported. see https://docs.docker.com/compose/release-notes/#1270 ("COMPOSE_SPEC") – AngryUbuntuNerd May 17 '21 at 09:16
17

I've often found using a wait-for-it bash script much more effective than the built in health check to docker-compose.

This runs a TCP health check against a given port and waits until this is complete before starting to run a process.

Sample code:

version: "2"
services:
  web:
    build: .
    ports:
      - "80:8000"
    depends_on:
      - "db"
    command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"]
  db:
    image: postgres

Here's some docs:

devingops
  • 196
  • 4
  • 1
    This is awesome, but I do have a question about this answer. How would you do this if you're not building your image in compose? (i.e. prebuilt image with dependency) – Chris Rutherford Apr 04 '19 at 13:12
  • You can add it to an ENTRYPOINT command/script in your Dockerfile, this way it runs when the container starts. (although you wouldn't then be able to reference the other container using the docker-compose internal DNS (i.e. "db"), you would need to do this another way depending on your setup. – devingops Apr 04 '19 at 14:07
0

I use wait-for-it.sh on nodejs on centos 8 and got the following error.

myimage-data-api | /usr/src/app/wait-for-it.sh:2
myimage-data-api | # Use this script to test if a given TCP host/port 
are available
myimage-data-api | ^
myimage-data-api | 
myimage-data-api | SyntaxError: Invalid or unexpected token
myimage-data-api |     at Object.compileFunction (node:vm:352:18)
myimage-data-api |     at wrapSafe 
(node:internal/modules/cjs/loader:1026:15)
myimage-data-api |     at Module._compile 
(node:internal/modules/cjs/loader:1061:27)
myimage-data-api |     at Object.Module._extensions..js 
(node:internal/modules/cjs/loader:1149:10)
myimage-data-api |     at Module.load 
(node:internal/modules/cjs/loader:975:32)
myimage-data-api |     at Function.Module._load 
(node:internal/modules/cjs/loader:822:12)
myimage-data-api |     at Function.executeUserEntryPoint [as runMain] 
(node:internal/modules/run_main:81:12)
myimage-data-api |     at node:internal/main/run_main_module:17:47
myimage-data-api | 
myimage-data-api | Node.js v17.3.0
Alex Aung
  • 2,637
  • 5
  • 34
  • 63