Docker-Compose: как дождаться готовности другого сервиса?

У меня есть следующий докер-сочинять, где мне нужно дождаться, пока служба jhipster-реестр будет запущена и принимает соединения, прежде чем запускать myprogram-приложение.

Я попробовал способ проверки здоровья, следуя официальному документу https://docs.docker.com/compose/compose-file/compose-file-v2/

version: '2.1'
services:
    myprogram-app:
        image: myprogram
        mem_limit: 1024m
        environment:
            - SPRING_PROFILES_ACTIVE=prod,swagger
            - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:$${jhipster.registry.password}@jhipster-registry:8761/eureka
            - SPRING_CLOUD_CONFIG_URI=http://admin:$${jhipster.registry.password}@jhipster-registry:8761/config
            - SPRING_DATASOURCE_URL=jdbc:postgresql://myprogram-postgresql:5432/myprogram
            - JHIPSTER_SLEEP=0
            - SPRING_DATA_ELASTICSEARCH_CLUSTER_NODES=myprogram-elasticsearch:9300
            - JHIPSTER_REGISTRY_PASSWORD=53bqDrurQAthqrXG
            - EMAIL_USERNAME
            - EMAIL_PASSWORD
        ports:
            - 8080:8080
        networks:
          - backend
        depends_on:
          - jhipster-registry:
              "condition": service_started
          - myprogram-postgresql
          - myprogram-elasticsearch
    myprogram-postgresql:
        image: postgres:9.6.5
        mem_limit: 256m
        environment:
            - POSTGRES_USER=myprogram
            - POSTGRES_PASSWORD=myprogram
        networks:
          - backend
    myprogram-elasticsearch:
        image: elasticsearch:2.4.6
        mem_limit: 512m
        networks:
          - backend
    jhipster-registry:
        extends:
            file: jhipster-registry.yml
            service: jhipster-registry
        mem_limit: 512m
        ports:
            - 8761:8761
        networks:
          - backend
        healthcheck:
          test: "exit 0"
networks:
  backend:
    driver: "bridge"

но я получаю следующую ошибку при запуске docker-compose up:

ERROR: The Compose file './docker-compose.yml' is invalid because:
services.myprogram-app.depends_on contains {"jhipster-registry": {"condition": "service_started"}}, which is an invalid type, it should be a string

Я что-то делаю не так, или эта функция больше не поддерживается? Как добиться такой синхронизации между сервисами?

Обновленная версия

version: '2.1'
services:
    myprogram-app:
        image: myprogram
        mem_limit: 1024m
        environment:
            - SPRING_PROFILES_ACTIVE=prod,swagger
            - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:$${jhipster.registry.password}@jhipster-registry:8761/eureka
            - SPRING_CLOUD_CONFIG_URI=http://admin:$${jhipster.registry.password}@jhipster-registry:8761/config
            - SPRING_DATASOURCE_URL=jdbc:postgresql://myprogram-postgresql:5432/myprogram
            - JHIPSTER_SLEEP=0
            - SPRING_DATA_ELASTICSEARCH_CLUSTER_NODES=myprogram-elasticsearch:9300
            - JHIPSTER_REGISTRY_PASSWORD=53bqDrurQAthqrXG
            - EMAIL_USERNAME
            - EMAIL_PASSWORD
        ports:
            - 8080:8080
        networks:
          - backend
        depends_on:
          jhipster-registry:
            condition: service_healthy
          myprogram-postgresql:
            condition: service_started
          myprogram-elasticsearch:
            condition: service_started
        #restart: on-failure
    myprogram-postgresql:
        image: postgres:9.6.5
        mem_limit: 256m
        environment:
            - POSTGRES_USER=myprogram
            - POSTGRES_PASSWORD=tuenemreh
        networks:
          - backend
    myprogram-elasticsearch:
        image: elasticsearch:2.4.6
        mem_limit: 512m
        networks:
          - backend
    jhipster-registry:
        extends:
            file: jhipster-registry.yml
            service: jhipster-registry
        mem_limit: 512m
        ports:
            - 8761:8761
        networks:
          - backend
        healthcheck:
          test: ["CMD", "curl", "-f", "http://jhipster-registry:8761", "|| exit 1"]
          interval: 30s
          retries: 20
          #start_period: 30s
networks:
  backend:
    driver: "bridge"

Обновленная версия выдает другую ошибку,

ERROR: for myprogram-app  Container "8ebca614590c" is unhealthy.
ERROR: Encountered errors while bringing up the project.

говоря, что контейнер jhipster-registry неисправен, но доступен через браузер. Как я могу исправить команду в проверке работоспособности, чтобы она работала?

Смотрите также: Docker Compose ждет контейнера X перед запуском Y
KyleMit 20.11.2020 00:14
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
13
1
18 762
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

документация предполагает, что в файлах Docker Compose версии 2, в частности, depends_on: может быть списком строк или отображением, где ключи являются именами служб, а значения - условиями. Для служб, для которых у вас нет (или необходимости) проверки работоспособности, существует условие service_started.

