Мы продолжаем цикл обучающих статей для начинающих системных администраторов. В этом материале мы разберем Ansible, Ansible-Playbook, и как поднять полноценный веб-сервер с помощью системы автоматизации. Отметим, что если вы являетесь опытным администратором, можете смело пропускать данный материал.
Вот о чем мы сегодня расскажем:
-
Знакомство.
-
Разновидности инструментов автоматизации.
-
Как работает Ansible?
-
Установка Ansible.
-
Подключаемся к удаленному сервер с Master.
-
Конфигурация.
-
Командные модули Ansible.
-
Ansible-playbooks.
-
Ansible Roles.
-
Итог.
Знакомство
Ansible — это инструмент автоматизации процессов администрирования.
Пример: вышло обновление вашего приложения. Поставлена задача изменить версию php с 7.4 на 8.1. Как поступить?
-
Сделать вручную.
Зайти на каждый сервер и обновить версию. Этот вариант подходит, если у вас 2-3 сервера. А если серверов будет 100? Можно также сделать это вручную. Но зачем? Это займет очень много времени.
-
С помощью инструментов автоматизации.
Здесь на помощь приходят инструменты, которые позволяют написать конфигурацию и выполнить обновление в автоматическом режиме. Это экономит ваше время. И избавляет от кучи рутинной работы.
Понятия, которые нам помогут в дальнейшем:
-
Master — это главный сервер, на котором пишется код автоматизации (чаще всего в формате yml).
-
Удаленный сервер — это управляемые сервера.
Разновидности инструментов автоматизации
-
Pull — на удаленных серверах устанавливается пакет, который делает выгрузку настроек с Master.
Пример: Пакет автоматизации будет применять настройки только в том случае, если на удаленном сервере установлен точно такой же пакет и он готов принимать соединение с master сервера.
-
Push — на серверах не нужно устанавливать никакое ПО, требуется только доступ по SSH и master-сервер.
Пример: у нас есть master-сервер и 40 серверов. Заходить на новые сервера нет необходимости, достаточно будет запустить конфигурацию на master. После этого master сам запустит конфигурации на удаленный сервер.
Как работает Ansible?
Представьте себе master-сервер: на нем мы пишем конфигурацию, указываем ip-адреса серверов и полностью управляем процессом.
Пример: Мы написали конфигурацию по обновлению php7.4 до 8.1. Выполнили Push, после чего все настройки начали устанавливаться на всех удаленных серверах, которые были указаны в Ansible.
Установка Ansible
Установку делаем на master-сервере.
Добавим репозиторий ansible:
mcedit /etc/apt/sources.list
Вставляем:
deb http://ppa.launchpad.net/ansible/ansible/ubuntu focal main
Добавляем ключ репозитория:
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 93C4A3FD7BB9C367
Обновляем репозитории:
apt update
Установка:
apt install ansible
Проверяем:
ansible --version ansible [core 2.12.5] config file = /etc/ansible/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0] jinja version = 2.10.1 libyaml = True
Если у вас другая ОС, можете обратиться на официальный мануал.
Ansible установлен и готов к работе!
Подключаемся к удаленному серверу с Master
Создаем директорию для управления Ansible:
mkdir /var/ansible/
Переходим:
cd /var/ansbile/
Создаем inventory-файл. Файл, в котором будут перечислены все ip-адреса удаленных серверов. Формат файла можно использовать обычный txt либо yml. Название тоже любое.
touch hosts.txt
Основные ключи:
-
[ ] — В данные скобки мы указываем название группы серверов.
Пример: [dev] -
ansible_host — ip адрес.
Пример: ansible_host = 0.0.0.0 -
ansible_user — имя пользователя для подключения на удаленный сервер.
Пример: ansible_user — test -
ansible_pass — Пароль пользователя.
Пример: ansible_pass = 12345 -
ansible_ssh_private_key_file — путь до закрытого ключа. Для входа без участия пароля.
Пример: ansible_ssh_private_key_file = /home/test/.ssh/id_rsa -
ansible_port — порт подключения ssh.
Пример: ansible_port = 2222
Данные ключи будут основными. Стоит иметь в виду, что здесь перечислены не все ключи, остальные можно посмотреть в официальном мануале.
Прокидываем ваш ключ ssh на удаленный сервер.
На master генерируем ключ:
ssh-keygen -t rsa
Далее выводим ключ:
cat ~/.ssh/id_rsa.pub
Получится примерно такой ключ:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO2w+l5l0PM2cq8WAFWK3dJCAHuqYR5tno9aIQ1hoqMGdsZWRNntDQvIsId/uvXcqUZddK33QbhDjb4k5yq1IqkoClY/z5Ps3V/xvA3uWALFzB8SuFRB+OtJjbvqGO9QHct4RKEiIAdDdMWNhPHBoa4KDJszhs1+0j5DXp3N96BatO4sE4X6AzUWDb+YD3Lb3g2pPrr4YRvEDGRgE6YZLANV3nYmAaqVMqznWKnnXkbx4ccAEkmND4L/6FuJ+lv3mXpaSnLkDr3NhKjiCCH88BV+Nh3KD+dpp76hWvrgp5yrWvmJ6kpZU0jbgb4RXW0HkLb9TpVkyZgRV96RdWtr9JkQ0eSCgvNN+mtAOmDHmogijhrv0Eq54LINNsSNUjeeSPM51MiZRmXW68WgXjKbKKKpTzH0vj6E6p9vznlexRB2FulX+1fMj/toG8Js75GZXejpQ2XI9BWgrzZwsfhYx8m7jDa4/HOpsl6IqSm2ZYTRAydH+YhJjMWsMYnzXugmc= test@ansible2
Копируем ключ. Подключаемся к удаленному серверу и сохраняем этот ключ в authorized_keys. По адресу ~/.ssh/authorized_keys
touch ~/.ssh/authorized_keys
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO2w+l5l0PM2cq8WAFWK3dJCAHuqYR5tno9aIQ1hoqMGdsZWRNntDQvIsId/uvXcqUZddK33QbhDjb4k5yq1IqkoClY/z5Ps3V/xvA3uWALFzB8SuFRB+OtJjbvqGO9QHct4RKEiIAdDdMWNhPHBoa4KDJszhs1+0j5DXp3N96BatO4sE4X6AzUWDb+YD3Lb3g2pPrr4YRvEDGRgE6YZLANV3nYmAaqVMqznWKnnXkbx4ccAEkmND4L/6FuJ+lv3mXpaSnLkDr3NhKjiCCH88BV+Nh3KD+dpp76hWvrgp5yrWvmJ6kpZU0jbgb4RXW0HkLb9TpVkyZgRV96RdWtr9JkQ0eSCgvNN+mtAOmDHmogijhrv0Eq54LINNsSNUjeeSPM51MiZRmXW68WgXjKbKKKpTzH0vj6E6p9vznlexRB2FulX+1fMj/toG8Js75GZXejpQ2XI9BWgrzZwsfhYx8m7jDa4/HOpsl6IqSm2ZYTRAydH+YhJjMWsMYnzXugmc= test@ansible2" >> ~/.ssh/authorized_keys
Для проверки подключения можете попробовать подключится по ssh.
ssh USER@HOST
Возвращаемся на master. Открываем inventory-файл.
cd /var/ansible mcedit hosts.txt
-
Добавляем группу.
[test]
-
Добавляем удаленный сервер в данную группу.
Указываем название сервера:ansible2
-
Указываем ip-адрес удаленного сервера:
ansible_host=0.0.0.0
-
Указываем порт:
ansible_port=22
-
Указываем пользователя:
ansible_user=root
-
Указываем путь к закрытому ключу на master-сервере:
ansible_ssh_private_key_file=/root/.ssh/id_rsa
Вот что получилось:
[test] ansible2 ansible_host=0.0.0.0 ansible_port=22 ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa
Для проверки подключения нам необходимо запустить команду ansible с ключами.
ansible -i hosts.txt all -m ping
-
-i путь к файлу inventory.
-
all — это запуск на всех серверах, указанных в данном inventory-файле. Можно запускать вместо all название группы.
Пример: test -
-m модули ansible. В данном случае мы используем модуль ping, для проверки соединения.
Проверяем:
ansible -i hosts.txt all -m ping The authenticity of host '192.168.0.24 (192.168.0.24)' can't be established. ECDSA key fingerprint is SHA256:YejdpawsmOZjAh8M518r+lk7eRPTETdCEPsPzQezNd8. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Соглашаемся с сохранением отпечатка и получаем следующее (это делается единоразово; в дальнейшем мы проверку отпечатка отключим):
ansible2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" }
На наш запрос ping нам пришел ответ pong. Это значит, что соединение установлено, и мы можем делать с сервером все, что нам необходимо.
Конфигурация
Для дальнейшего удобства редактируем файл конфигурации Ansible, в котором можно будет указать все нужные параметры для запуска.
Ключи:
-
ask_pass — Может быть либо TRUE либо FALSE. Включить/выключить запрос пароля. По умолчанию стоит false. Если вы используете ключ для подключения, то менять нет необходимости.
-
ask_sudo_pass — Значение либо TRUE, либо FALSE. По умолчанию указано TRUE. Это запрос sudo-пароля на удаленном сервере. Если на удаленном сервере отключен запрос sudo-пароля, то менять нет необходимости. Если запрос пароля необходим, измените данное значение на FALSE.
-
forks — Количество параллельных процессов ansible. По умолчанию 5. Если у вас много серверов, то данное значение можно изменить. Тогда ansible будет выполнять настройки параллельно не на пяти серверах, а, например, на двадцати. Однако, нагрузка на сервер и сеть вырастет.
-
host_ket_checking — проверка отпечатка hosts. По умолчанию указано TRUE. FALSE отключает проверку отпечатка.
-
inventory — адрес inventory-файла по умолчанию.
-
log_path — адрес log-файла по умолчанию.
Больше ключей в официальном мануале.
Открываем конфигурацию:
mcedit /etc/ansible/ansible.cfg
Добавляем настройки по умолчанию:
[defaults]
Отключаем проверку отпечатка:
host_key_checking = false
Указываем файл inventory, чтобы не писать всегда ключ -i при запуске ansible:
inventory = /var/ansible/hosts.txt
Указываем log-файл:
log_path = /var/log/ansible/ansible.log
Получается:
[defaults] host_key_checking = false inventory = /var/ansible/hosts.txt log_path = /var/log/ansible/ansible.log
Проверяем:
ansible all -m ping ansible2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" }
Как видим, без указания ключа -i все работает.
Командные модули ansible
Все командные модули вызывается ключом -m.
command — выполняет команды на выбранных группах без участие оболочки shell. Команда для выполнение вызывается ключом -a (аргумент) и помещается в кавычки.
Пример: ansible test -m command -a «date»
# ansible test -m command -a "date" ansible2 | CHANGED | rc=0 >> Вс 22 мая 2022 08:28:23 UTC
У этого модуля есть минус: не будут работать переменные «<«, «>», «|», «;», «&». Например, вы не сможете делать grep с помощью данного модуля.
Более подробно: Официальный мануал.
shell — Делает все тоже самое, что и модуль command, только с участием оболочки shell.
Пример:
ansible test -m shell -a "cat /var/log/syslog | tail -5" ansible2 | CHANGED | rc=0 >> May 22 08:27:30 ansible2 python3[7211]: ansible-ansible.legacy.command Error Executing CMD:'“time”' Exception:[Errno 2] No such file or directory: b'\xe2\x80\x9ctime\xe2\x80\x9d' May 22 08:28:23 ansible2 python3[7238]: ansible-ansible.legacy.command Invoked with _raw_params=date _uses_shell=False warn=False stdin_add_newline=True strip_empty_ends=True argv=None chdir=None executable=None creates=None removes=None stdin=None May 22 08:29:23 ansible2 systemd[1]: session-16.scope: Succeeded. May 22 08:32:58 ansible2 systemd[1]: Started Session 17 of user nik. May 22 08:32:59 ansible2 python3[7381]: ansible-ansible.legacy.command Invoked with _raw_params=cat /var/log/syslog | tail -5 _uses_shell=True warn=False stdin_add_newline=True strip_empty_ends=True argv=None chdir=None executable=None creates=None removes=None stdin=None
Более подробно: Официальный мануал.
copy — модуль позволяет скопировать файл с master на удаленный сервер.
Аргументы:
-
scr — адрес файла на master;
-
dest — адрес куда сохранить файл на удаленный сервер;
-
owner — имя пользователя, кому будет принадлежать файл;
-
group — группа, кому будет принадлежать файл;
-
mode — права на файл.
Пример:
ansible test -m copy -a "src=/var/ansible/test.txt dest=/var owner=test group=test mode=644" ansible2 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": true, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/var/test.txt", "gid": 1000, "group": "test", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "test", "size": 0, "src": "/root/.ansible/tmp/ansible-tmp-1653209819.5195355-7928-33699130649859/source", "state": "file", "uid": 1000 }
Если делаете не из под root пользователя, то необходимо добавить -b (sudo) в конце.
ansible test -m copy -a "src=/var/ansible/test.txt dest=/var owner=nik group=nik mode=644" -b
В ином случае прав для записи в /var будет недостаточно, и будет выдана ошибка.
Более подробно: Официальный мануал.
file — выполняет действие с файлом. Удаляет, изменяет права пользователя и много чего еще.
Аргументы:
-
path — путь до файла на удаленном хранилище;
-
state — состояние.
Пример: Удалим файл, который мы скачали с помощью предыдущего модуля:
ansible test -m file -a "path=/var/test.txt state=absent" ansible2 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": true, "path": "/var/test.txt", "state": "absent" }
Более подробно: Официальный мануал.
apt — модуль для установки пакетов на удаленном сервере при условии использования операционных системах Debian и основанных на них (Ubuntu, Linux Mint и т. п.). При использовании Red Hat ОС можно использовать модуль yum.
Аргументы:
-
name — имя сервиса, пакета;
-
state — команда установить, удалить, обновить.
Пример:
ansible test -m apt -a "name=htop state=latest" ansible2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "cache_update_time": 1653211045, "cache_updated": false, "changed": false }
Более подробно: Официальный мануал.
service — позволяет запускать/останавливать/перезагружать сервисы на удаленном сервере.
Аргументы:
-
name — «название сервиса»;
-
state — команда для изменения состояния;
-
enabled — когда необходимо добавить в автозагрузку.
Пример:
test -m service -a "name=nginx state=started" ansible2 | FAILED! => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "msg": "Could not find the requested service nginx: host" }
В данном случае возвращается ошибка, т.к. nginx не установлен на удаленном сервере.
Более подробно: Официальный мануал.
Ansible-playbooks
Ansible Playbooks — это система управления конфигурацией и развертыванием на нескольких удаленных серверах. Формат файла: yml.
Пример: выше мы писали все команды вручную. С помощью playbook мы сможем все это объединить в один файл и запускать с помощью одной команды.
Запуск:
ansible-playbook и Адрес playbook.
Пример:
ansible-playbook playbook.yml
Как пример напишем playbook, который будет отправлять ping на все удаленные сервера.
Для начала создадим файл:
touch playbook.yml
Далее открываем:
mcedit playbook.yml
Напоминаем, что это формат yml, который не любит TAB, поэтому никогда его там не используйте.
Ключи:
-
name — присваивание названия группе/команде.
Пример: name: Test PING -
hosts — указание группы серверов, на которых необходимо выполнить данную команду.
Пример: hosts: all -
become — запуск sudo (если вы делаете настройки не под root-пользователем).
-
tasks — указываем, что дальше будет идти исполняемая команда.
-
name — присваивание названия команде.
Получается так:
- name: Test PING. hosts: all become: yes tasks: - name: ping ping:
ping: — это название модуля, который мы просим использовать.
Пробуем запустить:
ansible-playbook playbook.yml PLAY [Test PING.] ************************************************************************************TASK [Gathering Facts] *******************************************************************************ok: [ansible2] TASK [ping] ******************************************************************************************ok: [ansible2] PLAY RECAP *******************************************************************************************ansible2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
playbook вернул ok. Значит ping прошел, и playbook написан без ошибок.
Красиво написанные ansible playbook не обходятся без так называемых Roles:
Ansible Roles
Ansible Roles — это роли, позволяющие автоматически загружать связанные переменные, файлы, задачи, обработчики и другие артефакты Ansible на основе известной файловой структуры. После того, как вы сгруппируете свой контент по ролям, вы сможете легко использовать его повторно и загружать в репозитории — для использования его в дальнейшем на других хостах. Оф. мануал.
Roles позволяет создать удобную и понятную структуру директорий. Это очень упрощает администрирование в дальнейшем и позволяет понимать чужие playbook.
Для создания структуры директорий используется команда:
ansible-galaxy init <Название>
# ansible-galaxy init test - Role test was created successfully
Получаем такую структуру:
.└── test ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
defaults — присваиваются переменные по умолчанию. Данные переменные имеют низкий приоритет. Использоваться будут только в том случае, если до этого данная переменная не была объявлена ранее. В данной директории мы присваиваем defaults-переменные.
Пример: DOC_ROOT: /var/www/DOMAIN_NAME.com/
files — хранятся файлы, которые необходимо будет передать на удаленные сервера с помощью ролей. В данную директорию мы складываем файлы, которые необходимо перенести и использовать на удаленных серверах.
Пример: В данную директорию помещается код площадки для копирования на удаленный сервер.
handlers — это обработчик, который выполняется только при запуске через notify
-директиву. Обработчик выполняется в самом конце playbook, когда все задачи завершены без ошибок. В данную директорию мы помещаем обработчики, которые необходимо запустить в самом конце.
Пример:
handlers: - name: Restart Nginx service: name: nginx state: restarted
meta — метаданные для роли, включая ролевые зависимости. В данной директории мы указываем так называемые метаданные для проекта. Название компании, название репозиторий, название проекта.
По умолчанию main-файл в данной директории выглядит так:
galaxy_info: author: your name description: your role description company: your company (optional) license: license (GPL-2.0-or-later, MIT, etc) min_ansible_version: 2.1 galaxy_tags: [] dependencies: [] root@php:/var/ansible/test/meta# root@php:/var/ansible/test/meta# cat main.yml galaxy_info: author: your name description: your role description company: your company (optional) license: license (GPL-2.0-or-later, MIT, etc) min_ansible_version: 2.1 galaxy_tags: [] dependencies: []
tasks — основной список задач для Ansible. В данной директории мы указываем все задачи, которые необходимо выполнить на удаленном сервере.
Пример: установить nginx и открыть 80 порт.
templates — в данной директории хранятся файлы шаблоны для развертывания на удаленном сервере.
Пример: Мы помещаем default страницу nginx и default index.php, после чего передаем на удаленный сервер
tests — это название проекта, который был создан при использовании команды ansible-galaxy init <Название>
. В данной директории будет создан inventory-файл, в котором будут перечислены хосты удаленных серверов. В test.yml помещаются переменные для подключения к удаленному серверу (пользователь, порт и т.д.).
vars — аналог defaults. В данной директории присваиваются переменные для запуска ролей. Эта директория имеет приоритет выше, чем defaults.
Итог
В этой статье мы с вами рассмотрели теоретическую часть, которая нам будет необходима в будущем. В следующей статье мы будем использовать теорию на практике: построим план действий и развернем LEMP на удаленном сервере с помощью инструмента автоматизации.
Если у вас остались вопросы, можете задавать их в комментариях. Ставьте лайки и подписывайтесь на нас — в дальнейшем будем публиковать еще больше обучающих статьей.
Также подписывайтесь на наш telegram-канал DevOps FM.
Рекомендации для чтения:
ссылка на оригинал статьи https://habr.com/ru/company/nixys/blog/668458/
Добавить комментарий