Глава 11. Предоставление инфраструктуры

Практически всё в центрах обработки данных превращается в программно- определяемое, начиная с сетевых сред, вплоть до инфраструктуры серверов, в которых исполняется наше программное обеспечение. Поставщики Инфраструктуры в качестве службы (IaaS, Infrastructure as a Service) предлагают API для управления программным образом образами, серверами, сетевыми средами и компонентами хранилищ. Эти ресурсы часто рассматриваются как создаваемые по щелчку пальцами для снижения стоимости и увеличения эффективности.

Как результат, с момента выхода последнего издания этой книги были приложены гигантские усилия в отношении обеспечения облачных решений Ansible, причём в официальном выпуске Ansible представлено более 30 поставщиков инфраструктуры. Они варьируются от решений с открытым исходным кодом, таких как OpenStack и oVirt, вплоть до таких проприетарных производителей как VMware и поставщики облачных решений, подобных AWS, GCP и Azure.

Существует намного больше вариантов использования, чем мы могли бы охватить в данной главе, но, тем не менее, мы рассмотрим следующие способы, при помощи которых Ansible взаимодействует с этими различными службами:

  • Управление собственной облачной инфраструктурой

  • Управление инфраструктурой в неком общедоступном облачном решении

  • Взаимодействие с контейнерами Docker

  • Применение контейнеров Ansible

Технические требования

Ознакомьтесь с видеоматериалами Code in Action.

Управление облачной инфраструктурой

Облако является популярным, однако нечётким понятием, применяемым при описании IaaS. Существует множество видов ресурсов, которые могут предоставляться облаком, хотя наиболее часто обсуждаемыми являются вычислительные ресурсы и ресурсы хранения. Ansible способен взаимодействовать с многочисленными поставщиками облачных ресурсов с целью обнаружения, создания или прочего управления ресурсами внутри них. Отметим, что хотя в этой главе мы и сосредоточимся на вычислительных ресурсах и ресурсах хранения, Ansible обладает модулями для взаимодействия с многочисленными дополнительными видами ресурсов, такими как балансировщики нагрузки и даже управления доступом на основе ролей к облаку.

Одним из тех поставщиков, с которым способен взаимодействовать Ansible, является OpenStack (облачная операционная система с открытым исходным кодом), и возможно это именно то решение, которое требуется для функциональности на вашей площадке IaaS. Некий комплект служб предоставляет интерфейсы для управления службами вычислений, хранения и сетевых ресурсов, плюс многие прочие службы сопровождения. Не существует некого единого производителя OpenStack; вместо этого множество общедоступных и частных поставщиков облачных решений собирают при помощи OpenStack свои собственные продукты и тем самым несмотря на то, что сами поставщики могут разниться, они предоставляют одни и те же API и интерфейсы программного обеспечения с тем, чтобы Ansible был способен запросто автоматизировать задачи в этих средах.

Ansible поддерживает службы OpenStack с самого начала своего проекта. Это начальное сопровождение выросло и включает более сорока модулей с поддержкой управления следующим:

  • Вычислениями

  • Вычислениями на голом железе

  • Вычислительными образами

  • Аутентификацией учётных записей

  • Сетевыми ресурсами

  • Хранением объектов

  • Блочным хранением

Помимо этого, для выполнения действий CRUD (create, read, update и delete) во всех предыдущих типах ресурсов, Ansible также содержит собственную возможность применения OpenStack (и прочих облачных ресурсов) в качестве некого источника инвентаризации и мы этого касались ранее в Главе 1, Архитектура системы и проектирование Ansible. Всякое исполнение ansible и ansible-playbook, которое использует облачное решение OpenStack в качестве источника инвентаризации, получает по запросу информацию относительно того какие вычислительные ресурсы присутствуют, а также различные факты относительно таких вычислительных ресурсов. Поскольку сами облачные службы уже отслеживают эти подробности, это может снижать накладные расходы избавляя от отслеживания ресурсов вручную.

Для демонстрации способности Ansible к управлению и взаимодействию с облачными ресурсами, мы пройдём по двум сценариям: ситуации с созданием и последующим взаимодействием с новыми вычислительными ресурсами, а также неким вариантом, который продемонстрирует применение OpenStack в качестве источника описи.

Создание серверов

Вычислительная служба OpenStack предоставляет некий API для создания, чтения, обновления и удаления серверов виртуальных машин. Посредством данного API мы будем иметь возможность создания определённого сервера для своей демонстрации. После выполнения доступа к серверу и его изменению через SSH, мы также применим этот API для удаления своего сервера. Такая возможность самостоятельного обслуживания себя выступает в качестве ключевой особенности облачных вычислений.

Ansible может применяться для управления следующими серверами с применением различных модулей os_server:

  • os_server: Этот модуль применяется для создания и удаления виртуальных серверов.

  • os_server_facts: Данный модуль используется для получения фактов относительно некого сервера.

  • os_server_actions: Применяется для осуществления различных действий с сервером.

  • os_server_group: Этот модуль позволяет создавать т удалять группы серверов.

  • os_server_volume: Данный модуль применяется для подключения и отключения томов блочного хранения к/ от некому серверу.

  • os_server_metadata: Этот модуль применяется для создания, обновления и удаления метаданных виртуальных серверов.

Загрузка виртуальных серверов

Для своей демонстрации мы применим os_server. Нам требуется предоставить подробности аутентификации для своего облака, такие как значение URL аутентификации и наши регистрационные параметры доступа. Помимо этого нам потребуется установить свой хост Ansible со всем верным предварительно требующимся программным обеспечением для функционирования данного модуля. Как мы уже обсуждали ранее в данной книге при решении вопросов динамической инвентаризации, Ansible для своей работы порой требует дополнительного программного обеспечения или библиотек в заданном хосте. На самом деле именно в этом состоит политика разработчиков Ansible и они не снабжают Ansible сам по себе библиотеками облачных решений, поскольку они бы быстро устаревали, а различные операционные системы требовали бы различные версии.

Вы всегда имеете возможность обнаружить программные зависимости в документации Ansible для каждого из модулей, а потому не лишним буде проверить её при использовании на этот раз некого модуля (в особенности модуля некого поставщика облачного решения). Тот хост Ansible, который мы применяем для целей демонстрации на протяжении данной книги, основывается на CentOS 7, а для того чтобы мой модуль os_server заработал, мне придётся вначале запустить такую команду:


sudo pip install openstacksdk decorator==4.0
		

Точное название самого программного обеспечения м его версии могут зависеть от операционной системы вашего хоста и могут измениться в более новых выпусках Ansible. К тому же могут иметься доступными в вашей операционной системе и её собственные пакеты - не будет лишним потратить несколько минут на проверку этого прежде чем начинать.

После размещения по своим местам всех требуемых модулей, мы можем продолжить создание необходимого сервера. Для этого нам потребуется особенности (flavor), образ, сетевая среда и название. Также вам понадобится некий ключ и это требуется задать в GUI (либо в CLI) OpenStack перед началом. Естественно, все эти подробности могут разниться для каждого из облачных решений OpenStack. Для данной демонстрации я применяю обособленную, самодостаточную ВМ на основе devstack и я применяю установки по умолчанию там где это возможно для простоты действий.

