Ansible практика – урок №4: Использование условий when в плейбуке.

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

В прошлый раз мы познакомились и попрактиковались в использовании двух инструментов контроля исполнения плейбука. Сегодня мы рассмотрим еще один – условие when.

Зачем плейбуку нужен when?

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

Использование условий when в плейбуке.

Не будем терять время, обновим наше окружение.

Шаг 1: Вносим разнообразие в тестовое окружение

До этого момента у нас было три виртуальные машины, одна из которых контрольная нода, две другие управляемые хосты. На обоих Managed нодах ОС CentOS Stream 9. Добавим еще одну виртуальную машину, но на этот раз под управлением Ubuntu.

Я провел ту же базовую подготовку, что и для других управляемых серверов в уроке№0 – настроил SSH доступ по ключу, обновил  python3, лишь с минимальными поправками на используемую ОС.

Теперь у нас в инфраструктуре присутствуют сервера с двумя разными ОС. IP адрес новому хосту я дал следующий по списку: 192.168.0.153

Добавим новую ноду в инвентору, файл inventory станет:

Managed-Node-1 ansible_host=192.168.0.151
Managed-Node-2 ansible_host=192.168.0.152
Managed-Node-3 ansible_host=192.168.0.153

Запустим наш плейбук:

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

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

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

TASK [Install PHP] **********************************************************************************************************************************************************************************
fatal: [Managed-Node-3]: FAILED! => {"changed": false, "msg": "Could not import the dnf python module using /usr/bin/python3 (3.12.3 (main, Nov  6 2025, 13:44:16) [GCC 13.3.0]). Please install `python3-dnf` or `python2-dnf` package or ensure you have specified the correct ansible_python_interpreter. (attempted ['/usr/libexec/platform-python', '/usr/bin/python3', '/usr/bin/python2', '/usr/bin/python'])", "results": []}
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-1]
ok: [Managed-Node-2]

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

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
Managed-Node-3             : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

[root@Control-Node ansible]#

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

Рассмотрим повнимательнее ошибку, которую нам вернул Ansible:

fatal: [Managed-Node-3]: FAILED! => {"changed": false, "msg": "Could not import the dnf python module using /usr/bin/python3 (3.12.3 (main, Nov  6 2025, 13:44:16) [GCC 13.3.0]). Please install `python3-dnf` or `python2-dnf` package or ensure you have specified the correct ansible_python_interpreter. (attempted ['/usr/libexec/platform-python', '/usr/bin/python3', '/usr/bin/python2', '/usr/bin/python'])", "results": []}

Наверняка вы уже догадались, проблема в отсутствии пакетного менеджера dnf на новом хосте. Оно и понятно, dnf используется в дистрибутивах RHEL, а в Ubuntu пакетный менеджер – apt.

Значит, нам нужно адаптировать плейбук под наличие двух ОС и с помощью условий, контролировать ход его исполнения.

Шаг 2: Добавляем when в плейбук

Добавим второй набор задач по установке пакетов, но заменим в них ansible.builtin.dnf на ansible.builtin.apt (документация по модулю).

Названия пакетов одних и тех же программ могут отличаться в разных дистрибутивах Linux, но конкретно эти – php, nginx и mariad – совпадают. В противном случае нужно было бы поправить и названия устанавливаемых пакетов в соответствии с ОС.

А еще нужно как то определить, на каком сервере какая ОС. К счастью, мы уже знаем как – базовый модуль Ansible gather_facts, который собирает информацию об управляемых нодах. Он собирает огромное количество данных, и сегодня нас интересует ansible_distribution:

[root@Control-Node ansible]# ansible all -m gather_facts | grep '"ansible_distribution"'
        "ansible_distribution": "Ubuntu",
        "ansible_distribution": "CentOS",
        "ansible_distribution": "CentOS",
[root@Control-Node ansible]#

Ansible видит ОС на серверах как Ubuntu и CentOS. После всех изменений плейбук будет выглядеть следующим образом:

