Ansible и Infrastructure as Code: автоматизация настройки серверов

Когда у вас один сервер, его можно настроить вручную. Когда их десять — это уже утомительно. Когда сто — без автоматизации не обойтись. Infrastructure as Code (IaC) — это подход, при котором инфраструктура описывается в виде кода, который можно версионировать, тестировать и многократно применять. Ansible — один из самых популярных инструментов для реализации IaC, который не требует установки агентов на целевые серверы и использует простой язык YAML.

В этой статье мы подробно разберём:

  • Что такое Infrastructure as Code и зачем он нужен.
  • Что такое Ansible, его архитектура и преимущества.
  • Установку и настройку Ansible.
  • Инвентарь (Inventory) — описание серверов.
  • Плейбуки (Playbooks) — сценарии автоматизации.
  • Модули, переменные, шаблоны, условия и циклы.
  • Роли (Roles) — структурирование плейбуков.
  • Ansible Vault — хранение секретов.
  • Практические примеры: настройка веб-сервера, деплой приложения.
  • Интеграцию с CI/CD.
  • Лучшие практики и частые ошибки.

1. Что такое Infrastructure as Code (IaC)

Infrastructure as Code — это практика управления инфраструктурой (серверы, сети, базы данных, балансировщики) через машиночитаемые файлы конфигурации, а не через ручные операции или интерактивные панели.

Преимущества IaC:

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

Инструменты IaC:

  • Ansible — безагентный, простой, на YAML.
  • Terraform — для управления облачными ресурсами (AWS, Yandex Cloud, DigitalOcean).
  • Puppet — требует агентов, сложнее.
  • Chef — тоже требует агентов, используется реже.
  • SaltStack — мощный, но сложный.

Мы сосредоточимся на Ansible, так как он наиболее дружелюбен для начинающих и не требует установки агентов на серверы.

2. Что такое Ansible

Ansible — это open-source инструмент для автоматизации настройки, управления конфигурациями и развёртывания приложений. Он был создан в 2012 году и сейчас поддерживается Red Hat.

2.1 Архитектура Ansible

Ansible работает по модели push: управляющая машина (control node) подключается к целевым серверам (managed nodes) по SSH и выполняет задачи.

Компоненты:

  • Control node — машина, с которой запускается Ansible (обычно ваш компьютер или CI-сервер).
  • Managed nodes — целевые серверы, которыми управляют.
  • Inventory — файл со списком серверов и их группировкой.
  • Playbook — YAML-файл с описанием задач.
  • Module — единица работы (установка пакета, копирование файла, запуск сервиса).
  • Role — структурированный набор плейбуков, шаблонов и переменных.
  • Ansible Vault — шифрование секретов.

Ключевая особенность: Ansible не требует установки агента на целевые серверы. Всё, что нужно — SSH и Python (обычно уже установлен).

2.2 Преимущества Ansible

  • Безагентность — не нужно ставить и обновлять агенты.
  • Простота — YAML-синтаксис, легко читается.
  • Идемпотентность — повторный запуск не меняет состояние, если всё уже настроено.
  • Мощность — более 3000 модулей для разных задач.
  • Интеграция — работает с облаками, Docker, Kubernetes, CI/CD.

3. Установка Ansible

3.1 Установка на Ubuntu/Debian

Bash
sudo apt update
sudo apt install ansible
ansible --version

3.2 Установка на CentOS/RHEL/Rocky Linux

Bash
sudo dnf install epel-release
sudo dnf install ansible
ansible --version

3.3 Установка на macOS

Bash
brew install ansible

3.4 Установка через pip (универсальный способ)

Bash
sudo apt install python3-pip
pip3 install ansible

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

Ansible подключается к серверам по SSH. Убедитесь, что у вас есть SSH-ключи и доступ к целевым серверам.

Генерация ключа (если ещё нет):

Bash
ssh-keygen -t ed25519

Копирование ключа на сервер:

Bash
ssh-copy-id user@server

Проверка подключения:

Bash
ssh user@server

ВАЖНО! Если при запуске Ansible появляется ошибка «Permission denied (publickey)», проверь, добавлен ли ключ в ssh-agent:

Bash
ssh-add ~/.ssh/id_ed25519

4. Инвентарь (Inventory)

Inventory — это файл, в котором перечислены серверы, сгруппированные по назначению.

4.1 Простой инвентарь

Создайте файл inventory.ini:

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

