Thank you for reading this post, don't forget to subscribe!
Группы хостов
Создадим тестовую группу хостов, на которой будем тестировать удаленную установку приложения.
Открываем файл хостов ansible:
vi /etc/ansible/hosts
Добавляем группу хостов или редактируем ее:
[redhat-servers]
192.168.0.11
[debian-servers]
192.168.0.12
* в данном примере мы создаем 2 группы хостов — redhat-servers для серверов семейства Red Hat и debian-servers — для deb-серверов. В каждую группу входят по одному серверу — 192.168.0.11 и 192.168.0.12.
Проверить доступность хостов для ansible можно командой:
ansible -m ping all -u ansible -k
* данной командой мы пропингуем все хосты из инвентаризационного файла hosts.
Создание плейбука
Создаем файл для playbook:
vi /etc/ansible/play.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
--- - hosts: redhat-servers become: true become_method: su become_user: root remote_user: ansible roles: - epel - nginx - hosts: debian-servers become: true become_method: sudo become_user: root remote_user: ansible roles: - nginx |
* где:
- --- — начало файла YAML. Данный формат имеет строгую структуру — важен каждый пробел;
- hosts — группа хостов, к которым будут применяться правила плейбука (если мы хотим, чтобы правила применялись ко всем хостам, указываем hosts: all);
- become — указывает на необходимость эскалации привилегий;
- become_method — метод эскалации привилегий;
- become_user — пользователь под которым мы заходим с помощью become_method;
- remote_user — пользователь, под которым будем подключаться к удаленным серверам;
- roles — список ролей, которые будут применяться для плейбука.
* В данном случае мы задействуем нашу группы хостов, которые создали в самом начале; повышаем привилегии методом su под пользователем root (su - root) для группы redhat-servers и методом sudo для debian-servers; подключение к серверам выполняется от пользователя ansible; используем созданную нами роль nginx (саму роль мы создадим позже). Для систем RPM сначала выполним роль epel — она будет отвечать за установку репозитория EPEL, так как в стандартном репозитории nginx нет.
Стоит отдельно уделить внимание вопросу повышения привилегий. IT-среды могут применять разные политики относительно безопасности. Например, на серверах CentOS, по умолчанию, нет sudo и повышать привилегии нужно с помощью su. В Ubuntu наоборот — по умолчанию есть sudo, а su не работает, так как пароль на root не устанавливается. В данном случае есть несколько путей при работе с Ansible:
- Как в нашем примере, разделить группы хостов на разные семейства операционных систем и применять к ним разные методы повышения привилегий. Чтобы данный плейбук корректно отработал, учетная запись, под которой идет удаленное подключение к серверу (в нашем примере ansible) должна иметь такой же пароль, как у пользователей root на серверах семейства Red Hat. Данный метод удобен с точки зрения отсутствия необходимости приводить к единому виду безопасность серверов разного семейства. Однако, с точки зрения безопасности лучше, чтобы пароли у root и ansible были разные.
- Использовать метод для создания плейбука, как описан выше, но запускать его с ключом --limit, например, ansible-playbook --limit=debian-servers … — таким образом, мы запустим отдельные задания для каждого семейства операционных систем и сможем ввести индивидуальные пароли для каждого случая.
- Мы можем на всех серверах deb установить пароль для пользователя root, таким образом, получив возможность для become_method: su.
- И наконец, можно для серверов Red Hat установить sudo и проходить become с помощью метода sudo.
Создание роли
Роли в Ansible используются для логического разделения плейбука. Они имеют строгий синтаксис и файловую структуру. Таким образом, конфигурация становится более упорядоченной и понятной для дальнейшей поддержки.
И так, для ролей должна быть четкая файловая структура — создаем каталоги:
mkdir -p /etc/ansible/roles/nginx/tasks
mkdir -p /etc/ansible/roles/epel/tasks
* в данном случае мы создали каталоги nginx, epel и tasks внутри каталога roles. В ansible это означает, что мы создали роли с названием nginx и epel, а файл main.yml, который мы поместим в каталоги tasks будет описывать задачи данных ролей.
Создаем файл с описанием задач для роли nginx:
vi /etc/ansible/roles/nginx/tasks/main.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
--- - name: Install Nginx Web Server on RedHat Family yum: name=nginx state=latest when: ansible_os_family == "RedHat" notify: - nginx systemd - name: Install Nginx Web Server on Debian Family apt: name=nginx state=latest when: ansible_os_family == "Debian" notify: - nginx systemd |
* где
- --- — начало файла YAML;
- name — название для роли (может быть любым);
- yum/apt — используемый модуль для установки приложения;
- yum/apt name — название пакета, которое мы устанавливаем;
- yum/apt state — состояние пакета, которое должно контролироваться ролью;
- when — условие, при котором данная роль будет выполняться;
- notify — обработчик, который будет вызван в случае успешного выполнения задачи. При необходимости, можно задать несколько обработчиков;
* В данном примере мы создали простую задачу для роли по развертыванию nginx. На системы RPM установка выполняется с помощью модуля yum, на deb — apt. Версия должна быть последней (latest); после установки пакета, необходимо разрешить автозапуск сервиса и запустить его.
* при установке пакетов также следует учитывать, что некоторые могут иметь разные названия в разных системах. Например, Apache в RMP-системах называется httpd, в deb — apache2.
Создаем файл с описанием задач для роли epel:
vi /etc/ansible/roles/epel/tasks/main.yml
1 2 3 4 5 |
--- - name: Install EPEL Repo yum: name=epel-release state=present |
Обратите внимание, что в плейбуке выше мы задействовали notify, но не задали handlers — в качестве примера, мы вынесем его в отдельный файл:
mkdir /etc/ansible/roles/nginx/handlers
vi /etc/ansible/roles/nginx/handlers/main.yml
1 2 3 4 5 6 |
--- - name: nginx systemd systemd: name: nginx enabled: yes state: started |
* handlers — описание обработчика, который может быть вызван с помощью notify; systemd — модуль для управления юнитами systemd; systemd enabled — разрешает или запрещает сервис; systemd state — состояние, которое должно быть у сервиса. В данном примере мы указываем, что у демона nginx должно быть состояние started и разрешен автозапуск (enabled).
Запуск плейбука
Запускаем наш плейбук:
ansible-playbook /etc/ansible/play.yml -kK
После ввода данной команды система запросит первый пароль для учетной записи, от которой мы подключаемся к удаленным серверам (в нашем примере мы задали ее в самом плейбуке, опции remote_user):
SSH password:
После ввода пароля, будет запрошен второй пароль — для повышения привилегий на самой удаленной системе:
BECOME password[defaults to SSH password]:
… в итоге мы должны увидеть следующую картину:
192.168.0.11 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.0.12 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Настройка NGINX с помощью шаблона ansible
После установки веб-сервера nginx необходимо его настроить. Процесс настройки мы разделим на создание переменных и шаблонов конфигурационных файлов, а также настройки роли для формирования конфигурационных файлов на основе шаблона.
Создаем общие переменные
Переменные задаются в файле main.yml, который находится в каталоге vars, который, в свою очередь, находится в каталоге роли. И так, создаем каталог для переменных:
mkdir /etc/ansible/roles/nginx/vars
… и сам файл main.yml:
vi /etc/ansible/roles/nginx/vars/main.yml
1 2 3 |
worker_processes: auto worker_connections: 2048 client_max_body_size: 512M |
* где представлены некоторые опции настройки NGINX:
- worker_processes — определяет количество рабочих процессов. Чаще всего, оптимальнее выставлять автоматическое конфигурирование.
- worker_connections — максимальное количество соединений одного рабочего процесса.
- client_max_body_size — максимальный размер загружаемых данных.
Шаблон для nginx.conf
Создаем каталог для хранения шаблонов:
mkdir /etc/ansible/roles/nginx/templates
… и создаем первый шаблон для конфигурационного файла nginx.conf:
vi /etc/ansible/roles/nginx/templates/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
user {{ nginx_user }}; worker_processes {{ worker_processes }}; worker_priority -1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections {{ worker_connections }}; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; reset_timedout_connection on; client_body_timeout 35; send_timeout 30; gzip on; gzip_min_length 1000; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript; gzip_disable "msie6"; types_hash_max_size 2048; client_max_body_size {{ client_max_body_size }}; proxy_buffer_size 64k; proxy_buffers 4 64k; proxy_busy_buffers_size 64k; server_names_hash_bucket_size 64; include /etc/nginx/modules-enabled/*.conf; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } |
* это пример рабочего конфигурационного файла. Переменных могло быть и больше, но для демонстрации их использования, вполне, достаточно. Сами переменные заключены в двойные фигурные скобки и были нами определены в файле выше (кроме переменной nginx_user, которая будет определена в настройках плейбука, так как для каждого типа операционной системы она должна быть своя).
Теперь настраиваем нашу роль для использования шаблона:
vi /etc/ansible/roles/nginx/tasks/main.yml
1 2 3 4 |
- name: Replace nginx.conf template: src=templates/nginx.conf dest=/etc/nginx/nginx.conf |
* данная роль определяет, каким файлом на сервере ansible (src) необходимо заменить файл на удаленной системе (dest).
И последнее, открываем файл плейбука:
vi /etc/ansible/play.yml
1 2 3 4 5 6 7 8 9 |
- hosts: redhat-servers vars: nginx_user: nginx ... - hosts: debian-servers vars: nginx_user: www-data ... |
* в данном примере мы создаем переменную nginx_user. Так как для разных семейств операционных систем используются разные пользователя для nginx по умолчанию, мы также сделали переменную с разными значениями для RPM и deb.
Готово — запускаем плейбук:
ansible-playbook /etc/ansible/play.yml -kK
… и вводим дважды пароли. На наших серверах должен появиться конфигурационной файл nginx.conf в соответствии с нашим шаблоном.
Шаблон для создания виртуальных доменов в NGINX
Создадим виртуальные домены при помощи ansible. Сначала создадим переменные — для каждого сервера должны быть свои домены — такие переменные можно задать в файле hosts, котором мы создавали хосты для ansible:
vi /etc/ansible/hosts
1 2 3 4 5 |
[redhat-servers] 192.168.0.11 virtual_domain=domain1.test.ru [debian-servers] 192.168.0.12 virtual_domain=domain2.test.ru |
* мы создали переменную virtual_domain, у которой будут свои значения для каждого хоста.
Создаем шаблон:
vi /etc/ansible/roles/nginx/templates/nginx_vhosts.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
server { listen 80; server_name {{ virtual_domain }} www.{{ virtual_domain }}; root /var/www/{{ virtual_domain }}; access_log /var/log/nginx/{{ virtual_domain }}_access_log; error_log /var/log/nginx/{{ virtual_domain }}_error_log; location / { fastcgi_pass unix:{{ fastcgi_pass_path }}; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|docx|xls|xlsx|exe|pdf|ppt|tar|wav|bmp|rtf|js)$ { expires modified +1w; } } |
* в данном примере мы создаем простой конфигурационный файл для создания виртуального домена. В качестве самого домена берется значение переменной virtual_domain, которую мы задали через файл hosts. Переменная fastcgi_pass_path будет создана для каждой группы систем своя и определяем путь до сокетного файла для взаимодействия nginx с fastcgi.
Настраиваем нашу роль — создаем 3 задачи:
vi /etc/ansible/roles/nginx/tasks/main.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
--- ... - name: Create home directory for www file: path: /var/www/{{ virtual_domain }} state: directory - name: Add virtual domain in NGINX for RPM vars: fastcgi_pass_path: /var/run/php-fpm/php5-fpm.sock template: src=templates/nginx_vhosts.conf dest=/etc/nginx/conf.d/{{ virtual_domain }}.conf when: ansible_os_family == "RedHat" notify: - nginx restart - name: Add virtual domain in NGINX for Deb vars: fastcgi_pass_path: /run/php/php7.2-fpm.sock template: src=templates/nginx_vhosts.conf dest=/etc/nginx/sites-enabled/{{ virtual_domain }}.conf when: ansible_os_family == "Debian" notify: - nginx restart |
* первая задача нужна для создания каталога, в котором будут находиться файлы сайта (без данного каталога наш конфигурационный сайт выдаст ошибку при попытке перезапустить сервис nginx). Вторая задача создаем конфигурационный файл для виртуального домена, который находится в каталоге /etc/nginx/conf.d; источником данных служит созданный нами шаблон nginx_vhosts.conf; также мы задаем переменную fastcgi_pass_path, которая будет указывать путь до сокетного файла. Третья задача также создает конфигурацию для виртуального домена на базе созданного шаблона; в отличие от второй задачи, третья создает конфигурационный файл в каталоге /etc/nginx/sites-enabled, а также имеет другое значение переменной fastcgi_pass_path. После успешного выполнения задачи, будет отправлен сигнал на перезапуск службы nginx для применения настроек (некоторые сервисы принимают более предпочтительный вариант — reloaded).Также мы добавили условие — вторая задача будет применяться к система на базе Red Hat, третья — Debian.
* на самом деле, мы могли две последние задачи объединить в одну, а переменную fastcgi_pass_path задать в файле плейбука. Но мы так поступили намеренно, чтобы продемонстрировать возможность использования переменных при описании роли.
Открываем обработчик:
vi /etc/ansible/roles/nginx/handlers/main.yml
Дописываем:
1 2 3 4 5 6 7 |
--- ... - name: nginx restart service: name=nginx state=restarted |
Запускаем плейбук:
ansible-playbook /etc/ansible/play.yml -kK
Теги
В нашем примере нам не довелось использовать теги — еще одну удобную возможность управления запуском плейбука.
Теги позволяют отметить роль и при запуске плейбука запустить именно ее, проигнорировав другие роли. Например, есть такой плейбук:
1 2 3 4 5 6 |
... roles: - role: nginx tags: web1 - role: apache tags: web2 |
* в данном плейбуке есть две роли — одна называется nginx, вторая — apache; для каждой роли мы задали свой тег.
Теперь, чтобы запустить плейбук, но выполнить в нем определенную роль, нам достаточно указать тег:
ansible-playbook --tags web2 /etc/ansible/play.yml -kK
* данная команда запустит плейбук с выполнением только роли с тегом web2 (в нашем примере, apache).
Ansible Galaxy
пара слов о Ansible Galaxy. Грубо говоря, это репозиторий готовых плейбуков и ролей. Найти файлы, соответствующую задаче, а также документацию можно на портале galaxy.ansible.com. Установка выполняется командой ansible-galaxy, например:
ansible-galaxy install geerlingguy.apache
* данная команда создаст в каталоге пользователя папку .ansible/roles/geerlingguy.apache — в нее поместит файлы с описанием роли.
Готовые библиотеки можно использовать для выполнения задач или просто как шпаргалки.