Примеры работы с Ansible

Обновлено Обновлено: Опубликовано Опубликовано:

Используемые термины: Ansible.

Инструкция представляет из себя шпаргалку по работе с Ansible. У автора не стоит задачи подробного пояснения всех операций — только описание задачи и пример того, как ее можно решить с помощью ansible. Для более подробного описания я постараюсь указать ссылки на официальную документацию. Также в данную шпаргалку не войдут все возможные действия, которые можно выполнить с помощью данной системы — только популярные и те, с которыми приходилось сталкиваться самому автору. По мере возможности, их список будет пополняться.

Для удобства, мы попробуем разбить примеры на операции, которые логически можно объединить в одну группу.

Получение информации

Сюда войдут примеры, которые позволят собирать информацию, выводить ее на экран, помогать в отладке и всякое такое.

1. Показать информацию об удаленной системе, на которой запускается ansible.

Выполняется с помощью модуля debug, который должен показать содержимое ansible_facts:

- name: Print all available facts
  ansible.builtin.debug:
    var: ansible_facts

ansible_facts содержит массив данных с информацией о системе. Однако, функция сборки информации может быть отключена (так как на ее работу тратится, относительно, много времени) в настройках плейбука с помощью опции gather_facts: false — в этом случае, значение нужно изменить на true.

Также мы можем обратиться к конкретному элементу массива ansible_facts, получив информацию о конкретной настройке или опции:

    ...
    ansible_facts.hostname

* например, имя компьютера.

Ссылка на документацию: https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html.

2. Отображение на экран переменной.

Выше мы уже использовали debug для отображения переменной — принцип тот же:

- name: Show Value of Variable
  debug:
    msg: "{{ variable }}"

* при выполнении задачи на экране мы увидим значение переменной variable. Обратите внимание, что запись ansible.builtin.debug и debug — это одно и то же, то есть, ansible.builtin можно не писать.

О debug: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html.

3. Сохранение результата в переменную.

Выполняется с помощью register:

- name: Run a shell command and register its output as a variable
  shell: command
  register: command_result

* в данном примере мы запишем в переменную command_result все то, что мы получили с помощью команды command.

Вывести на экран содержимое можно с помощью debug:

- name: Show Value of Variable
  debug:
    var: command_result.stdout

* обратите внимание, что мы выводим не все содержимое, а только stdout, то есть то, что должна была вывести в консоль команда.

4. Получить список сервисов.

Для этого существует service_facts:

- name: Populate service facts
  ansible.builtin.service_facts:

- name: Print all available facts
  ansible.builtin.debug:
    var: ansible_facts.services

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

О service_facts: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_facts_module.html.

Проверки и условия

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

1. Проверка на пустую папку.

Задачи сводится к двум операциям:

  • получении списка файлов в целевом каталоге (например, с помощью команды ls) и регистрации полученного значения в переменную с помощью register.
  • проверка содержимого переменной, которую мы получили на шаге 1 с помощью when.

Пример будет таким:

- name: Register Contents of PGDATA Folder
  shell: ls /var/lib/postgresql/11/main
  register: pg_contents

- name: Init PostgreSQL DB
  shell: /opt/pgpro/std-11/bin/pg-setup initdb
  environment:
    PGDATA: "/var/lib/postgresql/11/main"
  when: pg_contents["stdout_lines"] | length == 0

* в данном примере мы в первой задаче выводим содержимое каталога /var/lib/postgresql/11/main и помещаем его в переменную pg_contents. Во второй задаче мы уже проверяем с помощью when количество строк — если их 0, то тогда выполняем команду initdb. На практике, это важно, так как инициализация базы PostgreSQL при непустом каталоге выводит сообщение об ошибке.

О when: https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html.

2. Проверить, определена ли переменная.

Для этого используется опция is defined (определена) или is not defined (не определена):

when: pgpro is defined

when: pgpro is not defined

* в данном примере мы проверим наличие переменной pgpro. На практике такая проверка имеет значение, так как если мы попробуем выполнить действия с несуществующей переменной, Ansible нам вернет ошибку.

В официальной документации про это сказано в статье о when (ссылка выше).

3. Выполнение команды, если сервис в рабочем состоянии.