Я назову свой плейбук boot-server.yaml. Наше воспроизведение начинается с некого названия и в качестве шаблона хоста применяет localhost. Поскольку мы не полагаемся ни на какие реальные факты, я также отключу сбор фактов:


--- 
- name: boot server 
  hosts: localhost 
  gather_facts: false
 	   

Чтобы создать некий сервер, я воспользуюсь модулем os_server и предоставлю для некого облака OpenCloud, к которому я осуществляю доступ, необходимые существенные подробности auth, помимо особенностей, образа, сетевой среды и названия. Обратите внимание на переменную key_name, которое указывает значение общедоступного ключа SSH из той пары ключей, которую вам пришлось создать для себя в OpenStack прежде чем писать данный плейбук (как это обсуждалось ранее в данной главе). Данный общедоступный ключ SSH интегрирован в наш образ Fedora 29, которым мы пользуемся при первой загрузке в OpenStack с тем чтобы мы могли в дальнейшем получать к нему доступ поверх SSH. Для целей демонстрации в данной главе я также выгрузил некий образ Fedora 29, так как он делает доступными больше манипуляций чем установленный по умолчанию образ Cirros, который входит в состав дистрибутива OpenStack. Данный образ можно бесплатно выгрузить, причём готовым к применению, с https:/​/​alt.​fedoraproject.​org/​cloud/. Наконец, как вы и ожидали, я затеняю свой пароль:


tasks:
    - name: boot the server
      os_server:
        auth:
          auth_url: "http://devstack.example.com/identity/v3"
          username: "admin"
          password: "password"
          project_name: "demo"
          project_domain_name: "default"
          user_domain_name: "default"
        flavor: "ds1G"
        image: "Fedora 29"
        key_name: "mastery-key"
        network: "private"
        name: "mastery1"
 	   
[Замечание]Замечание

Подробности аутентификации могут быть записаны в неком внешнем файле, который будет считываться лежащим в основе кодом. Такой код модуля применяет os-client-config, стандартную библиотеку для управления правами доступа OpenStack. В качестве альтернативы их можно хранить в Ansible Vault, как мы это поясняли в Главе 2, Защита ваших ключей безопасности в Ansible, а затем передавать в данный модуль в виде переменных.

Запуск данного воспроизведения в том виде как оно представлено просто создаст соответствующий сервер и ничего более. Я могу воспользоваться созданным ранее mastery-hosts в качестве источника описи, так как я применяю из него лишь localhost:

 

Рисунок 11.1



Я усёк получаемый вывод, поскольку имеется слишком много данных, возвращаемых этим модулем. Что в особенности важно, мы получаем данные, относящиеся к значению IP адресов своего хоста. Данное конкретное облако применяет плавающие IP для предоставления общедоступного доступа к этому экземпляру сервера, которые можно видеть заданными в значении регистрируемого вывода и затем в отладочном выводе на печать самого значения openstack.accessIPv4:


tasks:
    - name: boot the server
      os_server:
        auth:
          auth_url: "http://devstack.example.com/identity/v3"
          username: "admin"
          password: "password"
          project_name: "demo"
          project_domain_name: "default"
          user_domain_name: "default"
        flavor: "ds1G"
        image: "Fedora 29"
        key_name: "mastery-key"
        network: "private"
        name: "mastery1"
      register: newserver

    - name: show floating ip
      debug:
        var: newserver.openstack.accessIPv4
 	   

На этот раз при исполнении самая первая задача не имеет результатом изменения, поскольку тот сервер, который нам необходим, уже существует:

 

Рисунок 11.2



Наш вывод показывает некий IP адрес 172.24.4.46. Я могу воспользоваться данными сведениями для подключения к своему только что созданному в облаке серверу.

Добавление учёта ресурсов в реальном времени

Сам по себе просмотр какого- то сервера не слишком полезен. Этот сервер существует для его применения и скорее всего потребует некой конфигурации чтобы стать полезным. Хотя и имеется возможность обладать одним плейбуком для создания ресурсов и совершенно иным плейбуком для управления конфигурацией, мы также способны делать всё это в том же самом плейбуке. Ansible предоставляет некую возможность добавления хостов в имеющуюся опись как часть некого воспроизведения, что позволит применять такие хосты в последующих воспроизведениях.

Работая с предыдущим примером мы получили достаточно сведений для добавления своего нового хоста в опись времени исполнения посредством модуля add_host:


- name: add new server
      add_host:
        name: "mastery1"
        ansible_ssh_host: "{{ newserver.openstack.accessIPv4 }}"
        ansible_ssh_user: "fedora"
 	   

Я знаю что этот образ имеет некого пользователя по умолчанию fedora, а потому я устанавливаю соответствующим образом переменную хоста совместно с заданием значения IP адреса в качестве адреса подключения.

[Замечание]Замечание

Данный пример скрывает все требуемые настройки группы безопасности в OpenStack и все принимаемые значения ключа SSH хоста Для управления этими моментами могут быть добавлены дополнительные задачи.

После того как мы добавили в свою опись данный сервер, мы можем предпринять нечто с ним. Давайте представим некую ситуацию, при которой мы желаем применять этот облачный ресурс для преобразования какого- то файла образа при помощи программного обеспечения ImageMagick. Для осуществления этой задачи нам потребуется новое воспроизведение для применения в данном новом хосте. Я знаю, что этот конкретный образ fedora не содержит Python, а потому мне потребуется добавить Python и все связки Python для dnf (чтобы мы могли применять dnf) в качестве своей первой задачи с применением модуля raw:


- name: configure server 
  hosts: mastery1 
  gather_facts: false 
 
  tasks: 
    - name: install python 
      raw: "sudo dnf install -y python python2-dnf"
 	   

Затем нам потребуется само программное обеспечение ImageMagick, которое мы можем установить при помощи полученного модуля dnf:


- name: install imagemagick 
      dnf: 
        name: "ImageMagick" 
      become: "yes"
 	   

Запустив свой плейбук в этот раз, мы покажем изменения задач для своего нового хоста; обратите внимание, что теперь нам требуется снабдить ansible-playbook местоположением своего файла частного ключа из OpenStack с тем, чтобы он мог выполнить аутентификацию нашего образа fedora:

 

Рисунок 11.3



Мы можем видеть в отчёте Ansible два изменения задач в своём хосте mastery1, который мы только что создали в своём первом воспроизведении. Этот хост не существует в нашем файле описи mastery-hosts.

Нам также придётся отключить здесь подробности отчёта, поскольку получаемый вывод в противном случае будет черезчур громоздким для его преодоления; тем не менее, имея в виду, что у нас имеется файл частного ключа для нашего экземпляра OpenStack, мы способны зарегистрироваться вручную и проверить получаемые для своего плейбука результаты:

 

