Compose: Есть ли способ отложить запуск контейнера для поддержки зависимых служб с более длительным временем запуска?

Созданный на 5 авг. 2014  ·  314Комментарии  ·  Источник: docker/compose

У меня есть контейнер MySQL, запуск которого требует немного времени, так как ему необходимо импортировать данные.

У меня есть контейнер Alfresco, который зависит от контейнера MySQL.

На данный момент, когда я использую fig, служба Alfresco внутри контейнера Alfresco не работает, когда пытается подключиться к контейнеру MySQL ... якобы потому, что служба MySQL еще не прослушивает.

Есть ли способ справиться с подобной проблемой на Fig?

Самый полезный комментарий

Да, мне было бы интересно что-то подобное - я хотел опубликовать об этом раньше.

Наименьший образец воздействия, который я могу придумать, который мог бы исправить этот сценарий использования, был бы следующим:

Добавьте «wait» в качестве нового ключа в fig.yml с семантикой значения, аналогичной ссылке. Docker будет рассматривать это как предварительное условие и ждать, пока этот контейнер не выйдет, прежде чем продолжить.

Итак, мой файл докеров будет выглядеть примерно так:

db:
  image: tutum/mysql:5.6

initdb:
  build: /path/to/db
  link:
    - db:db
  command: /usr/local/bin/init_db

app:
  link:
    - db:db
  wait:
    - initdb

При запуске приложения он запустит все контейнеры ссылок, затем запустит контейнер ожидания и перейдет к реальному контейнеру приложения только после выхода из контейнера ожидания (initdb). initdb запускает сценарий, который ожидает, пока база данных станет доступной, затем выполняет любые инициализации / миграции / что-то еще, а затем завершает работу.

Во всяком случае, это мои мысли.

Все 314 Комментарий

На работе мы оборачиваем наши зависимые службы в сценарий, который проверяет, установлена ​​ли связь. Я знаю, что одному из моих коллег это тоже будет интересно! Лично я считаю, что на уровне контейнера нужно ждать доступности сервисов, но я могу ошибаться :)

Точно так же поступаем и с упаковкой. Вы можете увидеть пример здесь: https://github.com/dominionenterprises/tol-api-php/blob/master/tests/provisioning/set-env.sh

Было бы удобно иметь сценарий точки входа, который перебирает все ссылки и ждет, пока они не заработают, прежде чем запускать переданную ему команду.

Это должно быть встроено в сам Docker, но решение пока еще далеко. Контейнер не следует считать запущенным, пока открытая ссылка не открылась.

@bfirsh это больше, чем я мог себе представить, но было бы отлично.

Контейнер не следует считать запущенным, пока открытая ссылка не открылась.

Думаю, это именно то, что нужно людям.

На данный момент я буду использовать вариант https://github.com/aanand/docker-wait

Да, мне было бы интересно что-то подобное - я хотел опубликовать об этом раньше.

Наименьший образец воздействия, который я могу придумать, который мог бы исправить этот сценарий использования, был бы следующим:

Добавьте «wait» в качестве нового ключа в fig.yml с семантикой значения, аналогичной ссылке. Docker будет рассматривать это как предварительное условие и ждать, пока этот контейнер не выйдет, прежде чем продолжить.

Итак, мой файл докеров будет выглядеть примерно так:

db:
  image: tutum/mysql:5.6

initdb:
  build: /path/to/db
  link:
    - db:db
  command: /usr/local/bin/init_db

app:
  link:
    - db:db
  wait:
    - initdb

При запуске приложения он запустит все контейнеры ссылок, затем запустит контейнер ожидания и перейдет к реальному контейнеру приложения только после выхода из контейнера ожидания (initdb). initdb запускает сценарий, который ожидает, пока база данных станет доступной, затем выполняет любые инициализации / миграции / что-то еще, а затем завершает работу.

Во всяком случае, это мои мысли.

(исправлено, см. ниже)

+1 здесь тоже. Делать это в самих командах не очень привлекательно.

+1 тоже. Просто столкнулся с этой проблемой. Отличный инструмент, кстати, делает мою жизнь намного проще!

+1 было бы здорово иметь это.

+1 тоже. Недавно столкнулись с тем же набором проблем

+1 тоже. любое заявление от dockerguys?

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

После некоторых размышлений и экспериментов я вроде как согласен с этим.

Как такое приложение, которое я создаю, в основном имеет синхронный
Функция waitfor (host, port), которая позволяет мне ждать обслуживания приложения
зависит от (обнаруживается через среду или явно
конфигурация через опции cli).

ура
Джеймс

Джеймс Миллс / прологик

Э: [email protected]
W: prologic.shortcircuit.net.au

Пт, 22 августа 2014 г., 18:34, Марк Стюарт [email protected]
написал:

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

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/docker/fig/issues/374#issuecomment -53036154.

Да, здесь нужны некоторые основные "зависимости от" ...
так что, если у вас есть 20 контейнеров, вы просто не хотите запускать фиг, и все начинается с правильного порядка ...
Однако у него также есть опция тайм-аута или другие механизмы обнаружения сбоев.

Еще +1 здесь. У меня Postgres запускается дольше, чем Django, поэтому БД не существует для команды миграции без взлома.

@ahknight интересно, почему миграция выполняется во время run ?

Разве вы не хотите запускать миграцию на этапе build ? Так вы сможете загружать свежие изображения намного быстрее.

Увы, для рассматриваемого приложения есть сценарий запуска большего размера. На данный момент мы сначала выполняем работу, не связанную с БД, используя nc -w 1 в цикле для ожидания БД, а затем выполняем действия БД. Это работает, но я чувствую себя грязным (э-э).

Я добился больших успехов в выполнении этой работы на этапе fig build . У меня есть один пример этого с проектом django (работа над которым все еще продолжается): https://github.com/dnephin/readthedocs.org/blob/fig-demo/dockerfiles/database/Dockerfile#L21

Не нужно опрашивать для запуска. Хотя я сделал что-то подобное с mysql, где мне пришлось опросить для запуска, потому что сценарий mysqld init еще не делал этого. Этот сценарий инициализации postgres кажется намного лучше.

Вот что я подумал:

Используя идею docker / docker # 7445, мы могли бы реализовать этот атрибут "wait_for_helth_check" на рис.
Так это фига не докер проблема?

есть ли способ заставить фиг проверять статус tcp в связанном контейнере, если да, то я думаю, что это путь. знак равно

@dnephin, не могли бы вы подробнее объяснить, что вы делаете в Dockerfiles, чтобы помочь в этом?
Разве фаза сборки не может повлиять на время выполнения?

@docteurklein Я могу. Я исправил ссылку сверху (https://github.com/dnephin/readthedocs.org/blob/fig-demo/dockerfiles/database/Dockerfile#L21)

Идея состоит в том, что вы выполняете все более медленные операции «установки» во время сборки, поэтому вам не нужно ничего ждать во время запуска контейнера. В случае базы данных или поискового индекса вы должны:

  1. запустить службу
  2. создавать пользователей, базы данных, таблицы и данные фикстур
  3. выключить службу

все как один шаг сборки. Позже, когда вы fig up контейнер базы данных, он будет готов к работе практически сразу, и вы также сможете воспользоваться преимуществами кеша сборки докеров для этих более медленных операций.

отлично! благодаря :)

@dnephin мило, не думал об этом.

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

Не могли бы вы привести пример, зачем и когда это нужно?

В моем случае использования у меня есть сервер Elasticsearch, а затем сервер приложений, который подключается к Elasticsearch. Для запуска Elasticsearch требуется несколько секунд, поэтому я не могу просто выполнить fig up -d потому что сервер приложений сразу выйдет из строя при подключении к серверу Elasticsearch.

Допустим, один контейнер запускает MySQL, а другой запускает приложение, которому требуется MySQL, и оказывается, что другое приложение запускается быстрее. Из-за этого у нас бывают временные отказы fig up .

В кране есть способ обойти это, позволяя создавать группы, которые можно запускать индивидуально. Итак, вы можете запустить группу MySQL, подождать 5 секунд, а затем запустить другие вещи, которые от нее зависят.
Работает в небольших масштабах, но не является реальным решением.

@oskarhane не уверен, что это «подождите 5 секунд» поможет, в некоторых случаях может потребоваться подождать больше (или просто не уверен, что это не продлится 5 секунд) ... это не очень безопасно полагаться на время ожидания.
Также вам придется вручную сделать это, ожидая и загружая другую группу, и это отчасти хромает, fig должен сделать это за вас = /

@oskarhane , @dacort , @ddossot :

Вы правы, но до тех пор, пока мы не исправим все существующие приложения, чтобы они могли выполнять такие вещи, как плавное восстановление после отсутствия их критических ресурсов (например, БД) при запуске (что является отличным, но, к сожалению, редко поддерживается фреймворками), мы должны fig start для запуска отдельного контейнера в определенном порядке с задержками вместо fig up .

Я вижу сценарий оболочки, который управляет рисом для управления докером: wink:

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

Я видел в некотором коде, связанном с более ранним комментарием, это было сделано:

while ! exec 6<>/dev/tcp/${MONGO_1_PORT_27017_TCP_ADDR}/${MONGO_1_PORT_27017_TCP_PORT}; do
    echo "$(date) - still trying to connect to mongo at ${TESTING_MONGO_URL}"
    sleep 1
done

В моем случае нет пути /dev/tcp , возможно, это другой дистрибутив Linux (?) - Я использую Ubuntu

Вместо этого я нашел этот метод, который, похоже, работает нормально:

until nc -z postgres 5432; do
    echo "$(date) - waiting for postgres..."
    sleep 1
done

Кажется, это работает, но я недостаточно знаю о таких вещах, чтобы знать, надежен ли он ... кто-нибудь знает, есть ли возможное состояние гонки между портом, показывающим до nc и сервером postgres, который действительно_ может принять команды?

Я был бы счастливее, если бы можно было инвертировать проверку - вместо опроса из зависимых контейнеров, можно ли вместо этого отправить сигнал из целевого (то есть сервера postgres) всем зависимым?

Может это глупая идея, у кого-нибудь есть мысли?

@anentropic Docker-ссылки односторонние, поэтому опрос из нижестоящего контейнера в настоящее время является единственным способом сделать это.

Кто-нибудь знает, существует ли возможное состояние гонки между портом, отображаемым на NC, и сервером postgres, действительно способным принимать команды?

В общем случае невозможно узнать - это может быть верно для postgres, может быть неверным для других служб - что является еще одним аргументом в пользу того, что это не делается на рис.

@aan и я пробовал использовать ваш подход с изображением докера / ожидания, но я не уверен, что происходит. Так что в основном у меня есть контейнер Orientdb, на который ссылаются многие другие контейнеры приложений NodeJS. Этому контейнеру orientdb требуется некоторое время, чтобы начать прослушивание порта TCP, и это заставляет другие контейнеры получать ошибку «Соединение отказано».

Я надеялся, что, связав контейнер ожидания с Orientdb, я не увижу эту ошибку. Но, к сожалению, я все еще получаю его случайно. Вот моя установка (Docker версии 1.4.1, рис. 1.0.1 в Ubuntu 14.04 Box):

orientdb:
    build: ./Docker/orientdb
    ports:
        -   "2424:2424"
        -   "2480:2480"
wait:
    build: ./Docker/wait
    links:
        - orientdb:orientdb
....
core:
    build:  ./Docker/core
    ports:
        -   "3000:3000"
    links:
        -   orientdb:orientdb
        -   nsqd:nsqd

Любая помощь приветствуется. Благодарю.

@mindnuts изображение wait является скорее демонстрацией; он не подходит для использования в fig.yml . Вы должны использовать ту же технику (повторный опрос) в вашем контейнере core чтобы дождаться запуска контейнера orientdb перед тем, как начать основной процесс.

+1 только начал сталкиваться с этим, поскольку я вытягиваю созданные пользователем изображения вместо создания их в fig.yml. Приложение Node не работает, потому что mongodb еще не готов ...

Я просто потратил часы на отладку, почему MySQL был доступен при запуске WordPress вручную с помощью Docker и почему он был отключен при запуске с Fig. Только теперь я понял, что Fig всегда перезапускает контейнер MySQL всякий раз, когда я запускаю приложение, поэтому WordPress entrypoint.sh умирает еще не может подключиться к MySQL.

Я добавил свой собственный переопределенный файл entrypoint.sh, который ждет 5 секунд перед выполнением настоящего entrypoint.sh. Но ясно, что это вариант использования, который требует общего решения, если предполагается, что легко запустить комбинацию контейнеров MySQL + WordPress с Docker / Fig.

поэтому WordPress entrypoint.sh умирает, еще не имея возможности подключиться к MySQL.

Я думаю, это проблема с контейнером WordPress.

Хотя изначально я был поклонником этой идеи, после прочтения https://github.com/docker/docker/issues/7445#issuecomment -56391294 я думаю, что такая функция будет неправильным подходом и фактически поощряет плохие практики.

Кажется, есть два случая, на которые направлена ​​эта проблема:

Служба зависимостей должна быть доступна для выполнения некоторой инициализации.

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

Должна быть доступна служба зависимостей, чтобы можно было открыть соединение

Приложение действительно должно быть устойчивым к сбоям подключения и повторять попытки подключения.

Я полагаю, что корень проблемы в том, что нет никаких основных правил относительно того, кто должен ждать готовности услуг. Но даже если бы это было, я думаю, немного нереально ожидать, что разработчики добавят повторные попытки подключения к базе данных в каждый отдельный сценарий инициализации. Такие сценарии часто необходимы для подготовки пустых томов данных, которые были только что смонтированы (например, для создания базы данных).

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

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

На самом деле он не просто _ перезапускает_ контейнеры, он _ уничтожает и воссоздает_ их, потому что это самый простой способ убедиться, что изменения в fig.yml приняты. В конечном итоге мы должны реализовать более разумное решение, которое может сравнивать «текущую конфигурацию» с «желаемой конфигурацией» и воссоздавать только то, что было изменено.

Возвращаясь к исходной проблеме, я действительно не считаю нереалистичным ожидать, что контейнеры будут иметь логику повторных попыток подключения - это фундаментально для разработки работающей распределенной системы. Если разные сценарии должны совместно использовать его, он должен быть выделен в исполняемый файл (или специфичный для языка модуль, если вы не используете оболочку), чтобы каждый сценарий мог просто вызывать waitfor db вверху.

@kennu как насчет --no-recreate ? / cc @aanand

@aan и я имел в виду нереалистичный комментарий с точки зрения Docker Hub, уже заполненный опубликованными изображениями, которые, вероятно, не обрабатывают повторные попытки соединения в своих сценариях инициализации, и что было бы довольно сложно заставить всех добавить его. Но я думаю, что это можно было бы сделать, если бы Docker Inc опубликовал какие-то официальные рекомендации / требования.

Лично я предпочел бы, чтобы контейнеры / изображения были простыми, и пусть базовая система заботится о разрешении зависимостей. Фактически, политика перезапуска Docker может уже решить все (если контейнер приложения не может подключиться к базе данных, он перезапустится и попытается снова, пока база данных не станет доступной).

Но использование политики перезапуска означает, что она должна быть включена по умолчанию, иначе люди тратят часы на отладку проблемы (как я только что сделал). Например, Kubernetes по умолчанию использует RestartPolicyAlways для подов.

какой прогресс в этом? Я хотел бы повторить, что ожидать, что все образы докеров изменятся, и все сообщество реализует методы повторных попыток подключения, неразумно. Fig - это инструмент оркестровки Docker, и проблема заключается в порядке, в котором он выполняет действия, поэтому изменения нужно вносить в Fig, а не в Docker или сообществе.

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