depends_on:
  # notice: these lines don't start with "-"
  jhipster-registry:
    condition: service_healthy
  myprogram-postgresql:
    condition: service_started
  myprogram-elasticsearch:
    condition: service_started

В зависимости от того, насколько вы контролируете свою программу и ее библиотеки, еще лучше, если вы можете организовать запуск службы без обязательной доступности ее зависимостей (эквивалентно, чтобы она работала, если ее зависимости умирают во время работы службы) , а не использовать опцию depends_on:. Вы можете вернуть ошибку HTTP 503 Service Unavailable, например, если база данных не работает. Другая часто полезная стратегия - немедленно выйти, если ваши зависимости недоступны, но использовать установка, например restart: on-error, чтобы попросить оркестратор перезапустить службу.

Хорошо, предыдущая ошибка исчезла. Я обновил вопрос с вашим исправлением, но используемая команда, похоже, не работает. Как мне сделать так, чтобы curl возвращал 0 (я прочитал его, но это не так), если jhipser-registry: 8761 запущен?

1Z10 14.09.2018 02:02

Справочная страница curl имеет довольно исчерпывающий список кодов выхода; Документы Docker HEALTHCHECK предлагает curl -f http://localhost/ || exit 1 в качестве типичной проверки работоспособности (для этого требуется, чтобы в вашем образе был установлен curl).

David Maze 14.09.2018 03:18

этот ответ больше не актуален. из документов: Version 3 no longer supports the condition form of depends_on

Liran Brimer 13.11.2018 16:33

Это снова актуально. Из docker-compose 1.27.0 он поддерживает стандарт COMPOSE_SPEC для v3, который включает condition для depends_on, см. примечания к выпуску

AngryUbuntuNerd 12.05.2021 19:27

Хотя вы уже получили ответ, следует отметить, что то, чего вы пытаетесь достичь, сопряжено с некоторыми неприятными рисками.

В идеале сервис должен быть самодостаточным и достаточно умным, чтобы повторить попытку и дождаться появления зависимостей (до того, как произойдет сбой). В противном случае вы будете больше подвержены риску распространения одного сбоя на другие службы. Также учтите, что перезагрузка системы, в отличие от ручного запуска, может игнорировать порядок зависимостей.

Если сбой одной службы приводит к отказу всей вашей системы, у вас может быть инструмент, чтобы перезапустить все снова, но было бы лучше иметь службы, которые сопротивляются этому случаю.

Обновитесь до версии 3+.

Следуйте документы версии 3:

There are several things to be aware of when using depends_on:

depends_on does not wait for db and redis to be “ready” before starting web - only until they have been started.
If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
Version 3 no longer supports the condition form of depends_on.
The depends_on option is ignored when deploying a stack in swarm mode with a version 3 Compose file.

Я бы подумал об использовании параметра restart_policy для настройки вашего myprogram-приложение для перезапуска, пока jhipster-реестр не будет включен и принимать соединения:

 restart_policy:
        condition: on-failure
        delay: 3s
        max_attempts: 5
        window: 60s

Лучший подход - запуск отказоустойчивого приложения

Хотя docker делает поддерживает зависимости запуска, они официально рекомендуют обновить логику запуска вашего приложения, чтобы проверить наличие внешних зависимостей и повторить попытку. Это имеет множество преимуществ для надежных приложений, которые могут перезапускаться в дикой природе на лету, в дополнение к обходу состояния гонки в docker compose up.

Докерский подход - wait-for-it.sh

Рекомендуемый подход от докеров в соответствии с их документами на Управление порядком запуска и завершения работы в Compose - загрузить wait-for-it.sh, который принимает domain:port для опроса, а затем выполняет следующий набор команд в случае успеха.

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

Примечание: это требует переопределения команды запуска образа, поэтому убедитесь, что вы знаете, что нужно передать, чтобы сохранить четность запуска по умолчанию.

Исторический подход - depends_on - service_healthy (устарело 3+)

Исторически вы могли определить healthcheck (все еще хорошая практика), а затем установить условие для depends_on на service_healthy, однако это условное отклонение зависит от устаревшего в версии 3.0.

version: '3.0'
services:
  php:
    build:
      context: .
      dockerfile: tests/Docker/Dockerfile-PHP
    depends_on:
      redis:
        condition: service_healthy
  redis:
    image: redis
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 1s
      timeout: 3s
      retries: 30

Дальнейшее чтение

Лучший подход, который я нашел, - это проверить желаемый порт в точке входа. Это можно сделать разными способами, например: wait-for-it, но мне нравится использовать это решение, которое является кроссплатформенным между изображениями apline и bash и не загружает пользовательские скрипты с GitHub:

Установите netcat-openbsd (работает с apt и apk). Затем в точке входа (работает как с #!/bin/bash, так и с #!/bin/sh):

#!/bin/bash

wait_for()
{
  echo "Waiting $1 seconds for $2:$3"
  timeout $1 sh -c 'until nc -z $0 $1; do sleep 0.1; done' $2 $3 || return 1
  echo "$2:$3 available"
}


wait_for 10 db 5432
wait_for 10 redis 6379

Вы также можете превратить это в однострочник, если не хотите ничего печатать.

Другие вопросы по теме