May 21, 2021

Нахуя ansible

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

До того как мы начнём, поставь ансибл, братиш!
pip install --user ansible

Для чего?

Очень часто мы руками раскатываем наши сервисы на сервера. Как это обычно происходит?

  • Влезть за сервер по ssh
  • Скопировать туда код
  • Запустить какие-то действия
    • миграция
    • сборка контейнера Докер
    • обновление конфигов
    • поставить новые пакеты\софт
    • etc
  • Остановить старую версию сервиса
  • Запустить новую
  • Убедиться что все конфиги поднялись.

Где тут проблема?
Проблема в куче ручных шагов, на которых можно ошибиться, тупануть, вставить не то, обрушить всё к хуям собачьим. Да и не удобно это всё. Точнее оно может и удобно до какой-то стадии повышения сложности, но потом точно не удобно.

Именно для этого и нужен Ансибл. Он позволяет всё это автоматизировать. Надёжно и просто(если понимаешь что делаешь).

Как это работает?

У ансибл есть два режима работы:

  • Работа с модулями Ансибл напрямую
  • Работа в режиме плейбуки

Работа напрямую

Это как разовый вызов модуля в пайтоне, а ля python -m pip install aiohttp.
Лично я это использую для разовой операции на куче серверов (да хоть на одном), чтоб что-то мелкое выполнить.
Например узнать uptime всех серверов:
ansible all -i inventory.yaml -m shell -a "uptime"

Работа в режиме плейбуки

Это более серьёзный режим. Playbook - это список правил, действий, по которым ваш сервер приводится к нужному состоянию.

Стоит упомянуть, что Ansible именно приводит к нужному состоянию.

Например у вас в плейбуке написано, чтоб ансибл установил nginx.
1. Ансибл лезет на первый сервер, собирает кучу инфы о сервере и пакетах, установленных там. Устанавливает nginx.
2. Ансибл лезет на второй сервер, собирает кучу инфы... смотрит, nginx уже стоит и ничего не делает вообще.

На выходе серверов может быть 10000 и на всех по итогу будет установлен nginx. Можно поставить тригер, чтоб nginx был установлен именно последней доступной в репозитории версии или определённой версии, тогда ансибл везде сделает nginx именно нужной версии.

Круто? Круто!

Немножко практики и ещё чуть теории

На данный момент нам важно узнать про две вещи.

inventory

inventory - это список серверов\машин\компьютеров с которым ansible работает.
inventory может быть в формате ini, в формате yaml (мой любимчик) и динамический.
Формат ini я не буду рассматривать, если интересно, найдёте в документации. А вот yaml я покажу.
Динамический inventory нигде не хранится кроме оперативной памяти. Чаще всего используется, когда вы автоматически листите какие-то ваши сервера в датацентре и\или создаёте сервер с нуля тем же ansible. Тобишь послали запрос на создание сервера, дождались статуса создания, записали в inventory его параметры.

Давайте напишем свой inventory.
Например у меня есть 2 машины, я назвал их raspi_four и raspi_zero.
Для интереса, я настрою всё так, чтоб ssh вход на raspi_four был по ssh ключу, а на raspi_zero по паролю.
Доступ по ключу на raspi_four настраиваем заранее. (прописываем ваш публичный ключ в authorized_keys на raspi_four, в интернете куча инструкций).

Дальше пишем в файле inventory.yaml

all:
  hosts:
    raspi_four:
      ansible_ssh_host: 192.168.0.119
      ansible_user: pi
    
    raspi_lite:
      ansible_connection: ssh
      ansible_ssh_host: 192.168.0.115
      ansible_user: pi
      ansible_ssh_pass: raspberry

Вместо имён, например raspi_four, можно написать доменное имя и не указывать ip. Ансибл сам разберётся.

Теперь команда ansible all -i inventory.yaml -m shell -a "uptime" будет работать.

Плейбука!

Давайте напишем простую плейбуку.
Рассмотрим два простых действия:
1. Установить какой-нибудь софт на сервер.
2. Скопировать файл с хоста (на котором запущена плейбука) на сервер.
3. Выполнить это на всех машинах в inventory

Приступим. Создаём файл test_playbook.yaml и пишем там это

- name: my tasks
  hosts: all
  tasks:
    - name: install nmap
      apt:
        name: ["nmap"]
      become: True

    - name: copy file
      copy:
        src: "{{ playbook_dir }}/some_file.txt"
        dest: /tmp/tempConfig.txt

Давайте разберёмся что тут происходит.

Если вы знакомы со структурой yaml, вы сразу видите список, а именно список из одного элемента, в котором лежит всё написанное. Этих элементов может быть несколько и все будут выполняться последовательно. Конкретно этот элемент отвечает за исполнение наших, так называемых tasks и называется my tasks. Это будет фигурировать в логах исполнения и весьма полезно давать осмысленные названия.

Далее мы указываем hosts: all. Помните инвентори, там в основе всего была группа all (да, там разделение по группам, но о них подробнее я расскажу в следующий раз, может быть). Вот со всеми входящими в группу хостами мы и производим действия.
Кстати вместо all можно указать local, и тогда все действия будут происходить на машине, на которой запустилась плейбука. Это удобно для разделения задач, например на локальной машине можно собрать артефакт или сбилдить образ, залив его на докер-хаб, а на хосте уже спуллить образ и запустить.

Далее мы видим список tasks. У каждой таски есть одинаковые параметры, это имя name, где любой текст, и имя модуля.
К слову о модулях, из коробки в ансибл есть ооооооочень дохуя модулей на все случаи жизни, да и сторонние можно ставить, их ещё больше. Описывать весь список я не смогу, но подробности есть в документации. Сейчас рассмотрим два модуля, это apt и copy.

apt имеет дополнительный параметр name:, который принимает строку или список строк с названиями того, что надо установить из apt. И ниже мы видим странное become: True, которое направлено на всю задачу. Как мы помним из inventory, мы заходим под пользователем pi, а он не имеет прав на установку пакетов. Чтоб он это умел, надо повысить права дописав перед командой sudo. (само собой юзер pi должен быть включён в sudoers). Именно для задач, где надо повысить права, прописывается become: True (можно так же become: yes)

copy, как можно понять из названия, копирует файл (или директорию) с хоста на целевую машину. Из параметров src: путь до файла на хосте и dest: куда положить на целевой машине. В src мы использовали переменную ансибла, где лежит путь до директории, где лежит текущая плейбука. Этих переменных у ансибла куча и о них поговорим потом. И да, знающие уже увидели тут Jinja2. Чтож - это он и есть) Всё (почти) что можете писать в jinja2, можете и тут.

Я рассмотрел только малую часть возможностей модулей apt и copy, там куча параметров и куча возможностей.

Запускаем

ansible-playbook test_playbook.yaml -i inventory.yaml

и наблюдаем за исполнением. Если запустить ещё раз, то ансибл просто пройдётся по задачам, убедится что всё уже сделано ранее и ничего менять не надо, поставить везде ok вместо changed и не будет нихрена делать =)

Если интересно посмотреть что он делает подробнее, можно к команде запуска дописать -vvv

На этом наша вводная лекция закончена.
Специально для python_sripts, Вадик.