Ansible практика – урок №2: Как запустить первый плейбук.

Предыдущий урок: Ansible практика – урок №1: Базовая настройка и первый запуск.

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

Что такое Ansible playbook?

Плейбук – это руководство для Ansible, в котором мы описываем какие действия, в какой последовательности и при каких условиях должен исполнить Ansible.

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

Все это можно легко описать в плейбуке. Тогда не нужно будет каждый новый сервер настраивать вручную, а оставить это Ansible.

Как запустить первый плейбук

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

Шаг 1: Создание плейбука

Допустим, мы часто подготавливаем веб сервера работающие на стеке LEMP. Чтобы не устанавливать каждый раз вручную пакеты NGINX, MariaDB и PHP, доверим это Ansible. Создадим на контрольной ноде файл install_lemp.yml следующего содержания:

---
- hosts: all
  tasks:

  - name: "Install PHP"
    ansible.builtin.dnf:
      name:
        - php
        - php-cli
        - php-fpm
        - php-common
        - php-mbstring
        - php-curl
        - php-mysqlnd
        - php-json
        - php-xml
        - php-phar
        - php-pdo
        - php-gd
      state: latest

  - name: "Install NGINX"
    ansible.builtin.dnf:
      name: nginx
      state: latest

  - name: "Ensure NGINX is started and enabled"
    ansible.builtin.service:
      name: nginx
      state: started
      enabled: true

  - name: "Install MariaDB"
    ansible.builtin.dnf:
      name: mariadb-server
      state: latest

  - name: "Ensure MariaDB is started and enabled"
    ansible.builtin.service:
      name: mariadb
      state: started
      enabled: true

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

Первым делом мы задаем хосты (hosts: all), с которыми будет работать плейбук. Далее идет серия заданий (tasks), которые должен выполнить Ansible. Названия таскам можно давать любые, но старайтесь делать их понятными, описывающими суть задания.

В данном плейбуке мы используем два модуля Ansible.

ansible.builtin.dnf – это встроенный модуль для работы с пакетным менеджером DNF. Директива  name указывает на имя пакета, а state на его состояние. state: latest говорит Ansible, что данный пакет должен присутствовать и быть последней версии. Подробнее о работе данного модуля и доступных параметрах вы можете узнать в официальной документации Ansible.

ansible.builtin.service – модуль для управления сервисами, используется для их запуска и остановки. Директива name задает имя сервиса, state – состояние, enabled – запуск по умолчанию. Страница руководства по данному модулю.

Шаг 2: Запуск Ansible плейбука

Наш первый плейбук готов. Давайте попробуем его запустить:

[root@Control-Node ansible]# ansible-playbook install_lemp.yml

PLAY [all] ******************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install PHP] **********************************************************************************************************************************************************************************
changed: [Managed-Node-2]
changed: [Managed-Node-1]

TASK [Install NGINX] ********************************************************************************************************************************************************************************
changed: [Managed-Node-1]
changed: [Managed-Node-2]

TASK [Ensure NGINX is started and enabled] **********************************************************************************************************************************************************
changed: [Managed-Node-2]
changed: [Managed-Node-1]

TASK [Install MariaDB] ******************************************************************************************************************************************************************************
changed: [Managed-Node-1]
changed: [Managed-Node-2]

TASK [Ensure MariaDB is started and enabled] ********************************************************************************************************************************************************
changed: [Managed-Node-1]
changed: [Managed-Node-2]

PLAY RECAP ******************************************************************************************************************************************************************************************
Managed-Node-1             : ok=6    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Managed-Node-2             : ok=6    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@Control-Node ansible]#

По умолчанию, первым шагом (Gathering Facts) Ansible собирает информацию о хостах. Далее выполняет таски из нашего плейбука один за одни, при этом одновременно на обоих серверах. Для каждого сервера таски выполнены с результатом changed, это значит, что изменения были внесены.

Можно зайти на любую из Managed Node и убедиться, что сервисы установлены и запущены:

[root@Managed-Node-1 ~]# mariadb --version
mariadb  Ver 15.1 Distrib 10.5.29-MariaDB, for Linux (x86_64) using  EditLine wrapper

[root@Managed-Node-1 ~]# systemctl status mariadb
● mariadb.service - MariaDB 10.5 database server
     Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: disabled)
     Active: active (running) since Mon 2025-12-08 12:22:29 +10; 30min ago
       Docs: man:mariadbd(8)
             https://mariadb.com/kb/en/library/systemd/
    Process: 12248 ExecStartPre=/usr/libexec/mariadb-check-socket (code=exited, status=0/SUCCESS)
    Process: 12270 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir mariadb.service (code=exited, status=0/SUCCESS)
    Process: 12367 ExecStartPost=/usr/libexec/mariadb-check-upgrade (code=exited, status=0/SUCCESS)
   Main PID: 12352 (mariadbd)
     Status: "Taking your SQL requests now..."
      Tasks: 8 (limit: 11100)
     Memory: 86.7M
        CPU: 1.029s
     CGroup: /system.slice/mariadb.service
             └─12352 /usr/libexec/mariadbd --basedir=/usr

Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: The second is mysql@localhost, it has no password either, but
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: you need to be the system 'mysql' user to connect.
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: After connecting you can set the password, if you would need to be
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: able to connect as any of these users with a password and without sudo
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: See the MariaDB Knowledgebase at https://mariadb.com/kb
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: Please report any problems at https://mariadb.org/jira
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: The latest information about MariaDB is available at https://mariadb.org/.
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: Consider joining MariaDB's strong and vibrant community:
Dec 08 12:22:29 Managed-Node-1 mariadb-prepare-db-dir[12309]: https://mariadb.org/get-involved/
Dec 08 12:22:29 Managed-Node-1 systemd[1]: Started MariaDB 10.5 database server.
[root@Managed-Node-1 ~]#

А что будет, если мы еще раз запустим тот же самый плейбук? Давайте попробуем:

[root@Control-Node ansible]# ansible-playbook install_lemp.yml

PLAY [all] ******************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install PHP] **********************************************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install NGINX] ********************************************************************************************************************************************************************************
ok: [Managed-Node-1]
ok: [Managed-Node-2]

TASK [Ensure NGINX is started and enabled] **********************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install MariaDB] ******************************************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Ensure MariaDB is started and enabled] ********************************************************************************************************************************************************
ok: [Managed-Node-1]
ok: [Managed-Node-2]

PLAY RECAP ******************************************************************************************************************************************************************************************
Managed-Node-1             : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Managed-Node-2             : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@Control-Node ansible]#

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

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

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

Итоги:

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

Следующий урок: Ansible практика – урок №3: Ограничение работы плейбука с помощью tags и limit.