Как использовать различные типы переменных Ansible (примеры)

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

Если вы все еще учитесь использовать Ansible, вам также могут быть полезны вводные статьи в блоге Ansible Tutorial или Working with Ansible Playbooks. Вы можете найти код этой статьи в этом репозитории, если хотите проследить за ходом работы.

Почему переменные полезны в Ansible

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

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

Факты Ansible — это особый тип переменных, которые Ansible получает с любого удаленного узла, чтобы мы могли использовать их в проектах Ansible. Например, мы можем получить информацию о дистрибутиве операционной системы с помощью ansible_distribution, информацию об устройствах на хосте, версию python, которую использует Ansible, с помощью ansible_python_version, архитектуру системы и т.д. Чтобы получить доступ к этим данным, мы должны обратиться к переменной ansible_facts.

Правила наименования переменных

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

Определение и ссылка на простые переменные

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

- name: Example Simple Variable
  hosts: all
  become: yes
  vars:
    username: bob

  tasks:
  - name: Add the user {{ username }}
    ansible.builtin.user:
      name: "{{ username }}"
      state: present
Вход в полноэкранный режим Выйти из полноэкранного режима

В приведенном выше примере после блока vars мы определяем переменную username и присваиваем ей значение bob. Позже, чтобы сослаться на это значение в задаче, мы используем синтаксис Jinja2 следующим образом "{{ имя пользователя }}".

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

Список, словарь и вложенные переменные

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

vars:
  version:
    - v1
    - v2
    - v3
Войти в полноэкранный режим Выйти из полноэкранного режима

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

version: "{{ version[2] }}"
Войти в полноэкранный режим Выйти из полноэкранного режима

Еще одна полезная возможность — хранить пары ключ-значение в переменных в виде словарей. Например:

vars:
  users: 
    - user_1: maria
    - user_2: peter
    - user_3: sophie
Ввести полноэкранный режим Выйти из полноэкранного режима

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

users['user_3']
users.user_3
Enter fullscreen mode Выйти из полноэкранного режима

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

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

vars:
  cidr_blocks:
      production:
        vpc_cidr: "172.31.0.0/16"
      staging:
        vpc_cidr: "10.0.0.0/24"

tasks:
- name: Print production vpc_cidr
  ansible.builtin.debug:
    var: cidr_blocks['production']['vpc_cidr']
Вход в полноэкранный режим Выход из полноэкранного режима

Специальные переменные

Существуют определенные типы переменных, которые мы считаем специальными в контексте Ansible. К ним относятся магические переменные, переменные соединения и факты. Имена этих переменных зарезервированы.

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

Мы уже говорили о фактах. Эти переменные содержат всю информацию, которую Ansible может получить от текущего хоста. Чтобы использовать их, Ansible должен сначала собрать их. Чтобы увидеть все факты, которые можно собрать на хосте, выполните команду:

ansible <hostname> -m ansible.builtin.setup
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Регистрация переменных

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

- name: Example Register Variable Playbook
  hosts: all

  tasks:
  - name: Run a script and register the output as a variable
    shell: "find hosts"
    args:
      chdir: "/etc"
    register: find_hosts_output
  - name: Use the output variable of the previous task
    debug:
      var: find_hosts_output
Вход в полноэкранный режим Выход из полноэкранного режима

В приведенном выше примере мы регистрируем вывод команды find /etc/hosts и показываем, как можно использовать переменную в следующей задаче, выводя ее значение.

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

- name: Example Registered Variables Conditionals
  hosts: all

  tasks:
  - name: Register an example variable
    shell: cat /etc/hosts
    register: hosts_contents

  - name: Check if hosts file contains the word "localhost"
    debug:
      msg: "/etc/hosts file contains the word localhost"
    when: hosts_contents.stdout.find("localhost") != -1
      var: find_hosts_output
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь мы зарегистрировали в переменной hosts_contents содержимое файла /etc/hosts, и выполняем вторую задачу, только если в файле есть слово localhost.

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

Совместное использование переменных с помощью YAML-якорей и псевдонимов

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

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

- name: Example Anchors and Aliases
  hosts: all
  become: yes
  vars:
    user_groups: &user_groups
     - devs
     - support
    user_1:
        user_info: &user_info
            name: bob
            groups: *user_groups
            state: present
            create_home: yes
    user_2:
        user_info:
            <<: *user_info
            name: christina
    user_3:
        user_info:
            <<: *user_info
            name: jessica
            groups: support

  tasks:
  - name: Add several groups
    ansible.builtin.group:
      name: "{{ item }}"
      state: present
    loop: "{{ user_groups }}"

  - name: Add several users
    ansible.builtin.user:
      <<: *user_info
      name: "{{ item.user_info.name }}"
      groups: "{{ item.user_info.groups }}"
    loop:
      - "{{ user_1 }}"
      - "{{ user_2 }}"
      - "{{ user_3 }}"
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь, поскольку некоторые опции являются общими для разных пользователей, вместо того, чтобы переписывать одни и те же значения, мы разделяем общие значения с помощью якоря &user_info. Для каждого последующего объявления пользователя мы используем псевдоним *user_info, чтобы избежать повторений, насколько это возможно.