Дело не в том, что приложению нужно повторять попытку из-за докеров или рис. Приложения должны быть устойчивыми к разрывам соединений, потому что сеть ненадежна . Любое приложение уже должно быть построено таким образом.

Мне лично не приходилось реализовывать повторные попытки ни в одном из моих контейнеров, а также мне не требовалось никаких задержек или ожиданий при запуске. Я считаю, что большинство случаев этой проблемы попадают в эти две категории (мое использование «повтора» здесь, вероятно, не очень хорошо, я имел в виду больше, что он восстановит соединение, если соединение было закрыто, не обязательно опрашивать в течение некоторого периода, пытаясь несколько раз).

Если вы убедитесь, что вся инициализация происходит на этапе «сборки» и что соединения восстанавливаются при следующем запросе, вам не нужно будет повторять попытку (или ждать запуска других контейнеров). Если соединения открываются лениво (при первом запросе), а не с нетерпением (во время запуска), я подозреваю, что вам вообще не нужно будет повторять попытку.

проблема заключается в том, в каком порядке [фиг] делает что-то

Я пока не вижу упоминания об этом в этом обсуждении. Fig заказывает запуск на основе ссылок, указанных в конфигурации, поэтому он всегда должен запускать контейнеры в правильном порядке. Можете ли вы предоставить тестовый пример, когда порядок неверен?

Я должен согласиться с @dnephin здесь. Конечно, было бы удобно, если бы compose / fig мог творить чудеса и проверять доступность сервисов, однако каково будет ожидаемое поведение, если сервис не отвечает? Это действительно зависит от требований вашего приложения / стека. В некоторых случаях следует уничтожить весь стек и заменить его новым, в других случаях следует использовать стек аварийного переключения. Можно придумать множество других сценариев.

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

Я хочу сказать, что

Я также хотел бы повторить пример инициализации WordPress: он запускает сценарий оболочки запуска, который создает новую базу данных, если в контейнере MySQL ее еще нет (это невозможно сделать при создании образа Docker, поскольку он зависит от внешний том данных). Такой сценарий становится значительно более сложным, если ему приходится отличать общие ошибки базы данных от ошибок типа «база данных еще не готова» и реализовывать разумную логику повтора в сценарии оболочки. Я считаю весьма вероятным, что автор изображения никогда не будет фактически проверять сценарий запуска на указанное условие гонки.

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

Лично я бы заставил Things Just Work, заставив Fig автоматически определять, какие порты контейнера доступны связанному контейнеру, проверять их перед запуском связанного контейнера (с разумным таймаутом) и, в конечном итоге, предоставлять параметр конфигурации для переопределения / отключения этой функции.

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

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

Такой сценарий значительно усложняется, если ему нужно отличать общие ошибки базы данных от ошибок типа «база данных еще не готова».

Compose / Fig столкнется с той же проблемой; Как проверить, работает ли MySQL и _принятие_ подключений? (и PostgreSQL, и (_вставьте сюда свою службу_)). Кроме того, _ где_ должен выполняться «пинг»? Внутри контейнера, который вы запускаете, с хоста?

Насколько я могу судить, официальный образ WordPress включает проверку, принимает ли MySQL соединения в docker-entrypoint.sh

@thaJeztah "Добавьте простую логику повтора в PHP для ошибок соединения MySQL", автор: tianon 2 дня назад - Хорошо. :-) Кто знает, может быть, это все-таки станет стандартным подходом, но я все еще сомневаюсь, особенно по поводу того, что такого рода реализации повтора фактически тестируются всеми авторами изображений.

По поводу пинга порта - не могу сразу сказать, какой будет оптимальная реализация. Я предполагаю, что может быть простая проверка соединения из временного связанного контейнера и повторная попытка при получении ECONNREFUSED. То, что решает 80% (или, возможно, 99%) проблем, поэтому пользователям не нужно каждый раз решать их самостоятельно.

@kennu Ах! Спасибо, не знал, что он был добавлен недавно, просто проверил скрипт сейчас из-за этого обсуждения.

Чтобы быть ясным, я понимаю проблемы, которые у вас возникают, но я не уверен, что Compose / Fig сможет решить их таким образом, который будет работать для всех (и надежно). Я понимаю, что многие изображения в реестре не имеют "защитных мер" для решения этих проблем, но я сомневаюсь, что Compose / Fig обязана исправить это.

Сказав выше; Я _do_ думаю, что было бы хорошо задокументировать это в разделе передовых практик Dockerfile .

Люди должны быть осведомлены об этом, и следует добавить несколько примеров, чтобы проиллюстрировать, как справиться с «простоями» службы. Включая ссылку на статью WikiPedia, упомянутую @dnephin (и, возможно, другие источники) для справки.

Я столкнулся с той же проблемой, и мне понравилась эта идея от @kennu

Personally, I would make Things Just Work, by making Fig autodetect which container ports are exposed to a linked container, ping them before starting the linked container (with a sane timeout), and ultimately provide a configuration setting to override/disable this functionality.

Я думаю, что это решит множество типичных случаев использования, например, для меня, когда я использую официальный контейнер mongodb .

Я согласен с @soupdiver. У меня также возникают проблемы с контейнером mongo, и хотя он работает со сценарием start.sh, сценарий не очень динамичен и добавляет еще один файл, который мне нужно сохранить в моем репо (я хотел бы просто иметь Dockerfile и docker-compose.yml в моем репозитории узлов). Было бы неплохо, если бы был какой-то способ просто заставить это работать, но я думаю, что что-то простое, например, таймер ожидания, в большинстве случаев не поможет.

Пинга IMO недостаточно, потому что базовое сетевое соединение может быть доступно, но сама служба все еще не готова.
Так обстоит дело с образом MySQL, например, использование curl или telnet для проверки соединения на открытых портах было бы безопаснее, хотя я не знаю, будет ли этого достаточно. Но в большинстве контейнеров эти инструменты не установлены по умолчанию.

Сможет ли docker или fig справиться с этими проверками?

Сможет ли docker или fig справиться с этими проверками?

Короче: _no_. По разным причинам;

  • Выполнение «пинга» из контейнера означало бы запуск второго процесса. Fig / Compose не может автоматически запускать такой процесс, и я не думаю, что вы хотите, чтобы Fig / Compose изменял ваш контейнер путем _installing_ в нем программного обеспечения (такого как curl или telnet).
  • (Как я уже упоминал в предыдущем комментарии), для каждой службы требуются разные способы проверки, принимает ли она соединения / готова ли она к использованию. Некоторым службам могут потребоваться учетные данные или сертификаты для _установления_ соединения. Fig / Compose не может автоматически придумать, как это сделать.

и я не думаю, что вы захотите, чтобы Fig / Compose изменил ваш контейнер, установив в него программное обеспечение (например, curl или telnet).

Нет, конечно, нет.

Fig / Compose не может автоматически придумать, как это сделать.

Не выдумывать. Думал еще про инструкцию на фиг или докер, как проверить, например.

web:
    image: nginx
    link: db
db:
   is_available: "curl DB_TCP_ADDR:DB_TCP_PORT"

Команда telnet будет выполняться на хосте-докере, а не в контейнере.
Но я просто громко думаю, я знаю, что это не идеальное решение. Но текущий способ использования настраиваемых проверочных скриптов для контейнеров можно улучшить.

Команда telnet будет выполняться на хосте-докере, а не в контейнере.

Тогда на хосте нужно будет установить curl или <name a tool that's needed> . Это может даже иметь серьезные проблемы с безопасностью (например, кто-то хочет пошутить и использует is_available: "rm -rf /" ). Кроме того, возможность доступа к базе данных с _host_ не гарантирует, что она также доступна изнутри контейнера.

Но я просто громко думаю ...

Я знаю и ценю это. Подумайте только, что нет надежного способа автоматизировать это или который подходил бы для большинства случаев использования. Во многих случаях вы получите что-то сложное (возьмем, например, пример curl ; сколько времени нужно пытаться подключиться? Повторить попытку?). Такую сложность лучше перемещать внутри контейнера, что также было бы полезно, если бы контейнер был запущен с помощью Docker, а не Fig / Compose.

@thaJeztah Я полностью с вами согласен. И очень вероятно, что 100% решения не будет.

Я собираюсь повторить предложение, которое я сделал ранее: для меня было бы достаточно, если бы я мог заявить в fig.yml «дождитесь выхода этого контейнера перед запуском этого другого контейнера».

Это позволило бы мне создать контейнер, который знает, как ждать всех своих зависимостей - проверять порты, инициализировать базы данных и т. Д. - и требует как можно меньше знаний fig.

Я бы увидел, что он настроен примерно так:

«» "
приложение:
ссылки:
- дб: дб
предварительные требования:
- первый раз

первый раз:
ссылки:
- дб: дб
«» »

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

Возможен ли это как ответ?

KJL

10 февраля 2015 года в 05:28 Тобиас Мунк [email protected] написал:

@thaJeztah https://github.com/thaJeztah Я полностью с вами согласен. И очень вероятно, что 100% решения не будет.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub https://github.com/docker/fig/issues/374#issuecomment -73561930.

Я только что попытался перенести свои средства запуска сценариев оболочки и столкнулся с этой проблемой. Было бы неплохо даже просто добавить простой ключ сна / ожидания, который просто спит в течение этого количества секунд перед запуском следующего контейнера.

db:
  image: tutum/mysql:5.6
  sleep: 10
app:
  link:
    - db:db

Мне это действительно не нравится по ряду причин.

а) Я думаю, это неподходящее место для этого
б) Как долго вы спите?
c) Что делать, если тайм-аут недостаточно велик?

Помимо очевидных проблем, я действительно не думаю
инфраструктура должна заботиться о том, что приложение
есть и наоборот. IHMO приложение должно быть написано
более терпимым и / или более разумным в отношении собственных требований.

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

а docker-compose.yml :

db:
  image: tutum/mysql:5.6
app:
  wait: db
  link:
    - db:db

Где wait ожидает, пока "открытые" службы на db станут доступны.

Проблема в том, как это определить?

В простейших случаях вы ждете, пока вы сможете успешно открыть
соединение tcp или udp с выставленными сервисами.

Это может быть излишним для этой проблемы, но было бы неплохо, если бы докер предоставил систему запуска событий, в которой вы могли бы инициировать триггер из одного контейнера, что привело бы к некоторому обратному вызову в другом контейнере. В случае ожидания импорта данных в базу данных MySQL перед запуском другой службы простого отслеживания доступности порта недостаточно.

Если сценарий точки входа устанавливает предупреждение для Docker изнутри контейнера (например, задает заранее определенную переменную среды), который запускает событие в другом контейнере (возможно, устанавливает ту же синхронизированную переменную среды), сценарии с обеих сторон могут знать, когда задачи выполнены.

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

@aanи у меня _почти_ что- то работает, используя ваш подход ожидания в качестве отправной точки. Однако между запуском docker-compose и docker run происходит что-то еще, где первый, кажется, зависает, а

пример docker-compose.yml:

db:
  image: postgres
  ports:
    - "5432"
es:
  image: dockerfile/elasticsearch
  ports:
    - "9200"
wait:
  image: n3llyb0y/wait
  environment:
    PORTS: "5432 9200"
  links:
    - es
    - db

затем используя ...

docker-compose run wait

однако этого не должно быть. Связанные службы запускаются, и похоже, что мы собираемся дождаться, пока они не задохнутся (по крайней мере, в моем окружении виртуального бокса. Я дохожу до цикла nc и мы получаем одну точку, тогда ... ничего).

Однако с запущенными связанными службами я могу использовать этот метод (по сути, это то, что я делал для наших сборок CI)

docker run -e PORTS="5432 9200" --links service_db_1:wait1 --links service_es_1:wait2 n3llyb0y/wait

Такое ощущение, что docker-compose run должны работать точно так же. Разница в том, что при использовании docker-compose run с флагом отсоединения -d вы не получаете выгоды от ожидания в качестве фона контейнера ожидания, и я думаю (в данный момент), что неиспользование флага вызывает ожидание подавить другие необоснованные сервисы. Я собираюсь присмотреться

После небольшого количества проб и ошибок кажется, что вышеуказанный подход действительно работает! Просто на базе busybox нет утилиты netcat, которая работает очень хорошо. Моя модифицированная версия утилиты @aanand wait работает против docker-compose 1.1.0 при использовании docker-compose run <util label> вместо docker-compose up . Пример использования в ссылке.

Не уверен, что он может обрабатывать ситуации цепочки в соответствии с исходным вопросом. Возможно нет.

Дайте мне знать, что вы думаете.

Это очень интересный вопрос. Я думаю, было бы действительно интересно иметь способ, которым один контейнер ждет, пока другой не будет готов. Но, как все говорят, что значит готов? В моем случае у меня есть контейнер для MySQL, еще один, который управляет своими резервными копиями и также отвечает за импорт исходной базы данных, а затем контейнеры для каждого приложения, которому эта база данных нужна. Очевидно, что дождаться открытия портов недостаточно. Сначала должен быть запущен контейнер mysql, а затем остальные должны подождать, пока служба mysql не будет готова к использованию, а не раньше. Чтобы получить это, мне нужно было реализовать простой скрипт, который будет запускаться при перезагрузке, который использует функциональность docker exec . По сути, псевдокод будет выглядеть так:

run mysql
waitUntil "docker exec -t mysql mysql -u root -prootpass database -e \"show tables\""
run mysql-backup
waitUntil "docker exec -t mysql mysql -u root -prootpass database -e \"describe my_table\""
run web1
waitUntil "dexec web1 curl localhost:9000 | grep '<h1>Home</h1>'"
run web2
waitUntil "dexec web2 curl localhost:9000 | grep '<h1>Home</h1>'"
run nginx

Где waitUntil функция имеет цикл с тайм-аутом, который исключает команду docker exec … и проверяет, равен ли код выхода 0.

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

Так что я думаю, что это может быть вариант для интеграции в утилиту Compose. Может быть, что-то в этом роде, где wait_until объявляет список других зависимостей (контейнеров) и ждет каждую из них, пока они не ответят нормально на соответствующую команду (или, может быть, с дополнительным шаблоном или регулярным выражением, чтобы проверить, соответствует ли результат то, чего вы ожидаете, даже если использовать команду grep может быть достаточно).

mysql:
  image: mysql
  ...
mysql-backup:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "show tables"
  ...
web1:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "describe my_table"
  ...
web2:
  links:
   - mysql
  wait_until:
   - mysql: mysql -u root -prootpass database -e "describe my_table"
  ...
nginx:
  links:
   - web1
   - web2
  wait_until:
   - web1: curl localhost:9000 | grep '<h1>Home</h1>'
   - web2: curl localhost:9000 | grep '<h1>Home</h1>'
  ...

А что, простая еда на порт нравится?
http://docs.azk.io/en/azkfilejs/wait.html#

@robsonpeixoto :

Было бы неплохо что-то вроде WaitCondition AWS CloudFormation. http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html

+1 У меня такая же проблема при использовании Docker для тестирования моих приложений Rails, которые зависят от MySQL

+1 У меня тоже есть эта проблема. Мне нравится идея @adrianhurt , где вы фактически

+1

Некоторое время у меня была открыта эта вкладка: http://crosbymichael.com/docker-events.html ... кажется актуальным

+1

+1 за простой тайм-аут

+1 за готовое состояние

+1

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

Просто чтобы дать вам представление о том, как это можно реализовать для MySQL + PHP, вот мой код.

От igorw / повтори :)

Поскольку сеть надежна, все должно работать всегда. Я прав? В тех случаях, когда они этого не делают, есть повторная попытка.

+1

@ schmunk42 Хорошая штука - мне нравится, что это хороший пример как установления соединения, так и выполнения идемпотентной операции настройки базы данных.

