Skip to content

3.4 Ansible

Знакомство с Ansible

Свойства Ansible
  • Декларативность
  • Идемпотентность (при повторном применении давать тот же результат)
  • Не требуется агент
Задачи Ansible
  • Автоматизация установки софта
  • Обеспечение повторяемости
  • Масштабируемость
4 концепции Ansible
  • Inventory - хранение информации о машинах в сети
  • Modules - непосредственно что загружается и выполняется
  • Plugins - расширяют функциональность самого Ansible (например ssh)
  • Api - интерфейс взаимодействия

Простые примеры запуска

Запуск модуля на всех хостах

ansible all -i hosts.ini -m ping
Запуск playbook
1
2
3
ansible-playbook playbook.yml -i hosts.ini

ansible-playbook playbook.yml -i hosts.ini -K

Пример заполнения hosts.ini

# все сервера ниже входят в группу all
192.168.0.12
192.168.0.14

[debi_servers]
debi ansible_host=192.168.0.20 ansible_user=debiuser ansible_ssh_private_key_file=/home/debuser/.ssh/id_ed25519
debi2 ansible_host=192.168.0.32 ansible_user=debiuser ansible_ssh_private_key_file=/home/debuser/.ssh/id_ed25519

# тестовый пред прод сервер баз
[staging_DB]
192.168.0.1
192.168.0.2

# тестовый пред прод сервер приложений
[staging_APP]
192.168.0.5
192.168.0.6

# Объединим группы серверов в одну более крупную
[staging_ALL:children]
staging_DB
staging_APP

Варианты задания переменных

1
2
3
4
5
6
7
192.168.0.1 test=123 testvar=['11', '22']
или
[centos]
192.168.0.1
192.168.0.2
[centos:vars]
test=123
- name: Basic group
  hosts: testvm
  become: true
  roles:
    - testrole
  vars:
    test_var: test
    version: 7.0

  tasks:
  - name: "Test vars"
    ansible.builtin.debug:
      msg: "Variable is set to {{ test_var }} {{ ansible_date_time }}"tasks

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

  • Одна переменная в одном месте
  • Называем переменные, включая роли/пакеты в имя
  • Избегаем простых имён (server, host)
  • ansible_facts - факты о машинах, переопределить невозможно
Разумная таблица приоритетов переменных

Примерно такая же, как тут, но без WTF'ов.

  1. Vars set on the command line -e foo=set_on_cmd_line
  2. Vars set in the vars_files: block in the play
  3. Vars set in the vars: block in the play
  4. Vars set in host_vars/
  5. Vars set in group_vars/
  6. Role default vars roles/.../defaults/main.yml

Пример ping

Из командной строки

1
2
3
ansible all -i hosts.ini -m ping

ansible all -i hosts.ini --ask-pass -m ping

С помощью плейбука

playbook.yaml
1
2
3
4
5
---
- hosts: "all"
  tasks:
  - name: "ping hosts"
    ansible.builtin.ping:

Примеры установки LAMP стека

├── ansible.cfg
├── group_vars
│   └── all.yml
├── host_vars
│   └── testhost1
├── hosts.ini
├── playbook.yml
├── requirements.yml
└── roles
    ├── mysql
    │   └── tasks
    │       └── main.yml
    ├── nginx
    │   ├── files
    │   │   └── html
    │   │       └── index.html
    │   └── tasks
    │       └── main.yml
    ├── php
    │   ├── files
    │   │   └── test-php
    │   │       ├── nginx.conf
    │   │       └── php-test
    │   │           ├── index.php
    │   │           └── test-connection.php
    │   └── tasks
    │       └── main.yml
    └── testrole
        ├── defaults
        │   └── main.yml
        └── tasks
            └── main.yml
1
2
3
4
5
[testvm]
testhost1 ansible_host=192.168.0.15 ansible_user=pk ansible_password=password

[testansible]
testhost2 ansible_host=192.168.0.188 ansible_user=pk 
[default]
inventory=./hosts.ini
---
- hosts: "testansible"
  become: true
  roles:
    - nginx
    - mysql
    - php

  tasks:
    - name: "Reload nginx"
      ansible.builtin.service:
        name: "nginx"
        state: "reloaded"
---
- name: "Install nginx via apt"
  ansible.builtin.apt:
    name: "nginx"
    state: "latest"
    update_cache: true

- name: "Delete /var/www/html folder"
  ansible.builtin.file:
    path: "/var/www/html"
    state: "absent"

- name: "Copy our landing to /var/www/html folder"
  ansible.builtin.copy:
    src: "files/html"
    dest: "/var/www"
    owner: "pk"
    group: "pk"
    mode: "0644"
---
- name: "Install mysql via apt"
  ansible.builtin.apt:
    name: "mysql-server"
    state: "latest"
    update_cache: true

- name: "Install pymysql via apt"
  ansible.builtin.apt:
    name: "python3-pymysql"
    state: "latest"
    update_cache: true

- name: "Set up root user"
  community.mysql.mysql_user:
    name: "root"
    password: "password"
    login_user: "root"
    login_password: "password"
    check_implicit_admin: true
    login_unix_socket: "/var/run/mysqld/mysqld.sock"

- name: "Remove anonymous users"
  community.mysql.mysql_user:
    name: ""
    state: "absent"
    login_user: "root"
    login_password: "password"

- name: "Remove test database"
  community.mysql.mysql_db:
    name: "test"
    state: "absent"
    login_user: "root"
    login_password: "password"

