Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Мы продолжаем цикл обучающих статей для начинающих системных администраторов. В этом материале мы разберем 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.0ansible_user - имя пользователя для подключения на удаленный сервер.
Пример: ansible_user - testansible_pass - Пароль пользователя
Пример: ansible_pass = 12345ansible_ssh_private_key_file - путь до закрытого ключа. Для входа без участия пароля.
Пример: ansible_ssh_private_key_file = /home/test/.ssh/id_rsaansible_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/authorized_keys >> ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO2w+l5l0PM2cq8WAFWK3dJCAHuqYR5tno9aIQ1hoqMGdsZWRNntDQvIsId/uvXcqUZddK33QbhDjb4k5yq1IqkoClY/z5Ps3V/xvA3uWALFzB8SuFRB+OtJjbvqGO9QHct4RKEiIAdDdMWNhPHBoa4KDJszhs1+0j5DXp3N96BatO4sE4X6AzUWDb+YD3Lb3g2pPrr4YRvEDGRgE6YZLANV3nYmAaqVMqznWKnnXkbx4ccAEkmND4L/6FuJ+lv3mXpaSnLkDr3NhKjiCCH88BV+Nh3KD+dpp76hWvrgp5yrWvmJ6kpZU0jbgb4RXW0HkLb9TpVkyZgRV96RdWtr9JkQ0eSCgvNN+mtAOmDHmogijhrv0Eq54LINNsSNUjeeSPM51MiZRmXW68WgXjKbKKKpTzH0vj6E6p9vznlexRB2FulX+1fMj/toG8Js75GZXejpQ2XI9BWgrzZwsfhYx8m7jDa4/HOpsl6IqSm2ZYTRAydH+YhJjMWsMYnzXugmc= test@ansible2
Для проверки подключения можете попробовать подключится по 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 PINGhosts - указание группы серверов, на которых необходимо выполнить данную команду
Пример: hosts: allbecome - запуск 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.
Рекомендации для чтения:
Зашита от dos/ddos.
Обучение docker.
10 частых ошибок в настройке nginx.
Настройка LEMP сервера с нуля.