Ansible полезен, когда настройку можно повторить на новой машине, а второй запуск не ломает уже работающую конфигурацию. В этом практикуме вы установите Nginx на отдельную Ubuntu VM, создадите страницу из шаблона, проверите конфигурацию до применения и убедитесь, что HTTP-ответ правильный.
Среда: управляющая Ubuntu 24.04 и новая учебная Ubuntu VM с SSH и sudo. Конфигурация Nginx на VM будет заменена учебной: не выполняйте этот playbook на сервере с существующими сайтами. Используйте собственную VM в частной сети. Адрес 192.0.2.20 в примере заменяется её настоящим IP.
1. Проверьте транспорт до Ansible
На управляющей машине:
sudo apt update
sudo apt install ansible openssh-client
ansible --version
ssh deploy@192.0.2.20
sudo -v
exit
Пользователь deploy должен существовать на VM. Проверка sudo -v выполняется внутри SSH-сеанса и подтверждает возможность повышения прав. При первом подключении проверьте отпечаток ключа хоста через консоль VM. Если SSH вручную не работает, запуск Ansible не исправит сеть, пользователя или ключ.
Для сайтов, ботов и pet-проектов можно использовать Beget: виртуальный хостинг от 420 ₽/мес., VPS от 330 ₽/мес. и тестовый период.
Пароль sudo можно запрашивать интерактивно через --ask-become-pass. Не записывайте его в inventory. В лаборатории допустим обычный пользователь с sudo; в команде границы прав и способ их предоставления согласуются отдельно.
2. Создайте структуру и inventory
ansible-lab/
inventory.ini
site.yml
templates/
nginx.conf.j2
index.html.j2
Файл inventory.ini:
[web]
lab-web ansible_host=192.0.2.20 ansible_user=deploy
[web:vars]
ansible_python_interpreter=/usr/bin/python3
lab-web — логическое имя узла, ansible_host — реальный адрес. Выполните из каталога проекта:
ansible-inventory -i inventory.ini --graph
ansible web -i inventory.ini -m ansible.builtin.ping
Ожидайте группу web и ответ pong. Это проверка SSH и исполнения Python-модуля, не ICMP. Для обычного Ubuntu образа Python 3 уже установлен; если его нет, установите через консоль VM до упражнений с модулями.
3. Подготовьте реальный конфигурационный шаблон
Файл templates/nginx.conf.j2 содержит весь учебный конфиг, поэтому команда проверки может проверить его независимо от текущего файла:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
events { worker_connections 256; }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen {{ http_port }};
server_name _;
root /var/www/devops-lab;
location / { try_files $uri $uri/ =404; }
}
}
Файл templates/index.html.j2:
<!doctype html>
<html lang="ru">
<meta charset="utf-8">
<title>Ansible lab</title>
<h1>{{ site_message }}</h1>
<p>Host: {{ inventory_hostname }}</p>
</html>
Не добавляйте в страницу текущую дату: тогда каждый запуск будет менять файл, даже когда желаемое состояние осталось тем же. Для обучения идемпотентности содержимое должно быть стабильным.
4. Напишите playbook с проверкой результата
Полный site.yml:
---
- name: Configure an isolated Nginx lab
hosts: web
become: true
serial: 1
vars:
http_port: 8081
site_message: 'Hello from Ansible'
tasks:
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
cache_valid_time: 3600
- name: Create document root
ansible.builtin.file:
path: /var/www/devops-lab
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Render page
ansible.builtin.template:
src: templates/index.html.j2
dest: /var/www/devops-lab/index.html
owner: www-data
group: www-data
mode: '0644'
- name: Validate and install Nginx configuration
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: true
validate: '/usr/sbin/nginx -t -c %s'
notify: Reload Nginx
- name: Ensure Nginx is running
ansible.builtin.service:
name: nginx
enabled: true
state: started
- name: Apply pending configuration before verification
ansible.builtin.meta: flush_handlers
- name: Read page from the managed host
ansible.builtin.uri:
url: 'http://127.0.0.1:{{ http_port }}/'
return_content: true
status_code: 200
register: page
when: not ansible_check_mode
- name: Verify expected page text
ansible.builtin.assert:
that:
- site_message in page.content
when: not ansible_check_mode
handlers:
- name: Reload Nginx
ansible.builtin.service:
name: nginx
state: reloaded
validate подставляет временный файл на место %s. При ошибке синтаксиса новый конфиг не заменит действующий. backup: true сохраняет предыдущий файл при изменении, но не создаёт полноценную процедуру восстановления всего сервера.
Handler вызывается только после изменения конфигурации. flush_handlers запускает его до HTTP-проверки; иначе проверка могла бы проверить старую конфигурацию, а reload выполнился бы только в конце play. uri работает на управляемом узле, поэтому loopback относится к VM, не к вашему ноутбуку.
5. Запустите по этапам
ansible-playbook -i inventory.ini site.yml --syntax-check
ansible-playbook -i inventory.ini site.yml --check --diff --ask-become-pass
ansible-playbook -i inventory.ini site.yml --limit lab-web --ask-become-pass
ansible-playbook -i inventory.ini site.yml --limit lab-web --ask-become-pass
Первый реальный запуск установит пакет и файлы. Второй при неизменной среде должен завершиться без failed/unreachable и обычно с changed=0. Проверяйте конкретные tasks, если значение другое: например, истёк период cache или изменился шаблон.
Check mode на совершенно пустой VM не всегда сможет пройти шаг template: пакет Nginx ещё не установлен фактически и команда nginx -t может отсутствовать. Это ограничение предварительного моделирования зависимых шагов, а не основание отключать проверку в реальном запуске. Отдельно проверяйте diff без секретных значений.
6. Измените и намеренно сломайте конфигурацию
Замените site_message на другой текст и запустите playbook. Изменится только страница; reload для такого изменения не нужен. Затем добавьте неизвестную директиву в шаблон Nginx. Запуск должен остановиться на validate, а прежняя страница останется доступна. Уберите директиву и повторите проверку.
Так вы проверяете не только «один раз получилось», но и границу отказа. При подключении нескольких VM параметр serial: 1 обрабатывает их по одной. Сам по себе он не обеспечивает zero downtime: это зависит от балансировки, готовности приложения и того, какие изменения выполняются.
Как разбирать ошибки
- UNREACHABLE: проверьте адрес, SSH-порт, пользователя, ключ и known_hosts обычной командой ssh.
- Missing sudo password: используйте интерактивный
--ask-become-passлибо согласованный механизм sudo. - Port already in use: на VM выполните
sudo ss -lntpи выберите свободный учебный порт. - HTTP 403: проверьте права document root, наличие index.html и итоговый конфиг через
sudo nginx -T.
Задание: добавьте второй учебный узел с другим site_message через host vars и докажите, что оба узла воспроизводимы. Готовая работа включает inventory без паролей, все шаблоны, вывод успешной проверки и объяснение второго запуска.
Официальные детали: template и validate, handlers, check mode.
Подборка онлайн-курсов для разработчиков — Python, Java, веб и DevOps.
14 практических страниц: SSH, firewall, обновления, резервные копии, WordPress, Docker и действия при признаках взлома.
Проверим SSH, firewall, обновления, резервные копии, Docker и журналы. Аудит — от 9 900 ₽.
Статья может содержать партнёрские ссылки. Это не влияет на стоимость для вас, но помогает развивать блог.

