Содержание статьи
Появившись, Docker практически сразу стал интересен IT-шникам, которые получили в руки удобный инструмент для безопасного и быстрого развертывания приложений. Но, немного поигравшись, понимаешь, что базового набора недостаточно. Большая популярность проекта привела к тому, что он мгновенно оброс сопутствующими субпроектами и хаками, предлагающими улучшения и устранения известных недостатков.
Мониторинг
Запуск ПО в продакшене без мониторинга в чем-то похож на вождение с завязанными глазами: когда-нибудь точно врежешься. Традиционные решения для мониторинга покрывают две проблемы: сбор метрик хоста и мониторинг конкретного приложения. Но контейнеры Docker находятся по положению где-то между ними, это не хост и не приложение, а значит, оба эти способа неэффективны. Кроме того, контейнеры постоянно появляются и исчезают, следить за каждым обычным способом нельзя. То есть без специальных средств не обойтись.
Docker предоставляется со встроенными функциями мониторинга, позволяющими контролировать все важные показатели CPU, Mem, I/O и сеть. Причем предлагает для их считывания аж три способа: при помощи sysfs
(расположены в /sys/fs/cgroup
), команды stat
и API:
$ cat /sys/fs/cgroup/cpuacct/docker/CONTAINER_ID/cpuacct.stat
$ docker stats CONTAINER_ID
Доступ к API также получить очень просто. Достаточно прочитать данные из сокета:
$ echo -e "GET /containers/[CONTAINER_ID]/stats HTTP/1.0\r\n" | nc -U /var/run/docker.sock
Кроме этого, часть stdout/stderr информации Docker выводит в файл журнала. В Ubuntu это /var/lib/docker.log
.
Xakep #205. Взлом Single Sign-On
Штатные инструменты дают общие сведения по нагрузке в конкретный момент времени, но не ведут статистику и не выдают предупреждения, а поэтому не предоставляют возможности полноценно контролировать использование ресурсов и характеристики контейнеров. Наглядностью данные тоже не отличаются. Наличие API позволило сторонним разработчикам создать свои приложения.
Одно из самых популярных, cAdvisor представляет собой специальный демон, который собирает статистику об общем использовании ресурсов, сетевом трафике и установленных пределах и отображает информацию в графическом виде. Новый контейнер автоматически подхватывается cAdvisor, и по нему выводится временной ряд. В отдельной вкладке предоставляются данные по конкретному контейнеру. Поддерживает потоки событий — создание, удаление, аномальные события. По умолчанию данные на графиках в скользящем окне показываются только за одну минуту. Нет возможности посмотреть более долгосрочные тенденции и получить предупреждение о достижении лимита. Хотя, вероятно, для разработки этого вполне и достаточно. Для хранения долгосрочных метрик cAdvisor интегрируется с InfluxDB и планируется с Google BigQuery. Для интеграции с InfluxDB достаточно указать в строке запуска -storage_driver=influxdb
.
cAdvisor реализован и как контейнер Docker, поэтому его получить проще простого (есть возможность запуска вне Docker):
$ docker run --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 --detach=true --name=cadvisor google/cadvisor
Теперь, чтобы подключиться, достаточно набрать http://localhost:8080
. Кроме ограничения в периоде выводимой информации, у cAdvisor есть еще один недостаток — он может контролировать только один хост Docker. Поэтому он не совсем подходит для использования в кластере из нескольких установок Docker.
Axibase Time-Series Database — решение, использующее метрики производительности, снятые cAdvisor (собственной доработанной версии), но умеющее их хранить, анализировать и визуализировать. Один экземпляр ATSD может собрать метрики нескольких хостов Docker и cAdvisor. Статистика отправляется по протоколу TCP, по умолчанию это локальный адрес, но удаленную систему можно указать при запуске с помощью параметров --atsd_storage_url
и --atsd_storage_write_host
. Также ATSD может собирать данные с демонов collectd, tcollector или Nmon, запущенных внутри контейнеров. Это позволит получать и анализировать в последующем еще большую информацию.
Среди open source решений следует вспомнить о системе мониторинга Prometheus, описанной в сентябрьском номере. Она полностью ориентирована на микросервисную архитектуру и поддерживает Docker из коробки.
Если развернута система мониторинга Zabbix, можно использовать специальный модуль, показывающий общую информацию о нагрузке системы и данные об отдельных контейнерах.
Журналы
Без журналов приложений тяжело понять суть возникшей ошибки, появившейся при работе сервиса. В Docker, чтобы получить журнал, требуется решить две проблемы: нужные данные надо собрать и доставить наружу, полученные данные — сохранить.
По умолчанию наружу контейнера доступен вывод STDOUT, а поэтому достаточно в него направить логи приложения и затем просматривать при помощи docker logs -f название_контейнера
. Но в этом случае нужно быть точно уверенным, что в STDOUT попадает все необходимое. О сохранении и анализе в дальнейшем придется позаботиться отдельно. Правда, нужно помнить, что при запуске контейнера с опцией -t STDOUT
будет уходить в открытый псевдоTTY.
Теперь как собрать. Используя параметр --log-driver
в команде запуска контейнера docker run
, можно журнал контейнера направлять в syslog, journald, fluentd, файл JSON и так далее:
$ docker run ubuntu --log-driver=syslog --log-opt syslog-address=udp://192.168.0.1:514 \
--log-opt labels=ubuntu
В репозитории легко найти контейнер, реализующий syslog, поэтому развернуть такую схему достаточно легко. К сообщению можно добавлять метки, чтобы легче было найти нужные данные в общем файле. При этом предусмотрено использование подстановок. Например, тег {{.Name}}
выведет имя контейнера, а {{.ID}}
— его идентификатор.
Другой вариант — смонтировать каталог с журналами, добавив -v /var/log/:/var/log/
, и таким образом получить доступ к ним. Но при большом количестве контейнеров такой вариант не всегда удобен. В ответ на проблемы появились и сторонние разработки, их решающие.
Проект logspout реализует простую функцию — собирает логи со всех запущенных контейнеров (STDOUT, STDERR и пока частично syslog) и отправляет на удаленный хост:
$ docker run –name="logspout" --volume=/var/run/docker.sock:/tmp/docker.sock \
gliderlabs/logspout syslog://example.org:514
Модульная конструкция позволяет расширять возможности. Например, модуль httpstream выводит поток логов в реальном времени. Для тех контейнеров, журналы которых нужно игнорировать при запуске, следует добавлять -e 'LOGSPOUT=ignore'
.
Logjam умеет собирать журналы с локального UDP-сокета или файла и отправлять на удаленный адрес. В качестве агрегатора журналов для Docker часто используют logstash — специальное приложение, умеющее собирать, фильтровать, нормализовать и хранить любые данные в любом формате.
Интерфейс
Управлять большим количеством контейнеров и образов без наглядного интерфейса не очень удобно, особенно если запускать контейнеры должны малоподготовленные пользователи. Официальный проект предоставляет только GUI Docker Kitematic, который доступен для OS X 10.9+ и Windows 7+ 64-bit, позволяющий быстро развернуть, сконфигурировать среду Docker, управлять ею и запускать контейнеры (через VirtualBox). Но в нашем случае он не подходит.
Хотя это не проблема, так как на сегодня доступно уже несколько десятков реализаций сторонних разработчиков. Проекты опираются на Docker Remote API, позволяющий производить все манипуляции, доступные в командной строке. Shipyard, наверное, самый продвинутый и идеальный интерфейс для удобной работы со всеми функциями Docker. С его помощью удобно запускать, перезапускать, уничтожать, создавать, получать подробную информацию о контейнерах (статус, использование, время создания, порты, процессы и прочее), просматривать журналы контейнеров. Также он выводит статистику по использованию CPU, памяти и сети, выводит логи. Реализован просмотр доступных образов и работа с тегами, просмотр узлов и IP. Есть возможность запуска команд при помощи docker exec
. Поддерживается работа в многопользовательской среде, интеграция с OpenLDAP и Active Directory. Пользователям назначаются роли, дающие разные права. Список ролей фиксированный и содержит одиннадцать вариантов, то есть его вполне достаточно для большинства задач.
Для хранения данных используется RethinkDB. Поддерживается кластер Docker Swarm, позволяющий объединить несколько Docker-хостов в один виртуальный. Получить его просто:
$ curl -sSL https://shipyard-project.com/deploy | ACTION=deploy bash -s
Все параметры, которые можно использовать для сборки и сборки в качестве ноды в Swarm, расписаны в документации. По умолчанию используется 8080-й порт, логин/пароль — admin/shipyard
. Остальные параметры (подключение к LDAP, внешней RethinkDB, сертификаты и прочее) можно узнать при помощи команды
$ docker run shipyard/shipyard server -h
Если нужен инструмент попроще, можно порекомендовать Dockerding, позволяющий управлять контейнерами, получать информацию по каждому (ID, образ, команда, статус, сетевые настройки, переменные и так далее), запускать, останавливать, перезапускать и удалять, просматривать журналы работы, создавать новый контейнер, для чего нужно просто заполнить предложенные поля. Все функции доступны в двух пунктах меню, запутаться в которых просто невозможно. По работе с образами пока реализована общая информация и возможность удаления. Простой и понятный инструмент, позволяющий не вспоминать названия команд и контейнеров, а сразу получать все данные:
$ docker pull evolutio/dockerding
$ docker run -d -p 3000:3000 --privileged --name dockerding \
-v /var/run/docker.sock:/var/run/docker.sock evolutio/dockerding
Набираем http://localhost:3000
и можем работать.
Управление собственным репозиторием
Когда собранных образов становится много, следует задуматься о частном репозитории. Для создания собственного репозитория разработчики Docker предлагают Docker Registry, к которому уже сегодня доступен десяток самых разных интерфейсов.
Docker Registry UI — веб-интерфейс для Docker Registry, позволяющий создавать приватный репозиторий, просматривать список образов, производить поиск и удаление образов, просматривать конфигурацию. Поддерживается управление несколькими репозиториями. Конфигурация по умолчанию сохраняется во внутренней базе H2, но можно подключаться и к внешней H2. Запуск прост. Вначале нам понадобится сам Docker Registry:
$ sudo docker run -p 5000:5000 registry
Запускаем, указав URL нужного репозитория (использовать localhost нельзя), хотя при необходимости подключить любое количество можно впоследствии и через веб-интерфейс:
$ sudo docker run -p 8080:8080 -e REG1=http://example.org:5000/v1/ atcol/docker-registry-ui
Теперь смотрим в браузере страницу http://example.org:8080
. Репозиторий должен быть показан во вкладке Registeres, а статус обязательно должен сообщать Ping succeeded. После этого в Images найдем все образы, добавленные в репозиторий. Параметр -e READ_ONLY=true
позволяет запускать контейнер в режиме «только чтение».
Те, кому нужен инструмент с бо́льшими функциями, должны обратить внимание на Portus, предлагающий улучшенные возможности по авторизации пользователей на основе ролей. Организация может иметь команды (teams). Кроме этого, предоставляются наборы пространств имен (namespaces), представляющих собой коллекцию репозиториев. Сами namespaces могут принадлежать конкретной команде, быть глобальными или персональными. Пользователи в namespaces могут иметь один из трех уровней доступа: Viewers (только получение образов), Contributors (плюс публикация образов) и Owners (плюс управление составом команды). Есть функция временного отключения пользователей. Реализован поиск в реестре, аудит (все события регистрируются), рейтинг хранилищ. Поддерживается аутентификация по протоколу LDAP.
Разработка и сборка
Развертывание и тестирование — самая сложная часть проекта. Когда количество сборок начинает превышать определенный предел, задумываешься о некоторой автоматизации и возможности контроля изменений.
Одна из популярных систем контроля версий Git вполне подходит для хранения версий Dockerfile и связанных с проектом файлов. Captain позволяет автоматизировать сборку новых контейнеров при коммите. Контейнеры в зависимости от настроек автоматически получают номер сборки. Предусмотрено тестирование сборки и отправка в репозиторий.
Zodiac — инструмент, использующий Docker Compose, упрощающий развертывание и откат к нужной версии при сборке контейнеров. Работает очень просто. После создания docker-compose.yml
производится сборка проекта zodiac deploy
. Затем после внесения изменений в docker-compose.yml
операция повторяется. Список zodiac list
покажет все сборки. Если после тестирования необходимо откатиться до предыдущей, то просто вводим zodiac rollback номер_сборки
.
Rocker-compose — приложение, идущее на замену официальному Docker Compose, предназначенному для запуска мультиконтейнерных окружений, но обладающее рядом полезных возможностей. Автоматически удаляются контейнеры, которые больше не используются в конфигурации. В случае краха перезапускается только проблемный контейнер, а не все. Поддерживаются настраиваемые имена в названиях контейнеров (Docker Compose не понимает символы подчеркивания). При пересборке проекта сохраняется имя контейнера, это упрощает сопровождение и избавляет от сообщений, что имя занято и старый контейнер нужно удалить. Использование шаблонов в файле манифеста (не только ENV).
Альтернативный образ Baseimage-docker
Образы для Docker распространяются через репозитории, откуда их можно скачать или загрузить. Для Docker официальным является Docker Hub, содержащий огромное количество образов, в том числе и предоставленные сторонними фирмами и разработчиками. Многие образы похожи по принципу, так как созданы из основных, доступных в репозитории, без особой переделки внутри. Но есть интересные проекты. Так, самый популярный образ сторонних разработчиков — Baseimage-docker, доступный как phusion/baseimage. Одна из причин его появления — проблема PID 1, возникшая из-за того, что многие дистрибутивы Linux изначально не рассчитаны на применение в контейнерах. Docker получается не совсем Linux и не использует единый init-процесс для инициализации и остановки всех дочерних процессов контейнера, как это принято в Linux. В случае Docker первым процессом может быть что угодно, даже CMD. В результате это может привести к большому количеству зомби-процессов, так как SIGTERM некорректно отрабатывается при остановке системы и перезапуске сервиса, что приводит еще и к потере данных. В некоторых ситуациях (например, тестирование приложения) это, может, и неважно, но веб-сайт держать в таком контейнере проблематично. Baseimage-docker поставляется с собственной системой инициализации /sbin/my_init
, являющейся родителем для всех процессов в контейнере.
Еще один момент. Docker построен вокруг идеи о том, что в каждом контейнере должен работать только один сервис. Все важные системные службы не запускаются автоматически, об этом необходимо позаботиться самому. При необходимости сервисы связываются. Такой подход дает большую гибкость, так как позволяет с легкостью менять конфигурацию, тестировать обновления и выполнять миграцию отдельных сервисов на другие машины. Поэтому в окружении нет корректного syslog, crond и прочих демонов, требуемых для нормальной работы любой UNIX-системы и приложений, а это вызывает проблемы. В образах нет SSH, а до появления docker exec
в Docker 1.4 дать команду внутри контейнера было непросто. В Baseimage-docker используется runit, позволяющий добавлять дополнительные приложения к образу. Специальный инструмент setuser
позволяет запускать разные демоны от разных учетных записей.
Вывод
Это далеко не полный список дополнительных приложений, расширяющих базовые возможности Docker. Хорошо поискав в интернете, можно найти решения для простого управления сетью, простого деплоя, непрерывной интеграции и доставки, создания и проверки Docker-файлов, менеджеры кластеров и многое другое.