Автоматизация управления с помощью Ansible

В предыдущей статье мы достаточно подробно рассмотрели вопросы связанные с автоматизацией управлением и настройкой ПО в средних и крупных сетях. Рассмотрели Vagrant и основные методы работы с виртуальной инфраструктурой. В этой статье мы подробно поговорим об использовании такого интересного инструмента, как Ansible.

Данное решение позволяет автоматизировать развертывание и настройку ресурсов в сети, подготовку контейнеров и виртуальных машин, и многое другое. Само приложение Ansible работает в так называемом проталкивающем режиме. Вся работа с инфраструктурой осуществляется с сервера управления. И с этой машины ведется применение настроек к управляемым узлам.

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

Сначала нам необходимо будет развернуть сервер управления Ansible. В качестве ОС я буду использовать Ubuntu 22.04. Предварительно сделав апгрейд и апдейт, выполним следующую команду: 

sudo apt install ansible

Установка не должна вызвать каких-либо сложностей. После ее завершения мы получим узел управления со всем необходимым ПО для администрирования целевых узлов. Как настоящие DevOps мы будем работать через консоль и для начала нам необходимо внести правки в файл инвентаризации /etc/ansible/hosts. Это файл содержит информацию о тех хостах, которыми будем управлять, параметры конфигурации и переменные.

В качестве примера пропишем в этот файл два сервера .150 и .137. Также пропишем путь к интерпретатору Python.

[servers]

server1 ansible_host=192.168.222.150

server2 ansible_host=192.168.222.137

[all:vars]

ansible_python_interpreter=/usr/bin/python3

С этим значением параметра удаленный сервер использует исполняемый файл Python 3 /usr/bin/python3, который может отсутствовать в некоторых версиях Ubuntu.

Об аутентификации

С настройками по умолчанию Ansible пытается подключиться ко всем нодам по протоколу SSH и с помощью аутентификации по ключам. Однако, не всегда есть возможность аутентифицироваться по ключам, и в качестве альтернативы вы можете указывать пароль при подключении. Но для использовании парольной аутентификации необходимо предварительно установить на сервере управления Ansible утилиту sshpass:

sudo apt install sshpass

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

На сервере управления Ansible отобразим открытый ключ в терминале:

Если такого файла нет, его можно создать:

ssh-keygen -t rsa

Далее необходимо зайти на клиентскую машину, перейти в сессию root и открыть файл  nano ~/.ssh/authorized_keys и поместить в него открытый ключ сервера управления:

В качестве проверки результатов настройки узнаем, какие версии ядра на управляемых машинах.

ansible all -a "uname -a"

Используем плейбуки

Мы научились выполнять команды на управляемых серверах и получать ответы от их операционных систем. Однако для настоящей автоматизации этого явно недостаточно. И здесь на помощь приходят плейбуки – базовые компоненты, которые записывают и исполняют конфигурацию Ansible, что позволяет по-настоящему автоматизировать выполнение задач на управляемых машинах.  

Немного о терминологии. В последнее время есть тенденция к отказу от англоязычных терминов, поэтому в некоторых источниках, особенно связанных с ИБ можно встретить замену иностранного слова “плейбук” российским аналогом – карта реагирования. Однако в данной статье мы будем использовать термин плейбук.

Итак, что из себя представляет плейбук: по сути это набор сценариев, которые выполняются в заданном порядке. Сценарий – это список задач для определенной группы хостов.

Инструментом для создания плейбуков является язык YAML. При написании сценариев большое значение имеет отступы, которые необходимо делать только с помощью пробелов, TAB использовать нельзя. У одинаковых элементов отступы тоже должны быть одинаковые. Вот пример Hello world в Ansible:

---

- hosts: all

  tasks:

    - name: Print message

      debug:

        msg: Hello Ansible World

В этом сценарии мы указываем в качестве целей все узлы из нашего hosts файла. Наименование задачи Print message, и вывод сообщения Hello Ansible World.

Сохраним этот плейбук в файл и запустим на выполнение.

ansible-playbook pl_1.yml

Задача успешно выполнена. В случае, если нам необходимо выполнить плейбук только на одном управляемом узле, необходимо указать параметр –limit и имя данного узла, указанное в файле hosts.

ansible-playbook pl_1.yml --limit server1

Далее рассмотрим работу с переменными в Ansible. В следующем примере мы будем работать сразу с двумя видами переменных: встроенной переменной Ansible и определенной в нашем плейбуке.

Перед началом блока определяемых в плейбуке переменных мы указываем vars:, далее указываем сами переменные и их значения. В нашем примере мы определяем переменную txt со значением IP_address. В блоке tasks, в разделе msg переменные указываются в двойных фигурных скобках с отступом с каждой стороны. Сначала мы указываем нашу переменную txt, а затем встроенную переменную ansible_default_ipv4.address. Определять данную переменную не надо, так как она уже определена в самом Ansible.