---
- hosts: all
  tasks:

  - name: "Install PHP on CentOS"
    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
    tags:
      - installation
      - php
    when: ansible_distribution == "CentOS"

  - name: "Install PHP on Ubuntu"
    ansible.builtin.apt:
      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
    tags:
      - installation
      - php
    when: ansible_distribution == "Ubuntu"

  - name: "Install NGINX on CentOS"
    ansible.builtin.dnf:
      name: nginx
      state: latest
    tags:
      - installation
      - nginx
    when: ansible_distribution == "CentOS"

  - name: "Install NGINX on Ubuntu"
    ansible.builtin.apt:
      name: nginx
      state: latest
    tags:
      - installation
      - nginx
    when: ansible_distribution == "Ubuntu"

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

  - name: "Install MariaDB on CentOS"
    ansible.builtin.dnf:
      name: mariadb-server
      state: latest
    tags:
      - installation
      - mariad
    when: ansible_distribution == "CentOS"

  - name: "Install MariaDB on Ubuntu"
    ansible.builtin.apt:
      name: mariadb-server
      state: latest
    tags:
      - installation
      - mariad
    when: ansible_distribution == "Ubuntu"

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

Шаг 3: Применяем when на практике

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

Это приведет к ошибке плейбука на этапе запуска NGINX, так как и то и другое – веб сервер, и они оба используют одни и те же порты. Если это ваш случай – отключите и удалите Apache c Managed-Node-3:

Отключение:

root@Managed-Node-3:~# systemctl disable --now apache2
Synchronizing state of apache2.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable apache2
Removed "/etc/systemd/system/multi-user.target.wants/apache2.service".
root@Managed-Node-3:~#

Удаление:

root@Managed-Node-3:~# apt remove apache2
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  apache2-data apache2-utils
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
  apache2
0 upgraded, 0 newly installed, 1 to remove and 78 not upgraded.
After this operation, 465 kB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 76728 files and directories currently installed.)
Removing apache2 (2.4.58-1ubuntu8.8) ...
root@Managed-Node-3:~#

Запускаем плейбук и ожидаем результат исполнения:

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

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

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

TASK [Install PHP on CentOS] ************************************************************************************************************************************************************************
skipping: [Managed-Node-3]
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install PHP on Ubuntu] ************************************************************************************************************************************************************************
skipping: [Managed-Node-1]
skipping: [Managed-Node-2]
changed: [Managed-Node-3]

TASK [Install NGINX on CentOS] **********************************************************************************************************************************************************************
skipping: [Managed-Node-3]
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [Install NGINX on Ubuntu] **********************************************************************************************************************************************************************
skipping: [Managed-Node-1]
skipping: [Managed-Node-2]
changed: [Managed-Node-3]

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

TASK [Install MariaDB on CentOS] ********************************************************************************************************************************************************************
skipping: [Managed-Node-3]
ok: [Managed-Node-1]
ok: [Managed-Node-2]

TASK [Install MariaDB on Ubuntu] ********************************************************************************************************************************************************************
skipping: [Managed-Node-1]
skipping: [Managed-Node-2]
changed: [Managed-Node-3]

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

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

[root@Control-Node ansible]#

Плейбук успешно раскатался. И у нас появился новый тип результата исполнения таска – skipped. Если хост не соответствует заданному условию, он пропускается, без каких либо действий.

Посмотрите внимательно на всю выдачу Ansible, задачи для CentOS исполнены на серверах Managed-Node-1 и Managed-Node-2, а на Managed-Node-3 скипнуты, таски для Ubunty – наоборот.

Итоги:

Мы добавили новый сервер в наше тестовое окружение, и перестроили плейбук на работу с хостами с двумя видами ОС. В условиях when можно использовать любые факты собираемые Ansible, а так же свои переменные.

Следующий урок: Ansible практика – урок №5: Роли создание и применение.