Рисунок 11.4



Здесь мы можем расширить своё второе воспроизведение для выгрузки файла образа источника при помощи

copy, затем выполнить в этом хосте команду при помощи

ImageMagick для преобразования полученного образа. Ещё одна задача может быть добавлена для выборки нашего преобразованного файла обратно с помощью модуля

slurp, либо этот изменённый модуль может быть выгружен в некое хранилище объектов на основе облачного решения. Наконец, можно добавить последнее воспроизведение для удаления самого сервера.

Всё пятно жизнедеятельности нашего сервера, начиная с создания через конфигурацию и применение, и, в конечном счёте, удаление, все они могут управляться внутри единственного плейбука. Этот плейбук может быть сделан динамическим посредством считывания переменных данных времени исполнения для определения того какой файл следует выгрузить/ видоизменить и где его надлежит сохранять, естественно, превращая этот плейбук в повторно применяемую программу. Хотя это и слишком упрощённо, надеюсь, пример даёт вам ясное понимание насколько мощен Ansible при работе с поставщиками инфраструктуры служб.

Использование источников учёта ресурсов OpenStack

Наш предыдущий пример выдумал некий одноразовый сервер облака с кратким временем жизни. А что если мы пожелаем создавать и применять вместо этого облачные серверы с длительным временем жизни? Проходя через задачи их создания и добавления их в некую временную опись всякий раз, когда иы желаем их затронуть выглядит не эффективным. Запись вручную всех подробностей такого сервера в некую статическую опись также выглядит не очень действенным, а к тому же и подверженным ошибкам. К счастью, имеется и лучший способ: использование самого облачного решения в качестве источника динамической описи.

Как мы уже обсуждали в Главе 1, Архитектура системы и проектирование Ansible, Ansible снабжается целым рядом сценариев динамической инвентаризации для поставщиков облачных решений. Здесь мы продолжим свой пример для OpenStack. Кратко повторим, репозиторий источника самого Ansible содержит такие сценарии сотрудничества в contrib/inventory/, а сценарием для OpenStack выступает contrib/inventory/openstack_inventory.py, с неким связанным с ним файлом contrib/inventory/openstack.yml. Для применения этого сценария просто скопируйте этот файл .py в каталог своего плейбука для его применения, либо сделайте путь доступным для всех пользователей/ плейбуков той системы, которая будет выполнять Ansible. Для рассматриваемого примера я скопирую его в каталог своего плейбука.

Его файл настроек требует немного дополнительных соображений. Этот файл содержит подробности аутентификации для того облачного решения OpenStack, к которому мы подключаемся. Это делает данный файл существенным и он должен быть виден лишь тем пользователям, которым необходим доступ к этой информации. Кроме того, сам сценарий описи попытается загружать эти настройки из стандартных путей при помощи os-client-config (https:/​/​docs.​openstack.​org/​developer/​os-​client-​config/), лежащего в основе кода аутентификации. Это означает, что эти настройки для данного источника описи могут обитать в:

  • clouds.yaml в текущем рабочем каталоге при выполнении данного сценария инвентаризации

  • ~/.config/openstack/clouds.yaml

  • /etc/openstack/clouds.yaml

  • /etc/openstack/openstack.yaml

  • /etc/openstack/openstack.yml

Будет применён самый первый обнаруженный файл. Для нашего примера я применяю файл clouds.yaml в самом каталоге плейбука совместно с самим сценарием чтобы обособить эту конфигурацию от всех прочих путей.

Вывод help для данного сценария отображает несколько возможных параметров; однако те, которые будет применять Ansible, это --list и --host:

 

Рисунок 11.5



Самый первый используется для получения некого списка тех серверов, которые видны для применяемой нами учётной записи, а второй применялся бы для получения данных переменной хоста от каждого, за исключением тех, которые этот сценарий описи возвращает все значения переменных хоста в самом вызове --list. Возврат необходимых данных в самом списке хоста выступает в качестве улучшения производительности, как мы уже ранее обсуждали в этой книге, избавляя от необходимости вызова API OpenStack для всех и каждого из возвращаемых хостов.

Вывод с применением --list достаточно длинный; здесь мы приводим лишь первые несколько строк:

 

Рисунок 11.6



Наша настроенная учётная запись видит лишь один сервер, который имеет UID 63338332-de64-4200-bb60-c74a92fcba82, тот экземпляр, который мы загрузили в предыдущем примере. Мы видим, к примеру, этот экземпляр перечисленным в значении групп ds1G и Fedora 29. Самая первая группа служит для всех серверов, запускаемых со свойством ds1G, а вторая предназначена для всех серверов, запускаемых из образа Fedora 29. Такое группирование происходит автоматически внутри самого встраиваемого модуля описи и может отличаться для различных применяемых вами установок OpenStack. Окончательный вывод отобразит все прочие группы, предоставляемые этим встраиваемым модулем:

 

Рисунок 11.7



[Совет]Совет

Обратите внимание на то, что для появления в приведённых выше группированиях, в нашем файле clouds.yml должна быть выполнена установка expand_hostvars: True.

Некими дополнительными группами выступают:

  • devstack: Все серверы, запущенные в нашем экземпляре devstack

  • flavor-ds1G: Все серверы, которые применяют свойство (flavor) ds1G

  • image-Fedora 29: Все серверы, которые пользуются образом Fedora 29

  • instance-63338332-de64-4200-bb60-c74a92fcba82: Некая группа, именованная самим экземпляром

  • nova: Все серверы, запущенные под службой nova

Предоставляется множество групп, причём каждая с потенциально отличающимся слоем своих серверов, обнаруженных в данном сценарии описи. Такие группы упрощают целеопределение только для нужных экземпляров при воспроизведениях. Все хосты определяются значениями UUID своего сервера. Поскольку они уникальны по своей природе и к тому же достаточно длинны, они не имеют широкого применения в качестве задания цели внутри некого воспроизведения. Это делает группы ещё более важными.

Для демонстрации применения этого сценария в качестве источника описи мы повторно создадим свой предыдущий пример, пропуская создание самого сервера и лишь написав своё второе воспроизведение с применением некой подходящей целевой группы. Мы озаглавим этот плей бук как configure-server.yaml:


--- 
- name: configure server 
  hosts: all 
  gather_facts: false 
  remote_user: fedora 
 
  tasks: 
    - name: install python 
      raw: "sudo dnf install -y python python2-dnf" 
 
    - name: install imagemagick 
      dnf: 
        name: "ImageMagick" 
      become: "yes"
 	   

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

В этот раз значением шаблона хостов установлено all, поскольку теперь у нас имеется лишь один хост в нашей демонстрации сервера OpenStack; тем не менее, в реальной жизни маловероятно что вы будете настолько широки в установлении целей для Ansible.

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

 

Рисунок 11.8



