Ansible — давайте попробуем

от автора

Ansible — сравнительно молодая система управления конфигурацией, его история насчитывает чуть более трех лет. Но, несмотря на это, он стремительно и быстро ворвался в мир систем управления конфигурацией, потеснив Chef, Puppet и SaltStack.

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

Итак, чем же хорош ansbile:

  • низкий порог входа;
  • декларативный язык описания конфигурации;
  • на управляемые узлы не нужно устанавливать никакого дополнительного ПО;
  • просто написать дополнительный модуль.

Низкий порог входа

Начать пользоваться ansible можно за пару минут. Допустим, вы используете OSX.

$ brew install ansible  $ ansible --version ansible 1.8.4   configured module search path = None 

Теперь создадим файл hosts:

[test] localhost ansible_connection=local 

Поехали:

$ ansible -i hosts -m ping all  localhost | success >> {     "changed": false,     "ping": "pong" } 

Что мы сделали? Для всех хостов (параметр all) из файла hosts выполнить модуль ping. Давайте посмотрим еще что-нибудь.

ansible -i hosts -a 'ls -lah' all

$ ansible -i hosts -a "ls -lah" all localhost | success | rc=0 >> total 12K drwxr-xr-x  5 brun staff  170 Apr  1 11:50 . drwxr-xr-x 91 brun staff 3.1K Apr  1 11:37 .. -rw-r--r--  1 brun staff  230 Apr  1 12:07 export.sh -rw-r--r--  1 brun staff   42 Apr  3 14:48 hosts -rw-r--r--  1 brun staff  376 Apr  1 12:49 playbook.yml 

Если модуль (ключ -m) не задан, то используется модуль command. Фактически, ansible можно использовать не только как систему управления конфигурацией, но и как фреймворк для распределенного выполнения команд.

Декларативный язык описания конфигурации

Помимо утилиты ansible, есть еще утилита ansible-playbook, которой вы будете пользоваться наиболее часто.

Для дальнейших примеров я завел машинку t2.micro на aws с Ubuntu 14.04 и прописал ее в hosts.

# hosts [web] 111.111.111.111 

Также, чтобы не вводить каждый раз в командную строку параметры, я в директории проекта создал файл ansible.cfg.

# ansible.cfg [defaults] hostfile       = hosts 

После этого создадим наш первый сценарий (playbook в терминологии ansible) web.yml.

web.yml

# web.yml --- - hosts: all   user: ubuntu    tasks:     - name: Update apt cache       apt: update_cache=yes       sudo: yes      - name: Install required packages       apt: name={{ item }}       sudo: yes       with_items:         - nginx         - postgresql  

Запускаем наш первый сценарий, который обновляет кэш apt, а потом ставит два пакета: nginx и postgresql.

ansible-playbook web.yml

$ ansible-playbook web.yml  PLAY [all] ********************************************************************  GATHERING FACTS *************************************************************** ok: [111.111.111.111]  TASK: [Update apt cache] ****************************************************** ok: [111.111.111.111]  TASK: [Install required packages] ********************************************* changed: [111.111.111.111] => (item=nginx,postgresql)  PLAY RECAP ******************************************************************** 111.111.111.111               : ok=3    changed=1    unreachable=0    failed=0 

Фактически, мы два раза вызвали модуль apt, только с разными параметрами. Сам же файл сценарии представляет себя файл на языке Yaml с вкраплениями шаблонизатора Jinja2.

На управляемые узлы не нужно устанавливать никакого дополнительного ПО

Действительно, для того, чтобы управлять машиной, на ней должен быть установлен Python (а он стоит по-умолчанию на всех современных linux системах) и должен быть доступ по ssh. Сравните это с остальными системами, где необходимо поставить клиента, которому нужны определенные версии различных языков и библиотек. Именно этот факт, кстати, делает старт с ansible гораздо более простым, чем для остальных систем.

Просто написать дополнительный модуль

Модуль можно написать на любом языке, он должен уметь принимать параметры на вход и выдавать json в ответ. Но зачем писать новый модуль, если уже есть 242 модуля на все случаи жизни (в версии 1.8.4). На случай, если вам действительно чего-то не хватает, есть хорошее описание того, как написать свой модуль.

Что-нибудь серьезное

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

Для тех, кому лень что-то писать самому, уже есть тысячи готовых ролей на сайте ansible galaxy, и они вполне достойного качества, чтобы пользоваться ими в бою.

Мы же создадим чистую роль.

ansible-galaxy init nginx -p roles

$ ansible-galaxy init nginx -p roles - nginx was created successfully  $ tree ├── roles │   └── nginx │       ├── README.md │       ├── defaults │       │   └── main.yml │       ├── files │       ├── handlers │       │   └── main.yml │       ├── meta │       │   └── main.yml │       ├── tasks │       │   └── main.yml │       ├── templates │       └── vars │           └── main.yml 

Доработаем файл web.yml.

web.yml

--- - hosts: all   user: ubuntu   sudo: yes    roles:     - nginx 

Обратите внимание на ключ sudo: yes. Он позволяет не писать в каждом задании эту строку. Большинство административных задач все равно должны выполняться с правами root, поэтому имеет смысл оставить его здесь.

А в файле roles/nginx/tasks/main.yml напишем следующее:

roles/nginx/tasks/main.yml

--- - name: Update apt cache   apt: update_cache=yes  - name: Install required packages   apt: name=nginx 

Используя роли, можно повторно использовать код (хотя является ли Yaml кодом — философский вопрос). Конечно, пример намеренно упрощен, но из него становится ясно, как организовывать на ansible проекты с большим количеством компонент.

Факты

В ansible есть встроенный модуль setup, который выполняется первым для всех управляемых нод. Давайте посмотрим, что он делает.

ansible -m setup all -u ubuntu

