⚙️ Паровой сервер ROADIT

Ansible: Паровой двигатель автоматизации и его внутреннее устройство

Представьте себе идеально отлаженный паровоз, который без единого рывка доставляет ваш код из точки разработки в точку назначения. Ansible — это именно такой механизм: agentless-оркестратор, который превращает рутинное управление серверами в слаженную работу паровой машины.

В этой статье мы разберём архитектуру Ansible до последнего винтика, поймём, как устроен его «котёл», и научимся запускать первые плейбуки.



Что такое Ansible?

Ansible — это инструмент управления конфигурациями и оркестрации с открытым исходным кодом, созданный Майклом ДеХааном (автором Cobbler и Func) и ныне развиваемый компанией Red Hat.

Главная философия Ansible — простота и отсутствие агентов. В отличие от Puppet или Chef, вам не нужно устанавливать демон на каждый управляемый сервер. Ansible работает поверх стандартного SSH (на Linux) или WinRM (на Windows), используя Python как «топливо» для выполнения задач.

Ключевые принципы:

  • Agentless — никаких демонов на клиентах.
  • Idempotent — многократное применение плейбука не ломает систему, если она уже в нужном состоянии.
  • Declarative — вы описываете желаемое состояние, а не последовательность команд.
  • Push-based — управляющий сервер сам «толкает» конфигурации к узлам.

Архитектура Ansible: из чего состоит паровая машина

Ansible — это не монолит, а набор взаимосвязанных компонентов. Разберём каждый «цилиндр» этого двигателя.

Control Node (Управляющий узел)

Это «кабина машиниста» — сервер или рабочая станция, с которой вы запускаете Ansible. Здесь хранятся:

  • Инвентаризационные файлы
  • Плейбуки
  • Роли
  • Шаблоны
  • Переменные

Требования:

  • ОС: Linux (RHEL, Ubuntu, Debian, CentOS) или macOS
  • Python: версия 3.8 или выше
  • Установленный Ansible

Windows не может быть Control Node (но может быть управляемым узлом через WinRM).

Managed Nodes (Управляемые узлы)

Это «вагоны», которыми вы управляете. На них должен быть:

  • SSH-сервер (для Linux/Unix)
  • WinRM (для Windows)
  • Python 2.7+ или 3.5+ (для Linux/Unix)

⚡ Важно

Ansible не требует установки специального ПО на managed nodes — достаточно стандартного SSH и Python.

Inventory (Инвентаризация)

Это «расписание движения поездов» — файл, в котором описаны все ваши серверы и их группировка.

Простой инвентарь (/etc/ansible/hosts или inventory.ini):

# Простой список хостов
web1.example.com
web2.example.com
db1.example.com

# Группировка по функциям
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

# Группировка по регионам
[moscow]
web1.example.com
db1.example.com

[piter]
web2.example.com

# Вложенные группы
[russia:children]
moscow
piter

# Переменные для группы
[webservers:vars]
http_port=80
max_requests=200

Динамический инвентарь (скрипт на Python, Bash или облачный плагин) позволяет автоматически получать список серверов из AWS, Azure, vSphere и других источников.

Playbooks (Плейбуки)

Это «инструкция по эксплуатации» — YAML-файлы, описывающие желаемое состояние системы.

Пример простого плейбука (deploy_web.yml):

---
- name: Установка и настройка веб-сервера
  hosts: webservers
  become: yes
  vars:
    http_port: 80
    document_root: /var/www/html

  tasks:
    - name: Установить пакет nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: yes
      when: ansible_os_family == "Debian"

    - name: Установить пакет httpd
      ansible.builtin.yum:
        name: httpd
        state: present
      when: ansible_os_family == "RedHat"

    - name: Создать директорию для сайта
      ansible.builtin.file:
        path: "{{ document_root }}"
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'

    - name: Развернуть индексную страницу
      ansible.builtin.copy:
        content: |
          <html>
          <head><title>RoadIT Steam Engine</title></head>
          <body><h1>Работает на Ansible!</h1></body>
          </html>
        dest: "{{ document_root }}/index.html"
        mode: '0644'

    - name: Запустить и включить сервис
      ansible.builtin.service:
        name: "{{ 'nginx' if ansible_os_family == 'Debian' else 'httpd' }}"
        state: started
        enabled: yes

    - name: Открыть порт в фаерволе
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: "{{ http_port }}"
        jump: ACCEPT
        comment: "Allow HTTP traffic"

Modules (Модули)

Это «инструменты в ящике инженера» — готовые функции для выполнения конкретных задач. Ansible поставляется с тысячами модулей:

  • ansible.builtin.apt/yum/dnf — управление пакетами
  • ansible.builtin.copy/template — работа с файлами
  • ansible.builtin.service/systemd — управление сервисами
  • ansible.builtin.user/group — управление учётными записями
  • ansible.builtin.command/shell — выполнение команд
  • ansible.builtin.file — работа с файловой системой

Список всех модулей:

ansible-doc -l

Facts (Факты)

Это «датчики давления и температуры» — информация о системе, которую Ansible собирает автоматически перед выполнением задач.

Посмотреть факты о хосте:

ansible web1.example.com -m ansible.builtin.setup

Или получить конкретный факт:

ansible web1.example.com -m ansible.builtin.setup -a "filter=ansible_default_ipv4"

Примеры фактов:

  • ansible_default_ipv4.address — IP-адрес
  • ansible_os_family — семейство ОС (Debian, RedHat)
  • ansible_memory_mb.total — объём RAM
  • ansible_processor_vcpus — количество CPU

Факты можно использовать в плейбуках:

- name: Вывести информацию о системе
  ansible.builtin.debug:
    msg: "Сервер {{ inventory_hostname }} работает на {{ ansible_distribution }} {{ ansible_distribution_version }}"

Roles (Роли)

Это «стандартизированные модули паровоза» — способ организации плейбуков для повторного использования.

Структура роли:

roles/
└── nginx/
    ├── defaults/
       └── main.yml      # Переменные по умолчанию
    ├── files/            # Статические файлы
    ├── handlers/
       └── main.yml      # Обработчики (restart service)
    ├── meta/
       └── main.yml      # Метаданные роли
    ├── tasks/
       └── main.yml      # Основные задачи
    ├── templates/        # Jinja2-шаблоны
       └── nginx.conf.j2
    └── vars/
        └── main.yml      # Переменные роли

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

---
- hosts: webservers
  roles:
    - nginx
    - common

Установка Ansible: запускаем паровой двигатель

На Control Node (Ubuntu/Debian):

# Обновить индексы пакетов
sudo apt update

# Установить Ansible
sudo apt install -y ansible

# Проверить версию
ansible --version

На Control Node (RHEL/CentOS):

# Включить репозиторий EPEL
sudo dnf install -y epel-release

# Установить Ansible
sudo dnf install -y ansible

# Или через pip (более свежая версия)
pip3 install ansible

Настройка SSH-доступа

Ansible требует беспарольного SSH-доступа к управляемым узлам:

# Сгенерировать SSH-ключ (если ещё нет)
ssh-keygen -t rsa -b 4096 -f ~/.ssh/ansible_rsa

# Скопировать ключ на управляемый узел
ssh-copy-id -i ~/.ssh/ansible_rsa.pub admin@web1.example.com

# Проверить доступ
ssh -i ~/.ssh/ansible_rsa admin@web1.example.com

Настроить использование ключа в Ansible через ansible.cfg или inventory:

[all:vars]
ansible_ssh_private_key_file=~/.ssh/ansible_rsa
ansible_user=admin

Первый запуск: Ad-Hoc команды

Прежде чем писать плейбуки, попробуйте Ad-Hoc команды — разовые задачи, выполняемые напрямую из командной строки.

Проверка доступности хостов:

ansible all -m ansible.builtin.ping

Получение информации о системе:

ansible web1.example.com -m ansible.builtin.setup -a "filter=ansible_*_mb"

Выполнение команды:

ansible all -m ansible.builtin.command -a "uptime"

Установка пакета:

ansible webservers -m ansible.builtin.apt -a "name=nginx state=present" --become

Перезапуск сервиса:

ansible webservers -m ansible.builtin.service -a "name=nginx state=restarted" --become

Копирование файла:

ansible all -m ansible.builtin.copy -a "src=/local/file.txt dest=/remote/file.txt mode=0644" --become

Флаги:

  • -m — модуль
  • -a — аргументы модуля
  • --become — выполнить с правами root (sudo)
  • -i inventory.ini — использовать конкретный инвентарь

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

Создайте файл test_playbook.yml:

---
- name: Тестовый плейбук
  hosts: all
  gather_facts: yes
  
  tasks:
    - name: Вывести приветствие
      ansible.builtin.debug:
        msg: "Привет от {{ ansible_hostname }}!"
    
    - name: Проверить свободное место
      ansible.builtin.command: df -h /
      register: disk_usage
      changed_when: false
    
    - name: Показать результат
      ansible.builtin.debug:
        var: disk_usage.stdout_lines

