Ansible#

Astra Automation использует Ansible как основной инструмент для установки и настройки систем различной сложности.

Назначение#

Ansible – это система управления развертыванием и настройкой программного обеспечения. Система выполняет заданные директивы на указанных серверах, подключаясь к ним по протоколу SSH. Для этого необходимы только ключи SSH. Установка агентов на управляемые узлы не требуется.

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

  • расширения (plugins);

  • модули (modules);

  • роли (roles);

  • коллекции (collections).

Структура управления#

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

../../../_images/nodes-schema-light.svg ../../../_images/nodes-schema-dark.svg

Управляющий узел#

Управляющим узлом (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. По умолчанию в нем указан следующий порядок разрешения имен:

  1. Проверка записей, хранящихся в файле /etc/hosts.

  2. Обращение к серверу 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, описаны в разделе Automation Hub.

Факты#

Факты (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.