Введение
Идемпотентность означает, что плейбук можно запускать многократно, и он будет вносить изменения в систему только в том случае, если желаемое состояние отсутствует или отличается от текущего.
В этой лабораторной работе вы будете использовать стандартные модули Ansible для создания каталогов и конфигурационных файлов для псевдонимов хостов, а затем запустите плейбук дважды, чтобы доказать, что второй запуск не вносит изменений.
Создание проекта для практики идемпотентности
На этом этапе вы создадите небольшой проект Ansible с двумя локальными псевдонимами управляемых хостов. Каждый псевдоним записывает данные в свой собственный каталог, что позволит вам видеть результаты для конкретного хоста, оставаясь при этом в рамках одной виртуальной машины RHEL 10.
Начните с рабочей области LabEx по умолчанию.
cd /home/labex/project
Опция -p указывает команде mkdir создавать родительские каталоги при необходимости и завершаться успешно, если каталог уже существует.
mkdir -p rhce-ansible/{inventory/group_vars,playbooks,managed,reports}
cd rhce-ansible
Создайте настройки проекта по умолчанию, которые указывают Ansible на ваш инвентарь и отключают создание файлов повторных попыток (retry files).
cat > ansible.cfg <<'EOF'
[defaults]
inventory = ./inventory/hosts
host_key_checking = False
retry_files_enabled = False
EOF
Каталог managed будет содержать файлы, созданные плейбуком, а reports — сохраненные результаты выполнения плейбука. Разделение этих данных упрощает сравнение желаемого содержимого с результатами работы Ansible.
Определение локальных управляемых хостов и переменных
На этом этапе вы создадите инвентарь и групповые переменные. Псевдонимы используют ansible_connection=local, что означает, что Ansible нацеливается на именованные хосты, выполняя операции безопасно на этой же виртуальной машине.
Перед выполнением команд на этом этапе вернитесь в каталог проекта Ansible. Это обеспечит стабильность команд, даже если LabEx запускает каждый этап отдельно.
cd /home/labex/project/rhce-ansible
Создайте два псевдонима хостов приложений в одной группе.
cat > inventory/hosts <<'EOF'
[app]
app1 ansible_connection=local
app2 ansible_connection=local
EOF
Групповые переменные описывают желаемое состояние, общее для всех хостов в группе.
cat > inventory/group_vars/app.yml <<'EOF'
app_owner: labex
app_environment: training
app_message: Managed by Ansible common modules
EOF
Убедитесь, что Ansible видит оба хоста.
ansible app --list-hosts
В выводе должны быть указаны app1 и app2. Эта проверка полезна перед написанием плейбука, так как плей, нацеленный на группу app, может повлиять только на те хосты, которые инвентарь разрешает в эту группу.
Написание плейбука желаемого состояния
На этом этапе вы напишете плейбук, использующий модули file, copy и lineinfile. Эти модули описывают конечное состояние вместо ручного выполнения команд оболочки.
Перед выполнением команд на этом этапе вернитесь в каталог проекта Ansible.
cd /home/labex/project/rhce-ansible
Создайте плейбук. Пути включают {{ inventory_hostname }}, чтобы каждый псевдоним имел свой собственный каталог вывода.
cat > playbooks/common-modules.yml <<'EOF'
---
- name: Configure app host directories with common modules
hosts: app
gather_facts: false
tasks:
- name: Ensure host directory exists
ansible.builtin.file:
path: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}"
state: directory
mode: '0755'
- name: Install base application configuration
ansible.builtin.copy:
dest: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}/app.conf"
content: |
owner={{ app_owner }}
environment={{ app_environment }}
message={{ app_message }}
mode: '0644'
- name: Ensure managed message is present
ansible.builtin.lineinfile:
path: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}/app.conf"
line: "message={{ app_message }}"
create: true
mode: '0644'
EOF
Задача file создает каталог, copy записывает полную конфигурацию, а lineinfile демонстрирует, как обеспечить наличие конкретной строки. Эти модули сравнивают текущее состояние с желаемым, именно поэтому они являются идемпотентными.
Перед запуском нового плейбука выполните проверку синтаксиса.
ansible-playbook playbooks/common-modules.yml --syntax-check
Запуск плейбука и проверка файлов
На этом этапе вы запустите плейбук желаемого состояния в первый раз. Первый запуск должен сообщить об изменениях, так как целевые файлы еще не существуют. Перед выполнением команд на этом этапе вернитесь в каталог проекта Ansible.
cd /home/labex/project/rhce-ansible
Запустите плейбук и сохраните вывод для последующего сравнения.
ansible-playbook playbooks/common-modules.yml | tee reports/first-run.txt
Первый запуск должен показать изменения, так как каталоги хостов и файлы app.conf создаются впервые. Команда tee позволяет наблюдать за процессом и одновременно сохранять вывод для проверки идемпотентности.
Проверьте файлы, созданные Ansible для каждого хоста.
cat managed/app1/app.conf managed/app2/app.conf
Оба файла должны содержать одинаковые значения владельца, среды и сообщения, но они находятся в разных каталогах псевдонимов хостов. Это показывает, что плейбук применил одно и то же желаемое состояние к каждому хосту из инвентаря.
Повторный запуск плейбука для подтверждения идемпотентности
На этом этапе вы снова запустите тот же плейбук. Поскольку файлы уже соответствуют желаемому состоянию, Ansible должен сообщить об отсутствии изменений для обоих хостов. Перед выполнением команд на этом этапе вернитесь в каталог проекта Ansible.
cd /home/labex/project/rhce-ansible
Запустите плейбук во второй раз и сохраните вывод.
ansible-playbook playbooks/common-modules.yml | tee reports/second-run.txt
Ищите changed=0 в строках сводки (recap).
grep -E 'app[12].*changed=0' reports/second-run.txt
changed=0 при втором запуске — это ключевой признак идемпотентности. Это означает, что модули проверили существующие файлы и обнаружили, что исправления не требуются.
Резюме
Вы создали проект Ansible, использовали стандартные модули для описания желаемого состояния, запустили плейбук и доказали его идемпотентность вторым запуском, который не внес никаких изменений.


