Настройка LEMP-сервера с помощью Ansible для простых проектов. Часть первая: знакомство с Ansible

от автора

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

Вот о чем мы сегодня расскажем:

  1. Знакомство.

  2. Разновидности инструментов автоматизации.

  3. Как работает Ansible?

  4. Установка Ansible.

  5. Подключаемся к удаленному сервер с Master.

  6. Конфигурация.

  7. Командные модули Ansible.

  8. Ansible-playbooks.

  9. Ansible Roles.

  10. Итог.

Знакомство

Ansible — это инструмент автоматизации процессов администрирования.

Пример: вышло обновление вашего приложения. Поставлена задача изменить версию php с 7.4 на 8.1. Как поступить?

  1. Сделать вручную.

    Зайти на каждый сервер и обновить версию. Этот вариант подходит, если у вас 2-3 сервера. А если серверов будет 100? Можно также сделать это вручную. Но зачем? Это займет очень много времени.

  2. С помощью инструментов автоматизации.

    Здесь на помощь приходят инструменты, которые позволяют написать конфигурацию и выполнить обновление в автоматическом режиме. Это экономит ваше время. И избавляет от кучи рутинной работы.

Понятия, которые нам помогут в дальнейшем:

  • Master — это главный сервер, на котором пишется код автоматизации (чаще всего в формате yml).

  • Удаленный сервер — это управляемые сервера.

Разновидности инструментов автоматизации

  1. Pull — на удаленных серверах устанавливается пакет, который делает выгрузку настроек с Master.

    Пример: Пакет автоматизации будет применять настройки только в том случае, если на удаленном сервере установлен точно такой же пакет и он готов принимать соединение с master сервера.

  2. 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

Основные ключи:

  1. [ ] — В данные скобки мы указываем название группы серверов.
    Пример: [dev]

  2. ansible_host — ip адрес.
    Пример: ansible_host = 0.0.0.0

  3. ansible_user — имя пользователя для подключения на удаленный сервер.
    Пример: ansible_user — test

  4. ansible_pass — Пароль пользователя.
    Пример: ansible_pass = 12345

  5. ansible_ssh_private_key_file — путь до закрытого ключа. Для входа без участия пароля.
    Пример: ansible_ssh_private_key_file = /home/test/.ssh/id_rsa

  6. 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
  1. Добавляем группу.
    [test]

  2. Добавляем удаленный сервер в данную группу.
    Указываем название сервера: ansible2

  3. Указываем ip-адрес удаленного сервера:
    ansible_host=0.0.0.0

  4. Указываем порт:
    ansible_port=22

  5. Указываем пользователя:
    ansible_user=root

  6. Указываем путь к закрытому ключу на 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
  1. -i путь к файлу inventory.

  2. all — это запуск на всех серверах, указанных в данном inventory-файле. Можно запускать вместо all название группы.
    Пример: test

  3. -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, в котором можно будет указать все нужные параметры для запуска.

Ключи:

  1. ask_pass — Может быть либо TRUE либо FALSE. Включить/выключить запрос пароля. По умолчанию стоит false. Если вы используете ключ для подключения, то менять нет необходимости.

  2. ask_sudo_pass — Значение либо TRUE, либо FALSE. По умолчанию указано TRUE. Это запрос sudo-пароля на удаленном сервере. Если на удаленном сервере отключен запрос sudo-пароля, то менять нет необходимости. Если запрос пароля необходим, измените данное значение на FALSE.

  3. forks — Количество параллельных процессов ansible. По умолчанию 5. Если у вас много серверов, то данное значение можно изменить. Тогда ansible будет выполнять настройки параллельно не на пяти серверах, а, например, на двадцати. Однако, нагрузка на сервер и сеть вырастет.

  4. host_ket_checking — проверка отпечатка hosts. По умолчанию указано TRUE. FALSE отключает проверку отпечатка.

  5. inventory — адрес inventory-файла по умолчанию.

  6. 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 на удаленный сервер.

Аргументы: 

  1. scr — адрес файла на master;

  2. dest — адрес куда сохранить файл на удаленный сервер;

  3. owner — имя пользователя, кому будет принадлежать файл;

  4. group — группа, кому будет принадлежать файл;

  5. 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 — выполняет действие с файлом. Удаляет, изменяет права пользователя и много чего еще.

Аргументы:

  1. path — путь до файла на удаленном хранилище;

  2. 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 и основанных на них (UbuntuLinux Mint и т. п.). При использовании Red Hat ОС можно использовать модуль yum.

Аргументы:

  1. name — имя сервиса, пакета;

  2. 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 — позволяет запускать/останавливать/перезагружать сервисы на удаленном сервере.

Аргументы:

  1. name — «название сервиса»;

  2. state — команда для изменения состояния;

  3. 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, поэтому никогда его там не используйте.

Ключи:

  1. name — присваивание названия группе/команде.
    Пример: name: Test PING

  2. hosts — указание группы серверов, на которых необходимо выполнить данную команду.
    Пример: hosts: all

  3. become — запуск sudo (если вы делаете настройки не под root-пользователем).

  4. tasks — указываем, что дальше будет идти исполняемая команда.

  5. 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 сервера с нуля.


ссылка на оригинал статьи https://habr.com/ru/company/nixys/blog/668458/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *