Обзор новшеств Docker Engine с 1.0 до 1.8. Введение в Docker Compose

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


Эти статьи были написаны по Docker 1.1.2. С тех пор в Docker появилось много полезного, о чем мы расскажем в этой статье. Также мы рассмотрим подробнее Docker Compose, утилиту, позволяющую определять мультиконтейнерное приложение со всеми зависимостями в одном файле и запускать это приложение в одну команду. Примеры будут продемонстрированы на облачном сервере в InfoboxCloud.

Установка Docker и Compose в InfoboxCloud

Мы рекомендуем создать виртуальную машину с CentOS 7 для установки Docker в InfoboxCloud. Использование CoreOS/Fedora Atomic/Ubuntu Snappy в продакшне пока слишком рисковано. Для работы Docker сейчас необходима именно виртуальная машина, поэтому при создании сервера обязательно установите галочку «Разрешить управление ядром ОС».

Как правильно создать сервер в InfoboxCloud для Docker
Если у вас еще нет доступа в InfoboxCloud – закажите его.

Использование облака очень удобно тем, что никакой абонентской платы нет. При регистрации вы единовременно пополняете счет минимум на 500 рублей (по аналогии с покупкой sim–карты у мобильного оператора) и далее можете использовать облако по необходимости. Быстро рассчитать сколько примерно будет стоить для вас облачный сервер в месяц можно тут (указывайте правильно размерности, например 2 гигагерца частоты, а не 2000 гигагерц). Оплата производится на почасовой основе и замораживается на вашем счету. Используя автомасштабирование или изменяя объем доступных ресурсов сервера вручную можно оплачивать только за необходимые ресурсы и дополнительно экономить и иметь возможность получить больше ресурсов, когда это необходимо.

После регистрации вы получите данные для доступа к панели управления на email. Войдите в панель управления по адресу: https://panel.infobox.ru

В разделе «Облачная инфраструктура» вашей подписки нажмите «Новый сервер» (при необходимости подписка меняется в правом верхнем углу в выпадающем меню).


Задайте необходимые параметры сервера. Обязательно выделите серверу 1 публичный IP–адрес и установите галочку «Разрешить управление ядром ОС», как показано на скриншоте ниже.


В списке доступных операционных систем выберите CentOS 7 и завершите создание сервера.


После этого данные для доступа к серверу придут к вам на электронную почту.

После создания сервера с CentOS 7 подключитесь к нему по SSH.

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

Выполните команду для установки Docker и Compose:
bash <(curl -s http://repository.sandbox.infoboxcloud.ru/scripts/docker/centos7/install.sh)

Что делает скрипт
1. Обновляет ОС.
2. Останавливает postfix и запрещает его автозапуск. Postfix занимает 25 порт, но этот порт может понадобиться вашим сервисам в docker.
3. Добавляет официальный репозиторий Docker и устанавливает docker-engine.
5. Добавляет репозиторий EPEL, устанавливает pip, устанавливает Docker Compose с помощью pip.
6. Запускает сервис Docker и добавляет его в автозагрузку.


Обновление Docker и Compose в InfoboxCloud

Для обновления выполните скрипт:
bash <(curl -s http://repository.sandbox.infoboxcloud.ru/scripts/docker/centos7/update.sh)


Новые возможности Docker с версии 1.0

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

1.1
Поддержка .dockerignore
Вы можете добавить файл .dockerignore файл рядом с вашим Dockerfile и докер проигнорирует файлы и директории, указанные в файле при отправке билд-контекста в демон докера.

Контейнер ставится в паузу при коммите
Раньше коммит для запущенных контейнеров не рекомендовался, т.к. его целостность при одновременной работе и коммите могла быть нарушена (например, если велась запись в процессе коммита). Теперь в момент коммита контейнеры ставятся на паузу.

Если вам нужно отключить эту возможность, используйте следующую команду:
docker commit --pause=false <container_id>

Вывод последних строк логов
Теперь вы можете выводить последние строки логов контейнера.
Раньше для просмотра логов использовалась команда, выводящая весь лог:
docker logs <container_id>

Теперь можно вывести например последние 10 строк лога командой:
docker logs --tail 10 <container_id>

Также вы можете следить за тем, что добавляется в лог сейчас без чтения всего лога:
docker logs --tail 0 -f <container_id>

Поддержка tar файла как контекста при сборке докер-контейнера
Теперь вы можете передать архив tar в процесс сборки докера как контекст.
Архив может быть использован для автоматизации сборки шаблонов докера, например:
cat context.tar | docker build -
или
docker run builder_image | docker build -

Возможность примонтировать всю файловую систему хоста в контейнер
Теперь в --volumes можно передать корень файловой системы хоста /.
Например:
docker run -v /:/host ubuntu:ro ls /my_host

Тем не менее запрещено монтировать файловую систему хоста в корень файловой системы контейнера /, можно только в какую-то папку в контейнере.


1.2
Политики рестарта контейнеров
Раньше для каждого контейнера приходилось писать свой скрипт для запуска при загрузке системы. Теперь появилась возможность перезапускать контейнер с помощью Docker–сервиса.

Для команды docker run добавляется флаг --restart со следующими политиками:
  • no – не перезапускать контейнер, если он упал (по-умолчанию).
  • on–failure – перезапускать контейнер если он завершился с ненулевым кодом (т.е. нештатно). Также можно указать опцию количества попыток перезапуска (on-failure:5)
  • always – всегда перезапускать контейнер вне зависимости от кода выхода.
Флаг --restart для докер-демона теперь объявлен устаревшим благодаря новым опциям.
Например, контейнер с Redis будет бесконечно пытаться подняться пока существует:
docker run --restart=always redis

Другой пример: если контейнер не штатно завершился а упал — 5 раз попробует подняться.
docker run --restart=on-failure:5 redis

--cap-add --cap-drop
До версии 1.2 docker мог получить все привилегии или только привилегии из белого списка, запрещая все остальные. Использование флага --privileged давало контейнеру все привилегии вне зависимости от белого списка. Так делать не рекомендуется в продакшне и это реально небезопасно: это словно вы работаете напрямую на хосте.
В версии 1.2 появились два новых флага для использования с docker run: --cap-add и --cap-drop, которые дают вам более точный контроль над тем, что вы разрешаете контейнеру.

Например, для изменения статуса интерфейсов контейнера:
docker run --cap-add=NET_ADMIN ubuntu sh -c "ip link eth0 down"

Для запрещения chown в контейнере:
docker run --cap-drop=CHOWN ...

Для разрешения всего кроме mknod:
docker run --cap-add=ALL --cap–drop=MKNOD ...

--device
Ранее вы могли использовать устройства внутри контейнеров, монтируя их с помощью -v в --privileged контейнере. Теперь можно с docker run использовать флаг --device, который позволит вам использовать устройство без флага --privileged.

Например, использование устройства внутри контейнера:
docker run --device=/dev/snd:/dev/snd ...

Доступные для записи /etc/hosts, /etc/hostname, /etc/resolv.conf
Теперь вы можете редактировать /etc/hosts, /etc/hostname, /etc/resolve.conf в запущенном контейнере. Это полезно, если вам нужно установить bind или другие сервисы, которые могут переписать эти файлы.

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


1.3

Запуск дополнительного процесса через docker exec
Раньше для работы sshd (и не только) в контейнере приходилось запускать процесс sshd с работающим приложением, что создавало дополнительный риск и оверхед. Доступ к контейнеру очень важен для отладки. Поэтому была добавлена новая команда docker exec, которая позволяет пользователю запускать процесс внутри контейнера через docker api и CLI.

Например так выглядит команда, создающая bash–сессию внутри контейнера:
docker exec -it ubuntu_bash bash


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

Улучшения в управлении жизненным циклом контейнера с docker create
Команда docker run image_name создает контейнер и запускает процесс в нем. Многие пользователи просили разделить эти задачи для более точного контроля за жизненным циклом контейнера. Команда docker create делает это возможным.

Например:
docker create -t -i fedora bash
, создает слой контейнера и выводит ID контейнера, но не запускает его.
Для запуска выполните:
docker start -a -i <container_id>

Таким образом команда docker create дает пользователю и/или процессу гибкость в использовании docker start и docker stop команд для управления жизненным циклом.

Опции безопасности --security-opt
С этим релизом был добавлен новый флаг --security-opt, позволяющий пользователям настраивать произвольные метки и профили SELinux и AppArmor.

Например, ниже показана политика, позволяющая процессу контейнера слушать только порты Apache:
docker run --security-opt label:type:svirt_apache -i -t centos bash

Одно из преимуществ этой функции в том, что теперь пользователи могут запускать контейнеры docker в контейнерах docker без использования привилегированного режима на ядрах, поддерживающих SELinux и AppArmor. Не давая контейнеру права --privileged вы существенно снижаете поверхность атаки потенциальных угроз.


1.4
Этот релиз включает в себя существенные улучшения в безопасности.

1.5
Поддержка IPv6
Теперь для каждого контейнера можно выделить ipv6 адрес с новым флагом --ipv6. Внутри контейнера можно резолвить ipv6 адреса.

Контейнеры только для чтения
С помощью флага --read-only можно сделать файловую систему контейнеров доступной только для чтения. Это позволяет ограничить места в контейнере, куда приложения могут записывать файлы. Используя эту функцию вместе с томами вы можете быть уверены, что контейнеры записывают данные только в управляемое вами и известное место.

API для статистики
Появилось API для статистики, предоставляющее данные по CPU, памяти, сетевому IO и дисковому IO контейнера. Таким образом теперь можно мониторить контейнеры.

Возможность указать, какой Dockerfile использовать для сборки
Реализована одна из наиболее запрашиваемых функций — возможность использования docker build не только для файлов по-умолчанию. Используя docker build -f можно указать файл, из которого вы хотите собрать образ. Например, теперь можно использовать отдельные Dockerfile для тестирования и для использования в продакшне.

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


1.6
Теперь набор докер-утилит окончательно сформировался в отдельные Docker Engine, Registry, Compose, Swarm и Machine. О новых утилитах будет рассказано в разделах статьи ниже.

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

Драйверы логгирования
Появилась новая опция --log-driver, включающая в себя три опции:
  • json-file (по-умолчанию)
  • syslog
  • позволяет отправлять логи контейнеров в syslog.
  • none
Также появилось API логгирования, позволяющее подключать сторонние логгеры.

Ассоциативные идентификаторы образов: дайджесты
Когда вы скачиваете, строите или запускаете образы, вы можете указать их в форме namespace/repository:tag или просто repository. Теперь возможно скачивать, строить и запускать контейнеры по новому идентификатору, названному «дайджест» с синтаксисом: namespace/repo@digest. Дайджест — неизменяемая ссылка на контент внутри образа.

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

--cgroup-parent
Контейнеры состоят из комбинации пространств имен (namespaces), возможностей (capabilities) и cgroups. Docker раньше поддерживал произвольные пространства имен и возможности. Теперь добавлена поддержка cgroups с флагом --cgroup-parent. Вы можете передать специфичный cgroup в контейнер. Это позволяет создавать и управлять cgroups в контейнерах. Вы можете определить ресурсы для cgroups и положить контейнеры в общую родительскую группу.

Ulimits
До сих пор контейнеры наследовали настройки ulimit от демона докера. ulimit позволяет ограничить использование процесса. Ограничения могут быть очень высокими для производственных нагрузок, но не идеальными для контейнера. С новой опцией вы можете указывать настройки ulimit для всех контейнеров при настройке докер-демона, например:
docker -d --default-ulimit nproc=1024:2048
Эта команда установит soft limit 1024 и hard limit в 2048 дочерних процессов для всех контейнеров. Можно использовать опцию многократно для разных параметров:
--default-ulimit nproc=1024:2048 --default-ulimit nofile=100:200

Эти настройки можно перегрузить при создании контейнера:
docker run -d -ulimit nproc=2048:4096 httpd

Теперь можно использовать инструкции dockerfile при коммите и импорте
Появилась возможность провести изменения в образе налету без перестройки всего образа. Это стало возможным благодаря функциям commit --change и import --change, позволяющим указать изменения, которые применятся к новому образу. Поддерживаемые инструкции для commit и import, которые можно применить, указаны тут.


1.7
Этот релиз включает переписанные сетевую подсистему и подсистему томов, а так же повышение стабильности и драйвер ZFS.

1.8
Docker Content Trust – возможность проверки опубликованных Docker–образов
До публикации Docker-образа в удаленный репозиторий Docker Engine подписывает образ локально приватным ключем автора. Когда в будущем вы будете загружать образ, он будет проверен публичным ключем автора для того, чтобы удостовериться, что вы запускаете именно образ автора, a не подделку.

Добавление Content Trust не ухудшает удобство использования Docker. Не нужно изучать новых команд, все работает как и раньше, но уже на подписанном контенте. Пока что Content Trust – опциональная возможность. Если ее включить, все операции с удаленными регистрами будут выполняться только с подписанным содержимым.

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


Docker Content Trust состоит из 2х ключей: Offline Key и Tagging Key, которые генерируются когда автор отправляет образ в удаленный репозиторий и сохраняет у клиента. Каждый репозиторий имеет собственный уникальный Tagging Key. Когда пользователь скачивает образ, проверяется соответствие репозитория и Offline Key.
Tagging Key генерируется для каждого нового репозитория автора.
Offline Key самый важный ключ, основа безопасности вашего репозитория. Разные репозитории могут иметь разные Offline Key. Вам нужен только этот ключ для создания новых репозиториев или ротации существующих ключей. Этот ключ хранится офлайн у вас, что позволяет защититься от многих атак.

Когда доверие установлено, Content Trust использует TUF (update framework) для проверки целостности и свежести образа (генерируется Timestamp key и отправляется на удаленный сервер).

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

Поддержка Volume Plugins
С помощью Volume plugins можно к образам подключать сторонние хранилища, например Blockbridge, Ceph, ClusterHQ, EMC и Portworx.

Новые драйверы для логгирования
Ранее в Docker 1.6 появились драйверы логгирования. Теперь добавлена поддержка GELF, Fluentd и ротации логов на диске.

Возможность копирования файлов с docker cp в обе стороны
Раньше docker cp позволял копировать файлы из контейнера на хост, теперь можно копировать файлы и из хоста в контейнер, например:
docker cp foo.txt mycontainer:/foo.txt


Команда daemon вместо -d
Запуск демона теперь производится командой daemon вместо -d

Кастомизируемый формат ps
С помощью docker ps --format можно указать шаблон для вывода списка контейнеров

Настраиваемая директория конфигов клиента
Клиент Docker хранит конфиги в директории ~/.docker. Если нужно запустить несколько клиентов на сервере, используйте флаг --config или переменную окружения DOCKER_CONFIG для указания конфигов клиента.

Официальные deb и rpm репозитории
APT
# add the new gpg key
$ apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

# edit your /etc/apt/sources.list.d/docker.list
$ vim /etc/apt/sources.list.d/docker.list

# remove the contents and replace with the following depending on your os and version:

# Debian Wheezy
deb https://apt.dockerproject.org/repo debian-wheezy main

# Debian Jessie
deb https://apt.dockerproject.org/repo debian-jessie main

# Debian Stretch/Sid
deb https://apt.dockerproject.org/repo debian-stretch main

# Ubuntu Precise
deb https://apt.dockerproject.org/repo ubuntu-precise main

# Ubuntu Trusty
deb https://apt.dockerproject.org/repo ubuntu-trusty main

# Ubuntu Utopic
deb https://apt.dockerproject.org/repo ubuntu-utopic main

# Ubuntu Vivid
deb https://apt.dockerproject.org/repo ubuntu-vivid main

# Ubuntu Wily
deb https://apt.dockerproject.org/repo ubuntu-wily main


Для перехода со старой версии Docker выполните:
apt-get update
 
# remove the old
apt-get purge lxc-docker*
 
# install the new
apt-get install docker-engine


RPM
curl -sSL https://get.docker.com/ | sh

Либо вручную адреса репозиториев:
Нужно заменить yum.dockerproject.org/repo/main/$OS/$OS_VERSION на адрес вашего репозитория и выполнить команду:
cat >/etc/yum.repos.d/docker.repo <<-EOF
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/$OS/$OS_VERSION
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

Затем можно установить Docker:
yum install docker-engine



Docker Compose

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

Использование Compose обычно состоит из трех этапов:
  1. Определение окружений ваших приложений в Dockerfile.
  2. Определение сервисов, которые необходимо поднять для работы приложения в файле docker-compose.yml так, чтобы они могли запуститься вместе в изолированном окружении.
  3. Запуск команды docker-compose up. Docker Compose запустит ваши приложения.

С помощью Compose можно управлять жизненным циклом вашего приложения:
  • Запускать, останавливать и перестраивать сервисы
  • Просматривать статус запущенных сервисов
  • Транслировать вывод логов запущенных сервисов
  • Запускать необходимую команду на сервисе.

docker-compose.yml
Файл docker-compose.yml содержит в себе правила развертывания приложений в docker.
Каждый сервис в docker–compose.yml должен включать как минимум один образ (image) или скрипт для сборки (build). Все остальные параметры опциональны по аналогии с параметрами команды docker run.

Как и в случае с docker run, опции, указанные в Dockerfile (такие как CMD, EXPOSE, VOLUME, ENV) выполняются по-умолчанию, нет необходимости повторять их в docker-compose.yml.

Список доступных параметров docker–compose.yml описан в официальной документации.

Давайте сразу перейдем от теории к практике и напишем docker-compose для apache с PHP и MySQL.

web:
  image: trukhinyuri/apache-php
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./apache/www/:/var/www/
#    - ./apache/conf/sites-enabled/:/etc/apache2/sites-enabled/
  links:
    - db
  restart: always
db:
  image: centurylink/mysql:latest
  volumes:
    - ./mysql/conf/:/etc/mysql/conf.d/
    - ./mysql/data/:/var/lib/mysql/
  environment:
    MYSQL_ROOT_PASSWORD: **********
#    MYSQL_DATABASE: wordpress
  restart: always

Как мы писали docker-compose.xml для развертывания LAMP
  1. В этом файле мы определяем 2 контейнера docker: web и db.
  2. Указываем образы, из которых они строятся или файлы Dockerfile. (Уже готовые образы бы можете найти на hub.docker.com)
  3. Каждому из образов указываем, что они должны всегда рестартовать, что бы не случилось.
  4. Для контейнера db указываем с помощью переменной окружения пароль для доступа к базе данных (переменную окружения мы узнали из документации к образу на Dockerhub).
  5. В каждом из образов мы монтируем папки, где хранятся данные и настройки на хост, чтобы легко бекапировать их и изменять, не трогая приложения в docker.
  6. В образе web мы указываем ссылку на образ db. Таким образом в файл /etc/hosts будет добавлен хост db автоматически и на нем будут доступны все открытые порты базы данных. При обращении к базе данных из веб-приложения можно в качестве MySQL сервера указать хост db и веб-приложение найдет базу данных.
  7. В контейнере web мы пробрасываем наружу порты 80 и 443, чтобы наш сайт был доступен по сети.
В смонтированные папки кладем файлы сайта, конфигурацию apache, базу данных сайта. Если сайт новый — можно раскомментировать переменную окружения с названием базы данных, она будет создана при старте контейнера. Теперь мы получили переносимый сайт, который очень быстро можно развернуть на сервере.

Допустим, мы создали сервер в InfoboxCloud и установили docker и compose с помощью одной команды, указанной в начале статьи. Теперь просто скопируем папку lamp с docker–compose.xml, папками сайта и базы данных и запустим команду
docker-compose up -d

Поднимется стек LAMP и в нем уже будет работать наш сайт. Вот так просто! Хотите переместить сайт на другой сервер или развернуть на десяти серверах? Просто скопируйте папку LAMP на другой сервер и запустите docker–compose снова.




Таким образом, docker и compose позволяют вам упаковывать приложения и целые системы в подготовленные окружения и прописывать конфигурацию их развертывания. При этом развертывание происходит в одну команду и это может сделать даже неподготовленный пользователь. Развертывание даже сложных систем в InfoboxCloud (и вообще облака IaaS) происходит с простотой PaaS, но вы контролируете все аспекты работы инфраструктуры. Именно такой способ развертывания использует OnlyOffice

Если при повторном развертывании с compose вы встретились с ошибкой Duplicate bind mount
В этом случае посмотрите, какие контейнеры созданы. Для этого воспользуйтесь командой:
docker ps -a

Вы увидите контейнер со странным именем кроме описанных в docker-compose.yml контейнеров. В данном случае имя «335698fa2d_lamp_db_1».
Удалите его командой:
docker rm 335698fa2d_lamp_db_1
, где 335698fa2d_lamp_db_1 замените на имя вашего контейнера со странным именем.
После этого compose выполнит переразвертывание успешно.

Заключение

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

Успешного использования Docker в InfoboxCloud!

2 комментария

avatar
Каким образом возможно определить количество ресурсов (например, ОЗУ), которые будут доступны приложению в контейнере?
avatar
Это описано в разделе «Runtime constraints on resources» https://docs.docker.com/reference/run/. Флаг -m или --memory.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.