image

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

Итак, не так давно у нас появился новый клиент. У него было несколько нетипичных для нас требований: использовать для конфигурирования серверов 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)


  1. KorP
    29.05.2015 18:22

    У вас spoiler не сработал
    Сам первое что пробовал — Ansible, вот уже пол года активно пользуюсь и радуюсь. Но тут захотел попробовать Puppet, но что то модель pull мне совершенно не нравится


  1. foxmuldercp
    29.05.2015 21:25

    Кстати, судя по гитхабу и багтрекеру ансибл-модуля «докер», который бы Вам пригодился, Этот ансибл модуль докера я бы пока в продакшен не выпускал.
    а так — я бы на Вашем месте реально подумал про Docker — полноценная виртуалка требует больше внимания на администрирование.


    1. 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"


      1. 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 тестов.


        1. kotomyava
          30.05.2015 17:44

          Про deployment опечатка, прошу прощения.Подразумевалось, конечно, development.

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

          «после чего говорю какому-нить скрипту или mesos'у — эй, чувак, наплоди мне на вон том списке хостов стопицот контейнеров из этого образа.»
          И что должен сделать админ, при нахождении критической уязвимости в любой софтине/библиотеке вашего образа? Пересобрать его?
          Или по вашему цикл разработки вечен, и разработчик будет выкатывать каждый раз новые образы? В большинстве случаев, это и близко не так.

          Логи и мониторинг это несколько разные вещи. Или вы считаете, что вообще не важно, что делается в конкретном контейнере?
          Искать проблемы потом по логам, возможно, будет проблематично…

          «и у Вас повторимость, хоть на CoreOS, хоть на Ubuntu, да хоть на Debian 7»
          А так-ли это нужно в реальности — в рамках одного проекта такой зоопарк держать всё равно не будет никто. А если распространять приложение как образ контейнера для внешнего использования, то возникнет масса других проблем, частично описанных выше. Частично с доверием к вашему образу.


          1. 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.


            1. kotomyava
              01.06.2015 23:43

              «Админ — в случае уязвимости — да, пересобрать образ.»
              Ну вот это первое большое неудобство с точки зрения администрирования.

              «ssh и rdp — нужны для виртуалок на lxc/openvz/hyper-v. Виртуалок. полных.»
              hyper-v тут лишнее, остальное, это та же контейнерная виртуализация, обычно, действительно, с более полным окружением, но запустить в таком контейнере можно и 1 процесс init, вообще без какого-либо окружения.
              rdp обычно излишне, а вот ssh полезен хотя бы для того, чтобы автоматизировать что-либо тем же ansible на уровне контейнера.

              «запускать ОДНО конкретное приложение, висеть на хосте и молотить что надо после аппаратного балансера»
              Что точно также, но с большей изоляцией, часто, как раз и реализуется на тех же lxc/openvz.

              Или не делает, Но это обычно должно отсекаться разными вариантами тестов.
              В идеальном мире это так.

              Насчёт cpan — Ну нет нужных мне модулей в пакетном менеджере репозитория, нету. Не, вру. часть — есть, часть, кхм, устарела. Но часть требует сборки — Вы мне предлагаете сделать еще один образ для сборки cpan модуля в deb, и во втором образе подсовывать его из личного репозитория.
              Ну во-первых, оно где-то наверняка есть и поддерживается уже кем-то, в виде пакета, но если действительно нет, то да, поддерживать собственный репозиторий. Или не гоняться за последними версиями модулей при разработке, что тоже часто разумно, например, с точки зрения стабильности и поддерживаемости, о которой программисты часто забывают.


              1. foxmuldercp
                02.06.2015 12:29

                Всё-таки вы неправильно различаете полноценные окружения вроде lxc/openvz и docker.
                Идеология докера как раз в том. что в него не вмешиваются. Настроил образ, собрал, наплодил контейнеров и понеслась. всё. точка.
                Как раз для того, чтобы я мог написав свой перлобложек просто выложить Dockerfile и любой мог этот докерфайл собрать и получить готовый к работе бложик.
                В случае обновлений — просто его пересобрать.


                1. Ingtar
                  02.06.2015 23:00

                  Я честно смотрел на Докер и думал, как его прикрутить себе в проект. Не нашел возможности.
                  Для общего уровня развития — как происходит выкладка нового кода с контейнерами? Вот есть у меня фронт, за ним 6 апстримов… Что будет в момент перевыкладывания?..


                  1. foxmuldercp
                    03.06.2015 00:39

                    Пока билдится новая версия образа бложика старое работает. После успешного билда поднимаю новые контейнеры, прописываю в конфиг нгинкса апстримы, передергиваю нгинкс, тушу старые контейнеры, грохаю старый образ. CI в общем-то.

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


      1. VGusev2007
        01.06.2015 09:36

        Во многом согласен. Для себя выбрал lxc.


        1. foxmuldercp
          05.06.2015 18:26

          Как минимум он, как openvz уже в ядре, и не требует 2.6.32 с тонной патчей.
          у меня на одном и том же хосте соседствую как lxc, так и docker для разных целей. за год проблем не было


  1. Ingtar
    30.05.2015 01:19

    Про vars_promt даже не слышал, попробую. Очень интересная возможность


    1. foxmuldercp
      30.05.2015 12:35

      про Jinja2 тоже почитайте… конфиги под ситуацию править


      1. Ingtar
        01.06.2015 20:10

        Я уже давно использую ansible в продакшене, конфиги всякие доводилось мастерить :)
        А вот про интерактив с запуском плейбука услышал впервые :)


        1. foxmuldercp
          01.06.2015 20:40

          А как Вы себе представляете программирование без переменных?


          1. Ingtar
            02.06.2015 22:58

            Никак не представляю :) В том же var файле для плейбуков этих переменных вагон.
            Я отметил тот факт, что о возможности СПРАШИВАТЬ у пользователя переменные в момент выполнения плейбука я не знал. До этого все жестко прописывал в конфиге, ну или через ключ -е


            1. foxmuldercp
              03.06.2015 00:41

              В официальной доке же есть пример для ввода пароля, например. не в -е же его вводить.


              1. Ingtar
                03.06.2015 15:00

                «век живи — век учись»


              1. grossws
                03.06.2015 18:31

                Есть ещё удобный способ через ansible-vault, но что он, что vars_prompt появились не сразу.