Нам необходимо получить информацию о службах с помощью service_facts, после чего можно уже делать проверку с помощью when:

- name: Populate service facts
  ansible.builtin.service_facts:

- name: Stop Service If Running One
  shell: systemctl stop apache2
  when: ansible_facts.services["apache2.service"] is defined and ansible_facts.services["apache2.service"].state == "running"

* в данном примере мы проверим, есть ли служба apache2 и запущена ли она. Если это так, то мы ее останавливаем.

Подробнее о service_facts можно прочитать в документации (ссылка выше в разделе 4. Получить список сервисов).

Установки пакетов, модулей и расширений

В данном разделе мы коснемся всего, что приводит к установке чего бы то ни было. А именно:

  • Установки пакетов в систему.
  • Загрузки исходников.
  • Установке дополнительных модулей.
  • Распаковке архивов.

Рассмотрим это подробнее.

1. Установка модуля в nodejs.

Установка модулей в nodejs выполняется с помощью npm. Для него в ansible есть отдельная функция:

- name: Install nodejs modules.
  npm:
    name: newman
    global: yes

* в данном примере будет выполнена установка newman, которая будет доступна всем проектам (опция global).

О nodejs npm: https://docs.ansible.com/ansible/latest/collections/community/general/npm_module.html.

2. Загрузка из GIT.

Выполняется с помощью модуля git:

- name: Clone docker-compose
  git:
    repo: "https://github.com/docker/compose.git"
    dest: /tmp/docker-compose

* в данном примере мы сделаем клон репозитория в каталог /tmp/docker-compose.

О Git: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/git_module.html.

3. Распаковка архива.

Выполняется с помощью unarchive:

- name: Unpacking Nginx Source
  unarchive:
    src: "http://nginx.org/download/nginx-{{ nginx_ver }}.tar.gz"
    dest: /tmp/
    remote_src: yes
    creates: /tmp/nginx-{{ nginx_ver }}.tar.gz

* в данном примере мы распакуем исходник для nginx в каталог /tmp. Обратите внимание на две вещи:

  • Мы используем переменную nginx_ver. Данная переменная должна быть определена при запуске плейбука, или в инвентарном файле, или в var, или в default.
  • Опция creates позволит не выполнять операцию, если существует файл /tmp/nginx-{{ nginx_ver }}.tar.gz.

Об unarchive: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/unarchive_module.html.

Настройка системы

В данном разделе мы рассмотрим процессы, которые больше подходят для категории настройки системы. 

1. Добавить задание в cron.

Выполняется с помощью модуля cron:

- name: Add Job for Run Command
  cron:
    name: Start Script
    job: "/scripts/command.sh"
    user: root
    minute: "0"
    hour: "*/6"
    day: "*"
    month: "*"
    weekday: "*"

* в данном примере мы создадим задание для запуска команды /scripts/command.sh каждый день, каждые 6 часов.

О cron: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/cron_module.html.

2. Добавить публичный ключ хоста в known_hosts.

Делается с помощью known_hosts. Пример из официальной документации:

- name: Tell the host about our servers it might want to ssh to
  known_hosts:
    path: /etc/ssh/ssh_known_hosts
    name: foo.com.invalid
    key: "{{ lookup('file', 'pubkeys/foo.com.invalid') }}"

* в данном примере мы добавим ключ из файла pubkeys/foo.com.invalid в /etc/ssh/ssh_known_hosts.

О known_hosts: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/known_hosts_module.html.

3. Создание новых SSH-ключей для сервера.

Создание ключей реализуется с помощью модуля openssh_keypair:

- name: Generate New SSH Host Keys
  openssh_keypair:
    path: "/etc/ssh/ssh_host_{{ item.type }}_key"
    owner: root
    state: present
    type: "{{ item.type }}"
    size: "{{ item.size }}"
    force: yes
  loop:
    - { type: dsa, size: 1024 }
    - { type: ecdsa, size: 521 }
    - { type: ed25519, size: 2048 }
    - { type: rsa, size: 2048 }

* в данном примере мы создадим 4 ключа разных типов: dsa, ecdsa, ed25519, rsa. Так как у каждого из них свои требования к размеру, перечень представлен в виде двумерного массива. Ключи будут созданы в каталоге /etc/ssh/.

