Ansible для начинающих

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

Asible

Итак, Ansible – это система управления программным обеспечением на удаленных серверах. Есть ряд аналогичных систем (Chief, Puppet) с другими принципами работы, требующих установки клиента и пр. В чём плюс Ansible – для работы на клиенте достаточно ssh соединения с ним.

Задача Ansible – выполнить ряд операций на удаленной машине. При этом машин может быть сразу несколько.

Playbook

Все операции вы записываете в некий Ansible-скрипт. Действия выполняются последовательно. Логика работы похожа на обычный bash-скрипт, только на своих командах. Это позволяет отвязаться от дистрибутива, описав задачи на промежуточном языке. Такой Ansible-скрипт называется playbook (сценарий). Формат его очень простой и построен на yaml-разметке.

- name: "First step"
  hosts: localhost
  tasks:
  - taskA
  - taskB

Тут мы описали группу задач. Дали ей общее имя, name: “First step”. Указали на каких хостах выполнять, hosts: localhost (только на локальном хосте).

Далее следует перечень задач, которые надо выполнить: tasks: taskA, taskB. Такая группа задач называется play. Это что-то типа блока задач, которые вы выделяете по какой-то своей логике. В одном playbook-е может быть несколько блоков (play-ев):

- name: "First step"
  hosts: localhost
  tasks:
  - taskA
  - taskB

- name: "Second step"
  hosts: all
  tasks:
  - taskC
  - taskD

Заметьте, второй блок (Second step) мы поставили для всех хостов (hosts: all). То есть в первом мы могли, к примеру, что-либо подготовить локально (создать виртуальные машины, подготовить файлы, залить их), а потом применить для всех машин во втором блоке.

Task

Теперь давайте рассмотрим что из себя представляют сами команды (tasks).

Как правило это всего-лишь модули Ansible. То есть вызывая какой-либо task, мы на самом деле вызываем модуль Ansible с его параметрами. По этому богатство “языка” Ansible зависит от количества его модулей.

Записать task можно в двух видах: кратком, и полном. Вот пример команды установки переменной (set_fact) в кратком виде:

- set_fact: mytext="Hello world"

Тогда наш play с этим task выглядит так:

- name: "First step"
  hosts: localhost
  tasks:
  - set_fact: mytext="Hello world"

В данном скрипте мы установили переменную mytext, равную “Hello world” для хоста localhost.

Следующей командой можно вывести на экран переменную, используя модуль (команду) debug:

- name: "First step"
  hosts: localhost
  tasks:
  - set_fact: mytext="Hello world"
  - debug: var: mytext

Существует возможность более полно описать команду (task), дать ему имя (name). Совсем как в блоках задач (play). Тогда получившийся текст выглядит как подзадача нашего основного блока задач. На мой взгляд так более наглядно:

- name: "First step"
  hosts: localhost
  tasks:
  - name: "Set variable"
    set_fact:
      mytext="Hello world"
  - name: "Show variable"
    debug:
      var: mytext

В этому случае сразу видно, что есть блок задач “First step“, в нем существует 2 подзадачи. Первая – с установкой переменной. Вторая – вызывает модуль debug с параметром var: и указанием имени переменной mytext.

Запуск

Теперь можете сохранить получившийся текст в файл “first.yml” и запустить его так:

ansible-playbook ./first.yml

Вывод у вас будет:

PLAY [First step] *************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************
ok: [localhost]

TASK [Set variable] ***********************************************************************************************************
ok: [localhost]

TASK [Show variable] **********************************************************************************************************
ok: [localhost] => {
    "mytext": "Hello world"
}

PLAY RECAP ********************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0

Тут вы видите наш блок задач (PLAY), называемый “First step”, а так же команды (TASK) по установке переменной (Set variable) и ее выводу (Show variable).  Все задачи завершились успешно (ok=3, failed=0). Ничего не изменилось в состоянии хоста (changed=0), т.к. мы ничего пока не меняли (не устанавливали ПО, не изменяли файлы).

Дополнительная задача “Gathering Facts” – получение информации о хосте (такой как имя хоста и пр.), вызвалась автоматически. Она необходима для использования данных о хосте в своих сценариях. Можно запретить эту задачу, указав gather_facts : false

- name: "First step"
  hosts: localhost
  gather_facts: false
 ....

Inventory

Второй блок задач использовал у нас директиву hosts: all. Что это значит? Где все эти хосты, на которых должна примениться наша группа команд?

Это файл hosts. Так называемый файл инвентаризации, в котором у нас хранится перечень машин, с которыми будет работать Ansible.

Располагаться он может в вашей директории и иметь примерно такой вид:

[mail]
mail-01.burlutsky.su
mail-02.myserver.lan ansible_host=10.10.10.6

[web]
web-01.myserver.lan ansible_host=10.10.10.12

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

[all:vars]
ansible_user=root

Подробнее смотрите в официальной документации. Нам же достаточно того, что вместо hosts: all можно указать конкретную группу:

hosts: web

А затем вызвать наш playbook, указав параметром файл инвентаризации:

ansible-playbook ./first.yml -i ./hosts

Roles

Можно разбивать ваши задачи по разным playbook-файлам. К примеру вынести первичную настройку в common.yml, установку Apache в apache.yml, MySQL – в mysql.yml, PHP – в php.yml, потом все это включить в файл lamp.yml

- name: "LAMP"
  hosts: web
  tasks:
    - name: "Include common"
      include: common.yml
...

Подробнее смотрите тут и тут.

Но я предлагаю сразу перейти к ролевой модели. Роль – это как раз ваш LAMP в данном случае. Набор определенных типовых задач для конкретной машины. Ее роль.

Для того, чтобы определить роль, мы должны создать определенную файловую иерархию и разложить все по директориям. Вот пример такой иерархии для роли с именем “common”:

playbooks
├── roles
│   ├── common
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── text.txt
│   │   └── tasks
│   │       └── main.yml

Смысл в том, чтобы разнести все раздельно по директориям.

  • Переменные по умолчанию – в директорию defaults.
  • Файлы, используемые в роли (к примеру которые надо загрузить на сервер) – в дирекорию files.

Таких определенных директорий много.

  • Шаблоны – templates.
  • Обработчики задач (вызываемые после успешного или неуспешного из завершения) – handlers.
  • Прочие переменные – vars.
  • Метаданные – meta.

И в каждой директории главный файл – main.yml. Но не обязательно создавать все эти директории сразу. Достаточно создать roles/имя_роли/tasks/main.yml и прописать в нем все задачи, характерные для данной роли. Далее в осномном playbook-файле вы уже можете ссылаться на эти роли:

- name: "LAMP deployment"
  hosts: web
  become: true
  roles:
    - role: "common"
    - role: "php"
    - role: "apache"
    - role: "mysql"

Примерно так может выглядеть ваш playbook для установки LAMP. Теперь его можно “накатывать” сразу на кучу серверов в вашем hosts-файле!

Ссылки

В заключении приведу полезные, на мой взгляд, для начинающего ссылки:

Удачи в освоении автоматизации вместе с Ansible!

Tagged with:

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

Ваш e-mail не будет опубликован.