Введение Есть много статей о запуске контейнеров и написании docker-compose.yml .
Но долгое время для меня оставался неясным вопрос, как правильно поступить, если контейнер не должен запускаться до тех пор, пока другой контейнер не будет готов к обработке его запросов или не выполнит определенный объем работы.
Этот вопрос стал актуальным после того, как мы начали активно использовать docker-compose , вместо запуска отдельных докеров.
Зачем это нужно? Действительно, пусть приложение в контейнере Б зависит от готовности сервиса в контейнере А.
И при запуске приложение в контейнере Б не получает этот сервис.
Что оно должно делать? Вариант второй:
- первый - умереть (желательно с кодом ошибки)
- второй — подождать, а потом все равно умереть, если приложение в контейнере B не ответило в течение отведенного таймаута
И на самом деле это нормальный путь для многоконтейнерной архитектуры.
Но, в частности, мы столкнулись с ситуацией, когда контейнер А запускается и готовит данные для контейнера Б.
Приложение в контейнере Б не знает, как проверить, готовы данные или нет; он сразу начинает с ним работать.
Поэтому нам приходится самим получать и обрабатывать сигнал о готовности данных.
Я думаю, что можно привести еще несколько вариантов использования.
Но самое главное, вам нужно точно понимать, зачем вы это делаете.
В противном случае лучше использовать стандартные инструменты.
docker-compose Немного идеологии Если внимательно прочитать документацию, там все написано.
А именно - каждый Контейнер является независимой единицей и должен сам обеспечивать, чтобы все сервисы, включая ему доступны.
Поэтому вопрос не в том, запускать или не запускать контейнер, а в том, стоит ли внутри контейнера проверьте готовность всех необходимых сервисов и только после этого передаем управление приложению-контейнеру.
Как это реализовано В решении этой проблемы мне очень помогло описание docker-compose , Здесь этот Часть этого И статья , рассказывая о правильном использовании входная точка И cmd .
Итак, что нам нужно получить:
- есть приложение А, которое мы завернули в контейнер А
- он запускается и начинает отвечать ОК на порту 8000
- а также есть приложение Б, которое мы запускаем из контейнера Б, но оно должно начать работать не раньше, чем приложение А начнет отвечать на запросы на порту 8000
Первый — написать свой собственный входная точка в контейнере, который выполнит все проверки и затем запустит рабочее приложение.
Второй — использовать уже написанный командный файл подожди-for-it.sh .
Мы попробовали оба пути.
Написание собственной точки входа
Что случилось входная точка ? Это просто исполняемый файл, который вы указываете при создании контейнера в Докерфайл в поле ВХОДНАЯ ТОЧКА .Этот файл, как уже говорилось, выполняет проверки, а затем запускает основное приложение-контейнер.
Итак, что мы получаем: Давайте создадим папку Входная точка .
В нем есть две подпапки - контейнер_А И контейнер_B .
В них мы будем создавать наши контейнеры.
Для контейнера A возьмем простой http-сервер на Python. После запуска он начинает отвечать на запросы на порт 8000. Чтобы сделать наш эксперимент более наглядным, мы установим задержку в 15 секунд перед запуском сервера.
Оказывается следующее docker-файл для контейнера A :
Для контейнера B мы создадим следующее docker-файл для контейнера B :FROM python:3 EXPOSE 8000 CMD sleep 15 && python3 -m http.server --cgi
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl
COPY .
/entrypoint.sh /usr/bin/entrypoint.sh
ENTRYPOINT [ "entrypoint.sh" ]
CMD ["echo", "!!!!!!!! Container_A is available now !!!!!!!!"]
И в эту же папку поместим наш исполняемый файл enterpoint.sh. у нас будет так
#!/bin/bash
set -e
host="conteiner_a"
port="8000"
cmd="$@"
>&2 echo "!!!!!!!! Check conteiner_a for available !!!!!!!!"
until curl http://"$host":"$port "; do
>&2 echo "Conteiner_A is unavailable - sleeping"
sleep 1
done
>&2 echo "Conteiner_A is up - executing command"
exec $cmd
Что происходит в контейнере B:
- Когда он запускается, он работает ВХОДНАЯ ТОЧКА , т. е.
запускает точка входа.
sh
- точка входа.
sh , используя завиток , начинает опрашивать порт 8000 контейнера A. Он делает это до тех пор, пока не получит ответ 200 (т.е.
завиток в этом случае он закончится нулевым результатом и цикл завершится)
- При получении 200 цикл завершается и управление передается команде, указанной в переменной $cmd .
И показывает то, что мы указали в докер-файле в поле КМД , т.е.
echo "!!! Контейнер_A доступен!!!!!!!!" .
Почему это так, описано выше.
статья
- Мы печатаем - !!! Контейнер_А доступен!!! и мы заканчиваем.
docker-compose.yml у нас есть вот этот: version: '3'
networks:
waiting_for_conteiner:
services:
conteiner_a:
build: .
/conteiner_A container_name: conteiner_a image: conteiner_a restart: unless-stopped networks: - waiting_for_conteiner ports: - 8000:8000 conteiner_b: build: .
/conteiner_B
container_name: conteiner_b
image: waiting_for_conteiner.entrypoint.conteiner_b
restart: "no"
networks:
- waiting_for_conteiner
Здесь, в контейнер_а не обязательно указывать порты: 8000:8000 .
Это сделано для того, чтобы иметь возможность проверить работу работающего в нем http-сервера извне.
Кроме того, контейнер B не подлежит перезапуску после завершения работы.
Запустим: docker-compose up —-build
Видим, что секунд 15 появляется сообщение о недоступности контейнера А, а затем
Теги: #*nix #Системное администрирование #docker-compose
-
Эскимосско-Алеутские Языки
19 Oct, 24 -
Agile Ит-Консалтинговые Проекты?
19 Oct, 24 -
Бесплатный Vpn
19 Oct, 24 -
Aws Insight: Реплика Чтения Rds
19 Oct, 24 -
Переопределение На Основе Выпуска. Часть 2
19 Oct, 24 -
Радуг + Ди = Wwdc
19 Oct, 24