Материал открыт для чтения

Войдите, чтобы сохранять прогресс и результаты.

Войти
Ansible: автоматизация серверов с нуля

Зачем нужен Ansible и как он работает

чтение ~13 минУрок 1 из 21

Зачем нужен Ansible и как он работает

module ansible basics Image01

Одна из основных практик DevOps - Infrastructure as Code, или IaC (инфраструктура как код). Она решает вполне практическую проблему: как настраивать серверы одинаково и не зависеть от команд, которые кто-то выполнил вручную и нигде не записал.

Представь обычную рабочую задачу. Появился новый Linux-сервер, на котором нужно создать пользователя для приложения, скопировать конфигурацию, установить нужные пакеты и запустить службу. Один сервер можно настроить вручную: подключиться по SSH и выполнить команды по очереди.

Через неделю появляется второй такой же сервер. Затем третий. На одном из них меняется порт, на другом забывают создать каталог, а на третьем остаётся старая версия конфигурации. Когда приходит новая версия приложения, уже недостаточно вспомнить несколько команд. Нужно точно знать:

  • какие серверы относятся к приложению;
  • что на каждом из них должно быть установлено;
  • какие файлы и права должны получиться;
  • в каком порядке применять изменения;
  • как убедиться, что серверы настроены одинаково;
  • как повторить настройку через месяц без поиска команд в истории терминала.

Ручная работа перестаёт быть удобной не потому, что команды стали сложными. Проблема в количестве повторений и в том, что действия нигде полностью не записаны. Два человека могут настроить одинаковые серверы немного по-разному, а небольшие различия со временем превращаются в ошибки.

Такие уникальные серверы называют серверами-снежинками. Название появилось по аналогии с обычными снежинками: на первый взгляд они похожи, но у каждой свой уникальный узор. Так же и серверы, которые настраивали вручную: они могут выполнять одну задачу, но внутри отличаются друг от друга, и полностью воспроизвести их настройку сложно. Постепенное расхождение настроек называют configuration drift (дрейф конфигурации).

Подход IaC предлагает хранить настройку в файлах: какие пакеты установить, какие каталоги и пользователей создать, какие конфигурации скопировать и какие службы запустить. Ansible читает это описание, подключается к серверам и приводит их к нужному состоянию. Файлы можно хранить в Git, обсуждать с командой, проверять перед запуском и одинаково применять к одному или нескольким серверам.

Например, вместо инструкции в чате:

Зайди на сервер, создай /opt/demo, поставь права 0755,
скопируй app.conf и не забудь перезапустить службу.

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

Какие машины участвуют в работе

Для начала достаточно представить две стороны:

управляющая машина  -- SSH -->  сервер, который нужно настроить

Управляющая машина, или control node, запускает Ansible. Именно в её терминале человек вводит команду: проверить подключение, создать файл или настроить сервер по заранее описанному сценарию.

Управляемая машина, или target, - отдельный сервер, который нужно настроить. Ansible может создать на нём пользователя, изменить файл, установить пакет или запустить службу.

В каждой лабораторной виртуальная машина, на которой ты работаешь в терминале и VS Code, является control node, то есть управляющей машиной. Также у тебя будет доступ к одному или нескольким target-серверам, которые нужно настроить через Ansible. Это отдельные виртуальные машины со своими файлами, процессами, сетевыми адресами и именами. Если создать файл на управляющей машине, он не появится на target-сервере сам по себе.

В первой лабораторной ты сначала подключишься к target вручную по SSH и создашь там файл. Затем удалишь и создашь файлы уже через Ansible. Так будет видно, что Ansible не работает с каким-то условным объектом: он подключается к обычной Linux-машине и выполняет работу на ней.

module ansible basics Image11

Что происходит во время команды

Когда Ansible получает задание, он выполняет примерно такую последовательность:

1. Определяет, с какими серверами нужно работать.
2. Берёт адрес и параметры подключения.
3. Подключается к каждому серверу по SSH.
4. Передаёт небольшую программу для нужного действия.
5. Запускает её на сервере через Python.
6. Получает результат и показывает его в терминале.

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

Для работы с Linux-серверами обычно нужны:

  • сетевой доступ от управляющей машины до target;
  • возможность подключиться по SSH;
  • Python на target для выполнения небольших программ, которые Ansible передаёт на сервер;
  • пользователь с правами на нужные изменения.

Большинство модулей Ansible выполняются на target через Python. Если новая минимальная система ещё не содержит Python, обычные модули для его установки не помогут: им самим уже нужен интерпретатор. Для первоначальной подготовки существует модуль ansible.builtin.raw. Он отправляет команду напрямую через SSH и позволяет установить Python, после чего можно переходить к обычным модулям. В лабораториях Python уже установлен, поэтому команда python3 --version проверяет его версию, а не решает задачу первоначальной установки.

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

Одна команда через Ansible

Ansible можно использовать для разового действия. Например, выполнить hostname на группе серверов:

ansible -i inventory.ini web -m ansible.builtin.command -a 'hostname'

Пока не нужно разбирать весь синтаксис. Смысл команды простой:

  • взять список серверов из файла inventory.ini;
  • выбрать из него группу web;
  • выполнить на выбранных серверах команду hostname;
  • собрать результаты в одном терминале.

Такое разовое действие называют ad-hoc командой. Оно удобно для проверки связи, просмотра состояния или простой операции. Если действий много и их нужно повторять, их записывают в отдельный файл. До этого мы дойдём в статье про playbook.