Bash
ansible all -i inventory.ini -m ping

Если всё настроено правильно, вы увидите:

4.2 Группы и подгруппы

4.3 Динамический инвентарь

Ansible может получать список серверов из облака (AWS, Yandex Cloud) через плагины. Например, для AWS:

Bash
ansible-inventory -i aws_ec2.yml --graph

Где aws_ec2.yml — файл конфигурации плагина.

Пример для AWS:

YAML
plugin: aws_ec2
regions:
  - us-east-1
filters:
  tag:Environment: production
keyed_groups:
  - key: tags.Role
    prefix: role

5. Плейбуки (Playbooks)

Playbook — это YAML-файл, который описывает, какие задачи выполнить на каких серверах.

5.1 Структура плейбука

YAML
---
- name: Установка и настройка Nginx
  hosts: webservers
  become: yes

  tasks:
    - name: Обновление кеша apt
      apt:
        update_cache: yes

    - name: Установка Nginx
      apt:
        name: nginx
        state: present

    - name: Запуск и включение Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

Разбор:

  • name — описание плейбука.
  • hosts — группа серверов из инвентаря.
  • become: yes — выполнять задачи от root (аналог sudo).
  • tasks — список задач.
  • Каждая задача использует модуль (apt, systemd) и параметры.

5.2 Запуск плейбука

Bash
ansible-playbook -i inventory.ini playbook.yml

Проверка без изменений (dry run):

Bash
ansible-playbook -i inventory.ini playbook.yml --check

Просмотр различий:

Bash
ansible-playbook -i inventory.ini playbook.yml --diff

5.3 Идемпотентность

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

Например, если Nginx уже установлен, модуль apt не будет ничего делать и вернёт changed: false.

6. Модули, переменные, шаблоны, условия и циклы

6.1 Модули

Ansible имеет тысячи модулей. Вот самые популярные:

МодульНазначение
apt / yum / dnfУправление пакетами
copyКопирование файлов
templateКопирование с подстановкой переменных
fileУправление файлами и директориями
systemd / serviceУправление сервисами
user / groupУправление пользователями и группами
gitКлонирование репозиториев
command / shellВыполнение команд
docker_containerУправление Docker-контейнерами
mysql_db / mysql_userУправление MySQL

Пример с модулем copy:

YAML
- name: Копирование конфигурации Nginx
  copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
  notify: reload nginx

6.2 Переменные

Переменные позволяют параметризовать плейбуки.

YAML
- name: Установка пакетов
  hosts: webservers
  vars:
    packages:
      - nginx
      - php8.1-fpm
      - mysql-client

  tasks:
    - name: Установка пакетов
      apt:
        name: "{{ packages }}"
        state: present

Переменные можно задавать в:

  • vars в плейбуке.
  • Отдельных файлах (vars/main.yml в роли).
  • Инвентаре (групповые и хостовые переменные).
  • Командной строке (-e "var=value").

6.3 Шаблоны (Templates)

Шаблоны — это файлы с подстановкой переменных. Используется Jinja2.

Пример шаблона templates/nginx.conf.j2:

Nginx
server {
    listen 80;
    server_name {{ server_name }};
    root {{ document_root }};

    location / {
        try_files $uri $uri/ =404;
    }
}

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

YAML
- name: Генерация конфигурации Nginx
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/sites-available/{{ server_name }}.conf
  notify: reload nginx

6.4 Условия (when)

YAML
- name: Установка пакета только на Ubuntu
  apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"

Другие примеры:

YAML
- name: Запуск только если файл существует
  command: /opt/script.sh
  when: ansible_facts['distribution'] == "Ubuntu"

6.5 Циклы (loop)

YAML
- name: Создание пользователей
  user:
    name: "{{ item }}"
    state: present
  loop:
    - user1
    - user2
    - user3

С переменными:

YAML
- name: Установка пакетов
  apt:
    name: "{{ item }}"
    state: present
  loop: "{{ packages }}"

6.6 Обработчики (Handlers)

Обработчики выполняются только при изменении задачи.

YAML
tasks:
  - name: Копирование конфигурации
    copy:
      src: nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: reload nginx

handlers:
  - name: reload nginx
    systemd:
      name: nginx
      state: reloaded

7. Роли (Roles)

Роли — это способ структурировать плейбуки для повторного использования.

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

7.2 Создание роли

Bash
ansible-galaxy init roles/nginx

7.3 Пример роли для Nginx