Значения для state и create_home одинаковы для всех пользователей, а имя и группы заменяются с помощью оператора слияния <<.

Аналогично, мы повторно используем объявление user_groups в определении якоря user_info. Таким образом, нам не придется снова вводить те же группы для пользователя_2, но при этом у нас остается возможность переопределить группы, как это делается для пользователя_3.

В результате пользователь_1 и пользователь_2 будут добавлены в группы devs и support, а пользователь_3 будет добавлен только в группу support.

Область действия переменных

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

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

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

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

Опции установки переменных и приоритет

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

Как мы уже видели ранее, самый простой способ — определить переменные в пьесе с помощью раздела vars.

- name: Set variables in a play
  hosts: all
  vars:
    version: 12.7.1
Войти в полноэкранный режим Выйти из полноэкранного режима

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

[webservers]
webserver1 ansible_host=10.0.0.1 ansible_user=user1
webserver2 ansible_host=10.0.0.2 ansible_user=user2

[webservers:vars]
http_port=80
Вход в полноэкранный режим Выход из полноэкранного режима

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

group_vars/databases 
group_vars/webservers
host_vars/host1
host_vars/host2
Войти в полноэкранный режим Выйти из полноэкранного режима

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

- name: Example External Variables file
  hosts: all
  vars_files:
    - ./vars/variables.yml

  tasks:
  - name: Print the value of variable docker_version
    debug: 
      msg: "{{ docker_version}} "

  - name: Print the value of group variable http_port
    debug: 
      msg: "{{ http_port}} "

  - name: Print the value of host variable app_version
    debug: 
      msg: "{{ app_version}} "
Вход в полноэкранный режим Выход из полноэкранного режима

Файл vars/variables.yml:

docker_version: 20.10.12
Вход в полноэкранный режим Выход из полноэкранного режима

Файл group_vars/webservers:

http_port: 80
ansible_host: 127.0.0.1
ansible_user: vagrant
Войдите в полноэкранный режим Выйти из полноэкранного режима

Файл host_vars/host1:

app_version: 1.0.1
ansible_port: 2222
ansible_ssh_private_key_file: ./.vagrant/machines/host1/virtualbox/private_key
Войти в полноэкранный режим Выйти из полноэкранного режима

Файл host_vars/host2:

app_version: 1.0.2
ansible_port: 2200
ansible_ssh_private_key_file: ./.vagrant/machines/host2/virtualbox/private_key
Войти в полноэкранный режим Выход из полноэкранного режима

Файл инвентаризации содержит группу с именем webservers, в которую входят два наших хоста, host1 и host2:

[webservers]
host1 
host2
Войти в полноэкранный режим Выйти из полноэкранного режима

Если мы запустим этот плейбук, мы заметим, что в обоих хостах используется одно и то же значение для групповой переменной http_port, но разное значение для переменной app_version.

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

Иногда нам может быть полезно определить или переопределить переменные во время выполнения, передав их в командной строке с аргументом —extra-vars или -e. Например:

ansible-playbook example-external-vars.yml --extra-vars "app_version=1.0.3"
Войти в полноэкранный режим Выйти из полноэкранного режима

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

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

Явные определения переменных, такие как каталог vars или задача include_vars, переопределяют переменные из инвентаря. Наконец, дополнительные переменные, определенные во время выполнения, всегда имеют приоритет. Полный список опций и их иерархию можно найти в официальной документации Understanding variable precedence.

Где устанавливать переменные и лучшие практики

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

  • Всегда давайте описательные и понятные имена вашим переменным. Уделите время тому, чтобы как следует подумать о том, как назвать переменные, это всегда приносит долгосрочные плоды.
  • Если для общих переменных существуют значения по умолчанию, установите их в group_vars/all.
  • Предпочтите устанавливать групповые и хостовые переменные в каталогах group_vars и host_vars, а не в файле инвентаризации.
  • Если переменные, связанные с географией или поведением, привязаны к определенной группе, предпочитайте задавать их как групповые переменные.
  • Если вы используете роли, всегда устанавливайте переменные роли по умолчанию в файле roles/your_role/defaults/main.yml.
  • Когда вы вызываете роли, передавайте переменные, которые вы хотите переопределить, в качестве параметров, чтобы ваши пьесы было легче читать.
roles:
       - role: example_role
         vars:
            example_var: 'example_string'
Вход в полноэкранный режим Выход из полноэкранного режима
  • Вы всегда можете использовать —extra-vars или -e, чтобы отменить все остальные параметры.
  • Не храните важные переменные в репозитории исходного кода в виде обычного текста. В таких случаях вы можете использовать Ansible Vault.

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

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

Спасибо за чтение, и я надеюсь, что эта статья «Переменные Ansible» понравилась вам так же, как и мне.

Оцените статью
Procodings.ru
Добавить комментарий