Этот вывод отличается от последнего раза когда выполнялся плейбук boot-server.yaml лишь несколькими моментами. Во- первых, наш экземпляр mastery1 не создаётся и не загружается. Мы предполагаем, что те серверы, с которыми мы желаем взаимодействовать, уже были созданы и работают. Во- вторых, вытащили необходимую опись для запуска этого плейбука напрямую из самого своего сервера OpenStack, воспользовавшись динамическим сценарием инвентаризации, вместо того чтобы создавать её в своём плейбуке при помощи add_host. Во всём остальном получаемый вывод тот же самый.

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

Управление общедоступной облачной инфраструктурой

Управление общедоступными облачными инфраструктурами при помощи Ansible не намного сложнее управления им OpenStack, которое мы рассмотрели ранее.В целом, для каждого поддерживаемого Ansible поставщика IaaS имеется некий процесс из трёх этапов для получения её в рабочем состоянии:

  1. Выявление того, какие модули Ansible доступны для поддержки данного поставщика облачного решения.

  2. Установка всех предварительно необходимых программного обеспечения и библиотек на самом хосте Ansible.

  3. Задание необходимого плейбука и его запуск для предоставляемой поставщиком инфраструктуры.

Кроме того, существуют готовыми к применению сценарии динамической инвентаризации, и два из них мы уже демонстрировали в этой книге:

Давайте взглянем на AWS (Amazon Web Services) и в частности на его предложение EC2. Мы можем загрузить некий новый сервер из какого- то образа по своему выбору, применяя тот же самый процесс верхнего уровня, который мы осуществляли ранее для OpenStack. Однако, как я уверен, вы уже предвосхитили на этот раз, нам придётся применять некий модуль Ansible, который предлагает особую поддержку EC2. Давайте поcтроим необходимый плейбук. Прежде всего, наше первоначальное воспроизведение, опять- таки, будет запускаться с нашего локального хоста, так как оно будет запускать вызовы к EC2 для загрузки нашего нового сервера:


---
- name: boot server
  hosts: localhost
  gather_facts: false
 	   

Далее мы применяем вместо модуля os_server модуль ec2 для загрузки того сервера, который мы хотим. Этот код на самом деле всего лишь образец; обычно, как и в случае с нашим примером os_server, вы не будете включать свои секретные ключи в разрабатываемый плейбук, а будете хранить его где- то в vault:


- name: boot the server
      ec2:
        access_key: XXXXXXXXXXXXXXXXX
        secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        keypair: mastery-key
        group: default
        type: t2.medium
        image: "ami-000848c4d7224c557"
        region: eu-west-2
        instance_tags: "{'ansible_group':'mastery_server', 'Name':'mastery1'}"
        exact_count: 1
        count_tag:
          ansible_group: "mastery_server"
        wait: true
        user_data: |
          #!/bin/bash
          sudo dnf install -y python python2-dnf
      register: newserver
 	   
[Совет]Совет

Приводимый модуль ec2 требует установленной в своём хосте Ansible библиотеки boto; методы для этого будут отличаться для операционных систем, однако в нашем демонстрационном хосте CentOS7 она была установлена командой sudo yum install python-boto.

Наш предыдущий код предназначен для выполнения того же самого задания, что и в нашем примере os_server, и хотя он и выглядит похожим на верхнем уровне, имеется множество отличий. Следовательно, при всякой работе с новым модулем существенно прочесть документацию этого модуля чтобы в точности понимать как его использовать. Особый интерес обращайте на следующее:

  • Наш модуль ec2 создаёт некую новую виртуальную машину при каждом своём запуске, пока вы не установите свой параметр exact_count совместно с параметром count_tags (упомянутый в строке instance_tags набор параметров).

  • Значение поля user_data может применяться для отправки сценариев выполнения после создания в свою новую ВМ; это невероятно полезно в случае когда первоначальная конфигурация требуется немедленно, предоставляя себе команды raw. В данном случае мы применяем его для установки предварительных требований Python с целью последующей инсталляции ImageMagick.

Затем мы можем получить свой общедоступный IP адрес для нашего вновь созданного сервера воспользовавшись значением переменной newserver, которую мы зарегистрировали в самой последней задаче. Однако, обратите внимание на совершенно иную структуру переменной по сравнению с тем способом, которым мы получали доступ к этим сведениям когда применяли модуль os_server (и опять же, сверяйтесь с документацией):


- name: show floating ip
      debug:
        var: newserver.tagged_instances[0].public_ip
 	   

Другое ключевое отличие между модулем ec2 и os_server состоит в том, что ec2 не дожидается связи SSH чтобы стать доступным прежде чем завершится; следовательно мы должны определить некую задачу специально для этой цели чтобы обеспечить то, что наш плейбук не завершится отказом позднее из- за отсутствия связи:


- name: Wait for SSH to come up
      wait_for_connection:
        timeout: 320
 	   

После того как данная задача завершена, мы будем знать что наш хост доступен и отвечает по SSH, а потому мы можем продолжить применяя add_host для добавления этого нового хоста в своей описи, а затем установить ImageMagick в точности как мы это делали ранее (применяемый здесь образ является тем же самым образом Fedora 29 на основе облака, который мы применяли в своём примере с OpenStack):


- name: add new server
  add_host:
    name: "mastery1"
    ansible_ssh_host: "{{ newserver.tagged_instances[0].public_ip }}"
    ansible_ssh_user: "fedora"

- name: configure server
  hosts: mastery1
  gather_facts: false

  tasks:
    - name: install imagemagick
      dnf:
        name: "ImageMagick"
      become: "yes"
	  

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

 

Рисунок 11.9



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

Мы можем применить эту методологию к Azure, Google Cloud или любого иного поставщика облачного решения, для которого Ansible оснащён поддержкой. Если вы желаете повторить этот пример в Azure, тогда вам придётся применить модуль azure_rm_virtualmachine. Документация для этого модуля постулирует что вам требуется Python 2.7 или более новая версия (он уже является составной частью нашей демонстрационной машины CentOS 7), а также модуля Python azure с версией 2.0.0 или старше. В CentOS 7 не было RPM для более поздних зависимостей , поэтому они были установлены при помощи таких команд (самая первая устанавливает сам модуль azure Python, а вторая устанавливает поддержку Ansible для Azure):


sudo pip install azure
sudo pip install ansible[azure]
		

Удовлетворив эти предварительные требования, мы можем снова собрать свой плейбук. Обратим внимание что для Azure возможно использование различных методов аутентификации. Для целей краткости я употребляю права доступа Azure Active Directory , которые я создал для этой демонстрации; однако для того чтобы включить их, мне также придётся установить официальную утилиту CLI Azure и зарегистрироваться применив следующее:


az login
		

Это обеспечит ваш хост Ansible доверием со стороны Azure. На практике вы будете устанавливать ведущую службу, которая избавит вас от необходимости этого; однако выполнение этого выходит за рамки данной книги. Чтобы продолжить этот пример, мы установим необходимый заголовок своего плейбука как и ранее:


---
- name: boot server
  hosts: localhost
  gather_facts: false
  vars:
    vm_password: Password123!
 	   

