Контейнер - это самодостаточная среда выполнения, которая использует ядро хост-системы и может работать изолировано от других контейнеров в системе.
Вот такое определение приводится в libcontainer. От него мы и будем отталкиваться.
Одним из главных преимуществ контейнеров является эффективность по ресурсам, так как нам не нужен целый экземпляр ОС для выполнения приложения. Контейнер использует ядро хостовой ОС и память хостовой ОС, а следовательно нет накладных расходов на поддержание дополнительных слоёв и абстракций.
При использовании контейнеров мы можем выполнять только процессы совместимые с ядром, то есть нельзя запустить приложение для Windows напрямую на хосте Linux. И наоборот данное правило тоже работает.
Запуск контейнера
Запустить контейнер можно командой docker container run. На самом деле это команда включает в себя два шага:
docker container create - создаёт контейнер из образа
и
docker container start - выполняет контейнер
Эти команды можно выполнять и по отдельности, применяя к ним те же ключи, что и к run.
Базовая конфигурация
Имя контейнера
По умолчанию контейнер получает имя состоящее из прилагательного и имени какого-нибудь известного человека, но это действие можно легко изменить, с помощью аргумента --name
docker container create --name="test-service" ubuntu:latest sleep 120
В пределах хоста у контейнеров должны быть уникальные имена.
Метки
При создании контейнера ему автоматически передаются все метки от родительского образа, но также можно добавить и свои.
docker container run --rm -d --name test-service -l deployer=Tzintch ubuntu:latest sleep 120
Это даст нам возможность потом при поиске фильтровать метаданные
docker container ls -a -f label=deployer=Tzintch
Выше были использованы несколько аргументов значение которых необходимо пояснить.
rm - даёт команду удалить контейнер после выполнения задачи
d - запускает контейнер фоном
l - вешает лейбл
Также можно использовать аргументы
t - для выделения псевдо-TTY
i - указатель, что сеанс будет интерактивным и мы хотим оставить поток STDIN открытым
Если в образе не определена ENTRYPOINT, то при запуске контейнера нужно указывать команду на исполнение. Если ENTRYPOINT определена, то возможно передать аргументы для команды, которая там записана.
Также есть возможность задать имя хоста внутри контейнера, это делается с помощью аргумента --hostname.
... hostname="test-pc" ...
DNS
По умолчанию контейнер внутри себя делает точную копию файла /etc/resolve.conf с хостовой машины, но и это поведение можно переопределить с помощью аргументов --dns и --dns-search. Если Вы не хотите указывать поисковый домен, то можно просто указать --dns-search=.
MAC-адрес
Мы имеем возможность задать нужный MAC-адрес для нашего контейнера. Делается это с помощью аргумента --mac-address. В основном это никогда не нужно, но может пригодиться, если возникнет необходимость зарезервировать определённые адреса для Docker и избежать конфликтов с другими службами, которые также могут использовать частные диапазоны адресов.
Тома хранилища
Если возникает необходимость сохранять часть настроек контейнера, то можно подключить внешнюю директорию к внутренней директории контейнера, делается это с помощью команды --mount или -v
docker container run --rm -ti --mount type=bind,target=/mnt/session_data,source=/data ubuntu:latest /bin/bash
или
docker container run --rm -ti -v /mnt/session_data:/data ubuntu:latest /bin/bash
По умолчанию директории монтируются в режиме чтения/записи. Если нужно примонтировать только в режиме чтения, то используется дополнение readonly для --mount и :ro для -v
docker container run --rm -ti --mount readonly type=bind,target=/mnt/session_data,source=/data ubuntu:latest /bin/bash
или
docker container run --rm -ti -v /mnt/session_data:/data:ro ubuntu:latest /bin/bash
Если точки монтирования не созданы заранее, то они будут созданы автоматически.
Если на хосте включен SELinux, то могут возникнуть проблемы из-за отсутствия прав доступа, решается это с помощью опции -z
... -v /mnt/session_data:/data:z ...
z в нижнем регистре указывает, что содержимое является общим для нескольких контейнеров.
Z в верхнем регистре указывает, что содержимое доступно только для одного контейнера.
Квоты
Docker может ограничивать контейнеры в ресурсах благодаря использованию cgroups, но эти возможности должны быть включены в ядре. Если cgroups работают, то ограничивать можно ЦП, память и SWAP.
ЦП
Доля процессорного времени
В Docker пул процессорного времени делится на 1024. Если мы хотим отдать контейнеру половину вычислительной мощности, то можно выделить ему 512 долей --cpu-shares=512
Это не значит, что другие ресурсы не смогут выполнять свои действия на данных мощностях, но будет ограничено время их выполнения, в то время как контейнер получит свои стандартные 100 мкс.
Привязка к процессору
Мы можем привязать контейнер к одному или нескольким ядрам ЦП --cpuset-cpus=0
Данный аргумент задаёт начало индекса и берёт первое ядро. Данный вариант можно комбинировать с выделением долей процессорного времени.
Упрощение квот на ресурсы ЦП
В современных версиях Docker выставлять ограничения на использование ЦП стало проще. Используется команда -cpus со значением от 0.01 до количества ядер в системе.
... -cpus=".25"
Команда docker container update позволяет динамически корректировать ограничения ресурсов.
ОЗУ
В отличие от ограничений ЦП, ограничения на ОЗУ действуют жёстко и контейнер не получит больше памяти, чем ему было выделено и если выйдет за лимиты, то начнёт использовать файл подкачки.
Задаются ограничения аргументом --memory
... --memory 512m ...
Данное ограничение выделит контейнеру 512 МБ ОЗУ и столько же файла подкачки. Если же задать дополнительно параметр --memory-swap -1, то размер используемого свопа будет неограничен.
Если контейнер упрётся в ограничения памяти, то к нему может прийти OOM Killer и убить его. Чтобы отключить его для данного контейнера можно использовать аргументы --oom-kill-disable и --oom-score-adj, но лучше этого не делать.
Блочный ввод-вывод
При желании или необходимости можно также ограничить скорости чтения и записи на диск. Механизм будет действовать подобно ограничениям на ЦП.
--device-read-bps - ограничения скорости чтения с устройства (байт в секунду)
--device-read-iops - ограничения скорости чтения с устройства (операций в секунду)
--device-write-bps - ограничения скорости записи на устройство (байт в секунду)
--device-write-iops - ограничения скорости записи на устройство (операций в секунду)
Запуск контейнера
Запустить контейнер можно командой docker container start, но чтобы знать какой запускать нужно для начала узнать или его имя, или хэш, или часть хэша, главное, чтобы эта часть была уникальной, сделать это можно с помощью команды
docker container ls -a
или
docker ps -a
Если контейнеров много, то можно использовать фильтр
docker container ls -a --filter ancestor=redis:2.8
Автоматический перезапуск контейнера
Часто возникает необходимость, что контейнер должен автоматически перезапускаться после завершения работы. Данное поведение управляется с помощью аргумента --restart, которое может принимать четыре значения
no - никогда
always - всегда
on-failure - при сбое (количетсво попыток можно ограничить on-failure:3)
unless-stopped - пока не остановят
Остановка контейнера
Остановить контейнер можно командой docker container stop. Данная команда отправляет контейнеру сигнал SIGTERM контейнер будет выключен. Если же этого не произошло и процесс зависает, то можно использовать аргумент -t.
docker container stop -t 25
В этом случае будет отправлен сигнал SIGTERM и если он не отработает, то через 25 секунд (по умолчанию - 10), то будет отправлен сигнал SIGKILL и завершит процесс принудительно.
После этого его можно опять запустить при необходимости с той же конфигурацией.
Мы можем повторно запускать контейнер без создания новых до тех пор пока не удалим его.
Можно использовать сразу принудительно завершение docker container kill
Приостановка контейнера
Есть возможность приостановить работу контейнера, сохранив за ним выделенные ресурсы и оставить записи в таблице процессов - docker container pause. Это отправит сигнал SIGSTOP и поставит контейнер на паузу. Запустить снова можно с помощью docker container unpause.
Удаление контейнера
Удалить контейнер можно с помощью команды docker container rm, но сделать это можно только после остановки контейнера. Если же останавливать контейнер желания и необходимости нет, то можно сделать удаление с помощью аргумента -f или --force.
Далее можно удалить и образы, если они больше не нужны. Список всех образов выводится командой docker image ls, а потом нужный удаляется с помощью docker image rm.
Образы можно удалять только тогда, когда их не используют контейнеры
Удаление всего, что не используется
Если нужно удалить все контейнеры, образы и сети, которые не связаны ни с чем, то можно применить команду docker system prune.
Если нужно удалить всё, а не только несвязанное, то можно добавить аргумент -a.
Удалить все контейнеры можно командой
docker container rm $(docker container ls -a -q)
Удалить все образы можно командой
docker image rm $(docker image -q)