Связаться по Skype: vkarabedyants
Позвонить Написать
+7 (499) 404-28-83

Блог о системном администрировании серверов и сайтов

Установка, настройка программного обеспечения Linux, Windows операционных систем

Управление контейнерами Docker

Услуги установки настройки и поддержки контейнеров docker, office@system-admins.ru

Контейнеры докер могут находится в нескольких состояниях, перечислим их:

  • Исполняется>(running) >– контейнер работает. В выводе docker ps увидите статус «Up» и время, в течение которого он исполняется.
  • Создан> (created) > – контейнер создан, но в настоящий момент не выполняется. Такое состояние будет у контейнера после команды docker create.
  • Завершил исполнение> (exited) > – контейнер завершил исполнение.

В отличие от bash, команда busybox в образе, из которого запускался контейнер, присутствует. Успешно завершив выполнение команды busybox, контейнер завершил работу. Тот же результат (остановленный контейнер) мы получаем, если для работающего контейнера дадим команду docker stop. Второй способ остановить контейнер – docker kill. По умолчанию эта команда отправляет сигнал SIGKILL, однако при помощи опции -s можно отправить контейнеру и другие стандартные сигналы. Заново запустить остановленный контейнер можно командой docker start. В общем случае остановленный контейнер от созданного отличается тем, что первый уже когда-то запускался и на файловой системе остановленного контейнера могут быть уже произведены какие-то изменения. Файловая же система созданного контейнера аналогична образу, из которого создавался контейнер.

  • Поставлен на паузу> (paused) > – процесс контейнера остановлен, но существует. Поставить контейнер на паузу можно при помощи команды docker pause. При этом Docker использует контрольную группу freezer для того, чтобы «заморозить» процессы в контейнере. Проведем простой эксперимент. Запустим контейнер и убедимся, что он работает:

Контейнер с идентификатором 9b0117ecb82d запущен. Откроем на узле вторую консоль и проверим статус контейнера:

Теперь поставим его на паузу:

Убедимся, что виртуальная файловая система для контроллера freezer смонтирована:

Посмотрим содержимое поддиректории system.slice:

Мы видим виртуальную поддиректорию docker-*, соответствующую контейнеру 9b0117ecb82d для контроллера freezer. Очевидно, другие контейнеры не запущены. Проверим, что в настоящий момент контейнер «разморожен» (THAWED):

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

В выводе команды ps процессы контейнера будут отображаться с состоянием disk sleep:

  • Рестартует (restarting) > – контейнер рестартует. Остановленный контейнер можно рестартовать. Рестарт означает, что контейнер заново запустится с теми же идентификатором и настройками сети, что были до остановки. Однако это будет уже другой процесс с другим PID.
  • «Умер» (dead) > – контейнер перестал функционировать вследствие сбоя.

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

На рис. 1 представлен пример перехода контейнера из состояния в состояние.изменения состояния контейнера

Обратите внимание, что на рисунке показано то, что после рестарта контейнера создается новый процесс. Изначальный процесс контейнера завершил работу после команды docker stop.

Последняя команда на рисунке – docker rm – используется для удаления контейнера. После удаления самого контейнера можно удалить и образ, из которого он был запущен. Запущенные контейнеры удалять нельзя.

Если необходимо произвести действия сразу со всеми контейнерами или образами, необходимо в командах docker images и docker ps добавлять -q. При этом будут выведены только идентификаторы контейнеров или образов:

Далее можно подставить вывод этих команд в команды, манипулирующие соответственно контейнерами и образами. В следующем примере удаляются все контейнеры, а затем все образы на узле при помощи команды rmi:

Обмен данными с контейнером по сети

Мы научились запускать контейнер с демоном, работающим внутри. Но толку от такого контейнера немного. Нужно так- же уметь подключаться к службе по внешней сети. Один из возможных способов – это использование проброса пор- тов из контейнеров на хост. Давайте поэкспериментируем с более наглядным примером – веб-сервером Apache. Стра- ничка официального образа на Docker Hub. Из описания можно узнать, что корневая директория для веб-сервера /usr/local/apache2/htdocs/.

Загрузим образ и запустим с новой для нас опцией -p:

Данная опция позволяет перенаправить TCP-порт 80 контейнера на 8888-й порт хоста. Данное перенаправление будет также отображено в выводе команды docker ps:

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

В нашем примере у контейнера IP-адрес 172.17.0.2. Подробнее об организации сети контейнеров мы поговорим дальше, а сейчас протестируем работоспособность веб-сервера. Обратимся на порт 8888 хоста либо по его IP-адресу (в примере 10.0.2.7), либо на localhost:

Отлично! Контейнер доступен. Попробуем заменить стандартное сообщение своим, изменив index.html:

В качестве альтернативы можно возложить ответственность за выбор порта на сам Docker, отдав команду docker run с ключом -P:

В этом случае узнать порт, который был выделен контейнеру, можно командой docker port:

В данном примере порт 32768 был выбран случайным образом Docker, а порт 80 был определен автором образа. Как это задается, мы изучим, когда будем разбирать описание образов при помощи файла Dockerfile.
Просмотр информации о контейнере Познакомимся с тем, как получить информацию о контейнере. Посмотрим на вывод команды docker inspect. Вывод команды в формате JSON отображен ниже:

  • Опишем ряд полученных параметров:
    >>строка>3> – идентификатор контейнера;
  • >строка>4> – время и дата создания контейнера;
  • >>строки>7-18> – информация о статусе контейнера. Текущий статус running и PID на хосте – 1425;
  • >>строка> 20> – идентификатор образа, из которого запущен контейнер. Обратите внимание, что тут указан полный ID. При выводе команды docker images идентификаторы обрезаются до двенадцати символов. Используйте команду docker images —digests для вывода полного ID;
  • >>строки>21-23> – расположение на файловой системе хоста файлов resolv.conf, hostname и hosts контейнера;
  • >>строки>28-29> – метка SELinux файловой системы и контекст процесса;
  • >>строка>34> – целевая и монтируемая с хоста директории;
  • >>строки>42-49> – описание перенаправления портов;
  • >>строки>124-126> – объявленные доступными снаружи порты. В данном случае только один – http;
  • >>строки>130-138> – переменные окружения;
  • >>строки> 139-141 > – определение запускаемой команды в контейнере;
  • >>строка>170> – IP-адрес контейнера.

Для того чтобы вывести только часть информации, можно воспользоваться шаблоном языка Go при помощи опции -f. Например, для того, чтобы получить IP-адрес контейнера, можно воспользоваться командой:

Подключение к контейнеру постоянного хранилища

Все работает, однако, если удалите контейнер, изменения в index.html будут потеряны. На странице с описанием httpd на Dockrer Hub приведен пример использования контейнера:

Из нового тут опция -v. Эта опция позволяет смонтировать директорию хоста внутри контейнера. Целевая директория в примере /usr/local/apache2/htdocs, а монтируемая – текущая рабочая, путь которой содержится в переменной окружения $PWD. Если в команде опустить целевую директорию, то Docker создаст ее в /var/lib/docker/volumes/.
Используем предложенный синтаксис, создав index.html в специально выделенной директории:

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

Повторяем эксперимент:

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

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

Проиллюстрируем на примере. Создадим контейнер для хранения данных под именем my-data, смонтировав в директорию контейнера /usr/local/apache2/htdocs/ директорию хоста с файлом index.html:

Контейнер my-data остановлен. При помощи опции —volumes-from во время запуска другого контейнера можно смонтировать тома из первого. Проверим это при помощи тестового контейнера test:

Теперь тестовый контейнер нам не нужен. Удалим его и запустим контейнер с веб-сервером, который будет
использовать том с контейнера my-data:

Ну и убедимся при помощи docker inspect, из какого контейнера используются тома:

Если теперь удалить контейнер my-data, используемый контейнером my-httpd3 том c index.html удален не будет. Удалить тома вместе с контейнером можно, используя опцию -v команды docker rm, и только если тома не используются другими контейнерами. При запуске контейнера может быть полезной опция —rm.
Контейнер, запущенный с такой опцией, удаляется сразу после остановки. Покажем на примере контейнера, предназначенного исключительно для архивирования данных. Создадим директорию для резервного хранения данных:

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

Как мы видим, контейнер сделал свое дело.

Оставить комментарий

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.