Действие и желаемое состояние

Обычная команда чаще описывает действие:

mkdir /opt/demo

Она буквально говорит: «создай каталог». Если каталог уже существует, команда может завершиться ошибкой. Она не проверяет права и не понимает, подходит ли текущее состояние.

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

- name: Create demo directory
  ansible.builtin.file:
    path: /opt/demo
    state: directory
    mode: "0755"

Здесь указано: путь /opt/demo должен быть каталогом с правами 0755. Перед изменением Ansible проверит текущее состояние:

  • если каталога нет, создаст его;
  • если каталог есть, но права другие, исправит права;
  • если всё уже соответствует описанию, ничего менять не будет.

В выводе Ansible это видно по статусам:

changed  состояние пришлось изменить
ok       нужное состояние уже было достигнуто
failed   выполнить задачу не получилось
skipped  задача была пропущена по условию

Почему повторный запуск не должен ломать сервер

Свойство, при котором повторное применение одной и той же настройки не создаёт лишних изменений, называется идемпотентностью.

Важно понимать: сам Ansible не превращает любую команду в идемпотентную. Такая логика заранее реализована в его модулях. Например, модуль ansible.builtin.user сначала проверяет, существует ли пользователь и соответствуют ли его параметры описанию. При первом запуске модуль создаст пользователя deploy и покажет changed. При втором запуске он увидит, что пользователь уже настроен правильно, ничего не изменит и вернёт ok.

Если выполнить ту же работу обычной командой через shell, Ansible не сможет понять её смысл:

- name: Создать пользователя deploy
  ansible.builtin.shell: useradd deploy

При первом запуске команда создаст пользователя. При втором она снова попытается выполнить useradd, получит ошибку user already exists, и playbook остановится. Для Ansible это просто команда: он запускает её и получает результат, но не знает, что нужное состояние уже достигнуто.

Бывает и опаснее: команда не завершается ошибкой, а при каждом запуске снова меняет сервер. Например:

- name: Добавить настройку приложения
  ansible.builtin.shell: echo 'APP_MODE=production' >> /opt/app/.env

После нескольких запусков в файле появится несколько одинаковых строк. Таким же образом могут дублироваться задания cron, правила firewall или записи в /etc/fstab. В лучшем случае конфигурацию станет труднее читать. В худшем служба перестанет запускаться или сервер начнёт работать неправильно.

Именно поэтому идемпотентность так важна:

  1. Одну настройку можно регулярно применять ко всем серверам, изменяя только то, что действительно отличается.
  2. Если выполнение прервалось посередине, playbook можно запустить ещё раз без повторения уже сделанных изменений.
  3. Один и тот же playbook безопасно работает и с новым сервером, и с сервером, который уже был частично настроен.

Перед использованием shell сначала ищут подходящий модуль Ansible. Если без обычной команды не обойтись, нужно отдельно проверить текущее состояние сервера и запускать команду только тогда, когда изменение действительно требуется. Сам факт того, что команда записана в playbook, ещё не делает её идемпотентной.

Почему настройку хранят как код

Когда настройка записана в файлах, с ней можно работать так же, как с кодом приложения:

  • хранить историю изменений в Git;
  • видеть, кто и зачем поменял порт или путь;
  • проверить изменение перед применением;
  • сначала запустить его на тестовом сервере;
  • откатить ошибочное изменение в репозитории;
  • использовать один вариант настройки для всей команды.

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

Ansible не создаёт идеальный процесс сам по себе. Если в файлах записана опасная команда, он точно и быстро выполнит её на всех выбранных серверах. Поэтому область запуска, проверка синтаксиса, тестовое окружение и понятные изменения в Git остаются важной частью работы.

Push-модель

Ansible обычно работает по push-модели: управляющая машина сама начинает подключение и отправляет задания на target. Серверы не спрашивают центральную систему каждую минуту, появилась ли новая конфигурация.

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

У push-модели есть практическое следствие: управляющая машина должна видеть target по сети и иметь действующие данные для SSH-подключения. Если сервер находится в закрытой сети, запуск выполняют с машины, у которой есть доступ в эту сеть.

Где Ansible применяют

Ansible подходит для задач, где серверы нужно привести к известному и повторяемому состоянию:

  • первоначальная настройка Linux;
  • создание пользователей, SSH-ключей и прав;
  • установка и обновление пакетов;
  • создание конфигурационных файлов;
  • запуск и перезапуск служб;
  • развёртывание приложений;
  • последовательное обновление группы серверов;
  • выполнение проверок и сбор сведений;
  • настройка сетевого оборудования и облачных ресурсов через дополнительные модули.

Ansible не заменяет все инфраструктурные инструменты. Terraform обычно удобнее создаёт облачные сети и виртуальные машины. Kubernetes управляет контейнерными приложениями. Ansible может подготовить серверы, установить на них нужные компоненты, разложить конфигурацию и связать несколько шагов вместе.

Что нужно вынести из первой статьи

Ansible запускается на управляющей машине и по SSH меняет отдельные target-серверы. Его ценность не только в удалённом выполнении команд. Главное, что настройка:

  • записана в понятных файлах;
  • применяется одинаково к одному или многим серверам;
  • сравнивает текущее состояние с нужным;
  • допускает безопасный повторный запуск;
  • хранится и изменяется как код.

В следующей статье разберём первый реальный файл Ansible: обычный список серверов, который называется inventory.

Материал изучен?

Войдите, чтобы сохранить прогресс и перейти к практической лаборатории.

Войти и продолжить