Правильная структура и описание

── inventories 
│    ├── AWS 
│    │     ├── group_vars
│    │     │    ├── all 
│    │     │    └── web-servers
│    │     ├── hosts
│    │     └── host_vars
│    │           ├── hostname1
│    │           └── hostname2
│    └── Local
│          ├── group_vars
│          ├── hosts
│          └── host_vars
├── roles 
│    ├── nginx
|    |    ├──  tasks/
|    |    ├──  handlers/
|    |    |--- files/
|    |    |--- templates/
|    |    |--- vars/
|    |    |--- defaults/
|    |    |--- meta/
│    ├── grafana
│    └── common
├── ansible.cfg
├── README.md
├── grafana.yml
└── web-server.yml
  • inventories
    • host, group_vars, host_vars
      • hosts - основной инвентарный файл, в который добавляем хосты и параметры к хостам
      • group_vars - переменные которые будут применены к определенной группе хостов
      • host_vars - добавляются переменные для определенного хоста
  • roles - директория с ролями, пример название ролей nginx, php
    • Роль позволяет сгруппировать несколько задач в один конвейер
    • tasks/main.yml – основной список задач которые будет исполнять роль
    • handlers/main.yml – списки задач (обработчиков), триггеры notify
    • defaults/main.yml – переменные по умолчанию с очень низким приоритетом
    • vars/main.yml – переменные с большим приоритетом
    • files – директория с файлами которые используются в роли
    • templates – директория с шаблонами Jinja2
    • meta/main.yml – директория с метадатай об авторе, зависимостях которые использует роль
  • ansible.cfg - конфигурационный файл, в котором назначаются настройки по умолчанию
  • playbook.yml - файл в котором мы связываем хосты и роли которые нужно выполнять

Ansible galaxy

Коллекции в Ansible — формат распространения набора модулей и плагинов. Скачиваются и хранятся в ~/.ansible/collections

requirements.yml
1
2
3
4
5
6
7
8
roles:
- src: geerlinguy.postgresql

- name: green.mongodb
  src: https://github.com/UnderGreen/ansible-role-mongodb

collections:
- name: community.postgresql
Установка ролей из этого файла
ansible-galaxy collection install -r requirements.yml
ansible-galaxy install -r requirements.yml
Создание своей роли
ansible-galaxy role init test_galaxy
Список установленных коллекций (Коллекция ansible.builtin здесь не указана, так как это единственная коллекция модулей, встроенная прямо в ядро Ansible)
ansible-galaxy collection list
По умолчанию для установки пакетов и т.п. действий требуется пароль sudo Чтобы его не запрашивало можно на сервере в файле /etc/sudoers изменить sudo visudo /etc/sudoers

`myuser ALL=(ALL) NOPASSWD: ALL` for a single user, or
`%sudo  ALL=(ALL) NOPASSWD: ALL` for a group.

Info

Yandex cloud при создании из образа сразу добавляет эту строку в /etc/sudoers.d/cloud_init

Jinja шаблоны

# network interfaces
net:
 port: 27017
 bindIp: {{ mongodb_listen_ip }} # <-- Использование переменных
# Replication params
{% if mongodb_replication_replset -%} # <-- Условный оператор на основе
переменных
replication:
 replSetName: {{ mongodb_replication_replset }}
{% endif %}
1
2
3
4
- name: Create mongod.conf file for MongoDB
 template:
 src: templates/mongodb/mongod.conf.j2
 dest: /etc/mongod.conf

Notify and Handler

  • Notify это триггер (например если файл изменился то нужно перезагрузить nginx)
  • Вызывается только если task получило статус change (т.е. сделало какие то изменения)
  • Если несколько одинаковых notify выполниться всё равно один handler
  • Handler выполняется в конце каждого play’a (Play — связывает список ролей и тасков с списком хостов )
  • Notify одной роли может вызвать handler из другой
  • Если в процессе выполнения произошла ошибка то handler вызван не будет
playbook.yml
handlers:
- name: reload mongodb # <-- Имя задачи потом задаем в директиве notify
 service:
 name: mongod
 state: reloaded

tasks:
- name: Create mongod.conf file for MongoDB
 template:
 src: templates/mongodb/mongod.conf
 dest: /etc/mongod.conf
 notify:
 - reload mongodb # <-- Вызовем эту задачу, если конфигурация изменится

Dinamic inventory

  • Позволяет работать с inventory полученным из внешних сервисов
  • Решает проблему дублирования и отслеживания хостов
  • Поддерживает использования внешних скриптов для получения данных из внешних систем
ansible -i $HOME/test_inventroy.py -m ping all

Ansible Vault шифрование

  • Консольная утилита для работы с секретными данными
  • Переменные можно подключать через vars_files
  • Позволяет хранить в общих репозиториях файлах, в которых содержится приватная информация
  • Для более сложных случаев используется Hashicorp Vault

vars_files:
    - secrets.yml
secret_pass: password
Чтобы зашифровать файл
ansible-vault --vault-id dev@prompt encrypt --encrypt-vault-id dev secrets.yml
Запуск с запросом пароля от шифрования
ansible-playbook myplaybook.yml --ask-vault-pass

Отладка

  • -vvvv - подробный вывод
  • Пошаговое выполнение --step
  • Ansible-console
  • debugger (break point внутри task)
    • p task.vars
    • p task.args