- hosts: all

  vars:

    txt: IP_address

  tasks:

    - name: print facts

      debug:

        msg: "{{ txt }}: {{ ansible_default_ipv4.address }}"

Сохраним созданный файл и выполним плейбук для всех узлов.

 ansible-playbook pl_2.yml

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

Для этого мы сначала определим переменные user и file_name

vars:

    - user: otus

    - file_name: test1 

Затем выполним команду ls  

      command: ls /home/{{ user }}/{{ file_name }}

Далее мы используем ключевое слово register, которое создает новую переменную file_exists и присваивает ей выходные данные, полученные из команды.

Одна важная вещь, на которую следует обратить внимание, заключается в том, что по умолчанию Ansible прерывает работу плейбука, если команда, которую вы используете для оценки условия, завершается неудачей. По этой причине мы используем директиву ignore_errors, имеющую значение yes, и это заставит Ansible перейти к следующей задаче и продолжить работу.

      register: file_exists

      ignore_errors: yes

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

Далее в случае, если fail_exists имеет значение failed, мы создаем новый файл.

    - name: create file for user

      file:

        path: /home/{{ user }}/{{ file_name }}

        state: touch

      when: file_exists is failed

Если файл уже существует, мы просто выводим соответствующее сообщение:

  - name: show message if file exists

      debug:

        msg: The user file already exists.

      when: file_exists is succeeded

Далее приведен полный текст всего плейбука:

---

- hosts: all

  vars:

    - user: otus

    - file_name: test1 

  tasks:

    - name: Check if file already exists

      command: ls /home/{{ user }}/{{ file_name }}

      register: file_exists

      ignore_errors: yes

 

    - name: create file for user

      file:

        path: /home/{{ user }}/{{ file_name }}

        state: touch

      when: file_exists is failed

 

    - name: show message if file exists

      debug:

        msg: The user file already exists.

      when: file_exists is succeeded

Запустим наш плейбук на выполнение:

ansible-playbook pl_3.yml

Как видно, при первом запуске мы получили ругательства на тему отсутствия файла с таким именем. Однако, все эти сообщения были успешно проигнорированы и выполнение сценария было продолжено.

При повторном запуске плейбука:

Получаем сообщения, что файлы уже существуют.

Циклы в Ansible

Еще одной важной задачей автоматизации является необходимость повторения  выполнения одной и той же задачи, с использованием разных значений. Например, вам может потребоваться изменить разрешения для нескольких файлов или создать нескольких пользователей. Чтобы избежать многократного повторения задачи в вашем файле playbook, для этого лучше всего использовать циклы.

В следующем примере мы объявляем в переменной file_name значение ansible, затем создаем файлы с именами, содержащими значение file_name и через дефис значение одной из переменных внутри loop.

---

- hosts: all

  vars:

    - user: otus

    - file_name: ansible 

 

  tasks:

    - name: creates users files

      file:

        path: /home/{{ user }}/{{ file_name }}-{{ item }}

        state: touch

      loop:

        - test10

        - test20

        - test30

Запустим получившийся плейбук:

ansible-playbook pl_4.yml

В результате работы сценария получаем три файла с именами, соответствующими заданному шаблону:

ls

Заключение

В этой статье мы рассмотрели основные моменты связанные с установкой Ansible и выполнением базовых задач. Но это только малая часть того, что умеет данная система, например за кадром осталось управление узлами под Windows, поднятие привилегий, установка обновлений и многое другое. Так что мы еще обязательно вернемся к рассмотрению вопросов использования Ansible.

Также хочу порекомендовать всем бесплатный урок курса DevOps практики и инструменты от OTUS, где мои коллеги расскажут про 3 основных принципа безопасности инфраструктуры. В уроке будет демо, где эксперты OTUS разберут одну проблему на инфраструктуре - очень интересный протокол Диффи-Хеллмана на примере больших чисел с отсылкой на эллиптические кривые и криптографию.Преподаватель на пальцах покажет как работает алгоритм и как исправить проблему связанную с ним в nginx.

Комментарии (3)


  1. SlavikF
    17.01.2023 19:14
    +4

    Хорошая статья, но от ваших скриншотов ломаются глаза...

    Наверное лучше было бы сделать их простым текстом.


    1. PATRI0T
      19.01.2023 13:58
      +1

      Очень рекомендую уходить от putty в сторону Windows Terminal. Попробуйте, это бесплатно)


  1. NAI
    17.01.2023 21:14
    +5

    для начала нам необходимо внести правки в файл инвентаризации /etc/ansible/hosts

    Божечки-кошечки, зачем? Можно же просто положить inventory(.yml) в папку с проектом(репозиторий) и использовать ключ -i. Если же это лень делать то можно же в локальном конфиге прописать откуда брать инвентарь. Конфиг, кстати, тоже кладется в папку с проектом (репозиторий). И вот ваш проект полностью отвязан от хоста.

    В целом лучше рассказать про ansible-lint, структуру переменных и структуру проектов.