Было бы неплохо создать (некоторые) базовые примеры для включения в документацию для разных случаев, например, NodeJS, Ruby, PHP.

+1, по крайней мере, должен предоставить некоторые опции для добавления некоторой задержки перед успешным запуском контейнера.

+1

Как решить проблемы, когда вы пытаетесь подключить сервисы, которые не являются вашим кодом.
Например, если есть служба Service и база данных InfluxDB . Services требует InfluxDB а InfluxDB запускается медленно.

Как docker-compose ждать, пока будет готов InfluxDB ?

Если код мой, я могу решить его, повторив попытку. Но для третьего приложения я не могу изменить код.

@robsonpeixoto в этом билете есть несколько примеров использования netcat или аналогичных способов. Вы можете взглянуть на мой пример MySQL в другом тикете: https://github.com/docker/docker/issues/7445#issuecomment -101523662

Вот почему я думаю, что каждый контейнер должен иметь дополнительную возможность указывать свою готовность. Для БД, например, я хочу дождаться полной готовности сервиса, а не создания процесса. Я решаю эту проблему с помощью индивидуальных проверок с помощью docker exec и проверяю, например, может ли он решить простой запрос.

Некий необязательный флаг для docker run указывающий на внутреннюю команду проверки, было бы здорово позже связать его из другого контейнера, используя специальный флаг для ссылки.

Что-то вроде:

$ sudo docker run -d --name db training/postgres --readiness-check /bin/sh -c "is_ready.sh"
$ sudo docker run -d -P --name web --link db:db --wait-for-readiness db training/webapp python app.py

Где is_ready.sh - это простой логический тест, который отвечает за решение, когда контейнер считается готовым.

+1

@ schmunk42 хорошая цитата!

+1

+1

+1

+1

+1

+1

+1

+1

+1

На самом деле я передумал об этом, поэтому -1

Вашему контейнеру имеет больше смысла проверять, доступна ли сторонняя служба, и это легко сделать с помощью небольшого сценария-оболочки bash, который использует, например, nc .

Заманчиво полагаться на задержку, но это плохое решение, потому что:

  • Ваш контейнер будет _всегда_ ждать X секунд, прежде чем будет готов.
  • В некоторых случаях X секунд может быть недостаточно (например, интенсивный ввод-вывод или загрузка ЦП на хосте), поэтому ваш контейнер по-прежнему не является отказоустойчивым.
  • Стратегия без ошибок.

Полагаться на написание сценария оболочки bash лучше, потому что:

  • Ваш контейнер будет готов как можно скорее.
  • Вы можете реализовать любую неудачную стратегию, например, попробовать 10 раз, затем потерпеть неудачу, попробовать вечно и т. Д. Вы даже можете реализовать задержку самостоятельно, заснув перед попыткой!

Читая эту ветку, я понял, что никто не упоминает секреты. Я пытаюсь использовать контейнер только для данных, который запрашивает секреты после запуска. У меня есть проблема: если мои секреты слишком долго передаются / расшифровываются, тогда мой зависимый контейнер выходит из строя, потому что данных, которых он ожидает, нет. Я действительно не могу использовать метод «хорошо сложить все в контейнер, прежде чем запускать его», потому что это секреты.

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

Точно так же меняю свое мнение об этом, -1. Подход @dnephin совершенно правильный. Если ваше _приложение_ зависит от _услуги_, само приложение должно уметь корректно обрабатывать недоступность этой службы (например, повторно устанавливать соединение). Это не должен быть скрипт-оболочка bash или какая-то логика в Compose или Docker, это ответственность самого приложения. Все, что находится не на уровне приложения, также будет работать только при инициализации; если эта служба выйдет из строя, сценарий оболочки или что-то еще не будет выполнено.

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

Трудно сделать, учитывая подходы, которые вы могли бы использовать, включая загрузку других демонов, что не рекомендуется. В моем примере, где у меня есть приложение rails, которое пытается подключиться к базе данных MySQL, в то время как другое приложение rails в настоящее время мигрирует и заполняет БД при первоначальном запуске, чтобы я знал, что приложение rails не пытается использовать БД, я бы либо необходимо изменить библиотеку ActiveRecord (этого не произойдет) или запустить сценарий, который постоянно проверяет, была ли БД перенесена и заполнена. Но как я могу знать наверняка, не зная, какие данные там должны быть и / или имея какой-то скрипт, который запускается в системе, которая заполняет БД, чтобы сообщить остальным, чтобы они подключились к ней.

Может быть, мне не хватает очевидного решения, но ваш ответ «разработчики должны иметь возможность справиться с этим в своем собственном коде» не работает, когда вы используете готовые библиотеки и когда вы «не должны» загружать неопубликованные демоны в контейнер.

@mattwallington Я даже не уверен, как Compose может
Это также ужасно специфично, что сделало бы Compose еще сложнее. Я бы прочитал некоторые из советов @dnephin выше по инициализации / миграции / посеву, поскольку это может помочь в вашем случае.

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

Понятно. Мое предыдущее предложение, которое сработало бы для многих из этих вариантов использования, - это иметь общую переменную среды между контейнерами. Одна сторона может заблокировать опрос переменной, а другая может выполнить действие, а затем установить переменную.

+1 идея @mattwallington об общей переменной среды между контейнерами

Спасибо. Это просто (на уровне продукта. Я понятия не имею, что потребуется со стороны разработки, поскольку я не смотрел код), но он решит многие из этих проблем и, вероятно, многие другие, поскольку он не специфичен для Эта проблема.

Но как я могу знать наверняка, не зная, какие данные там должны быть и / или имея какой-то скрипт, который запускается в системе, которая заполняет БД, чтобы сообщить остальным, чтобы они подключились к ней.

@mattwallington : проверьте номер миграции в таблице схемы. Если номер правильный, значит, миграция выполнена.

Это не должен быть скрипт-оболочка bash или какая-то логика в Compose или Docker, это ответственность самого приложения. Все, что находится не на уровне приложения, также будет работать только при инициализации; если эта служба выйдет из строя, сценарий оболочки или что-то еще не будет выполнено.

@ agilgur5 : да, я согласен, что это будет обрабатываться приложением, но сценарий bash - простое решение для обработки тех приложений, которые не закодированы таким образом, например, путем перезапуска приложения, когда служба недоступна.

Можно целый день спорить о том, что следует или можно было бы сделать на уровне приложения, но вместо того, чтобы ожидать, что каждое приложение на рынке справится с этим и станет отличным при самовосстановлении (маловероятно), почему мы так против добавления некоторых функций, которые могут решить эта проблема для приложений, работающих в докере, независимо от того, как написаны сторонние приложения или что они ДОЛЖНЫ делать, но не будут. Это то, что мы контролируем. Давайте решать проблему, а не решать, кто должен ее решать, поскольку мы не можем это контролировать.

Я согласен с @mattwallington. Вам могут потребоваться эти дополнительные усилия для самовосстановления на уровне приложения от каждого отдельного разработчика каждого отдельного образа контейнера, но большой процент из них обязательно будет слишком невежественным или просто слишком занятым, чтобы реализовать и тщательно протестировать его. Конечным результатом будет то, что некоторые контейнеры умеют самовосстановиться, а многие нет. И как пользователь у вас не будет никаких инструментов для управления теми, которые этого не делают.

Идея, которая пришла мне в голову: вместо решения проблемы путем задержки запуска контейнера Compose может попытаться восстановить отказавший контейнер.

Что-то вроде recover: auto перезапустит отказавший контейнер 5 раз за 2, 4, 8, 16 и 32 секунды, а затем полностью откажется.

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

Например:

`` #! yml
db:
изображение: mysql

ждать:
ссылки:
- дб
объемы:
- /var/lib/docker.sock:/docker.sock
- $ {PWD} /docker-compose.yml:/docker-compose.yml
команда: docker-compose up -d app

приложение:
изображение: myuser / myapp
ссылки:
- дб
``

Основная идея здесь состоит в том, что вы решаете проблему контейнеров, у которых нет механизмов самовосстановления, создавая выделенную повторно используемую службу, которая может быть опубликована в Docker Hub, которую каждый может затем просто внедрить в свою композицию.

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

@prologic Проблема с зависимостью в том, как убедиться, что служба, с которой вы хотите поговорить, действительно работает?

Контейнер db может отвечать на ping но выполняет некоторую предварительную очистку / инициализацию базы данных, прежде чем она станет доступной для команд mysql / psql .

Может ли этот тест быть определен настраиваемым образом и / или предоставлен в сценарии для многоразовой службы типа waitfor ?

ИМХО, это очень распространенная проблема и у каждого свои специфические требования. Как уже отмечалось ранее в этом выпуске, я думаю, что докер может (и должен) предоставить контейнеру возможность указать простую команду для проверки собственной готовности. Очевидно, что мы, разработчики, должны конкретно указать, как проверять готовность каждого контейнера.

Некий необязательный флаг для запуска докера, указывающий на внутреннюю команду проверки, было бы здорово позже связать его из другого контейнера, используя специальный флаг для ссылки.

Что-то вроде:

$ sudo docker run -d --name db training/postgres --readiness-check /bin/sh -c "is_ready.sh"
$ sudo docker run -d -P --name web --link db:db --wait-for-readiness db training/webapp python 

Где is_ready.sh - это простой логический тест, который определяет, когда контейнер считается готовым.

Это также может быть команда для контейнера вручную проверить его готовность.

Где is_ready.sh - это простой логический тест, который определяет, когда контейнер считается готовым.

Это означает, что каждый разработчик должен подготовить свои изображения / контейнеры, чтобы включить в них что-то, что можно использовать для проверки готовности контейнера.

Это возвращает нас к квадрату 1 .; Разработчики несут ответственность за то, чтобы их контейнеры были устойчивыми к отключению / запуску службы, потому что они единственные, кто может сказать, «что» это означает для их ситуации?

Или что-то здесь не замечаю?

Я согласен. Ответственность лежит на разработчике / контейнере / сервисе

В четверг, 30 июля 2015 г., Себастьян ван Стейн [email protected]
написал:

Где is_ready.sh - это простой логический тест, отвечающий за
решение о том, когда контейнер считается готовым.

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

Это возвращает нас к квадрату 1 .; разработчики несут ответственность за
делая их контейнеры устойчивыми к отключению / запуску службы, потому что
они единственные, кто может сказать, «что» это значит для их ситуации?

Или что-то здесь не замечаю?

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/docker/compose/issues/374#issuecomment -126278215.

Джеймс Миллс / прологик

Э: [email protected]
W: prologic.shortcircuit.net.au

Да, конечно. Для меня единственный, кто действительно знает, когда контейнер готов, - это собственный контейнер. Докер ничего не может знать о содержимом контейнера. Это черный ящик. Единственное, что он может сделать, - это запросить контейнер (с указанием настраиваемого действия, когда вы хотите запустить, как я предлагал, или любым другим распространенным способом его тестирования). И, очевидно, разработчик - единственный, кто знает, что ему нужно, и содержимое этого черного ящика.

Да, это верно!

В четверг, 30 июля 2015 г., adrianhurt [email protected] написал:

Да, конечно. Для меня единственный, кто действительно знает, когда контейнер
готов собственный контейнер. Докер ничего не может знать о содержимом
контейнер. Это черный ящик. Единственное, что он мог сделать, это спросить
контейнер (с настраиваемым действием, указанным, когда вы хотите запустить, например, я
предложенный, или любой другой распространенный способ его проверки). И, очевидно, разработчик
- единственный, кто знает, что ему нужно и что это за черный ящик.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/docker/compose/issues/374#issuecomment -126285056.

Джеймс Миллс / прологик

Э: [email protected]
W: prologic.shortcircuit.net.au

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

Минимальный набор требований выглядит так:

  • Я хочу, чтобы Compose ждал запуска службы, пока другая служба не будет «готова».
  • Я хочу определить «готово» как «принимает TCP-соединения через порт X» или что-то еще.

Также предположим, что проверки работоспособности некоторое время не попадут в Docker.

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

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["db_wait"]

db_wait:
  image: netcat
  links: ["db"]
  command: sh -c "while ! nc -w 1 -z db 5432; do sleep 1; done"

db:
  image: postgres

Если вам нужна какая-то настраиваемая проверка работоспособности, определите ее в службе ожидания. Здесь db_wait выйдет только тогда, когда mytable существует в базе данных mydb :

db_wait:
  image: postgres
  links: ["db"]
  command: sh -c "while ! psql --host db --dbname mydb -c "\d mytable"; do sleep 1; done"

Если у вас есть сценарий подготовки базы данных, который нужно запустить первым, вы можете сделать это, чтобы дождаться:

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["prepare_db"]

prepare_db:
  image: prepare_db
  links: ["db"]
  command: ./prepare.sh

db:
  image: postgres

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

web:
  image: mywebapp
  links: ["db"]
  wait_for_tcp: ["db:5432"]

db:
  image: postgres

Во всем этом есть скрытый смысл: docker-compose up -d придется заблокировать во время работы промежуточной службы проверки работоспособности или подготовки, чтобы она могла запустить службу (службы) потребителя после ее завершения.

Да. Однако, на мой взгляд, сам docker должен предоставлять способ определить, когда контейнер готов, а затем compose может управлять им. Тогда мы могли бы поднять новую проблему прямо в докере. Для меня это могло быть что-то вроде:

web:
  image: mywebapp
  links: ["db"]
  wait_for: ["db"]

db:
  image: postgres
  ready_when: sh -c "while ! psql --host db --dbname mydb -c "\d mytable"; do sleep 1; done"

Тогда нет необходимости создавать новые службы в качестве временного решения.

Согласовано. Дайте гибкость разработчику. Кроме того, приостановка контейнера может быть не тем, что разработчику нужно делать, пока он ждет. Возможно, должен произойти какой-то собственный init, но затем подождите, пока база данных будет готова для соединений. Так что, если это простая общая переменная env, она позволяет разработчику использовать ее по мере необходимости.

Как будет обновляться общая переменная среды? Насколько мне известно, вы не можете вносить изменения в набор переменных среды процесса после его запуска.

Вы можете изменить их, например, в сеансе bash, но они не будут распространяться на все другие уровни.

Для этого необходимо зафиксировать изменение и перезапустить контейнер. В данном случае это бесполезно.

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