roles/nginx/tasks/main.yml:

YAML
---
- name: Установка Nginx
  apt:
    name: nginx
    state: present

- name: Копирование конфигурации
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/sites-available/default
  notify: reload nginx

- name: Запуск Nginx
  systemd:
    name: nginx
    state: started
    enabled: yes

roles/nginx/handlers/main.yml:

YAML
---
- name: reload nginx
  systemd:
    name: nginx
    state: reloaded

roles/nginx/defaults/main.yml:

YAML
server_name: example.com
document_root: /var/www/html

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

YAML
- name: Настройка веб-сервера
  hosts: webservers
  become: yes
  roles:
    - nginx

Или с передачей переменных:

YAML
- name: Настройка веб-сервера
  hosts: webservers
  become: yes
  roles:
    - role: nginx
      vars:
        server_name: mysite.com
        document_root: /var/www/mysite

7.5 Ansible Galaxy

Ansible Galaxy — это репозиторий готовых ролей. Можно скачать и использовать.

Bash
# Поиск роли
ansible-galaxy search nginx

# Установка роли
ansible-galaxy install geerlingguy.nginx

Установка из файла requirements.yml:

YAML
roles:
  - geerlingguy.nginx
  - geerlingguy.mysql
Bash
ansible-galaxy install -r requirements.yml

8. Ansible Vault — хранение секретов

Vault позволяет шифровать пароли, ключи и другие секреты.

8.1 Создание зашифрованного файла

Bash
ansible-vault create secrets.yml

Вас попросят ввести пароль. Затем откроется редактор, где можно ввести секреты:

YAML
db_password: super_secret_password
api_key: my_api_key_12345

8.2 Просмотр и редактирование

Bash
ansible-vault view secrets.yml
ansible-vault edit secrets.yml

8.3 Шифрование существующего файла

Bash
ansible-vault encrypt vars.yml

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

YAML
- name: Использование секретов
  hosts: dbservers
  vars_files:
    - secrets.yml
  tasks:
    - name: Создание базы данных
      mysql_db:
        name: mydb
        login_user: root
        login_password: "{{ db_password }}"

8.5 Запуск с паролем

Bash
ansible-playbook playbook.yml --ask-vault-pass

Или через файл с паролем:

Bash
echo "my_vault_password" > .vault_pass
ansible-playbook playbook.yml --vault-password-file .vault_pass

9. Практические примеры

9.1 Настройка LEMP-стека (Nginx, MySQL, PHP-FPM)

YAML
---
- name: Настройка LEMP-стека
  hosts: webservers
  become: yes
  vars:
    db_name: myapp
    db_user: myuser
    db_password: "{{ vault_db_password }}"

  tasks:
    - name: Обновление кеша apt
      apt:
        update_cache: yes

    - name: Установка Nginx
      apt:
        name: nginx
        state: present

    - name: Установка MySQL
      apt:
        name: mysql-server
        state: present

    - name: Установка PHP и расширений
      apt:
        name:
          - php8.1-fpm
          - php8.1-mysql
          - php8.1-curl
          - php8.1-gd
        state: present

    - name: Создание базы данных
      mysql_db:
        name: "{{ db_name }}"
        state: present
        login_user: root
        login_password: "{{ vault_db_root_password }}"

    - name: Создание пользователя MySQL
      mysql_user:
        name: "{{ db_user }}"
        password: "{{ db_password }}"
        priv: "{{ db_name }}.*:ALL"
        state: present
        login_user: root
        login_password: "{{ vault_db_root_password }}"

    - name: Запуск сервисов
      systemd:
        name: "{{ item }}"
        state: started
        enabled: yes
      loop:
        - nginx
        - mysql
        - php8.1-fpm

9.2 Деплой приложения из Git

YAML
---
- name: Деплой приложения
  hosts: webservers
  become: yes
  vars:
    app_dir: /var/www/myapp
    repo_url: https://github.com/user/myapp.git

  tasks:
    - name: Клонирование репозитория
      git:
        repo: "{{ repo_url }}"
        dest: "{{ app_dir }}"
        version: main
        force: yes

    - name: Установка зависимостей Composer
        command: composer install --no-dev --optimize-autoloader
      args:
        chdir: "{{ app_dir }}"
        become_user: www-data

    - name: Установка прав
      file:
        path: "{{ app_dir }}/storage"
        owner: www-data
        group: www-data
        mode: '0775'
        recurse: yes

    - name: Настройка Nginx
      template:
        src: templates/app.conf.j2
        dest: /etc/nginx/sites-available/myapp
      notify: reload nginx

    - name: Активация сайта
      file:
        src: /etc/nginx/sites-available/myapp
        dest: /etc/nginx/sites-enabled/myapp
        state: link
      notify: reload nginx

  handlers:
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded

ВАЖНО! Модуль composer не является стандартным, поэтому используем command. Для идемпотентности можно добавить register и проверять наличие vendor/autoload.php

9.3 Настройка Docker и запуск контейнеров

YAML
---
- name: Установка Docker
  hosts: all
  become: yes

  tasks:
    - name: Установка зависимостей
      apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - gnupg
        state: present

    - name: Скачивание GPG-ключа Docker
      ansible.builtin.get_url:
      url: https://download.docker.com/linux/ubuntu/gpg
      dest: /usr/share/keyrings/docker-archive-keyring.gpg
      mode: '0644'

    - name: Добавление репозитория Docker
      lineinfile:
    path: /etc/apt/sources.list.d/docker.list
    line: "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
    state: present


    - name: Установка Docker
      apt:
        name:
          - docker-ce
          - docker-ce-cli
          - containerd.io
        state: present

    - name: Запуск Docker
      systemd:
        name: docker
        state: started
        enabled: yes

    - name: Установка Docker Compose
      get_url:
        url: https://github.com/docker/compose/releases/latest/download/docker-compose-Linux-x86_64
        dest: /usr/local/bin/docker-compose
        mode: '0755'

10. Интеграция с CI/CD

Ansible отлично вписывается в пайплайны CI/CD.

10.1 Пример GitHub Actions

YAML
name: Deploy with Ansible

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Установка Ansible
        run: sudo apt install ansible

      - name: Настройка SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa

      - name: Запуск плейбука
        run: |
        echo "${{ secrets.VAULT_PASSWORD }}" > .vault_pass
        chmod 600 .vault_pass
        ansible-playbook -i inventory.ini playbook.yml --vault-password-file .vault_pass

10.2 Пример GitLab CI

YAML
deploy:
  stage: deploy
  image: alpine/ansible
  script:
    - apk add openssh-client
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ansible-playbook -i inventory.ini playbook.yml
  only:
    - main

11. Лучшие практики

  1. Храните всё в Git. Инвентарь, плейбуки, роли, переменные.
  2. Используйте роли. Не пишите всё в одном плейбуке.
  3. Шифруйте секреты. Ansible Vault.
  4. Пишите идемпотентные задачи. Повторный запуск не должен ломать систему.
  5. Проверяйте синтаксис. ansible-playbook --syntax-check.
  6. Используйте --check и --diff. Перед применением смотрите, что изменится. --check не работает с некоторыми модулями (например, command, shell без явной проверки состояния).
  7. Логируйте. Ansible пишет логи в /var/log/ansible.log (если настроено).
  8. Не используйте shell и command, если есть модуль. Модули идемпотентны.
  9. Организуйте структуру. group_vars/host_vars/ для переменных.
  10. Тестируйте. Используйте Molecule для тестирования ролей.

Для реальных проектов лучше выносить переменные в group_vars/ и host_vars/:

ВАЖНО! В YAML нельзя использовать табы — только пробелы. Это одна из самых частых ошибок.

12. Частые ошибки

ОшибкаПоследствияРешение
Отсутствует become: yesЗадачи не выполняются (нет прав)Добавьте become: yes на уровне плейбука или задачи.
Неправильный отступ в YAMLСинтаксическая ошибкаYAML чувствителен к отступам. Используйте пробелы (не табы).
Использование shell вместо модуляНеидемпотентностьИспользуйте модули, где возможно.
Секреты в открытом видеУтечкаИспользуйте Ansible Vault.
Нет обработчика для перезапуска сервисаИзменения не применяютсяДобавьте notify и handlers.
Игнорирование ошибокПлейбук падаетИспользуйте ignore_errors: yes, если ошибка допустима.
Неправильный инвентарьAnsible не видит серверыПроверьте синтаксис и доступность.
Отсутствует SSH-ключОшибка подключенияНастройте ключи и ssh-agent.

Освоив Ansible, вы сможете управлять десятками и сотнями серверов так же легко, как одним. Инфраструктура станет предсказуемой, а время на развёртывание сократится с часов до минут.

Нашли ошибку? Напишите нам!