Это не готовая инструкция, с большим количеством кода, а скорее описание алгоритма и результатов чего мы добились.
Итак, не так давно у нас появился новый клиент. У него было несколько нетипичных для нас требований: использовать для конфигурирования серверов ansible, контент сайта хранится в git, каждый сайт находится на своей виртуальной машине. Все это не сулило ничего хорошего, так как совсем не укладывалось в стандартную схему «Клиент всегда прав!», и мы начали разрабатывать новую схему. Но обо всем по порядку.
Исходные данные: есть клиент, у которого более 30 сайтов которые надо перенести на нашу площадку. Каждый сайт должен располагаться в отдельном контейнере (мы используем OpenVZ контейнеры). Используется только один внешний IP. Для конфигурирования серверов используется ansible. Для каждого сайта есть архив с конфигурационными файлами. Контент сайта находится в git.
И мы начали творить… Что у нас получилось, можно посмотреть под катом. Забегая вперед, скажу, разворот нового сайта сводится к нескольким командам.
У нас есть несколько шаблонов для разворачивания новых контейнеров, в виде архивов. Для начала мы внесли некоторые изменения в эти шаблоны, а точнее добавили пользователя ansilble и ключи. Это позволило сразу после разворота, без дополнительных действий настраивать контейнер с помощью ansible.
В ansible у нас было создано несколько ролей, не буду описывать их все, только про самые интересные:
- create_vm
- content_update
create_vm это роль, которая, собственно, и создает вм и и конфигурирует ее.
Чуть подробнее.
Эта роль применяется к хостовой машине на которой будет установлен контейнер. Сразу оговорюсь, везде активно используются host_vars. У хостовой машине в host_vars, есть только одна переменная vm_number. Эта переменная содержит номер последнего контейнера +1, после выполнения playbook этот номер будет увеличен на 1. Так же в playbook для это роли используются «vars_promt». Это первое, что нам показалось интересным и мало где описанный механизм. vars_promt позволяет интерактивно задавать переменные при выполнении playbook и в дальнейшем к этим переменным можно обращаться в шаблонах, заданиях и тд. Мы вынесли в эти переменные такие уникальные данные для каждого сайта как имя сайта, репозитарий git (где хранится контент сайта) и адрес, где расположены конфигурационные файлы для сайта.
Получилось примерно так:
<spoiler title="new_vm.yml">
- name: Create new vm
hosts: ds
remote_user: ansible
sudo: true
roles:
- new_vm
vars_prompt:
conf_url: "Введите url c архивов конфигов который приложен к заданию"
area_fqdn: "Введите имя сайта"
git_repo: "Введите адрес git репозитария"
</spoiler>
Описание самих тасков приводить не буду, так как получились достаточно длинными. Если кому-то будет интересно можем прислать.
А дальше все очень просто, ansible подключается к хосту, выкачивает архив шаблона, проверяет что вм с таким номером нет и создает вм, задает ей IP и имя, на этом все процедуры на хосте заканчиваются.
Дальше очень полезным оказался модуль ansible local_action, который позволяет выполнять действия на хосте откуда запускается playbook. Asible выкачивает файлы конфигурации для сайта (nginx, apache и т.д.), по ссылке которую мы задаем в интерактивной переменной, создает структуру каталогов в ansible, добавляет новый контейнер к ролям в ansible и раскладывает конфиги. А также создается host_vars для нового контейнера, в которых задается имя сайта и git репозитарий, это пригодится в дальнейшем, это нам потребуется в дальнейшем. На этом создание контейнера закончено.
Как было сказано в начале, есть только один белый ip для всех сайтов. Не проблема, был создан контейнер с проксирующим nginx. Для новых контейнеров надо добавлять правила проксирования. И тут нам на помощь пришли шаблоны и все те же интерактивные переменные. Также локально из шаблона создаётся файл конфигурации прокси для нового контейнера.
Ага, уже неплохо. Запустив playbook у нас создается контейнер со всеми настройками. Но на этом мы не останавливаемся. И добавили еще выгрузку контента из репозитария. За это как раз и отвечает роль content_update.
Вкратце о роли content_update. Ansible делает клон git репозитария и потом с помощью скрипта раскладывает контент сайта в нужные директории с нужными правами. На этом, собственно, подготовка контейнера почти закончена, остается запустить playbook для применения конфигурации для нового контейнера и все, контейнер можно передавать заказчику.
Автор: системный администратор компании Magvai69
Комментарии (20)
foxmuldercp
29.05.2015 21:25Кстати, судя по гитхабу и багтрекеру ансибл-модуля «докер», который бы Вам пригодился, Этот ансибл модуль докера я бы пока в продакшен не выпускал.
а так — я бы на Вашем месте реально подумал про Docker — полноценная виртуалка требует больше внимания на администрирование.kotomyava
30.05.2015 10:54-1Удел докера, это быстрое создание лёгкого окружения разработчика, а отнюдь не контейнерная виртуализация для продакшена.
Хоть и декларируется, что «Docker is an open platform for developers and sysadmins of distributed applications.», сисадминам удобнее использовать полноценные виртуальные машины с большей изоляцией, и полноценной операционкой.
Поддерживать в продакшене докер контейнеры не проще, наоборот — это редкостный геморрой, на самом-то деле. Можно запихать в каждый образ ssh, пакетный менеджер, клиент системы мониторинга и.т.п., но при этом он уже и не будет отличаться от других контейнеров при этом имея проблемы с изоляцией той же. А без этих инструментов для продакшена он просто не годится, т.к. без обновлений, мониторинга и.т.п. вы далеко в продакшене не уплывёте.
Обратите внимание на страничку www.docker.com/resources/usecases — для чего крупные компании используют докер — в основном это " testing and deployment"foxmuldercp
30.05.2015 13:06+3Простите, но Вы кажется не очень понимаете идеологию Docker'а.
Попробую объяснить на примере тот самый Demployment, который вы упомянули в конце комментария, в противоречие своим же словам «продакшене докер контейнеры», Вот, допустим, я пишу свой какойнить бложек на Perl + Mojolicious. у меня туева хуча зависимостей из Cpan, компилирующихся в ~blog/.perl… Чтобы не засырать этими сборками систему, я пишу нечто вроде:
RUN apt-get update && apt-get install -y make gcc postgresql-server-dev-all cpanminus && apt-get clean && apt-get autoremove -y && apt-get autoclean && cpanm -n Mojolicious DBI DBD::Pg Mojolicious::Plugin::Database Mojolicious::Plugin::I18N Date::Parse&& mkdir /opt/panel COPY pmblog /opt/panel/ EXPOSE 8080 VOLUME ["/opt/panel"] ENTRYPOINT ["/usr/local/bin/hypnotoad","-f","/opt/panel/script/pm_blog"]
после чего говорю какому-нить скрипту или mesos'у — эй, чувак, наплоди мне на вон том списке хостов стопицот контейнеров из этого образа.
после чего мне достаточно натравить на этот зоопарк nginx.
какой ssh, какое пакетный менеджер, Вы о чем?
идеология контейнеров как раз в том, что Вы в них не лезете и у Вас повторимость, хоть на CoreOS, хоть на Ubuntu, да хоть на Debian 7, хоть еще гдё.
С учётом того, что логи отправляются на какойнить Sentry для аналитики, живущий в контейненре из рядом лежащего образа.
Ну или про сборку/тесты — можно пойти например путём — собираем образ из нужных нам gcc/cpp/make с apt-get|yum install (нужный_список_библиотек) с точкой входа — скрипт компиляции. Про запуске контейнера делаем mount /src и /out на каталоги хост системы. После окончания работы контейнера получаем в /out собранный софт/библиотеки/пакеты. Ну, или в случае тестов получаем лог passed/failed тестов.kotomyava
30.05.2015 17:44Про deployment опечатка, прошу прощения.Подразумевалось, конечно, development.
«Чтобы не засырать этими сборками систему»
Как раз и нужно без cpan обойтись, поставив нужное пакетным менеджером системы контейнера. Иной способ хорош только при разработке, когда вы не знаете, что вам может понадобиться в итоге, и ставите пачку всего, и продолжаете этот процесс в течении цикла разработки.
«после чего говорю какому-нить скрипту или mesos'у — эй, чувак, наплоди мне на вон том списке хостов стопицот контейнеров из этого образа.»
И что должен сделать админ, при нахождении критической уязвимости в любой софтине/библиотеке вашего образа? Пересобрать его?
Или по вашему цикл разработки вечен, и разработчик будет выкатывать каждый раз новые образы? В большинстве случаев, это и близко не так.
Логи и мониторинг это несколько разные вещи. Или вы считаете, что вообще не важно, что делается в конкретном контейнере?
Искать проблемы потом по логам, возможно, будет проблематично…
«и у Вас повторимость, хоть на CoreOS, хоть на Ubuntu, да хоть на Debian 7»
А так-ли это нужно в реальности — в рамках одного проекта такой зоопарк держать всё равно не будет никто. А если распространять приложение как образ контейнера для внешнего использования, то возникнет масса других проблем, частично описанных выше. Частично с доверием к вашему образу.foxmuldercp
31.05.2015 20:09Админ — в случае уязвимости — да, пересобрать образ.
ssh и rdp — нужны для виртуалок на lxc/openvz/hyper-v. Виртуалок. полных.
А у контейнера другая задача — запускать ОДНО конкретное приложение, висеть на хосте и молотить что надо после аппаратного балансера или nginx'а какого.
Логи и ошибки должны собираться каким-нить Sentry, Elastix'ом и тикетной системой из почты.
Вот у меня на крайнем проекте было полсотни лезвий, apache kafka обрабатывал 5-6 миллионов запросов в секунду от всех.
Скорость добавления записей в логи — сколько-то сотен метров в секунду на все молотилки.
Вы думаете у Вас получится гигабайты логов в сутки, а самое главное — зачем, Если все события должны быть к чему-то привязаны, и могут происходить на разных лезвиях в рамках одной сесии.
Насчет что делается внутри контейнера — нет, не важно. Если там внутри приложение, то оно делает исключительно то, что написали программисты. Или не делает, Но это обычно должно отсекаться разными вариантами тестов.
Насчёт cpan — Ну нет нужных мне модулей в пакетном менеджере репозитория, нету. Не, вру. часть — есть, часть, кхм, устарела. Но часть требует сборки — Вы мне предлагаете сделать еще один образ для сборки cpan модуля в deb, и во втором образе подсовывать его из личного репозитория.
А повторимость нужна не только Вам. Вот у меня был проект из нескольких офисов — в Далласе CoreOS исторически, в Лондоне — debian, в Киеве — centos.kotomyava
01.06.2015 23:43«Админ — в случае уязвимости — да, пересобрать образ.»
Ну вот это первое большое неудобство с точки зрения администрирования.
«ssh и rdp — нужны для виртуалок на lxc/openvz/hyper-v. Виртуалок. полных.»
hyper-v тут лишнее, остальное, это та же контейнерная виртуализация, обычно, действительно, с более полным окружением, но запустить в таком контейнере можно и 1 процесс init, вообще без какого-либо окружения.
rdp обычно излишне, а вот ssh полезен хотя бы для того, чтобы автоматизировать что-либо тем же ansible на уровне контейнера.
«запускать ОДНО конкретное приложение, висеть на хосте и молотить что надо после аппаратного балансера»
Что точно также, но с большей изоляцией, часто, как раз и реализуется на тех же lxc/openvz.
Или не делает, Но это обычно должно отсекаться разными вариантами тестов.
В идеальном мире это так.
Насчёт cpan — Ну нет нужных мне модулей в пакетном менеджере репозитория, нету. Не, вру. часть — есть, часть, кхм, устарела. Но часть требует сборки — Вы мне предлагаете сделать еще один образ для сборки cpan модуля в deb, и во втором образе подсовывать его из личного репозитория.
Ну во-первых, оно где-то наверняка есть и поддерживается уже кем-то, в виде пакета, но если действительно нет, то да, поддерживать собственный репозиторий. Или не гоняться за последними версиями модулей при разработке, что тоже часто разумно, например, с точки зрения стабильности и поддерживаемости, о которой программисты часто забывают.foxmuldercp
02.06.2015 12:29Всё-таки вы неправильно различаете полноценные окружения вроде lxc/openvz и docker.
Идеология докера как раз в том. что в него не вмешиваются. Настроил образ, собрал, наплодил контейнеров и понеслась. всё. точка.
Как раз для того, чтобы я мог написав свой перлобложек просто выложить Dockerfile и любой мог этот докерфайл собрать и получить готовый к работе бложик.
В случае обновлений — просто его пересобрать.Ingtar
02.06.2015 23:00Я честно смотрел на Докер и думал, как его прикрутить себе в проект. Не нашел возможности.
Для общего уровня развития — как происходит выкладка нового кода с контейнерами? Вот есть у меня фронт, за ним 6 апстримов… Что будет в момент перевыкладывания?..foxmuldercp
03.06.2015 00:39Пока билдится новая версия образа бложика старое работает. После успешного билда поднимаю новые контейнеры, прописываю в конфиг нгинкса апстримы, передергиваю нгинкс, тушу старые контейнеры, грохаю старый образ. CI в общем-то.
У меня это все пошло немного дальше, я докер в условиях кластерного шаредхостинга хочу использовать, интересный опыт в процессе ковыряния получаю.
VGusev2007
01.06.2015 09:36Во многом согласен. Для себя выбрал lxc.
foxmuldercp
05.06.2015 18:26Как минимум он, как openvz уже в ядре, и не требует 2.6.32 с тонной патчей.
у меня на одном и том же хосте соседствую как lxc, так и docker для разных целей. за год проблем не было
Ingtar
30.05.2015 01:19Про vars_promt даже не слышал, попробую. Очень интересная возможность
foxmuldercp
30.05.2015 12:35про Jinja2 тоже почитайте… конфиги под ситуацию править
Ingtar
01.06.2015 20:10Я уже давно использую ansible в продакшене, конфиги всякие доводилось мастерить :)
А вот про интерактив с запуском плейбука услышал впервые :)foxmuldercp
01.06.2015 20:40А как Вы себе представляете программирование без переменных?
Ingtar
02.06.2015 22:58Никак не представляю :) В том же var файле для плейбуков этих переменных вагон.
Я отметил тот факт, что о возможности СПРАШИВАТЬ у пользователя переменные в момент выполнения плейбука я не знал. До этого все жестко прописывал в конфиге, ну или через ключ -еfoxmuldercp
03.06.2015 00:41В официальной доке же есть пример для ввода пароля, например. не в -е же его вводить.
grossws
03.06.2015 18:31Есть ещё удобный способ через ansible-vault, но что он, что vars_prompt появились не сразу.
KorP
У вас spoiler не сработал
Сам первое что пробовал — Ansible, вот уже пол года активно пользуюсь и радуюсь. Но тут захотел попробовать Puppet, но что то модель pull мне совершенно не нравится