Поскольку на самом деле мы говорим только о решении этой проблемы для устаревших контейнеров в средах разработки, я думаю, что ее можно решить как инструмент, который находится поверх compose docker-compose ps -s (список служб в порядке зависимости, # 1077).

С помощью этих двух команд можно написать инструмент, который будет делать что-то вроде этого:

  1. Запустите docker-compose ps -s чтобы получить список имен служб в порядке зависимости
  2. Запустить docker-compose up -d --no-recreate <first service from the list>
  3. Запустите команду «проверка работоспособности» для этой службы, пока она не станет работоспособной или не истечет время ожидания. Это может быть HTTP-запрос или вызов docker exec
  4. Повторите 2 и 3 для каждой службы в списке.
  5. Запустите docker-compose logs (или не выполняйте, если передано -d )

Таким образом, конфигурация "проверка работоспособности" и "ожидание" может быть внешней для компоновки, но я не думаю, что разработчик должен предоставлять что-либо сверх того, что потребовалось бы, если бы это было реализовано как часть самой компоновки.

По какой причине это не сработает?

Я рад, что мы ограничили область действия устаревшими контейнерами, это гораздо более разумно: +1:

@dnephin Я думаю, что это здорово с непосредственной точки зрения, потому что он гибкий и что Compose не обязательно должен иметь некоторую встроенную поддержку устаревших контейнеров, но я вижу немедленную проблему, аналогичную описанной @mattwallington : что, если другие контейнеры могут запускать некоторые вещи (например, init) перед подключением к этой службе? Блокировка этого контейнера _ работает_, но не идеальна (при этом я не уверен, есть ли идеальное решение для устаревшего контейнера). По крайней мере, это решило бы мою проблему, теперь я должен найти этот билет!

+1

для возможности указывать зависимости в файлах docker-compose ...

... без использования ссылок (поскольку они несовместимы с net = host). Я бы подумал, что задача или, по крайней мере, забота инструмента управления несколькими контейнерами - знать, в каком порядке должны запускаться вещи, подобно тому, как у марионетки есть собственное дерево зависимостей, но иногда пользователь знает лучше и может переопределить. Читая все вышесказанное, мне кажется, что единственная трудность заключается в том, чтобы решить, когда контейнер "запущен", чтобы можно было запустить следующий контейнер в цепочке зависимостей. Это может быть точно такой же механизм, как и механизм ссылок (на данный момент) - все лучше, чем ничего. Позже пояснение к «выполнению зависимости» может быть указано, например, в файле docker-compose - эта зависимость имеет значение, что контейнер работает

depends_on:
  container: foo
  requires: running

или эта зависимость имеет значение, что TCP-порты контейнеров прослушивают.

depends_on:
  container: foo
  requires: listening

Сказать, что это работа какого-то внешнего инструмента или скрипта поверх docker-compose, равносильно утверждению, что docker-compose не имеет реального интереса или ответственности за оркестровку запуска 2 или более контейнеров на одной машине. Так в чем его цель?

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

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

  1. Вы используете готовые образы контейнеров, которые не устойчивы к недоступности вышестоящих сервисов, от которых они зависят, и по техническим или деловым причинам вы не можете их изменить или расширить.
  2. Вы запускаете программное обеспечение исключительно в среде разработки, а не в производственной среде, и у вас есть вещи поважнее, чем реализация устойчивости.

Однако, если вы контролируете свое программное обеспечение и планируете развернуть его в производственной среде, вы не можете надеяться на внешний инструмент, который просто запускает вещи в правильном порядке, даже если вы тщательно определили условия своей готовности. Это не решение фундаментальной проблемы, и ваша система выйдет из строя в момент сбоя в сети. В лучшем случае вам придется автоматически перезапускать все контейнеры веб-интерфейса каждый раз, когда это происходит, и я не вижу, чтобы это было приемлемым временем простоя для кого-либо.

Согласитесь с вами, что хорошо написанное программное обеспечение справится с перебоями в работе сети. Я думаю, что мы оба согласны с тем, что не все программное обеспечение хорошо написано, и разработчики не всегда думают обо всех возможных вариантах использования.

Возможно, я хочу запустить контейнер клиентов, на котором запущена JVM, и еще один инструмент мониторинга, чтобы присоединиться к нему, как в пространстве имен хоста PID, так что один может отслеживать другой, и я только поддерживаю и лицензирую запуск такого инструмента с авторизованным изображением поставщика . Если инструмент мониторинга отслеживает существующие JVM, то имеет значение, в каком порядке они запускаются (очевидно). Вероятно, существуют сотни вариантов использования, в которых порядок имеет значение, некоторые из них связаны с сетями (были упомянуты mysql, elasticsearch, кластеры обнаружения служб), но некоторые связаны с другими вещами, которые можно совместно использовать, эффективно используя разные пространства имен.

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

Но также, как только инструмент касается нескольких вещей, он сразу же упирается в заказ. Если порядок важен и единственный способ гарантировать порядок - это написать сценарий bash вокруг docker-compose, чтобы сначала что-то создать, а затем что-то еще, docker-compose может даже не существовать в цепочке, кроме факта JSON / YAML красивее, чем аргументы cmdline.

IMHO В конечном итоге инструмент либо полезен, либо нет для множества вариантов использования. Docker-compose явно полезен для неупорядоченного запуска нескольких контейнеров на одном хосте. Если достаточно людей и достаточно вариантов использования связано с порядком, а инструмент не обращается к ним, люди просто пойдут в другое место для этих вариантов использования, что является позором.

В любом случае, я вижу, что просто перефразирую старые аргументы, так что сейчас я исключу из этой темы ..

Это тот же аргумент, который утверждается в тысячах потоков по стольким различным темам разработки: «Если бы весь код был написан правильно всеми, в этом не было бы необходимости, поэтому давайте не будем этого делать». Это эквивалентно высказыванию: если все люди в мире перестанут сжигать ископаемое топливо или использовать электричество, мы сможем решить проблемы, которые создаем нашей планете. Ты прав. Если бы все приложения делали то, что должны, мы бы здесь не говорили об этом. Но мы живем на земле. Место, в котором были огромные недостатки с видом существ, которым, как правило, приходится учиться чему-то на собственном горьком опыте. Те же люди, которые запускают компании только потому, что создают «минимально жизнеспособный продукт», чтобы молиться, чтобы они добрались до следующего раунда финансирования или следующего клиента, который может когда-нибудь позволить им создать версию, которую они хотели бы .

Мир не совершенен и никогда не будет идеальным, поэтому мы можем делать только то, что в наших силах. И в этом случае единственное, что я могу контролировать, - это попытаться убедить всех вас (то есть людей, которые разрабатывают инструмент, который мне очень нравится и который бы использовал как сумасшедший, если бы в нем была только эта функция), чтобы встроить его способ, которым он может обрабатывать программное обеспечение, существующее в мире, в котором мы живем. Не тот, в котором мы хотели бы жить.

31 июля 2015 г. в 3:42 Аананд Прасад [email protected] написал:

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

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

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

Вы запускаете программное обеспечение исключительно в среде разработки, а не в производственной среде, и у вас есть вещи поважнее, чем реализация устойчивости.

Однако, если вы контролируете свое программное обеспечение и планируете развернуть его в производственной среде, вы не можете надеяться на внешний инструмент, который просто запускает вещи в правильном порядке, даже если вы тщательно определили условия своей готовности. Это не решение фундаментальной проблемы, и ваша система выйдет из строя в момент сбоя в сети. В лучшем случае вам придется автоматически перезапускать все контейнеры веб-интерфейса каждый раз, когда это происходит, и я не вижу, чтобы это было приемлемым временем простоя для кого-либо.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub.

+1 @aanand. Это не то, что вы собираетесь ограничивать. Если эта функция будет реализована, люди смогут рассчитывать на нее. Они давно пишут код для «прочной» инфраструктуры, и требуется много времени, чтобы преобразовать массы. Они будут использовать это еще долгое время.

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

Но я хочу, чтобы мы были на одной странице в отношении того, для кого предназначена эта функция, какие проблемы она решит, какие проблемы она _не_ решит и в какой степени на нее можно положиться. Вот что я пытаюсь прочувствовать.

Кроме того, с учетом множества существующих определений готовности («контейнер запущен» против «контейнер принимает TCP-соединения» против «пользовательских проходов проверки работоспособности») и различной сложности реализации каждого из них, я хочу получить сравнительную представление о том, сколько людей выиграют от поддержки каждого из них.

Распространенный метод синхронизации служб - это что-то вроде «реестра служб» с использованием etcd или подобного. Как насчет wait_for_service:

web:
  image: mywebapp
  links: ["db"]
  wait_for_service:
    type: etcd (or consul, or zk)    -- or use swarm type notation
    addr: http://my.etcd.com/
    path: postgres.service

db:
  image: postgres

compose не знает, действительно ли готова служба, но может искать данные в реестре и запускать зависимый контейнер на их основе. Службы (например, postgres) несут ответственность за публикацию своей доступности в реестре, поэтому для устаревших приложений это будет делать какой-то сценарий обертывания: запустить приложение, следить за запуском порта, затем опубликовать в реестре.

Привет @aanand.

Я обсуждал это сегодня с @bfirsh в твиттерах, так как с этим я столкнулся.

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

Это приводило к проблемам, например, с тем, что Riak требовал времени для запуска по сравнению с чем-либо еще, что его использует.

Я не был бы особенно против того, чтобы вы говорили: «контейнеры запускают асинхронно, справляйтесь с этим», но проектирование вокруг каждой службы, обеспечивающей последовательную проверку работоспособности, по крайней мере, будет содержать «работу с ней» для одной реализации для каждой службы, а не иметь код чтобы иметь дело с повторными попытками подключения в каждом приложении, которое полагается на службу.

Сервисы, определяющие собственную проверку работоспособности, также полезны для целей мониторинга.

@elliotcm Согласен по обоим пунктам.

Для тестирования нашего CI мы создали небольшую утилиту, которую можно использовать в контейнере Docker для ожидания готовности связанных сервисов. Он автоматически находит все связанные TCP-службы по их переменным среды и многократно и одновременно пытается установить TCP-соединения, пока не завершится успешно или не истечет время ожидания.

Мы также написали сообщение в

@meeee выглядит очень красиво и полезно! Вы можете показать нам примеры того, как он раскручивается; в частности, при использовании с docker-compose?

Сегодня у меня был более сложный случай, когда я впервые запускал контейнер mysql. Контейнер загружается при первом запуске и перезапускает демон базы данных, когда он настроен. Это привело к преждевременному срабатыванию моих проверок доступности портов и запуску зависимых контейнеров, но не удалось подключиться. Это было в среде CI, где мы хотим, чтобы все было настроено полностью с нуля.

Я очень хотел, чтобы compose поддерживал какое-то поведение ожидания / проверки, но есть несколько обманчиво сложных случаев. Рад участвовать в обсуждениях.

@prologic Все, что вам нужно сделать, это запустить команду waitforservices в контейнере Docker в зависимости от других сервисов / контейнеров перед запуском приложения или тестов. Он находит все связанные службы и запускается до тех пор, пока не сможет подключиться к ним или пока не пройдет определенное время (по умолчанию 60 секунд). Просто запустите весь код, который зависит от других служб, после двоичного выхода (хотя вы можете проверить статус выхода).

@pugnascotia Ваш сервер базы данных может прослушивать localhost только во время начальной загрузки - вам нужно будет показать какой-то индикатор, готов ли контейнер в любом случае. Мы не используем MySQL, но waitforservices отлично работает с официальным образом postgres .

@aanand Postgres - отличный пример для выбора, потому что ждать открытия TCP-порта _не_ достаточно - если вы сделаете это в этом типе (докер) сценария, то иногда вы получите ошибку вроде FATAL: the database system is starting up. если ваш другой контейнер подключается слишком быстро после открытия TCP-соединения. Поэтому psql кажется необходимым, если вы хотите быть уверенным, что postgres готов - я использую select version() но, возможно, есть более легкая альтернатива.

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

Используя это как обходной путь (не уверен, что он пуленепробиваемый):

db:
  image: postgres:9.3
  ports:
    - "5432:5432"
createdbs:
  image: postgres:9.3
  links:
    - db
  command: >
    /bin/bash -c "
      while ! psql --host=db --username=postgres; do sleep 1; done;
      psql --host=db --username=postgres -c 'CREATE DATABASE \"somedatabase\";';
    "

Я использовал методы, похожие на @olalonde. При использовании одинарных кавычек для команды, которая выполняется после /bin/bash -c , я также могу использовать переменные среды, которые повторно используются из ссылок, когда другие приложения, поэтому я могу использовать имена пользователей и пароли без необходимости поддерживать их в двух места. Это хорошо работает в ситуациях, когда у меня есть служба, такая как API, для которой требуется, чтобы база данных была в рабочем состоянии и были загружены правильные данные путем запуска запроса, проверяющего, существует ли определенная таблица или запись. Это также означает, что мне нужно установить какой-то клиент в контейнере для правильного запроса базы данных, но он работает.

+1 Мне очень интересен этот функционал

+1 к зависимостям. Я согласен с тем, что в принципе архитектура должна быть достаточно надежной, чтобы поддерживать любой порядок запуска. НО, часто это непрактично.

Кажется, что противодействие этой функции происходит из-за того, что другие пытаются диктовать архитектуру издалека; где они действительно не имеют на это права. Эта функция позволит избежать трудоемких рефакторингов; с небольшой долгосрочной стоимостью. (Рефакторинг ради рефакторинга).

Да, я сказал «обходной путь»; и я чувствую себя грязным. Но для меня сочинение на самом деле помогает другим быть продуктивными. Эта простая конфигурация позволяет это.

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

@beardface и все остальные: какая функция, в частности, позволит вам продолжить разработку приложения?

  1. Возможность указать, что служба A должна ждать запуска, пока служба B не запустится? (что, имейте в виду, все равно не решит состояние гонки, когда контейнер запущен, но не готов принимать соединения)
  2. Возможность указать, что служба A должна ждать запуска, пока служба B не примет соединения? (что, имейте в виду, по-прежнему не решит состояние гонки, когда контейнер прослушивает, но не завершил инициализацию - например, контейнер postgres создает базу данных при запуске, чтобы использовать пример @rarkins )
  3. Возможность определить проверку работоспособности для службы B и указать, что служба A должна ждать для запуска, пока проверка работоспособности службы B не пройдет?

@aanand Номер 3 - мой голос. Это дает разработчику гибкость в выборе логики проверки работоспособности вместо того, чтобы снова полагаться на службу, чтобы решить, когда пришло время. Для этого конкретного случая использования больше свободы разработчика лучше. Невозможно предвидеть все типы приложений, которые будут установлены в контейнерах.

+3

Тем не менее, было бы неплохо включить некоторые базовые проверки здоровья. Что-то вроде _http 200 ok на порту 80_ настолько распространено, что оно того стоит.

Было бы неплохо иметь "батарейки в комплекте" номер 3 (смею ли я сказать все вышеперечисленное?)

Т.е. встроенная возможность для типов ожидания «контейнер запущен», «файл присутствует» и «порт открыт», а затем позволяет людям определять свои собственные проверки «уровня приложения».

3 получает мой голос

3 - более общий 2 - более общий 1. Все предпочтут 3, но для некоторых достаточно 2 или 1.

Голосовать за 3

Очевидно 3-й вариант. Только в этом обсуждении есть масса случаев. Так что 1-й и 2-й варианты были бы хороши, и многие люди были бы счастливы, но вопрос останется открытым.

Голосовать за 3

Голосовать за 3

Проголосуйте за 3. Бета-тестирование тоже интересует.

Проголосуйте за 3.

Проголосуйте за 3. Бета-тестирование тоже интересует.

Голосовать за 3

3

Всем спасибо. Вы можете прекратить голосование сейчас - я думаю, что смысл ясен.

Мне были бы интересны отзывы о дизайне, который я предложил в https://github.com/docker/compose/issues/374#issuecomment -126312313 - любые альтернативные предложения по дизайну, а также обсуждение их сильных и слабых сторон.

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

А как насчет того, что делает alexec в плагине docker-maven-plugin? Он явно разработал свою конфигурацию, подобную docker-compse / fig, и до сих пор она отлично работала для моих проектов.

healthChecks:
  pings:
     # check this URL for 200 OK
     - https://localhost:8446/info
     # check another URL with non-default time out, with a pattern, and non checking SSL certificates
     - url: https://localhost:8446/info
       timeout: 60000
       pattern: pattern that must be in the body of the return value
       sslVerify: false
  logPatterns:
     - pattern that must be in log file
     - pattern: another pattern with non-default timeout
       timeout: 30000

Источник: https://github.com/alexec/docker-maven-plugin/blob/master/USAGE.md

Проверка того, что TCP-соединение установлено, недостаточно, чтобы знать, что база данных запущена. Я думаю, лучше иметь какую-нибудь команду, которая проверяет работоспособность базы данных.

@ceagan Вот так . Пользовательские команды тоже были бы полезны. например

healthChecks:
  custom:
    # retry this command until it returns success exit code
    - cmd: psql --host=localhost --username=postgres
      sleep: 1s

Я также думаю, что checks было бы лучше, чем healthChecks потому что не нужно помнить о регистре. Также может быть полезно иметь wait (сколько секунд ждать перед запуском проверки работоспособности), attempts (сколько раз нужно проверять здоровье перед тем, как сдаться), retire (сколько секунд ждать, прежде чем полностью отказаться).

это идет в том же направлении, что и фреймворк марафона. основные зависимости плюс проверки работоспособности . поскольку он очень популярен для запуска контейнеров докеров, стоит проверить его параметры (тайм-ауты, интервал, коды ответа и т. д.), чтобы принять их для создания.

То же самое, вариант 3.

+1

+1

+1

Я буду придерживаться собственного сценария ожидания, однако это было бы очень хорошо.

+1

+1

Варианты 3-healthChecks звучат хорошо.

+1

+1

+1

+3.
Чтобы добавить некоторые другие мысли к обсуждению, предлагаемые варианты @aanand действительно говорят: за состояние контейнеров отвечает docker, а не docker-compose. Docker-compose мог бы реализовать все эти варианты использования чистым и элегантным способом, если бы docker предоставил информацию о состоянии. Но докер этого не делает. Похоже, он придерживается видения немедленных контейнеров без сохранения состояния, запускаемых так быстро, что такого рода проблемы синхронизации не важны.
В моем случае я преследую идею возможности выбрать лучшую архитектуру для моих сервисов для каждого случая. Например, иногда мне нужно несколько экземпляров MariaDB, каждый из которых обслуживает одно приложение. В других случаях мне нужен один экземпляр MariaDB, обслуживающий несколько приложений. Я не хочу, чтобы Docker подсказывал мне, что лучше, или что я должен делать вместо этого. У Докера всегда есть такие соблазны;).
Я думаю, что лучшее решение - убедить Docker позволить контейнерам объявлять произвольные метаданные о себе и использовать эту функцию, чтобы docker-compose узнал, считается ли контейнер «готовым», чтобы другие могли положиться на него.
Что касается подхода «одна база данных - несколько приложений», мне бы хотелось дать такое определение:

db:
  image: postgres:9.3
  ports:
    - "5432:5432"
app1:
  image: wordpress
  links:
    - db [WP]
app2:
  image: ghost
  links:
    - db [GST]

Docker Compose запустит «db» и спросит о его метаданных (относящихся к Docker Compose). Из файла yml он знает, что «app1» ожидает, что «db» будет «готовым к wordpress» (что означает не только прием соединений, но и требуемых объектов).

У меня нет простого решения, как разрешить эту ситуацию. В настоящее время я делаю это вручную, в два этапа: пользовательский образ postgresql-bootstrap, в котором я создаю базу данных и пользователя базы данных для доступа к нему; и настраиваемый образ Liquibase-postgresql для создания объектов базы данных из DDL, предоставленных (или извлеченных из) контейнера Wordpress. Только после этого я могу запустить «app1».
Это заставляет меня разделять контейнеры на группы «инфраструктура» и «приложения», если контейнеры «инфраструктуры» обслуживают разные приложения.

Docker Compose хочет быть таким же апатридным, как и сам Docker. Я не знаю, возможно ли это, если он действительно хочет быть полезным.

+1 за вариант 3

+1

+1 за вариант 3.

+1 за вариант 3

+1 за вариант 3

Эта проблема существует некоторое время, каково решение?

@ bweston92 Я думаю, что статус таков, что ранее в этой ветке предложил решение и ищет

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

Лично я думаю, что предложенное @aanand решение имеет большой смысл. Мне это кажется очень ясным, но в то же время гибким. Это покроет мои потребности - не ждать открытия TCP-порта или просто ждать фиксированное количество времени.

Мой вариант использования предназначен только для тестирования. Мои тесты завершатся неудачно, если они начнутся до создания базы данных, поэтому я изменил их команду на bash -c "sleep 2; python manage.py test --keepdb" , например:

db:
    image: postgres:9.5
test:
    build: .
    command: bash -c "sleep 2; python manage.py test --keepdb"
    volumes:
        - ./test_project:/app
    links:
        - db
        - selenium
    environment:
        - EXTERNAL_TEST_SERVER=http://testserver:8000/
        - SELENIUM_HOST=http://selenium:4444/wd/hub
selenium:
    image: selenium/standalone-chrome:2.48.2
    links:
        - testserver
testserver:
    build: .
    command: bash -c "sleep 5; python manage.py testserver 8000 --static"
    volumes:
        - ./test_project:/app
    ports:
      - "8000:8000"
    links:
        - db

так что я могу запустить docker-compose run test без предварительного запуска базы данных и ожидания.

Трудно сказать, какая проблема в наши дни является «правильным» местом для голосования за новую функцию компоновки докеров, которая позволяет объявлять явные зависимости, но считаю мой голос сильным. С новой сетевой функциональностью Docker 1.9 и приближающимся отказом от ссылок на контейнеры в пользу нее теперь нет отличного способа убедиться, что контейнер A запускается до контейнера B, потому что, если вы используете определяемую пользователем сеть Docker 1.9, вы можете больше не указывайте ссылки на контейнеры. Это ... сломано.

Я согласен. Есть ли сроки для получения варианта 3? Было бы здорово, если бы это ускорилось.

Стоит отметить, что упорядочение зависимостей на самом деле не решает эту проблему. Эта проблема касается и ссылок. Во многих случаях контейнер запускается достаточно быстро, и вы не замечаете проблемы, но проблема все еще существует.

Что необходимо для решения этой проблемы, так это проверка работоспособности с учетом приложений. Проверка работоспособности - это в основном цикл, который повторяет некоторую операцию до тех пор, пока либо: операция не будет успешной, либо не истечет время ожидания. В случае службы HTTP он может выполнять HTTP-запросы, пока вы не получите код 2xx. Для базы данных это может быть подключение и выбор из таблицы.

В любом случае, это зависит от приложения, поэтому разработчик должен его определить. Если бы мы реализовали вариант 3 из https://github.com/docker/compose/issues/374#issuecomment -135090543, вам все равно пришлось бы реализовать эту логику проверки работоспособности.

Об этом уже упоминалось несколько раз в этом выпуске (https://github.com/docker/compose/issues/374#issuecomment-53036154, https://github.com/docker/compose/issues/374#issuecomment-71342299 ), но чтобы повторить итерацию, вы можете решить эту проблему сегодня, сделав свое приложение устойчивым к сбоям , повторив попытку подключения. В любом случае это необходимо сделать для любой производственной системы.

Оказывается, функциональность по обеспечению устойчивости вашего приложения к сбоям фактически совпадает с логикой проверки работоспособности. Так что в любом случае вам все равно нужно реализовать ту же логику. Единственная разница будет в том, где вы его включаете. Прямо сейчас вы можете включить его в свое приложение или сценарий точки входа. С предлагаемым изменением вы сможете определить его в файле Compose. В любом случае, вам все равно придется реализовать проверку работоспособности для каждой службы.

Есть ли существенное преимущество во включении его в файл Compose вместо сценария точки входа? Возможно, это все еще обсуждается.

Большим _ неудобством_ помещения его в файл Compose является то, что он делает up значительно медленнее.

С новой сетью мы можем заставить up происходить параллельно (как мы делаем для остановки, rm и масштабирования). Каждый контейнер может запуститься сразу, выполнить некоторую инициализацию, а затем дождаться появления зависимостей для продолжения. Это делает запуск среды очень быстрым.

Если Compose нужно дождаться завершения проверки работоспособности, запуск выполняется последовательно. Запуск контейнера и инициализация приложения не происходят параллельно, и все происходит медленнее.

У большинства приложений есть проверки работоспособности из-за LB, внешнего мониторинга и т. Д. Открыть новое не сложно. Итак, если compose поддерживает его, то это выбор, который могут использовать люди. Это не обязательно. В реальном мире людям приходится иметь дело с множеством приложений, и идея о том, что внезапно все приложения можно сделать умными, нереалистична и непрактична. А логика обертки в точке входа просто уродлива. Я думаю, что в сообществе есть достаточный спрос на эту функцию, и, как вы видите, вариант 3 получил много голосов.

отправлено из моего Айфона

18 ноября 2015 г. в 11:01 Даниэль Нефин [email protected] написал:

Стоит отметить, что упорядочение зависимостей на самом деле не решает эту проблему. Эта проблема касается и ссылок. Во многих случаях контейнер запускается достаточно быстро, и вы не замечаете проблемы, но проблема все еще существует.

Что необходимо для решения этой проблемы, так это проверка работоспособности с учетом приложений. Проверка работоспособности - это в основном цикл, который повторяет некоторую операцию до тех пор, пока либо: операция не будет успешной, либо не истечет время ожидания. В случае службы HTTP он может выполнять HTTP-запросы, пока вы не получите код 2xx. Для базы данных это может быть подключение и выбор из таблицы.

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

Об этом уже упоминалось несколько раз в этом выпуске (# 374 (комментарий), # 374 (комментарий)), но, повторяя итерацию, вы можете решить эту проблему сегодня, сделав свое приложение устойчивым к сбоям, повторив попытку подключения. В любом случае это необходимо сделать для любой производственной системы.

Оказывается, функциональность по обеспечению устойчивости вашего приложения к сбоям фактически совпадает с логикой проверки работоспособности. Так что в любом случае вам все равно нужно реализовать ту же логику. Единственная разница будет в том, где вы его включаете. Прямо сейчас вы можете включить его в свое приложение или сценарий точки входа. С предлагаемым изменением вы сможете определить его в файле Compose. В любом случае, вам все равно придется реализовать проверку работоспособности для каждой службы.

Есть ли существенное преимущество во включении его в файл Compose вместо сценария точки входа? Возможно, это все еще обсуждается.

Большой недостаток помещения его в файл Compose заключается в том, что он выполняется значительно медленнее.

С новой сетью мы можем делать все параллельно (как мы делаем для stop, rm и scale). Каждый контейнер может запуститься сразу, выполнить некоторую инициализацию, а затем дождаться появления зависимостей для продолжения. Это делает запуск среды очень быстрым.

Если Compose нужно дождаться завершения проверки работоспособности, запуск выполняется последовательно. Запуск контейнера и инициализация приложения не происходят параллельно, и все происходит медленнее.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub.

@dnephin Конечным результатом является то, что у вас есть одинаковые сценарии оболочки для каждой службы. Я хочу сказать, что есть некоторые вещи, которые настолько распространены (например, HTTP 200 на 80 и 443 или TCP на 5432), что неплохо было бы отправлять их вместе с compose.

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

Я согласен как с @mbdas, так и с @jayfk , и просто добавлю: если сопротивление этому состоит в том, что даже с зависимостями-спецификациями и результирующим порядком запуска контейнера будут сбои, тогда использование контейнерных ссылок и томов - от до порядок запуска контейнера управления никогда не должен был произойти - все, что мы просим, ​​это то, что теперь, когда новая сетевая модель означает, что ссылки устарели (и что новая сетевая модель буквально не может сосуществовать со ссылками), тот же запуск -заказать функциональность, позволяющую каким-либо образом вернуть нам ссылки. Конечно, любые случаи сбоя, которые могли произойти при упорядочивании контейнеров на основе ссылок, все еще могут произойти с новой сетевой моделью и зависимостями контейнеров, но мы все научились жить с этим.

@delfuego : не могли бы вы

@Silex https://docs.docker.com/compose/networking. это вы имеете в виду?

@ h17liner : да, интересно! благодаря

Хотя я согласен с @dnephin, что

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

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

@delfuego Я думаю, что вы изначально попали в нужное место (# 686) по этому вопросу. Это проблема не в заказе, а в искусственной задержке запуска (когда заказ уже существует). Хотя эти вещи связаны, это отдельные проблемы.

Я не согласен с ссылками, которые не поддерживаются в сетях мостов, созданных пользователями, и задокументированы как устаревшие, в общем, нет никакого упорядочивания. Таким образом, вариант 3 касается как заказа, так и момента начала выпуска.

отправлено из моего Айфона

19 ноября 2015 г. в 8:14 Даниэль Нефин написал на [email protected] :

@delfuego Я думаю, что вы изначально попали в нужное место (# 686) по этому вопросу. Это проблема не в заказе, а в искусственной задержке запуска (когда заказ уже существует). Хотя эти вещи связаны, это отдельные проблемы.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub.

Я хотел бы предложить вариант 4 (некоторые могут сказать, что на самом деле это вариант 3)
Контейнер не готов, пока все команды запуска не завершатся с кодом выхода 0. Должна быть возможность определить эти команды запуска в файле yml для каждого контейнера. Эти команды выполняются так же, как если бы вы выполняли команду «docker exec» для запущенного контейнера. Подумайте о методах setUp () и tearDown () в классическом модульном тестировании. Да, у нас тоже могут быть команды "выключения".
Очевидно, что следующий контейнер в иерархии не запускается, пока не будут готовы все контейнеры, от которых он зависит.
PS Спасибо за отличный DockerCon.Eu 2015

Директива HEALTHCHECK гораздо более гибкая (т.е. может быть использована в любой момент позже) и полезна. Настройка должна выполняться в рамках сценария CMD или (еще лучше) ENTRYPOINT , разборки путем обработки сигналов процесса.

Я думаю, что суть проблемы здесь в том, что люди хотят, чтобы одна команда docker-compose up вызывала стек, и все просто волшебным образом работает.

Судя по всем отзывам, очевидно, что существует множество решений для различных случаев использования, но не существует «универсального решения».

Вы можете довольно легко выполнять задачи «инициализации», выполняя несколько команд docker-compose - и я думаю, что этот подход является наиболее универсальным и гибким.

Например, я запускаю Ansible playbook в контейнере «агента» с единственной задачей, которая ожидает, пока контейнер моей базы данных (MySQL) будет запущен на порту 3306. Этот контейнер «агент» связан с контейнером my «db», поэтому автоматически запускает его, когда выполняется следующее:

$ docker-compose run --rm agent
Creating db_1

PLAY [Probe Host] *************************************************************

TASK: [Set facts] *************************************************************
ok: [localhost]

TASK: [Message] ***************************************************************
ok: [localhost] => {
    "msg": "Probing db:3306 with delay=0s and timeout=180s"
}

TASK: [Waiting for host to respond...] ****************************************
ok: [localhost -> 127.0.0.1]

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0

После этого я могу запустить docker-compose up зная, что контейнер db полностью готов к работе.

Вот простой файл docker-compose.yml, который это поддерживает:

...
...
db:
  image: mysql
  hostname: db
  expose:
    - "3306"
  environment:
    MYSQL_DATABASE: xxx
    MYSQL_USER: xxx
    MYSQL_PASSWORD: xxx
    MYSQL_ROOT_PASSWORD: xxx

agent:
  image: cloudhotspot/ansible
  links:
    - db
  volumes:
    - ../../ansible/probe:/ansible
  environment:
    PROBE_HOST: "db"
    PROBE_PORT: "3306"

Контейнер «агент» запускает playbook с именем site.yml в смонтированном томе /ansible который показан ниже:

- name: Probe Host
  hosts: localhost
  connection: local
  gather_facts: no
  tasks: 
    - name: Set facts
      set_fact: 
        probe_host: "{{ lookup('env','PROBE_HOST') }}"
        probe_port: "{{ lookup('env','PROBE_PORT') }}"
        probe_delay: "{{ lookup('env','PROBE_DELAY') | default(0, true) }}"
        probe_timeout: "{{ lookup('env','PROBE_TIMEOUT') | default (180, true) }}"
    - name: Message
      debug: msg="Probing {{ probe_host }}:{{ probe_port }} with delay={{ probe_delay }}s and timeout={{ probe_timeout}}s"
    - name: Waiting for host to respond...
      local_action: >
        wait_for host={{ probe_host }}
        port={{ probe_port }}
        delay={{ probe_delay }}
        timeout={{ probe_timeout }}
      sudo: false

Одним из решений единственной цели docker-compose up может быть введение функции "рабочего процесса" для создания докеров и включение дополнительного файла спецификации рабочего процесса, который позволяет использовать более сложные и контролируемые сценарии оркестрации, указав одну или несколько команд для создания докеров как «задачи», которые необходимо выполнить:

# The default workflow, specified tasks will be run before docker-compose up
# The "up" task is implicit and automatically invoked for the default workflow
# The "up" task is explicit for custom workflows as some workflows may not want docker-compose up
default:
  tasks:
    - run --rm agent
    - up

# Custom workflows that can be invoked via a new docker-compose command option
# This example:
# 1. Runs agent container that waits until database container is up on port 3306
# 2. Runs Django database migrations from app container
# 3. Runs Django collect static task from app container
# 4. Runs test container that runs acceptance tests against linked app container
# Does not execute a docker-compose up afterwards

test:
  tasks:
    - run --rm agent 
    - run --rm app manage.py migrate
    - run --rm app manage.py collectstatic --noinput
    - run --rm test

Сегодня я достигаю вышеуказанного с помощью Makefiles, которые предоставляют возможность более высокого порядка определять мои собственные рабочие процессы для различных сценариев.

Было бы замечательно, если бы в docker compose можно было бы включить функцию «рабочего процесса» или что-то подобное, что обеспечило бы очень общее и гибкое решение этой конкретной проблемы и многих других.

Согласны, проблема в том, что люди ожидают, что docker-compose будет достаточно для производственного развертывания. Лично я думаю, что пройдет много времени, прежде чем это станет возможным, и Helm, похоже, намного ближе к этой цели.

@olalonde , конечно, мы хотели бы, чтобы compose был готов к производству ... но мы

С помощью директивы HEALTCHECK Docker функциональность depends_on может либо дождаться запуска контейнера (без проверки работоспособности), либо успешного завершения сценария проверки работоспособности (код выхода 0 ). Это настолько гибко, насколько возможно (вы можете определить произвольную логику) и сохраняет логику проверки работоспособности там, где она принадлежит (в пределах проверяемого контейнера).

@delfuego даже для разработки и тестирования эта функция будет полезна. Лично я хочу иметь возможность сделать docker-compose run test и заставить его работать без предварительного вызова служб и ожидания вручную. Хотя это возможно, но это лишь усложняет начало работы над проектом и добавляет больше способов, по которым тестирование может потерпеть неудачу.

+1

Я думаю, что разрешение требует среднего пути - Compose никогда не сможет учесть все различные способы, которыми приложения могут считаться доступными или нет. Идея проверки работоспособности будет означать разные вещи для разных людей и может быть не такой простой, как «работает она или нет». В производственной среде вы можете отключить контейнер, если он демонстрирует необычно долгое время отклика, даже если он проходит какие-либо проверки HTTP.

Поэтому я считаю, что базовой поддержки HTTP-ответов, открытых портов, созданных файлов или генерируемых строк журнала должно быть достаточно для разработки. Все, что более продвинуто, почти сразу становится специфичным для конкретного приложения. Мне также нравится идея побуждать разработчиков делать отдельные части своих стеков приложений более надежными.

@pugnascotia, спасибо, это конструктивный комментарий и разумный подход («лучшее из обоих миров»?)

Обсуждаемые в настоящее время решения, похоже, на самом деле не решают проблему, о которой _первоначально сообщалось_, что гораздо проще ... которая НЕ ожидает доступности службы, а ожидает ВЫХОДА службы.

У меня есть вариант использования, когда у меня есть два контейнера, которые открывают одни и те же порты. Первый длится 15-60 секунд, потом выходит. Затем должна запуститься вторая служба. Нет (очевидного?) Способа сделать это в compose сегодня, поскольку он обнаружит конфликт портов и завершит работу; даже «перезапуск: всегда» не является решением.

Да, Compose не предназначен для этого варианта использования. Compose ориентирован на среду выполнения, а не на построение конвейеров. Я не думаю, что это то, о чем первоначально сообщалось о проблеме.

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

@ewindisch - ваш

В этой части документации Compose рассматривается вопрос, почему у Compose нет такой возможности:

https://docs.docker.com/compose/faq/#how -do-i-get-compose-to-wait-for-my-database-to-be-ready-before-start-my-application

Однако на этих страницах проблема вообще не упоминается:

https://docs.docker.com/compose/django/
https://docs.docker.com/compose/rails/
https://docs.docker.com/compose/wordpress/

По крайней мере, эти страницы должны включать подтверждение того, что Compose не будет ждать готовности контейнера базы данных. Они также могут включать примеры способов борьбы с этим.

@ewindisch Собственно, это именно то, что я предлагал в https://github.com/docker/compose/issues/374#issuecomment -126312313 - с гипотезой о том, что решение _that_ проблемы также дает пользователям инструменты для решения проблемы заказа при запуске ( если не проблема долгосрочной устойчивости).

Я все еще заинтересован в изучении этого пространства решений, если кто-то еще.

Я.

Я тоже.

+1

+3

+1

+1 за реализацию решения https://github.com/docker/compose/issues/374#issuecomment -126312313.

Массивное голосование!
В настоящее время это влияет на использование инструментов, которые работают в контейнере, но полагаются на события докеров (например, jwilder / nginx-proxy). То, как я это делаю, - это просто вручную собрать слушателя в докере и после этого запустить все остальные контейнеры (что портит всю красоту docker-compose up как единой точки входа).

@meetmatt пробовали ли вы потом запустить jwilder / nginx-proxy? Порядок запуска не имеет значения, при запуске он подберет существующие (работающие) контейнеры.

+1

+1

Очень хотелось бы видеть прозрачное решение на основе каналов. В основном нравится libchan. Таким образом, если я запрашиваю базу данных, запрос буферизуется до тех пор, пока база данных не будет готова.

Я действительно не думаю, что порядок загрузки является достаточным решением в распределенных системах. Что, если, например, вам нужно перезапустить базу данных, но в результате могут произойти сбой других служб? Настоящее решение справится и с этим вариантом использования.

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

+1

Я, должно быть, что-то упускаю.

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

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

Я хотел бы запустить произвольную логику и сигнализировать докеру, когда я буду готов, как я решил (например, когда появляется определенное сообщение в журнале -> signal CONTAINER_UP).

net: "container:[name or id]" почему бы не заказать запуск моих контейнеров? Мне пришлось отказаться от links потому что он будет устаревшим, и я хочу, чтобы весь стек использовал сеть net: "host" . К сожалению, это не разрешено с links . Есть ли другой способ изменить порядок загрузки контейнеров или мне нужно разделить между ними бесполезные тома?

Обновить:

Я только что сделал повторный заказ с бесполезными томами вместо links :

base:
  build: ./base
  net: "host"
  volumes:
    - /root/lemp_base
phpmyadmin:
  build: ./phpmyadmin
  net: "host"
  volumes_from:
    - base
  volumes:
    - /root/lemp_phpmyadmin
ffmpeg:
  build: ./ffmpeg
  net: "host"
  volumes_from:
    - phpmyadmin
  volumes:
    - /root/lemp_ffmpeg
mariadb:
  build: ./mariadb
  net: "host"
  volumes_from:
    - ffmpeg
  volumes:
    - /root/lemp_mariadb
php:
  build: ./php
  net: "host"
  volumes_from:
    - mariadb
  volumes:
    - /root/lemp_php
nginx:
  build: ./nginx
  net: "host"
  volumes_from:
    - php
  volumes:
    - /root/lemp_nginx

(Я удалил другие общие тома из стека и другую информацию, такую ​​как имя_контейнера, порты, чтобы выглядеть просто.)

Если я хочу использовать с net: "container:base , у меня появляется сообщение об ошибке при выполнении команды docker-compose build .

ERROR: Service "mariadb" is trying to use the network of "lemp_base", which is not the name of a service or container.

Что мне не нравится в этом решении, так это то, что каждый второй контейнер будет получать файлы веб-сервера в папке /var/www из base .

РЕДАКТИРОВАТЬ:
По какой-то причине этот стек удаляет всю папку /var/www при запуске.

Мое скромное мнение заключается в том, что любой механизм, заканчивающийся тем, что Docker Compose знает о зависимости между контейнерами, противоречит разделению проблем. Docker Compose отвечает за запуск контейнеров A и B. Контейнеры A и B отвечают за свои собственные службы. Если B зависит от правильной работы A, то B должен подождать, пока A будет в рабочем состоянии. Как было сказано в обсуждении, это можно сделать с помощью тайм-аута, повторной попытки или чего-то еще, но это проблема B, а не Docker Compose или A. SoC имеет первостепенное значение для независимости службы и надлежащего масштабирования.

Есть ли работа над вашей идеей 3 @aanand ? Было бы хорошо узнать, есть ли какой-либо прогресс, это звучало как многообещающее начало, которое поможет в некоторых очень распространенных сценариях использования, даже если не является идеальным решением.

+1

+1

Может я ошибаюсь, но args: buildno: может заказать контейнеры в docker-compose.yml версии 2?

Я склонен согласиться с тем, что это проблема, которой нет в Compose. @jwilder «s отлично Dockerize только получил поддержку ждать зависимых контейнеров и вы можете указать протокол / порт , который вы ждете дальше. Я бы предположил, что это подходит для большинства описанных здесь случаев использования:

api:
  build: .
  ports:
   - "8000:80"
  expose:
  - "80"

test:
  build: test
  command: dockerize -wait http://api:80 -wait tcp://db:5432 somecommand -some arg -another arg2
  links:
    - api:api

В идеале мы используем API событий Docker для автоматического обнаружения этого, но это будет означать, что каждому контейнеру также потребуется доступ к среде выполнения Docker, что, вероятно, невозможно / что-то, что мы хотели бы.

Я думаю, что подождать нужно вне композиции. В моем разработчике я собираюсь использовать гибрид , что @mefellows предложил и timercheck.io страницы статуса. Я думаю, что это даст мне именно то, что мне нужно, без хлопот с использованием RabbitMQ или чего-то подобного.

Мы используем точку входа сценария оболочки, которая ожидает открытия порта с тайм-аутом 15 секунд:

#!/usr/bin/env bash

# wait for db to come up before starting tests, as shown in https://github.com/docker/compose/issues/374#issuecomment-126312313
# uses bash instead of netcat, because netcat is less likely to be installed
# strategy from http://superuser.com/a/806331/98716
set -e

echoerr() { echo "$@" 1>&2; }

echoerr wait-for-db: waiting for db:5432

timeout 15 bash <<EOT
while ! (echo > /dev/tcp/db/5432) >/dev/null 2>&1;
    do sleep 1;
done;
EOT
RESULT=$?

if [ $RESULT -eq 0 ]; then
  # sleep another second for so that we don't get a "the database system is starting up" error
  sleep 1
  echoerr wait-for-db: done
else
  echoerr wait-for-db: timeout out after 15 seconds waiting for db:5432
fi

exec "$@"

Это должно быть решено с помощью предстоящего (и, очевидно, неизбежного в связи с обновлением документации) depend_on , да?

Нет. depends_on только заказ. Чтобы действительно отложить запуск другого контейнера, должен быть способ определить, когда процесс завершил инициализацию.

Ах, спасибо за разъяснения. знак равно

Я написал чистую утилиту командной строки bash под названием wait-for-it, которую можно включить в развертывание докеров, чтобы помочь синхронизировать развертывание служб.

Для меня не рекомендуется жестко программировать произвольный набор «проверок доступности». Существует множество ситуаций, характерных для одного типа развертывания, и вы никогда не сможете охватить их все. Например, в моем многоконтейнерном приложении мне нужно дождаться появления определенного сообщения журнала в определенном файле журнала - только тогда контейнерная служба будет готова.
Вместо этого мне нужен SPI, который я могу реализовать. Если Docker предоставляет несколько примеров реализации для наиболее частых случаев использования (например, TCP-соединение), это нормально. Но должен быть способ подключить мои собственные функции и заставить Docker вызывать их.
Docker Compose в значительной степени бесполезен для меня как продукт в целом, если я не могу надежно настроить и запустить свои контейнеры. Таким образом, необходим стабильный и единообразный «SPI готовности контейнерных услуг». И «готово» не должно быть логическим, так как возможно больше уровней готовности (например, «теперь вы можете читать» и «теперь вы можете писать»).

@realulim Хорошая

Это то, что я придумал в файле точек входа;

until netcat -z -w 2 database 5432; do sleep 1; done
# do the job here, database host on port 5432 accepts connections

@kulbida ,
Я делаю нечто очень похожее с MySQL. "база данных" в данном случае - это ссылка в файле набора.

if [[ "$APP_ENV" == "local" ]]; then
    while ! mysqladmin ping -h database --silent; do
        sleep 1
    done
    # Load in the schema or whatever else is needed here.
fi

В этом потоке были некоторые комментарии, в которых утверждается, что порядок запуска - это только подмножество восстановления после ошибок на уровне приложения, которое ваше приложение в любом случае должно обрабатывать. Я хотел бы привести один пример, чтобы проиллюстрировать, где это может быть не всегда. Подумайте, зависят ли некоторые службы от кластеризованной базы данных, и всякий раз, когда кворум теряется из-за сбоя и т. Д., Вы _не_ хотите автоматически повторять попытку из приложения. Это может иметь место, например, если восстановление базы данных требует некоторых ручных действий, и вам нужно, чтобы службы оставались однозначно отключенными до тех пор, пока эти шаги не будут выполнены.

Теперь логика обработки ошибок приложения может сильно отличаться от логики запуска:

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

Возможно, это не самый распространенный сценарий, но иногда вы видите эту закономерность. В этом случае кластеризация используется для решения проблемы «сеть ненадежна» в общем случае, что меняет некоторые ожидания относительно того, какие условия ошибки следует повторить в приложении. Сбои кластера могут быть достаточно редкими, и их автоматический перезапуск может быть достаточно рискованным, поэтому перезапуск служб вручную предпочтительнее, чем повторная попытка в приложении. Я подозреваю, что есть и другие сценарии, которые могут поставить под сомнение предположения о том, когда следует повторить попытку.

В более общем плане я утверждаю, что порядок запуска и обработка ошибок не всегда эквивалентны, и что фреймворк должен предоставлять (необязательные) функции для управления порядком запуска. Я действительно задаюсь вопросом, принадлежит ли это docker-engine, а не компоновке. Он может понадобиться при запуске докера, независимо от того, используется ли compose.

В предложении https://github.com/docker/docker/issues/21142 начинается обсуждение репозитория docker Engine о добавлении поддержки проверки работоспособности. Как только эта поддержка станет доступной, Compose сможет предоставить способ ее настройки и использования для отложенного запуска.

Как насчет использования файловой системы для проверки существования файла?

ready_on: /tmp/this_container_is_up_and_ready

Таким образом, разработчик контейнера сам решает, когда все в порядке, но compose может подождать, пока контейнер не объявит себя готовым. Это явное соглашение, но его можно легко добавить в качестве дополнительного слоя к изображениям, которые не имеют такого поведения.

Встроенная поддержка проверки работоспособности будет хороша; А пока вот хак, который я использовал в своей локальной настройке docker-compose:

    nginx:
        image: nginx:latest
        command: /bin/bash -c "sleep 2 && echo starting && nginx -g 'daemon off;'"
        ...

(В процессе производства мое приложение передает прокси на несколько уже работающих вышестоящих серверов, используя proxy_pass ; в локальном разработчике и тестировании я запускаю их экземпляры докеров, и nginx должен немного подождать, пока они запустятся, иначе он вылетает и умирает. daemon off сохраняет nginx в одном процессе, иначе докер остановит контейнер, как только родительский процесс создаст своего дочернего демона.)

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

Наш сервер Jenkins CI раскручивает контейнеры проекта с помощью Docker Compose, а затем запускает ANT из основного контейнера, например:

docker-compose up -d
docker exec -it projectx-fpm-jenkins ant -f /var/www/projectX/build.xml

Это соответствующая часть конфигурации из файла docker-compose.yml. Обратите внимание, что, как обсуждалось выше, сделать fpm зависимым от mysql недостаточно, чтобы гарантировать, что служба MySQL будет готова, когда она действительно понадобится.

version: '2'
services:
  nginx:
    build: ./docker/nginx
    depends_on:
      - fpm
  fpm:
    build: ./docker/fpm
    depends_on:
      - mysql
  mysql:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=projectx
      - MYSQL_DATABASE=projectx

Но вы можете дождаться этого во время выполнения задачи ANT:

<!-- other targets... -->

<target name="setup db">
    <!-- wait until the 3306 TCP port in the "mysql" host is open -->
    <waitfor>
        <socket server="mysql" port="3306"/>
    </waitfor>

    <exec executable="php">
        <arg value="${consoledir}/console"/>
        <arg value="doctrine:database:create"/>
        <arg value="--no-interaction"/>
    </exec>
</target>

@kulbida Это

while ! nc -w 1 -z db 5432; do sleep 0.1; done

_depends_on_ может решить проблему.
Из документации docker-compose .
Выраженная зависимость между сервисами, имеющая два эффекта:

  1. docker-compose up запустит службы в порядке зависимости. В следующем примере db и redis будут запущены до web.
  2. docker-compose up SERVICE автоматически включит зависимости SERVICE. В следующем примере docker-compose up web также создаст и запустит db и redis.

версия: '2'
Сервисы:
Интернет:
сборка:.
зависит от:
- дб
- Redis
Redis:
изображение: redis
db:
изображение: postgres

@alexch : при тестировании производительности на стороне клиента (микросервис перенаправляется через nginx +). Dockerized nginx test - падение нагрузки от очень высоких до почти нулевого минимума повторялось каждые 1-2 минуты. В конце концов решил использовать Nginx без докеров, работающий как виртуальную машину (просто из-за огромной разницы в производительности), возможно, проблема с плагином сетевого драйвера / libNetwork.

@syamsathyan depends_on , похоже, не помогает.

@skorokithakis , @kulbida, это хорошее решение. К сожалению, netcat по умолчанию недоступен ни в одной из служб, которые мне нужно подключиться к моей базе данных (включая postgres ). Вы знаете какой-нибудь альтернативный метод?

@nottrobin Боюсь, что нет, я просто установил в свой образ: /

@nottrobin моя команда работает над этим,

Для тех, кто недавно использовал bash, есть решение без netcat (вдохновленное: http://stackoverflow.com/a/19866239/1581069):

while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/db/5432'; do sleep 0.1; done

или менее подробная версия:

while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/db/5432' >/dev/null 2>/dev/null; do sleep 0.1; done

@typekpb, который отлично работает. Благодаря!

Теперь, когда поддержка HEALTHCHECK объединена с восходящим потоком в соответствии с https://github.com/docker/docker/pull/23218 - это можно рассматривать для определения того, когда контейнер исправен, до запуска следующего по порядку. Половина головоломки решена :)

Теперь, когда поддержка HEALTHCHECK объединена с восходящим потоком согласно docker / docker # 23218 - это можно рассматривать как определение, когда контейнер исправен, до запуска следующего по порядку. Половина головоломки решена :)

Выглядит хорошо. Как это реализовать на docker-compose.yml ?

Выглядит хорошо. Как это реализовать на docker-compose.yml?

Другой частью головоломки будет наблюдение за исправными контейнерами с помощью docker-compose и использование чего-то вроде синтаксиса depends_on, упомянутого далее в этом выпуске. Потребуются патчи для создания докеров, чтобы все работало.

Также обратите внимание, что функция проверки работоспособности в Docker в настоящее время не выпущена, поэтому, вероятно, ее необходимо согласовать с циклом выпуска Docker / Docker Compose.

Я написал js-библиотеку с методом .waitForPort() . Как уже упоминалось ранее, это может работать не для всех ситуаций, но может отлично работать в большинстве случаев использования.
Смотрите мой блог .

Слияние HEALTHCHECK - отличная новость.

А пока в этом документе описывается проблема и некоторые решения.

@pablofmorales Нет, потому что depends_on просто проверяет, что контейнер запущен .

Некоторым демонам требуется дополнительное время для начальной загрузки и начала прослушивания назначенных им портов и адресов, в первую очередь MySQL.

Я все еще думаю, что объявление "READY_ON" по-прежнему является лучшим в целом. Он оставляет решение о том, когда что-то готово к самому контейнеру, независимо от изображения, это явное согласие, а функциональность пути к ресурсам (внутри контейнера) в Docker Remote API обеспечивает минимальные необходимые изменения.

Поведение контейнера "вверх" - единственное, на что это должно повлиять. Он будет сообщать как «работает» только тогда, когда существует файл READY_ON.

Я думаю, что это 90% поведения, которое все обсуждают. Я думаю, что здесь «проверка работоспособности» объединяется как два разных события, но я пытаюсь свести их в одно. Один «готов» к цепочке событий при развертывании инфраструктуры, другой - «работоспособен», чтобы поддерживать инфраструктуру в рабочем состоянии.

"Готово" - это совершенно подходящее место для помощи докеру. Что касается «здоровья», оно настолько разнообразно с точки зрения систем, что я думаю, что контейнер должен с этим справиться.

В качестве лучшей альтернативы проверке работоспособности вы можете посмотреть что-то вроде containerpilot, который охватывает не только работоспособность, но и обнаружение и мониторинг служб. https://github.com/joyent/containerpilot

Да, это точное и важное различие. Однако как контейнеры будут записывать этот файл без значительного усложнения изображений? Мне кажется, что для каждого отдельного контейнера, который хочет это использовать, потребуется сценарий-оболочка.

Что ж, вам в любом случае придется запустить сценарий для инициализации экземпляра ... последнее, что нужно сделать сценарию, - это прикоснуться к файлу. Мне это кажется намного проще, чем пытаться запустить exec на удаленном компьютере для проверки работоспособности. По крайней мере, с сенсорным файлом его можно просматривать и т. Д. Полностью через API пассивно, без необходимости входить в контекст контейнера.

Я согласен, но многие контейнеры не используют скрипт, они просто устанавливают такую ​​службу, как Postgres или Redis, и позволяют ей запускаться, не наблюдая за ней.

В моем случае я использую Kong API Gateway

Перед запуском контейнера kong я просто проверяю, работает ли Cassandra с этим скриптом

while true; do
    CHECK=`kong-database/check`
    if [[ $CHECK =~ "system.dateof" ]]; then
        break
    fi
    sleep 1;
done

контрольный файл содержит это

#!/bin/bash
docker cp cassandra-checker kong-database:/root/
docker exec -i kong-database cqlsh -f /root/cassandra-checker

cassandra-checker - это простой запрос

SELECT dateof(now()) FROM system.local ;

Конечно, но альтернативой является проверка работоспособности, для которой требуется сценарий, который вам все равно придется писать, поэтому нет никакой разницы в накладных расходах. Это также явное согласие, что означает, что вы заявляете, что хотите такого поведения. Что касается того, что не запускает скрипт, у вас всегда может быть проверка пути ready_on для файла pid или сокета unix; для чего не потребуется сценарий.

Это правда, ты прав.

Проверка существования файла может быть полезной во многих случаях, но принуждение контейнеров к использованию сценария запуска, когда он в противном случае им не нужен, является неприятностью. Почему не может быть проверок и на другие очень простые условия? Особенно полезно подождать, пока процесс прослушивает определенный порт TCP.

Эта идея является добровольной, поэтому ни к чему не принуждать. Фактически, вы прямо говорите, чего следует ожидать.

Прослушивания TCP-порта может быть недостаточно, чтобы определить, когда контейнер был инициализирован, так как может потребоваться запуск большого количества установочных данных. Черт, если вы слишком быстро подключитесь к контейнеру postgres, даже через tcp, вы получите сообщение об ошибке о том, что база данных еще не готова.

Если я вас правильно понял, это «подписка, иначе вы не сможете использовать эту функцию». Следовательно, если мне нужна эта функция, а мое приложение не использует файл pid, я вынужден использовать сценарий запуска.

Для MySQL (случай OP), когда он прослушивает, он готов. Они прилагают много усилий, чтобы убедиться, что это правда, вероятно, в таких случаях, как этот. Я считаю, что, вероятно, существует короткий список условий, которые можно перечислить, чтобы вы могли «согласиться», настроив готовую проверку на соответствие любому из этих условий. Я не вижу причин, по которым это нужно делать одним-единственным способом.

Для mysql, когда он прослушивает, он не готов. В простом случае с одним узлом он будет готов, но если у вас более одного узла, он, безусловно, еще не будет готов. Я понимаю, что вы имеете в виду под «одним-единственным способом», но я думаю, что в качестве базовой абстракции это просто идеально. Я вижу это больше как место, где вы можете применить любые инструменты, которые захотите. Черт возьми, ваш сценарий может даже связываться с внешними службами и заставлять их проверять контейнер, и в этом случае ваши внешние службы могут сигнализировать вашему агенту контейнера о записи файла. Гибкость ftw.

Если вы попробуете что-нибудь из этого списка «условий», ВСЕГДА это не сработает. Однако прикосновение к файлу всегда будет работать, поскольку изображение знает, когда оно считает, что оно готово (о, мне нужно ждать на других хостах, мне нужно загрузить файлы, мне нужно убедиться, что $ external_service также доступен, я охватываю правильно, но по какой-то причине у меня нет правильных прав доступа к базе данных, почему это изображение доступно только для чтения ... и т.д.

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

Другой вероятный случай - что-то вроде chef или ansible запускается против этого хоста, а затем записывает файл.

Если это вопрос проверки на стороне Docker, то что-то вроде:

UPCHECK --port=7474 --interval=0.5s --response="Please log in"

Для протокола, я считаю, что файловое решение имеет много достоинств, но оно также вносит сложность.
В 80% случаев проверка ответа tcp будет работать нормально.

ну ... я полагаю:

UPCHECK --file=/tmp/container_is_ready --interval=0.5s --timeout=2m

Точно так же.

На самом деле я работаю над повторной реализацией docker-compose, которая добавляет функциональность для ожидания определенных условий. Он использует libcompose (поэтому мне не нужно перестраивать взаимодействие с докером) и добавляет для этого кучу команд конфигурации. Посмотрите здесь: https://github.com/dansteen/controlled-compose

Обратите внимание, что код готов, но я жду решения пары проблем в восходящем направлении, прежде чем его можно будет использовать по-настоящему.

Goss можно использовать как довольно гибкую прокладку для задержки запуска контейнера, я написал сообщение в блоге, объясняющее, как этого можно добиться с помощью незначительного изменения изображения здесь:

В Kubernetes есть концепция init-контейнеров. Интересно, выиграет ли compose / swarm от подобной концепции.

+1

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

Например, для приложения PHP может зависеть соединение MySQL. Итак, в контейнере PHP ENTRYPOINT я написал что-то вроде этого.

#!/bin/bash
cat << EOF > /tmp/wait_for_mysql.php
<?php
\$connected = false;
while(!\$connected) {
    try{
        \$dbh = new pdo( 
            'mysql:host=mysql:3306;dbname=db_name', 'db_user', 'db_pass',
            array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
        );
        \$connected = true;
    }
    catch(PDOException \$ex){
        error_log("Could not connect to MySQL");
        error_log(\$ex->getMessage());
        error_log("Waiting for MySQL Connection.");
        sleep(5);
    }
}
EOF
php /tmp/wait_for_mysql.php
# Rest of entry point bootstrapping

Таким образом, я могу добавить любую логику, чтобы гарантировать, что зависимости сервиса, который я раскрываю, то есть php, были разрешены.

Набин Непал Шриб:

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

Вы, конечно, можете жестко запрограммировать это поведение в каждый контейнер, который использует ваш
Контейнер MySql. Но если что-то в вашей службе MySql изменится, значит, вы
изменение всех зависимых контейнеров, не говоря уже о повторяющемся кодировании
нужно в каждом. Это не СУХОЙ, стабильного контракта нет, поэтому он будет
приводят к хрупкости систем.

С точки зрения разработки программного обеспечения, должна быть какая-то
«SPI готовности контейнера», который может реализовать разработчик контейнера. На
с другой стороны должен быть «API готовности контейнера», который
услуги могут зависеть от.

Ульрих

@realulim Я согласен с тем, что любое изменение в контейнере MySQL должно быть реплицировано или распространено на все затронутые или связанные контейнеры.

Однако, если изменение касается таких параметров, как DB_HOST, DB_NAME, DB_USER и DB_PASSWORD. Их можно передать как ARG (аргумент) и использовать для всех связанных контейнеров. Если вы используете docker-compose.yml file, то изменение происходит в одном файле.

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

обходной путь until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done

@ piotr-s-brainhub Из приведенных выше комментариев упоминается, что наличие открытого порта не означает, что служба готова.

Можем ли мы иметь дополнительное условие готовности, которое может быть вызвано журналами, открытием порта или задержкой по времени? Что-то вроде:

ready_when:
  in_logs: `MySQL init process done`
  ports_open:
  - 3306

Я только что понял, что ожидание готовности контейнеров зависимостей можно легко реализовать с помощью таких инструментов, как ansible. Кто-нибудь использовал такой подход? Можете ли вы легко заменить docker-compose на ansible / chef / puppet? Любой проект на github, демонстрирующий этот подход?

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

В настоящее время я решил это с помощью инструмента, который написал: https://github.com/betalo-sweden/await

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

@djui , что делает await, пока ожидает данный ресурс?

@derekmahar Это опросы. По умолчанию время ожидания составляет 60 секунд. Каждый раз, когда он не видит ресурс, он просто повторяет попытку с интервалом в 1 секунду. В настоящее время он не выполняет обнаружение одновременных ресурсов, поэтому он выполняется последовательно, но этого оказалось достаточно, и его можно исправить.

Я использую его в следующем сценарии:

Я разворачиваю инфраструктуру для создания докеров, а затем запускаю драйвер тестирования интеграции. Служба драйвера запускается только после того, как все компоненты инфраструктуры становятся доступными, используя await; поэтому в конечном итоге await вызывает команду запуска драйвера.

Вот способ сделать это с помощью новой директивы Docker HEALTHCHECK с помощью make:

https://gist.github.com/mixja/1ed1314525ba4a04807303dad229f2e1

[ОБНОВЛЕНИЕ: обновлена ​​суть, если контейнер выходит с кодом ошибки, поскольку Docker 1.12 тупо сообщает статус Healthcheck в остановленном контейнере как «запускается»]

Спасибо @mixja , хорошее решение.

@mixja ,

Для тестирования я использую https://github.com/avast/docker-compose-gradle-plugin, и он также использует проверку работоспособности Docker - больше никаких искусственных пауз, более быстрые сборки.

@korya - Docker compose на самом деле не инструмент оркестровки - это скорее инструмент спецификации и управления средой. Я использую Make, чтобы обеспечить оркестровку процедурного стиля над Docker Compose и Docker (и другими необходимыми инструментами). Комбинация Make, Docker и Docker Compose очень эффективна, и с помощью этих строительных блоков вы можете реализовать множество различных сценариев.

@mixja ну может ты и прав. Но, как многие люди указали в этом потоке, функциональность оркестрации очень необходима в тестовых средах, и когда в вашем наборе инструментов есть docker-compose, очень заманчиво потребовать такую ​​функциональность от docker-compose.

Действительно, согласно документации, «Compose - это инструмент для определения и запуска многоконтейнерных приложений Docker». Хотя в нем не говорится, что compose является инструментом оркестровки, я думаю, что с точки зрения пользователя (например, меня самого) естественно ожидать от «инструмента для определения и запуска многоконтейнерных приложений Docker» поддержки базового управления зависимостями между управляемыми контейнерами. из коробки.

Я не говорю, что инструмент должен это поддерживать. Я говорю только о том, что этого вполне естественно ожидать. В противном случае каждому придется придумывать свои супер-умные способы сделать это. Фактически, мы используем сценарий bash, выполняющий нечто подобное тому, что делает ваш make-файл.

@mixja @korya Я бы хотел улучшить свой инструмент await и хотел бы попросить вас поделиться мнением о том, какие версии Makefile предоставляют вам, что отсутствует / более удобно / позволяет более await .

Кажется, что версия healthcheck + make кажется "глобальным" представлением, ни один контейнер не знает глобального состояния (но make-файл знает), а await - "локальное" представление, каждый включенный контейнер знает (только) что ему нужно знать, аналогично depends_on или links . Кроме того, вы предпочитаете отправлять контейнер с инструментами, необходимыми для проверки работоспособности (что иногда используется по умолчанию, например, mysqlshow ), а в противном случае оставлять Dockerfile нетронутым. Вдобавок вы, кажется, используете docker-compose больше не в основном для композиции, а в основном для гибкой конфигурации (например, docker-compose up -d mysql должно быть эквивалентно docker run -d -e ... -v ... -p ... mysql ).

Привет, @djui - это, вероятно, философская точка зрения, но я думаю, что вся предпосылка HEALTHCHECK продвигает правильное поведение - то есть контейнер может предоставлять средства для определения работоспособности контейнера без каких-либо внешних зависимостей.

Это ни в коем случае не умаляет ценности наличия чего-то внешнего подтверждения подключения, однако я обычно запускаю набор приемочных тестов, чтобы охватить это, поскольку вы хотите проверить подключение и многое другое (например, функциональность приложения). Конечно, обычно вы не можете запустить этот уровень тестирования, пока не будет создана полная среда и объем вашего инструмента await и другие подходы, которые я использовал в прошлом (сценарии Ansible, завернутые в agent container) действительно ориентирован на правильную организацию настройки среды (а не на конечную цель приемочного тестирования) и до сих пор был единственным подходом, доступным в мире Docker.

С Docker 1.12 у нас теперь есть средства для самоанализа среды Docker и возможность использовать хорошо зарекомендовавшие себя конструкции (например, механизмы bash / shell) для «ожидания» определенного состояния, конечно, если наши контейнеры определили свои собственные проверки работоспособности. . Я вижу большую ценность в использовании собственных возможностей платформы и поощрении владельцев контейнеров определять свои собственные проверки работоспособности, а не полагаться на исторический внешний (я начал процесс подачи заявки, это больше не моя проблема) подход, который мы должны были прибегать к.

В качестве родственной аналогии рассмотрим AWS CloudFormation и концепцию автомасштабирования групп и оркестровку последовательных обновлений. Как CloudFormation узнает, что новый экземпляр «здоров» и готов к работе, и что мы можем убить старый и запустить другой новый экземпляр? Пишем ли мы внешнюю проверку работоспособности или полагаемся на сам экземпляр, чтобы сигнализировать о работоспособности? Ответ заключается в последнем, это означает, что владелец экземпляра может установить любые критерии успеха, необходимые для его / ее экземпляра, а затем сигнализировать всеобъемлющей системе оркестровки (например, CloudFormation), что экземпляр «исправен».

Что касается ваших комментариев о Docker Compose - это инструмент, который может обеспечить оба упомянутых вами аспекта. Часть docker-compose.yml - это желаемая спецификация композиционной среды состояния, в то время как различные команды docker-compose предоставляют возможность взаимодействовать со средой различными способами. На данный момент нам нужны внешние инструменты оркестровки, потому что в принципе docker-compose недостаточно хорошо выполняет управление зависимостями между сервисами. Поскольку docker-compose получает такие функции, как встроенная поддержка проверки работоспособности, цель одной команды docker-compose up будет более реалистичной, если мы сможем указать, например, что служба должна быть помечена как работоспособная перед он считается «работающим», что означает, что наши зависимые службы эффективно ждут, пока зависимость не станет работоспособной.

@mixja Спасибо за подробное объяснение. я думаю

Я вижу большую ценность в использовании собственных возможностей платформы

это хорошо / главное. Просто ждите, пока Docker Compose использует встроенные проверки работоспособности либо в зависимости от значения, либо в новом ключе, await. Просто задайтесь вопросом, должен ли / пойдет ли еще на шаг дальше, чем это, и в основном приведет к отключению связанных контейнеров, если, например, установлено --abort-on-container-exit и проверка работоспособности во время выполнения устанавливает метку проверки работоспособности на _unhealthy_.

Возможный временный обходной путь для тех из вас, кто ищет delay функциональность для запуска тестов:

У меня есть два файла docker-compose yml. Один предназначен для тестирования, а другой - для разработки. Разница только в том, что контейнер sut в docker-compose.test.yml . sut container запускает pytest . Моя цель состояла в том, чтобы тест запуска docker-compose и если pytest команда в sut контейнер выходит из строя, не бегите развитие docker-compose . Вот что я придумал:

# launch test docker-compose; note: I'm starting it with -p argument
docker-compose -f docker-compose.test.yml -p ci up --build -d
# simply get ID of sut container
tests_container_id=$(docker-compose -f docker-compose.test.yml -p ci ps -q sut)
# wait for sut container to finish (pytest will return 0 if all tests passed)
docker wait $tests_container_id
# get exit code of sut container
tests_status=$(docker-compose -f docker-compose.test.yml -p ci ps -q sut | xargs docker inspect -f '{{ .State.ExitCode  }}' | grep -v 0 | wc -l | tr -d ' ')
# print logs if tests didn't pass and return exit code
if [ $tests_status = "1" ] ; then
    docker-compose -f docker-compose.test.yml -p ci logs sut
    return 1
else
    return 0
fi

Теперь вы можете использовать приведенный выше код в любой функции по вашему выбору (моя называется test ) и делать что-то вроде этого:

test
test_result=$?
if [[ $test_result -eq 0 ]] ; then
    docker-compose -f docker-compose.yml up --build -d
fi

У меня работает хорошо, но я все еще с нетерпением жду появления docker-compose поддержки такого рода вещей :)

+1

Возможно, то, что считается вне ядра docker-compose, можно будет поддерживать, разрешив плагины? Похоже на запрос №1341, кажется, есть дополнительные функции, которые некоторые сочтут полезными, но не обязательно полностью соответствуют текущему видению. Возможно, поддержка системы плагинов, такой как предложенная # 3905, предоставит способ, позволяющий сосредоточить внимание на основном наборе возможностей, и если это не один из них, то те, кто хочет этого для своего конкретного варианта использования, могут написать плагин для обработки выполнения up иначе?

Было бы неплохо, если бы docker-compose действовал как точка входа для всех проектов, которые у нас есть локально вокруг настройки docker env, вместо того, чтобы добавлять скрипт, сидящий перед всеми, чтобы действовать как точка входа по умолчанию вместо людям, которым нужно не забывать запускать скрипт в нечетных случаях.

Вот способ сделать это с помощью healthcheck и docker-compose 2.1+ :

version: "2.1"
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
    healthcheck:
      test: mysqladmin -uroot -ppassword ping
      interval: 2s
      timeout: 5s
      retries: 30
  web:
    image: nginx:latest # your image
    depends_on:
      db:
        condition: service_healthy

Здесь docker-compose up запустит веб-контейнер только после того, как контейнер db будет признан исправным.

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

Вот способ для PostgreSQL.

Спасибо @Silex 👍

version: '2.1'
services:
  db:
    image: postgres:9.6.1
    healthcheck:
      test: "pg_isready -h localhost -p 5432 -q -U postgres"
      interval: 3s
      timeout: 5s
      retries: 5

@Silex, к сожалению, с версией "3" и этим форматом:

    image: nginx:latest # your image
    depends_on:
      db:
        condition: service_healthy

Я получаю ERROR: The Compose file './docker-compose.yml' is invalid because: depends_on contains an invalid type, it should be an array

2.1 продолжает поддерживать его и не будет устаревать. 3.x в основном предназначен для режима роевых сервисов (нелокальных).

  From: Vlad Filippov <[email protected]>

Кому: docker / compose [email protected]
Копия: mbdas [email protected] ; Упомяните упоминание@noreply.github.com
Отправлено: среда, 8 марта 2017 г., 11:45
Тема: Re: [docker / compose] Есть ли способ отложить запуск контейнера для поддержки зависимых служб с более длительным временем запуска (# 374)

@Silex, к сожалению, с версией "3" и этим форматом: image: nginx: latest # ваше изображение
зависит от:
db:
condition: service_healthy
Я получаю ОШИБКУ: файл Compose './docker-compose.yml' недействителен, потому что: services.auth.depends_on содержит недопустимый тип, это должен быть массив -
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.

2.1 продолжает поддерживать его и не будет устаревать. 3.x в основном предназначен для режима роевых сервисов (нелокальных).

Благодаря!

@vladikoff : больше информации о версии 3 на https://github.com/docker/compose/issues/4305

По сути, он не будет поддерживаться, вам нужно сделать свои контейнеры отказоустойчивыми, а не полагаться на docker-compose.

Я считаю, что теперь это можно закрыть.

К сожалению, в v3 состояние больше не поддерживается . Вот обходной путь, который я нашел:

website:
    depends_on:
      - 'postgres'
    build: .
    ports:
      - '3000'
    volumes:
      - '.:/news_app'
      - 'bundle_data:/bundle'
    entrypoint: ./wait-for-postgres.sh postgres 5432

  postgres:
    image: 'postgres:9.6.2'
    ports:
      - '5432'

wait-for-postgres.sh:

#!/bin/sh

postgres_host=$1
postgres_port=$2
shift 2
cmd="$@"

# wait for the postgres docker to be running
while ! pg_isready -h $postgres_host -p $postgres_port -q -U postgres; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"

# run the command
exec $cmd

Пользовательская точка входа @ slava-nikulin - обычная практика, это почти единственный (собственный докер) способ определения и проверки всех необходимых условий, прежде чем запускать приложение в контейнере.

По правде говоря, было много споров, и я думаю, что поддержка 2.x условной поддержки для встроенной интеграции с проверками работоспособности и заказа запуска была очень необходимой поддержкой. Docker не поддерживает локальный модуль контейнеров изначально, и когда он это сделает, ему снова придется поддерживать что-то подобное, так же, как, например, kubernetes предоставляет семантику.

Docker 3.x - это серия, в которой реализована поддержка роя в compose, и, следовательно, было отказано от множества опций с учетом распределенной природы.

2.x сохраняет исходные особенности компоновки / локальной топологии.

Docker должен выяснить, как объединить эти две версии, потому что принудительное включение swarm в compose за счет сокращения набора функций compose - нежелательное направление.

10 мая 2017 года в 20:15 Слава Никулин [email protected] написал:

К сожалению, в v3 состояние больше не поддерживается. Вот обходной путь, который я нашел:

Веб-сайт:
зависит от:
- 'postgres'
сборка:.
порты:
- «3000»
объемы:
- '.: / news_app'
- 'bundle_data: / bundle'
точка входа: ./wait-for-postgres.sh postgres 5432

postgres:
изображение: ' postgres: 9.6.2 '
порты:
- '5432'
wait-for-postgres.sh:

! / bin / sh

postgres_host = $ 1
postgres_port = 2 доллара США
cmd = "$ @"

подождите, пока запустится докер postgres

в то время как ! pg_isready -h $ postgres_host -p $ postgres_port -q -U postgres; делать

& 2 echo "Postgres недоступен - спит"
спать 1
сделанный

& 2 echo "Postgres работает - выполняет команду"

запустить команду

exec $ cmd
-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.

Я смог сделать что-то подобное
// start.sh

#!/bin/sh
set -eu

docker volume create --name=gql-sync
echo "Building docker containers"
docker-compose build
echo "Running tests inside docker container"
docker-compose up -d pubsub
docker-compose up -d mongo
docker-compose up -d botms
docker-compose up -d events
docker-compose up -d identity
docker-compose up -d importer
docker-compose run status
docker-compose run testing

exit $?

// status.sh

#!/bin/sh

set -eu pipefail

echo "Attempting to connect to bots"
until $(nc -zv botms 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to events"
until $(nc -zv events 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to identity"
until $(nc -zv identity 3000); do
    printf '.'
    sleep 5
done
echo "Attempting to connect to importer"
until $(nc -zv importer 8080); do
    printf '.'
    sleep 5
done
echo "Was able to connect to all"

exit 0

// в моем файле docker compose

  status:
    image: yikaus/alpine-bash
    volumes:
      - "./internals/scripts:/scripts"
    command: "sh /scripts/status.sh"
    depends_on:
      - "mongo"
      - "importer"
      - "events"
      - "identity"
      - "botms"

У меня похожая проблема, но немного другая. Мне нужно дождаться запуска MongoDB и инициализировать набор реплик.
Я делаю всю процедуру в докере. т.е. создание и аутентификация набора реплик. Но у меня есть другой сценарий Python, в котором мне нужно подключиться к первичному узлу набора реплик. Я получаю сообщение об ошибке.

docker-compose.txt
Dockerfile.txt
и в скрипте python я пытаюсь сделать что-то вроде этого
for x in range(1, 4): client = MongoClient(host='node' + str(x), port=27017, username='admin', password='password') if client.is_primary: print('the client.address is: ' + str(client.address)) print(dbName) print(collectionName) break

У меня есть трудности с этим, у кого-нибудь есть идеи?

@patrickml Если я не использую docker compose, как это сделать с помощью Dockerfile?
Мне нужен cqlsh для выполнения моего build_all.cql. Однако cqlsh не готов ... нужно подождать 60 секунд, чтобы быть готовым.

кошка Dockerfile

С store / datastax / dse- сервер: 5.1.8

ПОЛЬЗОВАТЕЛЬ корень

ЗАПУСТИТЬ apt-get update
ЗАПУСТИТЬ apt-get install -y vim

ДОБАВИТЬ db-scripts-2.1.33.2-RFT-01.tar / docker / cms /
КОПИРОВАТЬ entrypoint.sh /entrypoint.sh

РАБОЧИЙ КАТАЛОГ /docker/cms/db-scripts-2.1.33.2/
ЗАПУСТИТЬ cqlsh -f build_all.cql

ПОЛЬЗОВАТЕЛЬ dse

=============

Шаг 8/9: ЗАПУСТИТЬ cqlsh -f build_all.cql
---> Запуск в 08c8a854ebf4
Ошибка подключения: ('Невозможно подключиться ни к одному серверу', {'127.0.0.1': ошибка (111, «Попытка подключиться к [('127.0.0.1', 9042)]. Последняя ошибка: В подключении отказано»)})
Команда '/ bin / sh -c cqlsh -f build_all.cql' вернула ненулевой код: 1

Требуется = var-lib-libvirt.mount var-lib-libvirt-images-ram.mount

Была ли эта страница полезной?
0 / 5 - 0 рейтинги