How to deploy Docker containers with Fabricio.
Fabricio supports image building, container creation and update, applying migrations, rollback, backup and restore.
Link to the project: https://github.com/renskiy/fabricio
9. 10
DEPLOY TOOL REQUIREMENTS
Arbitrary environment support
Easy adaptation (copy/paste)
Easy customization
No special education or experience requirements
Docker support
DB migrations apply and rollback
Support of private registry and complex networks
11. 12
FABRICIO DEPLOY CONFIG EXAMPLE
# fabfile.py
from fabricio import docker, tasks
class NginxContainer(docker.Container):
image = docker.Image('nginx:1.9')
ports = '80:80'
nginx = tasks.DockerTasks(
container=NginxContainer(name='web'),
hosts=['user@example.com'],
)
12. 13
FABRICIO DEPLOY PROCESS
$ fab --list
Available commands:
nginx backup -> pull -> migrate -> update
nginx.deploy backup -> pull -> migrate -> update
nginx.pull pull Docker image from registry
nginx.rollback rollback Docker container to previous version
nginx.update start new Docker container if necessary
$ fab nginx
[user@example.com] Executing task ‘pull’
[user@example.com] run: docker pull nginx:stable
[user@example.com] out: 1.9: Pulling from library/nginx
...
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec44b023adf0 nginx:1.9 "nginx -g" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp web
13. 14
FABRICIO FEATURES
Build Docker images
Create containers from images with provided tags
Unlimited infrastructures
Parallel execution (Fabric feature)
Rollback containers to previous version
Work with public and private Docker registries
DB migrations and rollback, backup and restore
14. 15
FABRICIO COMMAND PARAMS
# show detailed information about command
$ fab --display nginx
Displaying detailed information for task 'nginx':
backup -> pull -> migrate -> update
Arguments: self, tag=None, force=False, migrate=True, backup=False
# deploy container using image with provided tag
$ fab nginx:1.10
# force new container
$ fab nginx:force=yes
# combo!
$ fab nginx:1.10,force=yes
# rollback container to previous version
$ fab nginx.rollback
16. 18
FABRICIO AND PRIVATE DOCKER REGISTRY
# start local Docker registry
$ docker run -d -p 5000:5000 --name registry -v /data/registry:/var/lib/registry registry:2
nginx = tasks.PullDockerTasks(
container=NginxContainer('web'),
hosts=['user@example.com'],
)
$ fab --list
Available commands:
nginx prepare -> push -> backup -> pull -> migrate -> update
nginx.deploy prepare -> push -> backup -> pull -> migrate -> update
nginx.prepare prepare Docker image
nginx.pull pull Docker image from registry
nginx.push push Docker image to registry
nginx.rollback rollback Docker container to previous version
nginx.update start new Docker container if necessary
17. 19
BUILD DOCKER IMAGES WITH FABRICIO
class MyContainer(docker.Container):
image = docker.Image('my_image')
app = tasks.BuildDockerTasks(
container=MyContainer('my_service'),
hosts=['user@example.com'],
build_path='.',
)
$ fab --list
Available commands:
app prepare -> push -> backup -> pull -> migrate -> update
app.deploy prepare -> push -> backup -> pull -> migrate -> update
app.prepare prepare Docker image
app.pull pull Docker image from registry
app.push push Docker image to registry
app.rollback rollback Docker container to previous version
app.update start new Docker container if necessary
18. 20
FABRICIO ROLES AND INFRASTRUCTURES
from fabric import api as fab
@tasks.infrastructure
def production():
fab.env.update(roledefs={'front': ['user@example.com']})
nginx = tasks.DockerTasks(
container=NginxContainer(name='web'),
roles=['front'],
)
$ fab --list
Available commands:
production select production infrastructure to run task(s) on
production.confirm automatically confirm production infrastructure selection
...
$ fab production nginx
Are you sure you want to select production infrastructure to run task(s) on? [y/N]
19. 21
FABRICIO: DEPLOYING DJANGO PROJECTS
from fabric import api as fab
from fabricio import docker, tasks
from fabricio.apps.python.django import DjangoContainer
class BaseDjangoContainer(DjangoContainer):
image = docker.Image('my_django')
@property
def env(self):
return 'DJANGO_SETTINGS_MODULE=settings.{}'.format(
fab.env.infrastructure,
)
django = tasks.BuildDockerTasks(
container=BaseDjangoContainer('api'),
hosts=['user@example.com'],
migrate_commands=True,
)
20. 22
FABRICIO: DEPLOYING DJANGO PROJECTS
$ fab --list
Available commands:
django prepare -> push -> backup -> pull -> migrate -> update
django.deploy prepare -> push -> backup -> pull -> migrate -> update
django.migrate apply migrations
django.migrate_back remove previously applied migrations if any
django.prepare prepare Docker image
django.pull pull Docker image from registry
django.push push Docker image to registry
django.rollback rollback Docker container to previous version
django.update start new Docker container if necessary
21. 23
FABRICIO: DATA BACKUP AND RESTORE
from fabricio.apps.db.postgres import PostgresqlBackupMixin
class BackupDjangoContainer(BaseDjangoContainer,
PostgresqlBackupMixin):
volumes = '/data/backup/postgres:/backup'
db_backup_dir = '/backup'
django = tasks.BuildDockerTasks(
container=BackupDjangoContainer('api'),
hosts=['user@example.com'],
backup_commands=True,
)
$ fab --list
Available commands:
django.backup backup data
django.restore restore data
...
25. 27
USEFUL LINKS & QUESTIONS
Fabricio: https://github.com/renskiy/fabricio
Author of Fabricio: https://www.facebook.com/rinat.khabibiev
Хабра-блог Redmadrobot: https://habrahabr.ru/company/redmadrobot
Redmadrobot on Facebook: https://www.facebook.com/redmadrobot
The 12-factor App (SaaS dev patterns): https://12factor.net
Docker image with cron: https://hub.docker.com/r/renskiy/cron
Questions
Editor's Notes
Всем привет, спасибо что пришли на мой доклад. Сегодня мы погорим об автоматическом деплое Docker контейнеров.
Итак, меня зовут Ринат Хабибиев. Я являюсь руководителем отдела веб-разработки в компании Remadrobot.
Мы разрабатываем комплексные решения для российских и зарубежных заказчиков. Такие решения состоят из мобильного и веб приложений, а также бэкенда.
Начнем с небольшой статистики.
Обратим внимание на количество звед github, и этого всего за 3 года - по моему впечатляющее достижение!
Немного о грустном.
Многие наши заказчики недоверчиво относятся к Docker, не только потому что это технология молодая, но также Open Source.
Еще одна досада - это слегка увеличенные сетевые задержки.
И все же преимуществ больше. Среди них:
Упрощенные требования к инфраструктуре (нужен только Docker).
Более логичная система интеграции с CI/CD (образ работает одинаково на всех хостах, где установлен Docker).
Не нужен доступ в интернет, чтобы обновить зависимости.
Еще 12 факторов, перечисленных на 12factor.net.
1.5 года назад мы решили полностью перейти на Docker.
Но такой переход был сопряжен с рядом трудностей. Например, не все образы сразу можно найти на Docker Hub.
А если бы переход был неполный, то это не только не упростило бы нам работу, но добавило бы дополнительную по поддержке зоопарка технологий.
Однако, мы удачно справились со всеми трудностями, и на текущий момент три проекта нашей разработки работают в Docker контейнерах.
До перехода на Docker использовали Vagrant для запуска сервисов и разворачивания тестового сервера.
Потом приспособили Fabric. Fabric занимает один модуль.
После того, как появилась время заняться оптимизацией:
Ansible - YAML, требует специально обучения.
Capistrano - нет преимуществ над Fabric.
Docker Compose и Kubernetes - также YAML, плюс делают упор на оркестрации.
Остальное (Chef, Puppet, Salt и пр.) не стали рассматривать из-за чрезмерной сложности.
Мы так и не смогли подобрать удобного для себя инструмента.
Зато поиск решения привел к созданию списка требований и пожеланий к такой системе.
поддержка любых типов инфраструктуры: от dev и test до production
адаптация конфигов под новый проект (копи-паст рулит)
кастомизация под нужды проекта должна быть фичей, а не костылем
отсутствие необходимости переучиваться
поддержка Docker
миграция и их откат
работа с Docker Hub и приватными Registry для защищенных сетей
Правильно сформулированные требования - это половина успешного продукта.
А потому я принял решение о разработке совершенного нового инструмента для деплоя, непохожего на все то, что мы рассматривали.
Знакомтесь, Fabricio - средство для автоматизации деплоя на базе Fabric.
Большое внимание при его разработке уделяется стабильности и отсутствию ошибок, что достигается за счет высокого покрытия автоматическими тестами.
Как это принято при знакомстве с новым инструментом, сразу простой пример - разворачивание контейнера с Nginx на 80-м порту.
Свойства контейнера задаются при помощи специального класса, который описывает контейнер.
Внизу на уровне модуля создается сущность с описанием доступных команд Fabric.
Интеграция с Fabric означает работу всех его возможностей.
Например, для вывода списка доступных задач набираем fab -l.
Выполнить команду просто - достаточно указать ее название.
Внизу результат выполнения команды «fab nginx».
Кратко перечислю основные возможности Fabricio
сборка образов Docker из исходников
поддержка тегов
поддержка произвольного количества и типа инфраструктур
параллельная выкладка контейнера на несколько хостов
откат контейнера к предыдущей версии
работа с публичными и приватными репозиториями образов Docker
применение и откат миграций, а также бэкап и восстановление
Актуальный список всегда можно найти на странице проекта в Github
Почти все команды Fabricio содержат опциональные параметры.
Список параметров и значений по-умолчанию смотрим при помощи опции --display.
Можно использовать позиционный способ указания параметра и через keyword - все как в Python.
Перечисление параметров через запятую.
Обращение к нижестоящей по иерархии команде через точку.
Стандартный набор свойств контейнера можно увидеть в описании базового класса.
Большинство свойств можно передать в конструктор при создании экземпляра контейнера, либо переопределить их в потомках.
Когда я говорил о поддержке сложных сетевых конфигураций, я имел в виду тот факт, что целевая инфраструктура может быть настолько сильно защищена от внешнего воздействия, что порой на ней нет даже доступа в Интернет, либо он ограничен буквально несколькими доверенными сайтами, на которых хранятся критически важные обновления системы. А потому закачать, скажем, свежий образ приложения на боевой сервер становится довольно проблематично, не говоря уже о том, что сборка образа на самом сервере в таких условиях вообще невозможна.
В таких случаях нас выручает возможность установить SSH туннель между боевым сервером и компьютером администратора, у которого как правило нет ограничений на выход в Интернет. Нам повезло, что Fabric из коробки умеет устанавливать такой туннель, обеспечивая необходимый доступ к ресурсам с боевой инфраструктуры. Но есть одна проблема: даже при установке SSH туннеля демон Докера не может скачать образ из основного репозитория (hub.docker.com). Это связано с особенностью работы сетевых балансировщиков и маршрутизаторов, которые ожидают, что в заголовке Host клиент укажет доменное имя того хоста, к которому он хочет обратиться. Через туннель этот заголовок выставляется неверно, соответственно, запрос на скачивание образа Docker не доходит до нужного сервера.
Проблему в принципе можно решить переопределяя доменные имена в /etc/hosts, заворачивая их в localhost. Есть даже специальные расширения для Linux, которые позволяют установить, доменные алиасы для отдельного пользователя системы. Но я думаю многие со мной согласятся, что это не очень удобный способ.
Одной из самых интересных возможностей Fabricio является поддержка защищенных сетей (у которых нет прямого доступа к Docker Hub). Она реализована при помощи промежуточного Registry.
По-умолчанию, используется Registry запущенный локально, как в этом примере.
Применяется другой класс задач, который расширяет список двумя дополнительными командами: prepare и push.
prepare готовит образ, то есть скачивать его из основного репозитория, а push скачивает образ в промежуточный, доступ к которому с защищенной инфраструктуры обеспечивается через SSH туннель.
Для сборки образов используется еще один класс задач, в который можно передать путь до папки с Dockerfile.
В остальном отличий от предыдущего кейса нет.
Мощным инструментом Fabricio являются роли и поддержка различных инфраструктур.
И если роли наследуются от Fabric, то поддержка инфраструктур реализуются при помощи декоратора, которым можно обернуть специальную функцию, подготавливающую текущее окружение для работы с соответствующей инфраструктурой.
Применение этого декоратора создает дополнительные команды, предназначенные для выбора инфраструктуры. Для этого, одну из этих команд надо выполнить перед всеми остальными.
Каждый ORM фреймворк имеет свои собственные механизмы применения и отката миграций.
Единственный фреймворк, который пока поддерживается Fabricio - это Django.
Вся логика прозрачно инкапсулирована в специальном типе контейнера и автоматически задействуется при деплое и откате.
Применение и откат миграций осуществляется автоматически, но есть возможность вызвать команды вручную при помощи migrate и migrate_back.
В Fabricio также реализован простейший механизм бэкапа и восстановления для PostgreSQL на основе pg_dump и pg_restore.
Весь функционал реализован в отдельном классе и может быть при необходимости использован как примесь.
Если я смог вас заинтересовать, то вам наверняка будет интересно что требуется для работы Fabricio.
Использование Python 2 здесь обусловлено возможностями самого Fabric, который пока не осуществил переход на 3-ю версию.
Также для работы требуется установленный консольный клиент для Docker.
На хосте должна быть установлена соответствующая версия Docker, от версии зависит работоспособность некоторых опций.
Поддержка деплоя Master-Slave конфигураций PostgreSQL
Поддержка Docker Swarm
Интеграция с docker-py
Возможно MySQL
И другие отличные от Django фреймворки
О стоимости и ограничениях.
Спешу обрадовать, что Fabricio абсолютно бесплатен и не обладает какими-либо ограничениями на использование.
Полезные ссылки
Вопросы?
Одной из самых насущных проблем стала автоматизация деплоя.
Часто этим словом определяют совокупность трех операций: провизионинга, оркестрации и собственно сам деплоя.
Провизионинг - это подготовка сервера к работе (например, установка на нем Docker).
Оркестрация - описание конфигов взаимодействия контейнеров между собой и окружающей инфраструктурой.
А деплой - это процесс запуска нового контейнера из свежего образа.