Ansible#
Astra Automation использует Ansible как основной инструмент для установки и настройки систем различной сложности.
Назначение#
Ansible – это система управления развертыванием и настройкой программного обеспечения. Система выполняет заданные директивы на указанных серверах, подключаясь к ним по протоколу SSH. Для этого необходимы только ключи SSH. Установка агентов на управляемые узлы не требуется.
Базовая функциональность Ansible обеспечивается большим количеством встроенных модулей. При этом возможности Ansible можно расширять с помощью следующих компонентов:
расширения (plugins);
модули (modules);
роли (roles);
коллекции (collections).
Структура управления#
При использовании Ansible управляющий узел подключается к управляемым узлам и запускает на них команды настройки.
Управляющий узел#
Управляющим узлом (control node) называется компьютер, на который устанавливают компоненты Ansible и который используют для запуска заданий по настройке управляемых узлов.
Подробности об управляющем узле см. в документации Ansible.
Управляемые узлы#
Управляемым узлом (managed node) называется компьютер, настраиваемый с помощью Ansible.
Подробности об управляемых узлах см. в документации Ansible.
Инвентарь#
Инвентарь – это файл формата INI
или YAML
, в котором хранятся данные об управляемых узлах.
Подробности о файлах инвентаря см. в документации Ansible.
В самом простом случае достаточно указать для каждого управляемого узла только его IP-адрес:
192.168.56.11
192.168.56.12
192.168.56.13
Также допускается использовать доменные имена, например:
dc01.example.com
dc02.example.com
dc03.example.com
В этом случае разрешение доменного имени каждого узла в IP-адрес происходит путем обращения к системной службе разрешения имен.
В Astra Linux настройки этой службы хранятся в файле /etc/nsswitch.conf
.
По умолчанию в нем указан следующий порядок разрешения имен:
Проверка записей, хранящихся в файле
/etc/hosts
.Обращение к серверу DNS, указанному в настройках сети.
Чтобы сделать инвентарь не зависящим от службы разрешения имен, для каждого узла всегда явно указывайте его IP-адрес в поле ansible_host
, например:
dc01.example.com ansible_host=192.168.56.11
dc02.example.com ansible_host=192.168.56.12
dc03.example.com ansible_host=192.168.56.13
Использование переменных при заполнении инвентаря#
Использование переменных Ansible позволяет упростить заполнение инвентаря.
Пусть имеется инвентарь следующего вида:
[all]
node1 ansible_host=192.168.56.1 ansible_ssh_private_key=./node1-ssh-key
node2 ansible_host=192.168.56.2 ansible_ssh_private_key=./node2-ssh-key
node3 ansible_host=192.168.56.3 ansible_ssh_private_key=./node3-ssh-key
node4 ansible_host=192.168.56.4 ansible_ssh_private_key=./node4-ssh-key
node5 ansible_host=192.168.56.5 ansible_ssh_private_key=./node5-ssh-key
Поскольку имена файлов приватных ключей SSH содержат названия соответствующих узлов, эту запись можно упростить следующим образом:
[all]
node1 ansible_host=192.168.56.1
node2 ansible_host=192.168.56.2
node3 ansible_host=192.168.56.3
node4 ansible_host=192.168.56.4
node5 ansible_host=192.168.56.5
[all:vars]
ansible_ssh_private_key=./{{ inventory_hostname }}-ssh-key
Иерархия компонентов playbook#
Иерархия исполняемых компонентов в скриптах Ansible:
Playbook (набор сценариев) состоит из plays (сценариев), использующих инвентарный список, который указывается при запуске playbook с помощью параметра
-i
или в конфигурационном файлеansible.cfg
. Утилитаansible-playbook
начинает выполнение playbook.Play (сценарий) состоит из множества задач, выполняемых для указанных узлов и групп узлов из определенного инвентарного списка.
Task (задача) использует один из модулей Ansible для выполнения отдельной операции по настройке управляемого узла.
Module (модуль) реализует требуемую функциональность. Например, существуют модули для копирования файлов, управления пакетами и службами и т. д. Код модулей выполняется на управляемых узлах.
Plugin (расширение) расширяет функциональность Ansible. В отличие от модулей, код расширений выполняется на управляющем узле.
Задача#
Задача (task) – это минимальный шаг по настройке управляемого узла.
Подробности о задачах см. в документации Ansible.
Сценарий#
Сценарий (play) – это одна или несколько задач, выполняемых на указанных управляемых узлах.
Подробности о сценариях см. в документации Ansible.
Playbook#
Playbook – это файл формата YAML
, содержащий перечень сценариев по настройке управляемых узлов.
Подробности о playbook см. в документации Ansible.
Роль#
Роли используют для группирования задач при развертывании и настройке сложных систем. Роль объединяет несколько задач и может быть использована в различных playbook.
Пример создания структуры каталогов для роли:
ansible-galaxy init httpd
где httpd
– название каталога, который будет реализовывать требуемую роль.
Файлы playbook содержат список подключаемых ролей как в следующем примере:
- hosts: all
user: root
port: 22
gather_facts: True
roles:
- { role: selinux, tags: selinux }
- { role: httpd, tags: httpd }
- { role: resolver, tags: resolver }
Если необходимо выполнить какую-то одну роль, то можно выполнить этот playbook, указав конкретную роль с помощью аргумента -t
, например -t selinux
.
Подробности о ролях см. в документации Ansible.
Коллекция#
Коллекцией (collection) называется распространяемый как единое целое набор компонентов, расширяющих возможности Ansible.
Подробности о коллекциях см. в документации Ansible.
Особенности коллекций, доступных на портале Automation Hub, описаны в разделе Коллекции Ansible.
Факты#
Факты (facts) – это набор сведений об управляемом узле, например, архитектура и версия установленной ОС, версия BIOS, наличие в системе определенных устройств и тому подобное.
Для просмотра всех доступных фактов об узле необходимо выполнить команду:
- name: Show all available facts
ansible_builtin.debug:
var: ansible_facts
Пример списка фактов об управляемом узле
{
"ansible_facts": {
"all_ipv4_addresses": [
"10.0.2.15",
"192.168.56.101"
],
"all_ipv6_addresses": [
"fe80::a00:27ff:fe0d:82ad",
"fe80::a00:27ff:feac:2f5c"
],
"ansible_local": {},
"apparmor": {
"status": "disabled"
},
"architecture": "x86_64",
"bios_date": "12/01/2006",
"bios_vendor": "innotek GmbH",
"bios_version": "VirtualBox",
"board_asset_tag": "NA",
"board_name": "VirtualBox",
"board_serial": "NA",
"board_vendor": "Oracle Corporation",
"board_version": "1.2",
"chassis_asset_tag": "NA",
"chassis_serial": "NA",
"chassis_vendor": "Oracle Corporation",
"chassis_version": "NA",
"cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-6.1.50-1-generic",
"net.ifnames": "0",
"parsec.max_ilev": "63",
"quiet": true,
"ro": true,
"root": "UUID=17007b23-97d0-46fd-90b6-2c359be9c2b0"
},
"date_time": {
"date": "2024-01-29",
"day": "29",
"epoch": "1706532112",
"epoch_int": "1706532112",
"hour": "15",
"iso8601": "2024-01-29T12:41:52Z",
"iso8601_basic": "20240129T154152867152",
"iso8601_basic_short": "20240129T154152",
"iso8601_micro": "2024-01-29T12:41:52.867152Z",
"minute": "41",
"month": "01",
"second": "52",
"time": "15:41:52",
"tz": "MSK",
"tz_dst": "MSK",
"tz_offset": "+0300",
"weekday": "Понедельник",
"weekday_number": "1",
"weeknumber": "05",
"year": "2024"
},
"default_ipv4": {
"address": "10.0.2.15",
"alias": "eth0",
"broadcast": "10.0.2.255",
"gateway": "10.0.2.2",
"interface": "eth0",
"macaddress": "08:00:27:0d:82:ad",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.2.0",
"prefix": "24",
"type": "ether"
},
"default_ipv6": {},
"device_links": {
"ids": {
"sda": [
"ata-VBOX_HARDDISK_VBcf71a1d6-26264a12"
],
"sda1": [
"ata-VBOX_HARDDISK_VBcf71a1d6-26264a12-part1"
]
},
"labels": {},
"masters": {},
"uuids": {
"sda1": [
"17007b23-97d0-46fd-90b6-2c359be9c2b0"
]
}
},
"devices": {
"loop0": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop1": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop2": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop3": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop4": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop5": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop6": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"loop7": {
"holders": [],
"host": "",
"links": {
"ids": [],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "0",
"sectorsize": "512",
"size": "0.00 Bytes",
"support_discard": "0",
"vendor": null,
"virtual": 1
},
"sda": {
"holders": [],
"host": "SATA controller: Intel Corporation 82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode] (rev 02)",
"links": {
"ids": [
"ata-VBOX_HARDDISK_VBcf71a1d6-26264a12"
],
"labels": [],
"masters": [],
"uuids": []
},
"model": "VBOX HARDDISK",
"partitions": {
"sda1": {
"holders": [],
"links": {
"ids": [
"ata-VBOX_HARDDISK_VBcf71a1d6-26264a12-part1"
],
"labels": [],
"masters": [],
"uuids": [
"17007b23-97d0-46fd-90b6-2c359be9c2b0"
]
},
"sectors": "61435904",
"sectorsize": 512,
"size": "29.29 GB",
"start": "2048",
"uuid": "17007b23-97d0-46fd-90b6-2c359be9c2b0"
}
},
"removable": "0",
"rotational": "1",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "mq-deadline",
"sectors": "61440000",
"sectorsize": "512",
"size": "29.30 GB",
"support_discard": "0",
"vendor": "ATA",
"virtual": 1
}
},
"distribution": "Astra Linux",
"distribution_file_parsed": true,
"distribution_file_path": "/etc/os-release",
"distribution_file_variety": "NA",
"distribution_major_version": "1",
"distribution_release": "1.7_x86-64",
"distribution_version": "1.7_x86-64",
"dns": {
"domain": "astralinux.ru",
"nameservers": [
"10.0.2.3"
],
"search": [
"astralinux.ru"
]
},
"domain": "",
"effective_group_id": 1000,
"effective_user_id": 1000,
"env": {
"HOME": "/home/vagrant",
"LANG": "ru_RU.UTF-8",
"LC_CTYPE": "C.UTF-8",
"LOGNAME": "vagrant",
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/games",
"PWD": "/home/vagrant",
"SHELL": "/bin/bash",
"SHLVL": "1",
"SSH_CLIENT": "192.168.56.11 37284 22",
"SSH_CONNECTION": "192.168.56.11 37284 192.168.56.101 22",
"SSH_TTY": "/dev/pts/0",
"TERM": "xterm",
"USER": "vagrant",
"XDG_RUNTIME_DIR": "/run/user/1000",
"XDG_SESSION_CLASS": "user",
"XDG_SESSION_ID": "31",
"XDG_SESSION_TYPE": "tty",
"_": "/usr/bin/python3"
},
"eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "10.0.2.15",
"broadcast": "10.0.2.255",
"netmask": "255.255.255.0",
"network": "10.0.2.0",
"prefix": "24"
},
"ipv6": [
{
"address": "fe80::a00:27ff:fe0d:82ad",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "08:00:27:0d:82:ad",
"module": "e1000",
"mtu": 1500,
"pciid": "0000:00:03.0",
"promisc": false,
"speed": 1000,
"type": "ether"
},
"eth1": {
"active": true,
"device": "eth1",
"ipv4": {
"address": "192.168.56.101",
"broadcast": "192.168.56.255",
"netmask": "255.255.255.0",
"network": "192.168.56.0",
"prefix": "24"
},
"ipv6": [
{
"address": "fe80::a00:27ff:feac:2f5c",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "08:00:27:ac:2f:5c",
"module": "e1000",
"mtu": 1500,
"pciid": "0000:00:08.0",
"promisc": false,
"speed": 1000,
"type": "ether"
},
"fibre_channel_wwn": [],
"fips": false,
"form_factor": "Other",
"fqdn": "node-1",
"gather_subset": [
"all"
],
"hostname": "node-1",
"hostnqn": "",
"interfaces": [
"eth0",
"eth1",
"lo"
],
"is_chroot": false,
"iscsi_iqn": "",
"kernel": "6.1.50-1-generic",
"kernel_version": "#astra2+ci6 SMP PREEMPT_DYNAMIC Fri Oct 6 14:38:42 UTC 2023",
"lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"broadcast": "",
"netmask": "255.0.0.0",
"network": "127.0.0.0",
"prefix": "8"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 65536,
"promisc": false,
"type": "loopback"
},
"lsb": {
"codename": "1.7_x86-64",
"description": "Astra Linux 1.7 x86-64",
"id": "AstraLinux",
"major_release": "1",
"release": "1.7_x86-64"
},
"machine": "x86_64",
"machine_id": "d383adfed45648cdbd75a02273b61314",
"memfree_mb": 1639,
"memory_mb": {
"nocache": {
"free": 1805,
"used": 160
},
"real": {
"free": 1639,
"total": 1965,
"used": 326
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"memtotal_mb": 1965,
"module_setup": true,
"mounts": [
{
"block_available": 6732778,
"block_size": 4096,
"block_total": 7514846,
"block_used": 782068,
"device": "/dev/sda1",
"fstype": "ext4",
"inode_available": 1884545,
"inode_total": 1921360,
"inode_used": 36815,
"mount": "/",
"options": "rw,relatime,errors=remount-ro",
"size_available": 27577458688,
"size_total": 30780809216,
"uuid": "17007b23-97d0-46fd-90b6-2c359be9c2b0"
}
],
"nodename": "node-1",
"os_family": "Astra Linux",
"pkg_mgr": "apt",
"proc_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-6.1.50-1-generic",
"net.ifnames": "0",
"parsec.max_ilev": "63",
"quiet": true,
"ro": true,
"root": "UUID=17007b23-97d0-46fd-90b6-2c359be9c2b0"
},
"processor": [
"0",
"GenuineIntel",
"Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz",
"1",
"GenuineIntel",
"Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz"
],
"processor_cores": 2,
"processor_count": 1,
"processor_nproc": 2,
"processor_threads_per_core": 1,
"processor_vcpus": 2,
"product_name": "VirtualBox",
"product_serial": "NA",
"product_uuid": "NA",
"product_version": "1.2",
"python": {
"executable": "/usr/bin/python3",
"has_sslcontext": true,
"type": "cpython",
"version": {
"major": 3,
"micro": 3,
"minor": 7,
"releaselevel": "final",
"serial": 0
},
"version_info": [
3,
7,
3,
"final",
0
]
},
"python_version": "3.7.3",
"real_group_id": 1000,
"real_user_id": 1000,
"selinux": {
"status": "disabled"
},
"selinux_python_present": true,
"service_mgr": "systemd",
"ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJe9D5fI+xDzdcOfpQ/JzxooISS7wskk7RzuX1Qe2eB+yIitXmNBkzRUTvTGsokhQCGPzl8rRlPEOcWCkwA37O4=",
"ssh_host_key_ecdsa_public_keytype": "ecdsa-sha2-nistp256",
"ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAILjVQqxasGBvwxxIFoAV+b37omFihnDLe/AW1XT0raVF",
"ssh_host_key_ed25519_public_keytype": "ssh-ed25519",
"ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABgQC5SLc9hewzm7M9prRWaR+v5ds0Qjj41Bzb2rZz0ITwHrEAIcdSXXvlRkq2wQgGxdcVLgWNOrTrE/xEvX2iwJffJ2yyILr+yXlBQehYbqCJhZt7zkF7KyLwC/QESIRG416U5KQuviMStXCbLBOoTo1BmNHNW8jX2NE4/8hY/M94/naC86wJ805/l4Dc2+FKXTua8/yq53Abc8I9RBP7qMPOx7nAcbCmiKxJd1IED2Bj9avwhsYKCdWqBlKMJ3EUccrVYM20Jhp5j/EqTRYWtkpda2XSkFkXTYgU0nmyboav0JDd18PmnxcG3/Jzzm5m/EDM3vulRqWoqIYTCmAh5F32tleJllhBsMHsGOmYWgXUF0zEZob1kkn5/mUVMHxN3lLdxkjY7WRuTXjaplW71fgV6Mq3mJIaHHVuBnpUkwFwWLZdPkLEQyma0lrK5O1W2Uenxmed5Y72vMq2Mvj+X5P3TngSDBCTDsCsJRV7Yr0q7Q7Sb4lzYo617ki96jflZfk=",
"ssh_host_key_rsa_public_keytype": "ssh-rsa",
"swapfree_mb": 0,
"swaptotal_mb": 0,
"system": "Linux",
"system_capabilities": [
""
],
"system_capabilities_enforced": "True",
"system_vendor": "innotek GmbH",
"uptime_seconds": 58762,
"user_dir": "/home/vagrant",
"user_gecos": "vagrant,,,",
"user_gid": 1000,
"user_id": "vagrant",
"user_shell": "/bin/bash",
"user_uid": 1000,
"userspace_architecture": "x86_64",
"userspace_bits": "64",
"virtualization_role": "guest",
"virtualization_tech_guest": [
"virtualbox"
],
"virtualization_tech_host": [],
"virtualization_type": "virtualbox"
}
}
Подробности об использовании фактов см. в документации Ansible.