Обращаем ваше внимание на тот факт, что мы будем хранить некий пароль для своей новой ВМ в некой переменной; обычно мы бы сделали это в vault, но оставляем это в качестве упражнения для читателя. Здесь мы применяем модуль azure_rm_virtualmachine для загрузки своей новой ВМ. Чтобы воспользоваться образом Fedora 29 для непрерывности с нашими предыдущими примерами, мне придётся пройти на рынок Azure, что потребует определения неких дополнительных параметров, таких как plan. Чтобы включить применение этого образа в Ansible, мне вначале требуется отыскать его, затем принять авторское соглашение для разрешения его использования применяя утилиту командной строки az со следующими командами:


az vm image list --offer fedora --all --output table
az vm image show --urn tunnelbiz:fedora:fedora29:1.0.0
az vm image accept-terms --urn tunnelbiz:fedora:fedora29:1.0.0
		

Мне также придётся создать некую группу ресурсов и сетевую среду, которыми могла бы воспользоваться моя ВМ; это очень много особенных для Azure шагов, которые выходят за рамки данной книги. Тем не менее, когда всё было создано, я получил возможность написания следующего кода плейбука для загрузки нашего образа Fedora 29 на основе Azure:


tasks:
    - name: boot the server
      azure_rm_virtualmachine:
        ad_user: masteryadmin@example.com
        password: xxxxxxx
        resource_group: mastery
        name: mastery1
        admin_username: fedora
        admin_password: "{{ vm_password }}"
        vm_size: Standard_B1s
        image:
          offer: fedora
          publisher: tunnelbiz
          sku: fedora29
          version: latest
        plan:
          name: fedora29
          product: fedora
          publisher : tunnelbiz
      register: newserver
 	   

Как и ранее, мы получаем значение общедоступного IP адреса своего образа (обращаем ваше внимание, что для доступа к нему требуется составная переменная), обеспечиваем доступ SSH и затем применяем add_host для добавления своей новой ВМ в нашу опись времени исполнения:


- name: show floating ip
      debug:
        var: newserver.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.publicIPAddress.properties.ipAddress

    - name: Wait for SSH to come up
      wait_for_connection:
        delay: 1
        timeout: 320

    - name: add new server
      add_host:
        name: "mastery1"
        ansible_ssh_host: "{{ newserver.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.publicIPAddress.properties.ipAddress }}"
        ansible_ssh_user: "fedora"
        ansible_ssh_pass: "{{ vm_password }}"
        ansible_become_pass: "{{ vm_password }}"
 	   

Azure допускает либо аутентификацию на основе пароля, либо на основе ключа для SSH в ВМ Linux; для упрощения мы воспользуемся здесь применением аутентификации на основе пароля. Кроме того, обратите внимание на вновь применяемую переменную подключения ansible_become_pass, так как применяемый нами образ Fedora 29 выдаст запрос на ввод некого пароли при использовании sudo, что потенциально блокирует выполнение. Наконец, после завершения этой работы мы установим как и ранее ImageMagick:


- name: configure server
  hosts: mastery1
  gather_facts: false

  tasks:
    - name: install python
      raw: "dnf install -y python python2-dnf"
      become: "yes"

    - name: install imagemagick
      dnf:
        name: "ImageMagick"
      become: "yes"
 	   

Взглянем на всё это в действии:

 

Рисунок 11.10



Вывод очень похож на тот, что мы получали ранее, что демонстрирует то, что мы запросто можем выполнять одни и те же действия в различных облачных платформах всего лишь с небольшими усилиями в отношении изучения того как нам заставить работать различные модули. Данный раздел этой главы отнюдь не является полностью завершённым, учитывая то количество платформ, которое поддерживается Ansible, но мы надеемся, что предоставленная здесь информация снабжает неким пониманием самого процесса и необходимых этапов для интеграции Ansible с какой- то новой облачной платформой. Далее мы рассмотрим применение Ansible для взаимодействия с контейнерами Docker.

Взаимодействие с контейнерами Docker

Технологии контейнеров Linux, в особенности Docker, имеют растущую популярность в последние годы, и это продолжается с момента публикации последней редакции данной книги. Контейнеры предоставляют некий быстрый путь изоляции ресурсов, в то же время поддерживая согласованность имеющейся среды времени исполнения. Для своего исполнения они могут быстро и действенно запускаться, поскольку в это вовлечено очень мало накладных расходов. Такие утилиты как Docker предоставляют большое число инструментов для управления контейнерами, например, регистрацию образов для применения в качестве файловой системы, инструментов для построения самих образов, оркестровку построения кластеров и тому подобное. Благодаря простоте применения Docker стал одним из наиболее популярных способов управления контейнерами.

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

Для демонстрации работы с Docker мы изучим несколько вариантов применения. Самый первый вариант состоит в построении некого нового образа для его использования в Docker. Второй вариант применения состоит в запуске некого контейнера из созданного образа и взаимодействия с ним. Последний пример использования состоит в применении встраиваемого модуля инвентаризации для взаимодействия с неким активным контейнером.

[Замечание]Замечание

Создание некой работающей установки Docker выходит за рамки этой книги. Вебсайт Docker предоставляет подробные инструкции установки и применения. {Прим. пер.: обращаем внимание на свой перевод Docker для разработчиков Rails Роба Айзенберга}. Ansible лучше всего работает с Docker на хосте Linux, поэтому в этой книге мы продолжим работу с демонстрационной машиной CentOS 7, которую мы использовали.

Построение образов

Образы Docker, в целом, это файловые системы упакованные совместно с параметрами времени применения. Такая файловая система обычно выступает как небольшая часть пространства пользователя Linux с достаточными для начала желательного процесса файлами. Docker предоставляет инструментарий для построения таких образов, обычно основывающихся на базе очень небольших, предварительно существующих образов. В качестве входных данных эти инструменты основываются на Dockerfile, который представляет собой обычный текстовый файл с директивами. Для такого файла команда docker build осуществляет синтаксический разбор, а мы можем проводить анализ с помощью модуля docker_image. Все прочие примеры будут основываться на виртуальной машине CentOS 7, применяющей Docker версии 1.13.1 с добавленными пакетами cowsay и nginx, тем самым выполнение такого пакета предоставит нам некий веб сервер, который отобразит нечто из cowsay.

Прежде всего нам потребуется Dockerfile. Этот файл должен обитать в том пути, который способен читать Ansible и мы намерены расположит его в том же самом каталоге, где находятся мои плейбуки. Само содержимое Dockerfile будет очень простым. Нам понадобится определить некий базовый модуль, какую- то команду для запуска установки необходимого программного обеспечения, самая минимальная конфигурация программного обеспечения, порт для его выставления и действие по умолчанию для запуска контейнера с этим образом:


FROM docker.io/fedora:29 
 
RUN dnf install -y cowsay nginx 
RUN echo "daemon off;" >> /etc/nginx/nginx.conf 
RUN cowsay boop > /usr/share/nginx/html/index.html 
 
