Как мне отправить сигнал ОТ контейнера НА хост на какое-то событие? - PullRequest
1 голос
/ 30 октября 2019

У меня в контейнере работает mariadb. При «запуске докера» сценарий импорта (из дампа базы данных) запускается программой mariadb, которая создает пользователей, создает схему и т. Д.

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

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

В идеале я бы хотел сделать что-то вроде этого:

client = docker.from_env()
db_c = client.containers.run('my_db_image', ....)

# check for signal from db_c container
# do other things

Спасибо!

Ответы [ 2 ]

1 голос
/ 30 октября 2019

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

import os
import docker

client = docker.from_env()

container = client.containers.run('ubuntu:latest', 'bash -c "for i in {1..10}; do sleep 1; echo working; done; echo done"', detach=True)
print('container started')

for line in container.logs(stream=True):
    print line.strip()
    if line.strip() == 'done':
        break

print('continue....')

Если вывод скрипта импорта переходит к stdout, он может содержать простую печать в конце:

select 'The import has finished' AS '';

Дождитесь этой строки в скрипте Python.

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

import os
import docker
import errno

client = docker.from_env()

FIFO = '/tmp/apipe'

# create the pipe
try:
    os.mkfifo(FIFO)
except OSError as oe: 
    if oe.errno != errno.EEXIST:
        raise
# start the container sharing the pipe
container = client.containers.run('ubuntu:latest', 'bash -c "sleep 5; echo done > /tmp/apipe"', volumes={FIFO: {'bind': FIFO, 'mode': 'rw'}}, detach=True)
print("container started")

with open(FIFO) as fifo:
    print("FIFO opened")
    while True:
        data = fifo.read()
        if len(data) == 0:
            print("Writer closed")
            break
        print('Read: "{0}"'.format(data))

print("continue...")

Хост совместно использует именованный канал с контейнером. В скрипте python вызов read для FIFO блокируется до тех пор, пока некоторые данные не будут доступны в конвейере. В контейнере скрипт импорта пишет в канал, уведомляя программу о загрузке данных. Системная команда mysql , \! команда для выполнения внешней команды может пригодиться в этой ситуации. Вы можете просто добавить в конец сценария:

\! echo done > /tmp/apipe

Аналогичным образом вы можете использовать сокеты IPC (так называемые сокеты Unix) или разделяемую память, но все становится немного сложнее.

Еще одно решение - добавить проверку здоровья в контейнер. Состояние работоспособности может быть опрошено на хосте путем проверки контейнера. См. Как дождаться окончания docker start?

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

1 голос
/ 30 октября 2019

Вы можете добавить этот код, чтобы проверить, готова ли БД принять соединения:

import MySQLdb
import time


db = MySQLdb.connect(host='MYHost', user='MYNAME', passwd='PASS', db='MYDB')

if not db:
    while True:
        db = MySQLdb.connect(host='MYHost', user='MYNAME', passwd='PASS', db='MYDB')
        if db:
            break
        print("Still waiting for the DB")
        time.sleep(10)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...