Запустите:

ansible-playbook -i inventory.ini test_playbook.yml

С флагами для отладки:

# Подробный вывод
ansible-playbook -i inventory.ini test_playbook.yml -v

# Очень подробный вывод
ansible-playbook -i inventory.ini test_playbook.yml -vvv

# Проверка синтаксиса
ansible-playbook -i inventory.ini test_playbook.yml --syntax-check

# Dry-run (проверка без изменений)
ansible-playbook -i inventory.ini test_playbook.yml --check

# Выполнить только определённые задачи
ansible-playbook -i inventory.ini test_playbook.yml --tags "configuration"

Конфигурация: ansible.cfg

Файл ansible.cfg настраивает поведение Ansible. Приоритет файлов (от высшего к низшему):

  1. Переменная окружения ANSIBLE_CONFIG
  2. ./ansible.cfg в текущей директории
  3. ~/.ansible.cfg в домашней директории
  4. /etc/ansible/ansible.cfg глобальный

Пример конфигурации:

[defaults]
# Путь к инвентарю
inventory = ./inventory.ini

# Отключить проверку хостов (для разработки!)
host_key_checking = False

# Таймаут SSH
timeout = 30

# Количество параллельных хостов
forks = 10

# Логирование
log_path = /var/log/ansible.log

# Формат вывода
stdout_callback = yaml

# Использовать fact caching
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
# Ускорить SSH
pipelining = True
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

Best Practices: правила эксплуатации паровоза

Используйте версии модулей

# Хорошо
ansible.builtin.apt:
  name: nginx
  state: present

# Плохо (неявный namespace)
apt:
  name: nginx
  state: present

Всегда указывайте state

# Хорошо
ansible.builtin.package:
  name: nginx
  state: latest

# Плохо (неясно, что произойдёт)
ansible.builtin.package:
  name: nginx

Используйте handlers для перезапуска сервисов

tasks:
  - name: Обновить конфигурацию
    ansible.builtin.template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

handlers:
  - name: restart nginx
    ansible.builtin.service:
      name: nginx
      state: restarted

Применяйте теги для гибкости

tasks:
  - name: Установить пакеты
    ansible.builtin.apt:
      name: "{{ packages }}"
    tags:
      - install
      - packages
  
  - name: Настроить сервис
    ansible.builtin.template:
      src: config.j2
      dest: /etc/service.conf
    tags:
      - configure

Запуск с тегами:

ansible-playbook site.yml --tags "install"
ansible-playbook site.yml --skip-tags "configure"

Храните секреты в Ansible Vault

# Создать зашифрованный файл
ansible-vault create secrets.yml

# Зашифровать существующий
ansible-vault encrypt secrets.yml

# Редактировать
ansible-vault edit secrets.yml

# Посмотреть
ansible-vault view secrets.yml

# Запустить плейбук с vault
ansible-playbook site.yml --ask-vault-pass
# или
ansible-playbook site.yml --vault-password-file ~/.vault_pass

Используйте when для условного выполнения

tasks:
  - name: Установить nginx только на Debian
    ansible.builtin.apt:
      name: nginx
    when: ansible_os_family == "Debian"
  
  - name: Установить httpd только на RedHat
    ansible.builtin.yum:
      name: httpd
    when: ansible_os_family == "RedHat"

Тестируйте с –check и –diff

ansible-playbook site.yml --check --diff

Отладка: когда паровоз буксует

Включите подробное логирование:

export ANSIBLE_DEBUG=1
ansible-playbook site.yml -vvv

Проверьте подключение:

ansible all -m ansible.builtin.ping -vvv

Посмотрите факты:

ansible hostname -m ansible.builtin.setup | less

Используйте ansible-lint:

# Установить
pip install ansible-lint

# Проверить плейбук
ansible-lint site.yml

Проверьте синтаксис YAML:

python -c "import yaml; yaml.safe_load(open('playbook.yml'))"

Заключение

Ansible — это не просто инструмент, а целая философия управления инфраструктурой. Его архитектура проста, но мощна: один управляющий узел, SSH-соединения, модули на Python и декларативные плейбуки в YAML.

Помните: хороший сисадмин — это не тот, кто всё делает руками, а тот, кто построил паровую машину, которая делает это за него.



⚙️ Машинное отделение ROADIT благодарит за прочтение.
Больше команд, шпаргалок и обзоров — на roadit.ru и в нашем Телеграф-канале.
📋 Все команды

Оставьте комментарий