EXPOSE 80 
 
CMD /usr/sbin/nginx
 	   

Наш процесс построения выполнит такие этапы:

  • Мы применяем образ Fedora 29 из репозитория fedora в реестре образов Docker Hub.

  • Для установки cowsay и nginx мы пользуемся dnf.

  • Для непосредственного запуска nginx в самом контейнере нам потребуется off режим daemon в nginx.conf.

  • Для выработки содержимого веб страницы по умолчанию мы применяем cowsay.

  • Затем мы указываем Docker о необходимости expose порта 80, по которому nginx будет ожидать подключения.

  • Наконец, действием по умолчанию для данного контейнера будет запуск nginx.

Сам плейбук для построения необходимого образа будет располагаться в том же самом каталоге. Мы назовём его docker-interact.yaml. Этот плейбук будет действовать в localhost и будет иметь две задачи; одна состоит в построении необходимого образа с помощью docker_image, а вторая будет заключаться в запуске самого контейнера при помощи docker_container:


--- 
- name: build an image 
  hosts: localhost 
  gather_facts: false 
 
  tasks: 
    - name: build that image 
      docker_image: 
        path: . 
        state: present 
        name: fedora-moo 
 
    - name: start the container 
      docker_container: 
        name: playbook-container 
        image: fedora-moo 
        ports: 8080:80 
        state: started
 	   

Теперь, если вы, как это происходит и в моём случае, применяете это в том же самом хосте AWX, вы уже будете иметь несколько запущенных контейнеров Docker. К счастью, ни один из них не основывается на Fedora, а потому мы можем запросто воспользоваться в Docker параметром --filter для исключения всего того, что не содержит слова fedora в самом названии образа, что делает более простой интерпретацию вывода, как это показано на следующем снимке экрана:

 

Рисунок 11.11



Теперь давайте запустим некий плейбук чтобы построить требуемый образ и выполнить некий контейнер при помощи этого образа:

 

Рисунок 11.12



Для экономии пространства экрана была снижена многословность выполнения данного плейбука. Наш вывод просто отображает саму задачу построения необходимого модуля с получением в результате некого изменения, а также выполнения задачи по запуску построенного контейнера. Наши действия должны быть отражены в проверке запуска контейнеров и доступности образов:

 

Рисунок 11.13



При помощи curl для доступа к своему веб серверу мы можем проверить функционирование своего контейнера, который должен отобразить нам корову,произносящую boop:

 

Рисунок 11.14



Тем самым мы показали насколько просто взаимодействовать с Docker при помощи Ansible. Однако этот пример всё ещё базируется на применении естественного Dockerfile, а по мере продвижения по данной главе мы обнаружим более усовершенствованное использование Ansible, которое избавит нас от его использования.

Построение контейнеров без Dockerfile

Dockerfile полезны, однако многие выполняемые внутри Dockerfile действия вместо этого могут быть осуществлены при помощи Ansible. Ansible может применяться для запуска некого контейнера с использованием какого- то базового образа, а после этого взаимодействовать с таким контейнером посредством метода соединения docker для выполнения необходимых настроек. Давайте продемонстрируем это повторив свой предыдущий пример, но без необходимости в Dockerfile. Вместо этого вся работа будет целиком выполняться нашим совершенно новым плейбуком с названием docker-all.yaml. Самая первая часть этого плейбука запускает некий контейнер из предварительно имевшегося образа Fedora 29 из Docker Hub и добавляет получаемые в результате подробности контейнера в имеющуюся в памяти опись Ansible с применением add_host:


---
- name: build an image
  hosts: localhost
  gather_facts: false

  tasks:
    - name: start the container
      docker_container:
        name: playbook-container
        image: docker.io/fedora:29
        ports: 8080:80
        state: started
        command: sleep 500

    - name: make a host
      add_host:
        name: playbook-container
        ansible_connection: docker
        ansible_ssh_user: root
 	   

Далее, применяя этот вновь добавленный в опись хост мы определяем второе воспроизведение, которое запускает задачи Ansible внутри полученного и только что запущенного контейнера, настраивая так же как и раньше нашу службу cowsay, но без необходимости в Dockerfile:


- name: do things
  hosts: playbook-container
  gather_facts: false

  tasks:
    - name: install things
      raw: dnf install -y python-dnf

    - name: install things
      dnf:
        name: ['nginx', 'cowsay']

    - name: configure nginx
      lineinfile:
        line: "daemon off;"
        dest: /etc/nginx/nginx.conf

    - name: boop
      shell: cowsay boop > /usr/share/nginx/html/index.html

    - name: run nginx
      shell: nginx &
 	   

Этот плейбук составлен из двух воспроизведений. Самое первое воспроизведение создаёт необходимый контейнер из имеющегося базового образа Fedora 29. Задача docker_container снабжается некой командой sleep чтобы удержать наш контейнер от запуска на протяжении какого- то времени, поскольку встроенный модуль соединения docker работает лишь с активными контейнерами (не настроенный образы операционной системы из Docker Hub обычно немедленно выполняют выход при своём запуске, ибо у них нет настроенных по умолчанию действий для выполнения). Наша вторая задача этого первого воспроизведения создаёт ннекую запись описи времени выполнения для этого контейнера. Значение имени хоста описи обязано соответствовать названию этого контейнера. Метод самого соединения также устанавливается в docker.

Наше второе воспроизведение имеет целью наш только что созданный хост и его первая задача применяет модуль raw для получения в нужном месте пакета python-dnf (что введёт в действие весь остаток python), чтобы мы могли применять модуль dnf в своей следующей задаче. Этот модуль dnf далее применяется для установки нужных нам пакетов, а именно, nginx и cowsay. Затем модуль lineinfile применяется для добавления некой новой строки в имеющуюся конфигурацию nginx. Задача shell использует cowsay для создания содержимого под обслуживание в nginx. Наконец, запускается nginx сам по себе в качестве какого- то фонового процесса.

Прежде чем запускать созданный нами плейбук, давайте удалим все запущенный в нашем предыдущем примере контейнеры:

 

Рисунок 11.15



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

 

Рисунок 11.16



Мы видели выполнение задач своего первого воспроизведения в нашем localhost, а далее наше второе воспроизведение выполняет наш playbook-container. По его завершению мы имеем возможность проверить самую первую веб службу и перечислить все запущенные контейнеры чтобы убедиться в правильности выполненной работы. Обратите внимание на иной фильтр на этот раз; наш контейнер был построен и запущен непосредственно из имеющегося образа fedora без необходимости в промежуточном шаге создания соответствующего образа fedora-moo:

 

Рисунок 11.17



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

Другим способом применения этого метода взаимодействия является использование контейнеров Docker для имитации множества хостов чтобы проверять исполнение плейбука по множеству хостов. Некий контейнер может быть запущен с какой- то системой инициализации как соответствующий процесс времени исполнения, что позволяет запускать дополнительные службы, как если бы они были бы полной операционной системой. Этот вариант применения имеет ценность внутри некой непрерывной среды интеграции для того чтобы быстро и действенно удостоверяться в изменениях содержимого плейбука.

Учёт Docker

Аналогично описанным ранее в книге встраиваемым модулям описей OpenStack и EC2, доступен также и сценарий описи Docker. Этот сценарий Docker располагается в contrib/inventory/docker.py внутри репозитория источника Ansible совместно с неким связанным с ним файлом конфигурации contrib/inventory/docker.yml. Чтобы воспользоваться этим сценарием, просто скопируйте этот файл .py в каталог того плейбука, который вы собираетесь применять, либо в некий путь, доступный всем пользователям/ плейбукам в вашей системе, которая будет применять Ansible. Для нашего примера я скопирую его в каталог своего плейбука. Для данного примера не требуется применять файл конфигурации, который может использоваться для задания того как подключаться к одному или более демонам Docker, так как мы просто подключаемся к своему локальному демону Docker.

Вывод help для этого сценария отобразит множество возможных параметров; тем не менее, Ansible будет применять лишь --list и --host:

 

Рисунок 11.18



Если собранный ранее контейнер всё ещё запущен когда данный сценарий выполняется для перечисления хостов, он должен проявиться в получаемом выводе (для того чтобы сделать это более очевидным мы воспользовались для получаемого снимка экрана grep):

 

Рисунок 11.19



Как и ранее, представлен ряд групп, которые имеют в качестве участников исполняемые контейнеры. Двумя ранее показанными группами выступают группа короткого идентификатора контейнера и группа длинного идентификатора контейнера. Многие переменные также определяются как часть получаемого вывода, которые были жёстко обрезаны в нашем предыдущем снимке экрана. Завершающий хвост нашего вывода выявляет несколько дополнительных групп:

 

Рисунок 11.20



Дополнительными группами выступают следующие:

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

  • image_name: Некая группа для каждого из применяемых выявленных контейнеров

  • container name: Некая группа, которая устанавливает соответствие значение названия самому контейнеру

  • running: Группа всех запущенных контейнеров

  • stopped: Группа всех остановленных контейнеров

Данный встраиваемый модуль инвентаризации и все предоставляемые им группы и данные могут применяться плейбуками для указания целей различных выборов из доступных контейнеров для взаимодействия без необходимости инвентаризации вручную или при помощи add_hosts.

Контейнер Ansible

Контейнеры Ansible являются множеством инструментов, которые собираются на основе введённых ранее в этой главе понятий, для предоставления всестороннего рабочего потока разработки контейнеров, их проверки и развёртывания. С момента выхода последней редакции этой книги стала доступной стабильная версия.

На момент написания этой книги Контейнеры Ansible не устанавливались совместно с Ansible и их следует устанавливать отдельно. Их можно установить из pypi в качестве пакета с названием ansible-container, либо же его можно установить из источника в репозитории GitHub. На момент написания данной книги, ansible-container имеет некие достаточно строгие требования для своей среды Python; в частности, необходимо удалять docker-py и доступна лишь версия 2.7.0 для установки модуля Python docker. Кроме того обращаем внимание, что (на момент написания книги) существует известная проблема во взаимодействии между самой последней версией ansible-container и самим модулем docker, причём имеющийся модуль docker следует исправлять вручную для подобной работы. Надеемся, в будущем это будет исправлено - однако на момент написания книги это всё ещё требовалось.

Для установки в нашей демонстрационной машине CentOS 7 я вызвал такие команды:


sudo pip uninstall docker-py
sudo pip uninstall docker
sudo pip install docker==2.7.0
sudo sed -i "s/return os.path.join(os.sep, 'run', 'secrets')/return os.path.join(os.sep, 'docker', 'secrets')/g" /usr/lib/python2.7/site-packages/container/docker/engine.py 
sudo pip install -U setuptools
sudo pip install "ansible-container[docker,openshift]"
		

При наличии Контейнеров Ansible у нас имеется возможность задания одной или более служб в виде контейнеров. Это определяется в неком файле YAML, который близко следует схеме версии 2 Docker Compose (поддержка для такой версии 2 схемы была добавлена в выпуске 0.3.0 ansible-container). Все определяемые службы становятся контейнерами и выставляются в виде некого хоста Ansible. Эти хосты используются неким файлом плейбука для выполнения всех требуемых настроек для подготовки контейнера к запуску соответствующей службы. Для определения любых требований применяемых этим плейбуком библиотек Python, зависимостей этого плейбука роли Ansible Galaxy, значений метаданных Ansible Galaxy для совместного использования этим проектом и неким конфигурационным файлом Ansible, применяемым с таким плейбуком могут применяться дополнительные файлы.

Основным исполняемым файлом Контейнеров Ansible выступает ansible-container, который содержит ряд подчинённых команд:

  • init: Субкоманда init создаст саму необходимую структуру каталога и временные файлы для некого нового project Контейнеров Ansible внутри такого текущего каталога. В качестве возможного варианта она способна подключаться к Ansible Galaxy и применять некий шаблон проекта для предварительного наполнения имеющихся файлов; в противном случае они в основном будут созданы пустыми.

  • build: Подчинённая команда build применяется для запуска всех контейнеров для каждой заданной службы и одного контейнера с Ansible внутри него, который применяется для запуска самого плейбука для всех контейнеров службы. После завершения данного плейбука из этих настроенных контейнеров создаются образы.

  • run: Подчинённая команда run запустит новые контейнеры для каждой службы при помощи образов, созданных в процессе фазы build.

  • stop: Эта подкоманда stop остановит контейнеры, запущенные подкомандой run.

  • push: Подчинённая команда push выгрузит все построенные образы в некий целевой реестр образов Docker.

  • shipit: Подкоманда shipit выработает содержимое Ansible для развёртывания контейнеров из построенных образов в платформы оркестровки контейнеров, такие как Kubernetes or Red Hat OpenShift:

 

Рисунок 11.21



Для демонстрации Контейнеров Ansible мы воспроизвели свой предыдущий контейнер службы Docker для отображения cowsay через некий веб сервер и его локальный запуск.

Применение init ansible-container

Контейнер Ansible полагается не некое дерево каталога содержимого, которое создаётся при помощи подчинённой команды init. Это содержимое является именно тем, что мы сделали доступным внутри данного контейнера при помощи запуска самого Ansible:

 

Рисунок 11.22



Для данного примера мы создаём каталог ansible/ и запускаем в нём подкоманду init:

 

Рисунок 11.23



Прежде всего, для определения наших служб, нам потребуется изменить файл container.yml внутри только что созданного каталога ansible/. Наш пример имеет лишь одну службу, которую мы именовали как cowsay. Мы желаем воспользоваться образом docker.io/fedora:29.

В качестве составной части процесса сборки, ansible-container применяет контейнер с названием conductor - по существу именно это тот самый образ контейнера, из которого может выстраиваться, развёртываться и запускаться наш целевой контейнер. Помимо всех прочих вещей, он содержит сам Ansible времени исполнения, ассоциированные библиотеки и некую среду Python, как это требует Ansible. Что важно, так это то, что по- возможности данный контейнер соответствует выстраиваемой операционной системе настолько близко, насколько это допустимо; в противном случае отличия в версиях Python или иных библиотек способны вызывать проблемы. Тем самым, мы определили некий контейнер на основе проводника (conductor) Fedora 29 контейнер с применением параметра conductor_base.

Сам процесс построения ожидает container.yml для ссылки по крайней мере на одну роль для данного процесса построения; вскорости мы создадим эту роль и мы назовём её cowsay. В этот раз мы выставим порт 8081, просто чтобы отличать его от предыдущих экспериментов. Мы настроим необходимые команды для этой службы в nginx:


version: "2"
services:
  cowsay:
    from: docker.io/fedora:29
    conductor_base: fedora:29
    roles:
      - cowsay
    ports:
      - "8081:80"
    command: ['nginx']
 	   

Когда эта служба установлена, нам потребуется написать соответствующие воспроизведения для настройки самого базового образа для своих потребностей. Прежде всего мы создадим некий скелет каталога ролей:


mkdir -p roles/cowsay/tasks/
		

После этого мы создадим необходимый файл roles/cowsay/tasks/main.yml. Основной целью данного файла является установка соответствия тем задачам, которые мы применяли в предыдущем примере, за единственным исключением - новой задачей set_fact. Когда ansible-container выстроит наш новый контейнер, необходимая среда Python из ранее упомянутого контейнера проводника смонтирована в /_usr в самом целевом контейнере, причём она применяется для всех задач. Это прекрасно пока мы не начнём применять свой модуль dnf, который не запускается из этой смонтированной среды Python, так как он в ней не установлен! Чтобы обойти это мы воспользуемся set_fact для задания переменной хоста ansible_python_interpreter и указания на неё в качестве среды Python, которую мы устанавливаем в самой первой задаче:


---
- name: install things
  raw: dnf install -y python-dnf

- name: use local python
  set_fact:
    ansible_python_interpreter: /usr/bin/python

- name: install things
  dnf:
    name: ['nginx', 'cowsay']

- name: configure nginx
  lineinfile:
    line: "daemon off;"
    dest: /etc/nginx/nginx.conf

- name: boop
  shell: cowsay boop > /usr/share/nginx/html/index.html
 	   

В отличии от нашего предыдущего примера, нам нет нужды добавлять какую- то задачу для запуска nginx; это произойдёт при запуске самого контейнера.

Применение build ansible-container

Для данного примера не требуется изменять никакие файлы из их первоначальных состояний. Мы теперь готовы собирать все образы, которые созданы при помощи подчинённой команды build для ansible-container:

 

Рисунок 11.24



[Совет]Совет

Если вдруг сам процесс построения завершился неудачей, вы можете получить установленным docker-py, который, по крайней мере на момент написания, к сожалению прерывает ansible-container. Кроме того, ansible-container работает лишь с некой исправленной версией (2.7.0) соответствующего модуля Python docker. Надеемся, в будущем это не будет требоваться.

Наш собранный процесс выгрузит некий образ Docker с названием ansible-conductor. Внутри этого контейнера будет запущен Ansible и он будет применяться для оркестровки всех изменений в соответствующем целевом контейнере (с названием ansible-cowsay в нашем следующем примере). Он запустит некий контейнер при помощи данного образа и установит соответствие содержимому каталога _usr/. Затем он запустит сам контейнер службы и выполнит для него необходимый плейбук. По завершению этого плейбука, получаемый настроенный контейнер службы будет сохранён в виде некого образа Docker в нашей локальной системе, вместо того чтобы экспортироваться в саму файловую систему (если такое потребуется, для выполнения этого имеется встроенная команда Docker).

Само название образа составляется из двух частей: самая первая именуется по тому базовому каталогу, из которого запускается этот ansible-container (в данном случае ansible), а вторая часть из самого названия службы (cowsay), что мы можем обнаружить при помощи docker images:

 

Рисунок 11.25



По завершению всех шагов предварительных требований, мы получим клёвую инфраструктуру для построения образов контейнеров Docker без необходимости в Dockerfile, а потому все наши процессы сборки остаются в ролях Ansible, помимо их переносимости.

Применение run ansible-container

Имея созданный образ мы можем теперь запустить саму службу. Мы можем запускать свой контейнер вручную при помощи docker или написать некий плейбук для того чтоы Ansible запускал его. Оба этих подхода вполне выполнимы, но требуют больше усилий, чем оно того заслуживает, поскольку мы уже определили как этот контейнер должен запускаться в своём файле container.yml. Мы можем воспользоваться этой настройкой и просто применить подчинённую команду run из ansible-container:

 

Рисунок 11.26



Имеется несколько дополнительных параметров для данной подкоманды run. Вы можете указывать для запуска некую конкретную службу, подцеплять тома, задавать переменные, переключать промышленные настройки и тому подобное. Тот параметр,который интересует нас, это наш аргумент --detached, так как именно он запустит наше приложение в фоновом режиме, возвращая управление обратно в наш Терминал:

 

Рисунок 11.27



Наша подчинённая команда run воспользуется Контейнером Ansible для поднятия соответствующих контейнеров службы. На данный момент мы должны иметь возможность видеть свой контейнер исполняемым в docker ps и взаимодействовать с этим контейнером чтобы увидеть что сказала наша коровка:

 

Рисунок 11.28



данный пример лишь качается поверхности того что можно делать с помощью Контейнеров Ansible. Имеющиеся файлы управления поддерживают шаблонные значения для создания достаточно динамичных параметров службы, которые достаточно просто проверять локально, а затем помещать в развёрнутые промышленные среды, такие как Kubernetes. Дополнительные свойства продолжают добавляться и функциональность может меняться, а потому не забывайте сверяться с соответствующей документацией прежде чем приступать к работе с Контейнерами Ansible.

Выводы

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

В этой главе мы изучили то, как управлять облачными инфраструктурами на своей площадке, например, OpenStack, применяя Ansible. Затем мы расширили это примерами из общедоступных облачных инфраструктур, предоставляемых как AWS, так и Microsoft Azure. наконец, мы изучили как взаимодействовать с Docker при помощи Ansible и как искусно упаковывать определения служб Docker при помощи Контейнеров Ansible.

Ansible способен запускать практически любой хост, за исключением того, на котором он запущен сам, причём с надлежащими правами доступа, при этом он способен создавать некую инфраструктуру, которой он хотел бы управлять, либо для однократных действий, либо для развёртывания некой новой версии какого- то приложения в систему управления промышленными контейнерами. Окончательный результат состоит в том, что как только ваше оборудование будет установлено и ваши поставщики служб настроены, вы получает возможность управления всей инфраструктурой через Ansible, если только пожелаете!

В своей заключительной главе этой книги мы рассмотрим некую новую и быстро растущую область автоматизации: предоставление сетевых сред при помощи Ansible.