О openssh_keypair: https://docs.ansible.com/ansible/latest/collections/community/crypto/openssh_keypair_module.html.

4. Создание системной учетной записи.

Для этого есть модуль user. У него много опций, но для создания системной учетной записи нам достаточно:

- name: Create User Consul
  user:
    name: consul
    system: yes
    comment: "Consul Agent"

* в данном примере будет создана учетная запись consul.

О user: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html.

5. Работа с systemd.

Для данной настройки есть одноименный модуль systemd. Рассмотрим варианты его использования.

а) перечитать конфигурацию (необходимо делать каждый раз, когда мы меняем настройки юнита):

- name: systemd reload
  systemd:
    daemon_reload: yes

б) разрешить сервис (автозапуск):

- name: mysql enable
  systemd:
    name: mysql
    enabled: yes

* для сервиса mysql.

в) перезапустить сервис:

- name: mysql reload
  systemd:
    name: mysql
    state: restarted

* для сервиса mysql.

О systemd: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html.

6. Настройка брандмауэра.

Выполняется разными модулями в зависимости от используемой системы управления netfilter:

  • firewalld
  • iptables
  • ufw

Рассмотрим небольшие примеры.

а) firewalld:

- name: permit traffic in default zone for https service
  firewalld:
    service: https
    permanent: yes
    state: enabled

Подробнее: https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html.

б) iptables:

- name: Block specific IP
  iptables:
    chain: INPUT
    source: 8.8.8.8
    jump: DROP

Подробнее: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/iptables_module.html.

в) UFW.

Добавить 80 порт:

- name: Allow all access to tcp port 80
  ufw:
    rule: allow
    port: '80'
    proto: tcp

Добавить порты с циклом:

- name: Allow Ports in Firewall
  ufw:
    rule: allow
    port: "{{ item.port }}"
    proto: "{{ item.proto }}"
    comment: "{{ item.comment }}"
  loop:
    - { port: 5432, proto: tcp, comment: 'PostgreSQL' }

Подробнее: https://docs.ansible.com/ansible/latest/collections/community/general/ufw_module.html.

Работа с папками и файлами

Рассмотрим задачи, которые помогут нам создавать, копировать и работать с файлами.

1. Создание каталогов и файлов.

Создание файлов и каталогов выполняется с помощью модуля file.

а) для каталога в качестве state указываем directory:

- name: Create Directories
  file:
    path: "{{ item }}"
    state: directory
    owner: www-data
    group: www-data
    mode: 0755
  loop:
    - '/var/www/site1'
    - '/var/www/site2'

* в данном примере мы создадим 2 каталога: site1 и site2 в каталоге /var/www.

б) для создания файла указываем убираем опцию state (или даем ей значение file):

- name: Create File
  file:
    path: "/var/www/site1/index.php"
    owner: www-data
    group: www-data
    mode: 0644

* в данном примере мы созданим файл index.php в каталоге /var/www/site1.

О file: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html.

2. Копирование файлов из каталога.

Для копирования данных мы используем модуль copy:

- name: Copy Cert File If Different
  copy:
    src: "{{ item }}"
    dest: /etc/ssl/dmosk
    remote_src: no
    mode: 0644
    owner: root
    group: root
  with_fileglob:
    - files/*

* в данном примере мы прочитаем все содержимое каталога files на компьютере с ansible, и скопируем его в каталог /etc/ssl/dmosk на целевом компьютере.

О copy: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html.

3. Используем шаблон.

Копирование из шаблона отличается от копирования из файла тем, что в шаблоне могут использоваться переменные, которые будет заменяться их значениями в момент копирования. Для самого процесса копирования из шаблона используется модуль template:

- name: Create Config for Consul Agent
  template:
    src: templates/consul/config.json.j2
    dest: /etc/consul.d/config.json

* в данном примере мы возьмом шаблон templates/consul/config.json.j2 на компьютере ansible и разместим его в по пути /etc/consul.d/config.json на целевом компьютере.

О template: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html.

4. Удалить последние 30 файлов.

Задача решается в два этапа:

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

Поиск выполняем с помощью модуля find, удаление — file:

- name: "Get list of backup files"
  find:
    paths: "/backup"
    file_type: file
  register: founds

- name: "Delete last 30 Copies"
  file:
    path: "{{ item }}"
    state: absent
  loop: "{{ (founds.files | sort(attribute='mtime', reverse=True) | map(attribute='path') | list )[30:] }}"

* в данном примере мы ищем файлы в каталоге /backup, после чего сортируем найденное и удаляем по списку все файлы, которые идут после 30-го.

О find: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/find_module.html.

Виртуализация VMware

Работа с виртуальными машинами на платформе VMware выполняется с помощью модуля vmware_guest.

Подробнее о vmware_guest: https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html.

Мы рассмотрим несколько примеров.

1. Базовое подключение.

Для выполнения действий над виртуальными машинами мы должны подключиться к хосту VMware. Для этого используем данные строки:

- name: Connect to ESX Host
  vmware_guest:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no

* параметр validate_certs, выставленный в no, позволит избежать ошибки, если у нас на хосте используется самоподписанный сертификат (как правило, так и есть).

2. Переименовать виртуальную машину.

Для выполнения действия нам нужно знать идентификатор виртуальной машины:

- name: Rename a virtual machine
  vmware_guest:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    uuid: "{{ hw_product_uuid }}"
    name: "Template-{{ vm_name }}"
    state: present

* где uuid — идентификатор виртуальной машины; name — новое имя виртуальной машины.

3. Конвертировать виртуальную машину в шаблон.

Для этого нужно просто задать признак is_template:

- name: Convert virtual machine to Template
  vmware_guest:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    uuid: "{{ vm_info.instance.hw_product_uuid }}"
    is_template: true
    state: present

Разное

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

1. Шифрование строки.

С помощью ansible-vault мы можем шифровать файлы и папки. Это позволит нам хранить секреты не в открытом виде. Данные расшифровываются в момент выполнения задач.

Данной командой мы получаем шифрованную строку:

ansible-vault encrypt_string

Система запросит ввести дважды пароль и предложит ввести строку, которую нужно зашифровать. После мы должны нажать 2 раза Ctrl + D — мы получим строку, которая начинается с !Vault и различные символы. 

Для того, чтобы в момент выполнения задачи ansible расшифровал данные, при запуске плейбука мы должны указать ключ --ask-vault-pass:

ansible-playbook ... --ask-vault-pass

Об ansible-vault: https://docs.ansible.com/ansible/latest/user_guide/vault.html.

2. Игнорировать ошибки.

Если ansible столкнется с ошибкой при выполнении задачи, работа плейбука будет завершена. Иногда, нужно пропустить ошибку при выполнении определенной задачи, чтобы выполнение было продолжено. Для этого существует опция ignore.

а) чтобы пропустить ошибки выполнения, в настройка задачи используем:

- name: Bad Task
  ...
  ignore_errors: yes 

б чтобы игнорировать ошибки при подключении к хосту:

- name: Bad Task
  ...
  ignore_unreachable: yes 

3. Начинать выполнение с определенной задачи.

При выполнении отладки, полезно запустить плейбук, но начать выполнение с определенной задачи. Остальные пропустить. 

Это можно сделать с помощью опции --start-at-task:

ansible-playbook ... --start-at-task="Start Job"

* в данном примере плейбук начнет выполнять задания с задачи Start Job.

4. Завершить выполнение плейбука после определенной задачи.

С помощью данной конструкции:

- meta: end_play

5. Зависимые роли.

С помощью файла meta/main.yml в роли мы можем определить пред-роль, от которой зависит выполнение текущей роли. Для этого настраивается опция dependencies:

dependencies:
  - role: pred

6. Вставка роли и ее задач.

Позволяет в процессе выполнения задачи подключить роль. Делается при помощи include_role:

- name: "Include Other Role"
  include_role:
    name: other_role

А это пример, как подключить роль и сделать так, чтобы все ее задачи выполнились на определенном хосте:

- name: "Include Other Role"
  include_role:
    name: other_role
    apply:
      delegate_to: "{{ deploy_vm.instance.ipv4 }}"

Читайте также

Другая информация по Ansible:

1. Инструкция по установке и запуску Ansible на Linux.

2. Примеры ролей Ansible для установки сервисов и настройки системы.

# Управление # DevOps
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет