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

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

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

Какова роль ролей?

Задача плейбука – подготовить сервер по заданной инструкции. Роль – часть общей задачи, обычно объединенная по логическому принципу и выделенная отдельную подзадачу. Например, роль, объединяющая всю установку пакетов или таски связанные с одним сервисом.

Роли создание и применение

Роли могут иметь разнообразные названия и содержать различные задачи, но главное правило Ansible – чем понятнее и логичнее, тем лучше.

Шаг 1: Выделяем таски в отдельные роли

У нас сейчас присутствует два вида задач – на установку и на запуск сервисов. В данном случае сервис – отличный общий признак, по которому таски можно выделить в роли.

Создадим директорию roles и поддиректории  roles/php, roles/nginx и roles/mariadb, а в каждой поддиректории еще одну директорию tasks:

[root@Control-Node ansible]# mkdir roles
[root@Control-Node ansible]# mkdir -p roles/php/tasks roles/nginx/tasks roles/mariadb/tasks
[root@Control-Node ansible]#

Ранее мы уже делили таски по такому же признаку, когда присваивали теги. Вынесем соответствующие задачи в файл main.yml внутри каждой директории tasks.

Таски PHP в файл roles/php/tasks/main.yml:

---
- 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"

Задачи, связанные с NGINX в roles/nginx/tasks/main.yml:

---
- 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

MariaDB в roles/mariadb/tasks/main.yml:

---
- 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

Мы вынесли таски в отдельные роли. Название ролей соответствуют названиям поддиректорий внутри директории roles.

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

Теперь поправим плейбук, удалим уз него все таски и заменим их ролями. Обновленный файл install_lemp.yml будет иметь следующий вид:

---
- hosts: all
  roles:
    - php
    - nginx
    - mariadb

Запустим Ansible и проверим работу плейбука:

[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 [php : Install PHP on CentOS] ******************************************************************************************************************************************************************
skipping: [Managed-Node-3]
ok: [Managed-Node-1]
ok: [Managed-Node-2]

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

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

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

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

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

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

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

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=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

[root@Control-Node ansible]#

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

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

Шаг 3: Создаем новую роль

Давайте, в качестве закрепления материала, создадим новую роль с нуля. Мы подготавливаем веб сервера, а значит, посетители должны иметь доступ к основным портам – 80 (http) и 443 (https).

На CentOS они обычно закрыты файерволом. А на минимальной установке Ubuntu файрвол по дефолту не установлен. Нам не нужно гадать, установлен файервол или нет,  открыты порты или нет, пусть Ansible просто обеспечит нам желаемый результат.

Создадим поддиректории roles/firewalld и roles/firewalld/tasks:

[root@Control-Node ansible]# mkdir roles/firewalld roles/firewalld/tasks
[root@Control-Node ansible]#

Далее создаем файл roles/firewalld/tasks/main.yml следующего содержания:

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

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

- name: "Ensure Firewalld is started and enabled"
  ansible.builtin.service:
    name: firewalld
    state: started
    enabled: yes
  tags:
    - start
    - firewalld

- name: "Open SSH service permanently in public zone"
  ansible.posix.firewalld:
    zone: public
    service: ssh
    permanent: true
    state: enabled
  tags:
    - firewalld

- name: "Open HTTP service permanently in public zone"
  ansible.posix.firewalld:
    zone: public
    service: http
    permanent: true
    state: enabled
  tags:
    - firewalld

- name: "Open HTTPS service permanently in public zone"
  ansible.posix.firewalld:
    zone: public
    service: https
    permanent: true
    state: enabled
  tags:
    - firewalld

- name: "Reload Firewalld to apply changes"
  ansible.builtin.service:
    name: firewalld
    state: restarted
  tags:
    - firewalld 

Первым делом мы должны быть уверены, что файрвол присутствует, для этого сначала идут таски по его установке. Далее запускаем файрвол и добавляем в публичный доступ сервисы SSH, HTTP и HTTPS.

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

Добавим роль в плейбук:

---
- hosts: all
  roles:
    - php
    - nginx
    - mariadb
    - firewalld

Запустим плейбук с тегом firewalld, так мы исключим из раскатки таски, которые ранее уже неоднократно исполнялись:

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

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

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

TASK [firewalld : Install firewalld on CentOS] ******************************************************************************************************************************************************
skipping: [Managed-Node-3]
changed: [Managed-Node-1]
changed: [Managed-Node-2]

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

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

TASK [firewalld : Open SSH service permanently in public zone] **************************************************************************************************************************************
ok: [Managed-Node-3]
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [firewalld : Open HTTP service permanently in public zone] *************************************************************************************************************************************
changed: [Managed-Node-1]
changed: [Managed-Node-3]
changed: [Managed-Node-2]

TASK [firewalld : Open HTTPS service permanently in public zone] ************************************************************************************************************************************
changed: [Managed-Node-1]
changed: [Managed-Node-3]
changed: [Managed-Node-2]

TASK [firewalld : Reload Firewalld to apply changes] ************************************************************************************************************************************************
changed: [Managed-Node-3]
changed: [Managed-Node-1]
changed: [Managed-Node-2]

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

[root@Control-Node ansible]#

Ansible успешно отработал. Firewalld был обнавлен/установлен на хостах, а доступ к сервисам открыт. Теперь наши сервера готовы принимать запросы, можете проверить с помощью curl:

[root@Control-Node ansible]# curl -I 192.168.151
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Wed, 10 Dec 2025 10:30:24 GMT
Content-Type: text/html
Content-Length: 2713881
Last-Modified: Tue, 04 Jun 2024 22:57:12 GMT
Connection: keep-alive
ETag: "665f9bc8-296919"
Accept-Ranges: bytes

[root@Control-Node ansible]#

Или вбив IP адрес хоста в браузере.

Итоги:

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

Следующий урок: Ansible практика – урок №6 Оптимизация плейбука с помощью block.