$ ansible -m setup all -u ubuntu     "ansible_facts": {         "ansible_all_ipv4_addresses": [             "172.31.7.80"         ],         "ansible_architecture": "x86_64",         "ansible_bios_date": "12/03/2014",         "ansible_bios_version": "4.2.amazon",         "ansible_cmdline": {             "BOOT_IMAGE": "/boot/vmlinuz-3.13.0-44-generic",             "console": "ttyS0",             "ro": true,             "root": "UUID=fd803688-5c41-4188-8a06-382a65a520bf"         },         "ansible_default_ipv4": {             "address": "172.31.7.80",             "alias": "eth0",             "gateway": "172.31.0.1",             "interface": "eth0",             "macaddress": "06:a8:07:41:47:a5",             "mtu": 9001,             "netmask": "255.255.240.0",             "network": "172.31.0.0",             "type": "ether"         }    ... и так далее 

Модуль setup собирает различные данные для ноды, это аналог ohai в chef (кстати, ansible тоже может использовать ohai для сбора информации). Все эти данные потом можно использовать в сценариях и шаблонах. Например, ip адрес по-умолчанию можно получить, обратившись к переменной ansible_default_ipv4.

# web.yml  tasks:   - debug: msg={{ansible_default_ipv4}} 
ansible-playbook web.yml

$ ansible-playbook web.yml  PLAY [all] ********************************************************************  GATHERING FACTS *************************************************************** ok: [111.111.111.111]  TASK: [debug msg="{{ansible_default_ipv4}}"] ********************************** ok: [111.111.111.111] => {     "msg": "{u'macaddress': u'06:a8:07:41:47:a5', u'network': u'172.31.0.0', u'mtu': 9001, u'alias': u'eth0', u'netmask': u'255.255.240.0', u'address': u'172.31.7.80', u'interface': u'eth0', u'type': u'ether', u'gateway': u'172.31.0.1'}" } 

Шаблоны

В ansible есть шаблоны, которые используют шаблонизатор Jinja2. Давайте сделаем 2 шаблона.

# roles/nginx/templates/ansible.conf.j2  server {         listen 80 default_server;          root /usr/share/nginx/html;         index index.html index.htm; } 
# roles/nginx/templates/index.html.j2 <html> <body> <pre> {{ ansible_default_ipv4 }}  {{ ansible_env }} </pre> </body> </html> 

Обратите внимание на переменные в двойных фигурных скобках (например, {{ ansible_env }}) — это переменные ansible, которые мы собрали с помощью уже известного нам модуля setup.

Хендлеры

Для того, чтобы отрабатывать какие-то действия асинхронно, в ansible есть хендлеры (обработчики), которые можно вызвать из задач. Создадим свой хендлер, который перезагружает nginx.

# roles/nginx/handlers/main.yml --- # handlers file for nginx  - name: reload nginx   service: name=nginx state=reloaded 

Доработаем теперь файл задач роли nginx.

roles/nginx/tasks/main.yml

# roles/nginx/tasks/main.yml --- - name: Update apt cache   apt: update_cache=yes  - name: Install required packages   apt: name=nginx  - name: Start nginx service   service: name=nginx state=started  - name: Delete default nginx site   file: path=/etc/nginx/sites-enabled/default state=absent   notify: reload nginx  - name: Create default nginx site   template: src=ansible.conf.j2 dest=/etc/nginx/sites-enabled/ansible owner=www-data group=www-data   notify: reload nginx  - name: Create index.html file   template: src=index.html.j2 dest=/usr/share/nginx/html/index.html owner=www-data group=www-data 

Как понятно из описания, данная задача ставит nginx, запускает его, удаляет файл конфигурации nginx по-умолчанию, создает файл конфигурации из шаблона ansible.conf.j2, который мы написали выше, и генерирует файл index.html из шаблона, который мы описали выше. Обратите внимание, что некоторые задачи посылают нотификацию notify: reload nginx. Причем, в данном случае должно быть послано 2 нотификации на перезагрузку nginx, но, по факту, они объединятся в одну, как будет видно ниже. Нотификации необходимы, чтобы перезагружать nginx (или любой другой сервис) только в случае, если шаблон (или что-то другое) изменился, чтобы не делать это каждый раз при запуске ansible.

Итак, запустим получившийся сценарий.

ansible-playbook web.yml

$ ansible-playbook web.yml  PLAY [all] ********************************************************************  GATHERING FACTS *************************************************************** ok: [111.111.111.111]  TASK: [nginx | Update apt cache] ********************************************** ok: [111.111.111.111]  TASK: [nginx | Install required packages] ************************************* ok: [111.111.111.111]  TASK: [nginx | Start nginx service] ******************************************* ok: [111.111.111.111]  TASK: [nginx | Delete default nginx site] ************************************* changed: [111.111.111.111]  TASK: [nginx | Create default nginx site] ************************************* changed: [111.111.111.111]  TASK: [nginx | Create index.html file] **************************************** changed: [111.111.111.111]  TASK: [debug msg="{{ansible_default_ipv4}}"] ********************************** ok: [111.111.111.111] => {     "msg": "{u'macaddress': u'06:a8:07:41:47:a5', u'network': u'172.31.0.0', u'mtu': 9001, u'alias': u'eth0', u'netmask': u'255.255.240.0', u'address': u'172.31.7.80', u'interface': u'eth0', u'type': u'ether', u'gateway': u'172.31.0.1'}" }  NOTIFIED: [nginx | reload nginx] ********************************************** changed: [111.111.111.111]  PLAY RECAP ******************************************************************** 111.111.111.111               : ok=9    changed=4    unreachable=0    failed=0 

Как видите, в конце nginx перезагрузил конфигурацию. Заглянем в браузер.

Вуаля! Мы установили и запустили nginx с нужным нам файлом конфигурации, сгенерировали для него страницу с данными из ansible, и перезагрузили nginx.

Недостатки

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

  • Отсутствие менеджера зависимостей. Сейчас все роли можно хранить в репозитарии, но как работать с зависимостями и обновлять роли — внятного ответа нет. Все пользуются этим подходом (так же было с Chef, например, 3 года назад), но при разрастании проекта очевидны недостатки такого подхода. UPDATE Менеджер зависимостей в каком-то виде есть, непонятно только почему об этом написано «снизу мелким шрифтом».
  • Неполная документация. Ответы на некоторые очевидные вопросы приходится гуглить, и зачастую они находятся в частных блогах и тикетах на github.
  • Режим ansible-pull для больших инсталляций потребует серьезной «доработки напильником».
  • Неудобный дебаг. Даже при вызове с ключом -vvvv не всегда понятно, какая же именно команда выполнялась на сервере и что помешало ей выполниться.
  • Быстрая разработка. Конечно, у этого недостатка есть обратная сторона — ansible действительно быстро развивается. Но я наткнулся на баг, когда версия 1.8.1 работала, а 1.8.4 — сломалась.

ссылка на оригинал статьи http://habrahabr.ru/post/254959/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *