Примеры ролей Ansible для установки сервисов и настройки системы
Используемые термины: Ansible, Bind, Prometheus, Grafana.
Мы рассмотрим простые примеры установки различных систем с помощью ролей Ansible. Инструкция больше имеет практическое применение с минимальным количеством пояснений и комментариев, но хорошо подойдет в качестве шпаргалки.
Подготовка к работе с ролями
Описание процесса
NGINX
BIND
Prometheus
Grafana
Vault
Kubernetes
Сборка NGINX из исходников
Обновление сертификатов
Работа с учетными записями пользователей
Подготовка к работе
Предполагается, что у нас уже есть сервер с установленным Ansible, например, по инструкции Установка и запуск Ansible на CentOS.
В файл hosts мы должны добавить серверы, на которые будем устанавливать наши сервисы:
vi /etc/ansible/hosts
[test_servers]
192.168.1.115
192.168.1.116
* в моем примере мы добавили тестовую группу test_servers, а в нее 2 сервера.
Мы будем работать относительно каталога с ролями, поэтому создадим его и перейдем в созданную директорию:
mkdir /etc/ansible/roles
cd /etc/ansible/roles
Можно приступать к созданию ролей.
Синтаксис и описание
Пару слов о том, как будем работать.
Каждую роль мы создаем с помощью команды ansible-galaxy. Синтаксис следующий:
ansible-galaxy init <Имя роли>
После ввода команды в текущем каталоге (в нашем примере, /etc/ansible/roles) будет создана папка с названием роли, а в ней следующая структура каталогов:
- defaults — переменные по умолчанию. У них самый низкий приоритет и их могут легко переопределить переменные в каталоге vars (ниже по списку).
- files — для файлов, которые могут быть скопированы на настраиваемый сервер.
- handlers — обработчики, которые могут запускаться при определенных обстоятельствах. Например, перезапуск сервиса в случае обновления конфигурационного файла.
- meta — добавление метаданных, например: автор, описание, среда и так далее.
- tasks — папка с описанием выполняемых задач.
- templates — файлы с шаблонами. Мы можем использовать переменные в данных шаблонах — тогда при копировании файлов, они будут заменяться значениями.
- tests — скрипты для выполнения тестов — ansible покажет результаты выполнения команд, но не применит их.
- vars — файлы с переменными. Имеют высокий приоритет.
После будем приступать к настройке роли, созданию и запуску плейбука.
NGINX
Установке и настройке NGINX с помощью Ansible я посвятил отдельную инструкцию.
Bind DNS
Инициализируем новую роль:
ansible-galaxy init Bind
* мы назвали нашу роль Bind.
Открываем основной файл для задачи:
vi Bind/tasks/main.yml
Добавляем:
---
- name: Include vars for os family
include_vars:
file: "{{ ansible_os_family }}.yml"
- name: Install Bind on RedHat Family
yum:
name: bind
state: present
when:
ansible_os_family == "RedHat"
notify:
- bind systemd
- name: Install Bind on Debian Family
apt:
name: "{{ item }}"
state: present
loop:
- bind9
- dnsutils
when:
ansible_os_family == "Debian"
notify:
- bind systemd
* в зависимости от типа операционной системы мы подгрузим разные переменные (так как в разных системах имя для bind разное), после чего устанавливаем bind с помощью yum (для систем на базе Red Hat) или apt (Debian). Обратите внимание, что для систем Debian мы выполняем установку двух пакетов, для перечисления которых используем цикл.
Создаем файл с переменными для debian:
vi Bind/vars/Debian.yml
---
service_name : bind9
* с переменной service_name и значением bind9.
Также создаем файл с переменными в роли Bind для систем на базе Red Hat:
vi Bind/vars/RedHat.yml
---
service_name : named
* во втором файле значение для переменной service_name будет named.
Редактируем файл для handlers:
vi Bind/handlers/main.yml
---
- name: bind systemd
systemd:
name: "{{ service_name }}"
enabled: yes
state: started
* после установки bind необходимо разрешить автозапуск сервиса и стартовать его. Имя сервиса подставляется из переменной и зависит от типа операционной системы Linux.
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Bind
* в данном примере мы запускаем выполнение роли Bind на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK
Prometheus
Создаем файлы для роли, которую назовем Prometheus:
ansible-galaxy init Prometheus
Открываем на редактирование файл с заданиями:
vi Prometheus/tasks/main.yml
Логически, мы поделим задачи на 3 файла:
---
- name: Prepare For Install Prometheus
include_tasks: tasks/prepare.yml
- name: Install Prometheus
include_tasks: tasks/install_prometheus.yml
- name: Install Alertmanager
include_tasks: tasks/install_alertmanager.yml
* в первом файле будут описаны задачи для подготовки системы к установке Prometheus; во втором файле мы выполним установку системы мониторинга; в третьем файле описание для установки alertmanager.
Создаем первый файл с задачами:
vi Prometheus/tasks/prepare.yml
---
- name: Security Settings For RedHat
block:
- name: Allow Ports
firewalld:
port: "{{ item }}"
permanent: true
state: enabled
loop: [ '9090/tcp', '9093/tcp', '9094/tcp', '9100/tcp', '9094/udp' ]
notify:
- firewalld systemd restart
- name: Disable SELinux
selinux:
state: disabled
- name: Stop SELinux
shell: setenforce 0
ignore_errors: yes
when:
ansible_os_family == "RedHat"
- name: Security Settings For Debian
block:
- name: Allow TCP Ports
iptables:
chain: INPUT
rule_num: '1'
action: insert
protocol: tcp
jump: ACCEPT
destination_port: "{{ item }}"
loop: [ '9090', '9093', '9094', '9100' ]
- name: Allow UDP Ports
iptables:
chain: INPUT
rule_num: '1'
action: insert
protocol: udp
jump: ACCEPT
destination_port: '9094'
when:
ansible_os_family == "Debian"
* в данном примере будут открыты в брандмауэре порты для корректной работы prometheus и alertmanager, а также будет отключен SELinux. Мы используем условие when, чтобы применить нужные команды, разделенные блоками (block), к нужному типу дистрибутива Linux, однако, если в вашей среде не используется брандмауэр или на CentOS применяется iptables, необходимо внести коррекции.
Открываем файл с переменными:
vi Prometheus/vars/main.yml
Создаем две:
---
prometheus_version : 2.23.0
alertmanager_version : 0.21.0
* данным переменным в качестве значения присваиваем версии prometheus и alertmanager, которые необходимо установить. В нашем примере взяты последние версии на момент обновления инструкции. Актуальные версии можно посмотреть на странице загрузки.
Создаем файл с описанием задач по установке Prometheus:
vi Prometheus/tasks/install_prometheus.yml
---
- name: Create User prometheus
user:
name: prometheus
create_home: no
shell: /bin/false
- name: Create directories for prometheus
file:
path: "{{ item }}"
state: directory
owner: prometheus
group: prometheus
loop:
- '/tmp/prometheus'
- '/etc/prometheus'
- '/var/lib/prometheus'
- name: Download And Unzipped Prometheus
unarchive:
src: https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz
dest: /tmp/prometheus
creates: /tmp/prometheus/prometheus-{{ prometheus_version }}.linux-amd64
remote_src: yes
- name: Copy Bin Files From Unzipped to Prometheus
copy:
src: /tmp/prometheus/prometheus-{{ prometheus_version }}.linux-amd64/{{ item }}
dest: /usr/local/bin/
remote_src: yes
mode: preserve
owner: prometheus
group: prometheus
loop: [ 'prometheus', 'promtool' ]
- name: Copy Conf Files From Unzipped to Prometheus
copy:
src: /tmp/prometheus/prometheus-{{ prometheus_version }}.linux-amd64/{{ item }}
dest: /etc/prometheus/
remote_src: yes
mode: preserve
owner: prometheus
group: prometheus
loop: [ 'console_libraries', 'consoles', 'prometheus.yml' ]
- name: Create File for Prometheus Systemd
template:
src=templates/prometheus.service
dest=/etc/systemd/system/
notify:
- systemd reload
- name: Systemctl Prometheus Start
systemd:
name: prometheus
state: started
enabled: yes
* в данном примере мы:
- Создаем пользователя prometheus.
- Создаем каталоги, в которые будут помещены файлы сервиса.
- Скачиваем и распаковываем архив прометея с официального сайта.
- Копируем бинарники.
- Копируем конфигурационные файлы.
- Создаем юнит в systemd.
- Стартуем сервис.
Создаем yml-файл с задачами по установке и запуску alertmanager:
vi Prometheus/tasks/install_alertmanager.yml
---
- name: Create User Alertmanager
user:
name: alertmanager
create_home: no
shell: /bin/false
- name: Create Directories For Alertmanager
file:
path: "{{ item }}"
state: directory
owner: alertmanager
group: alertmanager
loop:
- '/tmp/alertmanager'
- '/etc/alertmanager'
- '/var/lib/prometheus/alertmanager'
- name: Download And Unzipped Alertmanager
unarchive:
src: https://github.com/prometheus/alertmanager/releases/download/v{{ alertmanager_version }}/alertmanager-{{ alertmanager_version }}.linux-amd64.tar.gz
dest: /tmp/alertmanager
creates: /tmp/alertmanager/alertmanager-{{ alertmanager_version }}.linux-amd64
remote_src: yes
- name: Copy Bin Files From Unzipped to Alertmanager
copy:
src: /tmp/alertmanager/alertmanager-{{ alertmanager_version }}.linux-amd64/{{ item }}
dest: /usr/local/bin/
remote_src: yes
mode: preserve
owner: alertmanager
group: alertmanager
loop: [ 'alertmanager', 'amtool' ]
- name: Copy Conf File From Unzipped to Alertmanager
copy:
src: /tmp/alertmanager/alertmanager-{{ alertmanager_version }}.linux-amd64/alertmanager.yml
dest: /etc/alertmanager/
remote_src: yes
mode: preserve
owner: alertmanager
group: alertmanager
- name: Create File for Alertmanager Systemd
template:
src=templates/alertmanager.service
dest=/etc/systemd/system/
notify:
- systemd reload
- name: Systemctl Alertmanager Start
systemd:
name: alertmanager
state: started
enabled: yes
* в данном примере мы:
- Создаем пользователя alertmanager.
- Создаем каталоги, в которые будут помещены файлы сервиса.
- Скачиваем и распаковываем архив alertmanager с официального сайта.
- Копируем бинарники.
- Копируем конфигурационные файлы.
- Создаем юнит в systemd.
- Стартуем сервис.
Создаем файл в шаблонах с юнитом systemd для prometheus:
vi Prometheus/templates/prometheus.service
[Unit]
Description=Prometheus Service
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
Создаем файл в шаблонах с юнитом systemd для alertmanager:
vi Prometheus/templates/alertmanager.service
[Unit]
Description=Alertmanager Service
After=network.target
[Service]
EnvironmentFile=-/etc/default/alertmanager
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/usr/local/bin/alertmanager \
--config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/prometheus/alertmanager \
$ALERTMANAGER_OPTS
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
Открываем на редактирование файл с обработчиками:
vi Prometheus/handlers/main.yml
Приводим его к виду:
---
- name: firewalld systemd restart
command: firewall-cmd --reload
- name: systemd reload
systemd:
daemon_reload: yes
* в данном примере мы будем перезапускать firewalld и перечитывать юниты в systemd.
Создаем плейбук:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- role: Prometheus
tags: prom
* данный файл описывает плейбук для запуска роли Prometheus. Обратите внимание, что для примера мы добавили тег prom.
Запускаем наш плейбук для установки Prometheus + Alertmanager:
ansible-playbook --tags prom start_role.yml -kK
* в данном примере запуск вложенной роли запускается с тегом prom. Это ни на что не влияет, но, если бы у нас в плейбуке будет много ролей, с помощью тега мы можем запускать конкретную.
Grafana
Инициализируем файлы для роли Grafana:
ansible-galaxy init Grafana
Открываем на редактирование файл с заданиями:
vi Grafana/tasks/main.yml
Установка будет учитывать системы типа Debian или Red Hat с помощью блоков:
- name: Security Settings And Install Grafana For RedHat
block:
- name: Allow Ports
firewalld:
port: '3000/tcp'
permanent: true
state: enabled
notify:
- firewalld systemd restart
- name: Disable SELinux
selinux:
state: disabled
- name: Stop SELinux
shell: setenforce 0
ignore_errors: yes
- name: Add Repository
yum_repository:
name: Grafana
description: Grafana YUM repo
baseurl: https://packages.grafana.com/oss/rpm
gpgkey: https://packages.grafana.com/gpg.key
gpgcheck: yes
sslverify: yes
sslcacert: /etc/pki/tls/certs/ca-bundle.crt
- name: Install Grafana on RedHat Family
yum:
name: grafana
state: present
notify:
- grafana systemd
when:
ansible_os_family == "RedHat"
- name: Security Settings And Install Grafana For Debian
block:
- name: Allow TCP Ports
iptables:
chain: INPUT
rule_num: '1'
action: insert
protocol: tcp
jump: ACCEPT
destination_port: '3000'
- name: Import Grafana Apt Key
apt_key:
url: https://packages.grafana.com/gpg.key
state: present
- name: Add APT Repository
apt_repository:
repo: deb https://packages.grafana.com/oss/deb stable main
state: present
- name: Install Grafana on Debian Family
apt:
name: grafana
state: present
notify:
- grafana systemd
when:
ansible_os_family == "Debian"
* в нашем примере мы независимо от системы создаем правило в брандмауэре для порта 3000, добавляем репозиторий, устанавливаем графану.
Редактируем файл для handlers:
vi Grafana/handlers/main.yml
---
- name: firewalld systemd restart
command: firewall-cmd --reload
- name: grafana systemd
systemd:
name: grafana-server
enabled: yes
state: started
* в нашем handlers есть 2 задания:
- Перезапуск брандмауэра firewalld для применения настроек.
- Разрешение автозапуска сервиса grafana.
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Grafana
* в данном примере мы запускаем выполнение роли Grafana на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK
Hasicorp Vault
Подробнее об установке и настройке Hashicorp Vault.
Инициализируем файлы для роли Vault:
ansible-galaxy init Vault
Открываем на редактирование файл с заданиями:
vi Vault/tasks/main.yml
Разделим наше задание на два этапа — преднастройку системы и установку Vault:
---
- name: Prepare System
include_tasks: tasks/prepare.yml
- name: Install Vault
include_tasks: tasks/install_vault.yml
Создаем файл с задачами для преднастройки системы:
vi Vault/tasks/prepare.yml
---
- name: Prepare System For RedHat
block:
- name: Install Packages
yum:
name: "{{ item }}"
state: present
loop:
- wget
- chrony
- curl
- name: Allow Ports
firewalld:
port: "{{ item }}"
permanent: true
state: enabled
immediate: yes
loop: [ '8200/tcp' ]
when:
ansible_os_family == "RedHat"
- name: Security Settings For Debian
block:
- name: Install Packages
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop:
- wget
- chrony
- curl
- apt-transport-https
- iptables-persistent
- name: Allow TCP Ports
iptables:
chain: INPUT
rule_num: '1'
action: insert
protocol: tcp
jump: ACCEPT
destination_port: "{{ item }}"
loop: [ '8200' ]
notify:
- iptables save
when:
ansible_os_family == "Debian"
Теперь создаем файл с заданиями по установке Vault:
vi Vault/tasks/install_vault.yml
- name: Install Hashicorp Vault For RedHat
block:
- name: Add Repository
get_url:
url: https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
dest: /etc/yum.repos.d/hashicorp.repo
- name: Install Vault
yum:
name: vault
state: present
notify:
- vault systemd
- name: Set Shell Enviroment
copy:
src: profile.d/vault.sh
dest: /etc/profile.d/vault.sh
when:
ansible_os_family == "RedHat"
- name: Install Hashicorp Vault For Debian
block:
- name: Import Vault Apt Key
apt_key:
url: https://apt.releases.hashicorp.com/gpg
state: present
- name: Add APT Repository
apt_repository:
repo: deb [arch=amd64] https://apt.releases.hashicorp.com {{ ansible_lsb.codename }} main
state: present
filename: hashicorp
- name: Install Vault
apt:
name: vault
state: present
notify:
- vault systemd
- name: Set Shell Enviroment
lineinfile:
path: /etc/environment
line: export VAULT_SKIP_VERIFY=true
create: yes
when:
ansible_os_family == "Debian"
Создаем хендлер для сохранения правил iptables и настройки сервиса vault:
vi Vault/handlers/main.yml
---
- name: iptables save
shell: netfilter-persistent save
- name: vault systemd
systemd:
name: "vault"
enabled: yes
state: started
Создаем каталог:
mkdir Vault/files/profile.d
Создадим в нем файл для настройки среды окружения для CentOS:
vi Vault/files/profile.d/vault.sh
export VAULT_SKIP_VERIFY=true
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Vault
* в данном примере мы запускаем выполнение роли Vault на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK
Кластер Kubernetes
В нашем примере мы создадим сценарий для настройки кластера под управлением Ubuntu Server. Подробнее о настройке Kubernetes на Ubuntu.
Для описания нод кластера мы будем использовать отдельный inventory файл:
mkdir /etc/ansible/inventory
vi /etc/ansible/inventory/kube_servers.yml
kube_servers:
vars:
ansible_python_interpreter: /usr/bin/python3
hosts:
server01:
ansible_host: master.dmosk.local
ansible_ssh_host: 192.168.100.12
server02:
ansible_host: worker01.dmosk.local
ansible_ssh_host: 192.168.100.13
server03:
ansible_host: worker02.dmosk.local
ansible_ssh_host: 192.168.100.14
children:
master:
hosts:
server01:
worker:
hosts:
server02:
server03:
* в нашем примере установка будет выполнена на три сервера — один мастер и два воркера. Также мы выделили 2 группы — master и worker в которые вошли соответствующие серверы. Такая инвентаризация позволит нам точно указать, какие серверы мы планируем использовать в качестве мастера, а какие в качестве рабочих нод.
Инициализируем роль:
ansible-galaxy init Kubernetes
Откроем файл с задачами:
vi Kubernetes/tasks/main.yml
Пропишем следующее:
---
- name: Set hostname
hostname:
name: "{{ hostvars[inventory_hostname].ansible_host }}"
- name: Add to hosts file cluster machines
blockinfile:
path: /etc/hosts
block: |
{% for host in groups['kube_servers'] %}
{{ hostvars[host].ansible_ssh_host }} {{ hostvars[host].ansible_host }}
{% endfor %}
- name: Disable SWAP 1/2 (swapoff)
shell: swapoff -a
- name: Disable SWAP 2/2 (fstab)
replace:
path: /etc/fstab
regexp: '^([^#].*?\sswap\s+sw\s+.*)$'
replace: '# \1'
- name: Create File for modules load
file:
path: /etc/modules-load.d/k8s.conf
state: touch
owner: root
group: root
mode: 0644
- name: Add modules k8s
lineinfile:
path: /etc/modules-load.d/k8s.conf
line: "{{ item }}"
loop:
- br_netfilter
- overlay
- name: Add br_netfilter and overlay modules
modprobe:
name: "{{ item }}"
state: present
loop:
- br_netfilter
- overlay
- name: Set sysctl bridge-nf-call options
sysctl:
name: "{{ item }}"
value: '1'
state: present
reload: yes
sysctl_file: /etc/sysctl.d/k8s.conf
loop:
- net.bridge.bridge-nf-call-ip6tables
- net.bridge.bridge-nf-call-iptables
- name: Docker install
package:
name:
- docker
- docker.io
state: present
- name: Copy daemon.json config file
copy:
src: daemon.json
dest: /etc/docker/daemon.json
remote_src: no
mode: 0644
owner: root
group: root
- name: Docker systemctl enable and start
systemd:
name: docker
enabled: yes
state: restarted
- name: Import kubernetes repo key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: "Add kubernetes repository"
apt_repository:
repo: deb https://apt.kubernetes.io/ kubernetes-xenial main
filename: kubernetes
- name: kubernetes install
apt:
name:
- kubelet
- kubeadm
- kubectl
state: present
update_cache: yes
- name: Hold kubernetes to update
dpkg_selections:
name: "{{ item }}"
selection: hold
loop:
- kubelet
- kubeadm
- kubectl
- name: Master Settings
block:
- name: kubeadm init pod-network-cidr
shell: kubeadm init --pod-network-cidr=10.244.0.0/16
ignore_errors: yes
- name: Set KUBECONFIG system environment permanently
lineinfile:
path: /etc/environment
line: export KUBECONFIG=/etc/kubernetes/admin.conf
- name: Install CNI (Container Networking Interface)
shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
- name: Get join command
shell: kubeadm token create --print-join-command
register: join_command
- name: Open ports on a firewall for Master
iptables:
action: insert
rule_num: 1
chain: INPUT
protocol: tcp
destination_port: "{{ item }}"
jump: ACCEPT
loop:
- "6443"
- "2379:2380"
- "10250:10252"
when: "'master' in group_names"
- name: Workers Settings
block:
- name: Open ports on a firewall for Worker
iptables:
action: insert
rule_num: 1
chain: INPUT
protocol: tcp
destination_port: "{{ item }}"
jump: ACCEPT
loop:
- "10250"
- "30000:32767"
- name: kubeadm init pod-network-cidr
shell: "{{ hostvars[groups['master'].0].join_command.stdout }}"
ignore_errors: yes
when: "'worker' in group_names"
- name: Install iptables-persistent
package:
name: iptables-persistent
state: present
- name: Save firewall rule
shell: netfilter-persistent save
Создаем конфигурационный файл daemon.json:
vi Kubernetes/files/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: kube_servers
user: root
gather_facts: true
become: true
become_method: su
become_user: root
roles:
- Kubernetes
* в данном примере мы запускаем выполнение роли Kubernetes на серверы из группы kube_servers.
Запускаем созданный плейбук:
ansible-playbook -i /etc/ansible/inventory/test_servers.yml start_role.yml
* обратите внимание, что с помощью опции -i мы указываем путь до инвентарного файла, который создали специально для данного примера.
Сборка из исходников NGINX
Ранее была указана ссылка на страницу с описанием установки NGINX из пакетов при помощи Ansible. Но если нам нужно добавить дополнительный модуль, необходима сборка веб-сервера из исходников. Данный пример, в большей степени, можно использовать для сборки и других пакетов.
В нашем примере мы соберем NGINX и добавим в него модуль SPNEGO. Модуль может быть любым — главное, понять принцип.
Создаем новую роль с любым названием, например, Nginx_Make:
ansible-galaxy init Nginx_Make
Открываем файл с переменными:
vi Nginx_Make/vars/main.yml
---
nginx_ver : 1.19.3
* нам нужна одна переменная для указания конкретной версии NGINX, которую мы хотим установить.
Открываем на редактирование файл с заданиями:
vi Nginx_Make/tasks/main.yml
---
- name: Security Settings For RedHat
block:
- name: Allow Ports
firewalld:
port: '{{ item }}/tcp'
permanent: true
state: enabled
immediate: true
loop: [ '80', '443' ]
notify:
- firewalld systemd restart
- name: Disable SELinux
selinux:
state: disabled
- name: Stop SELinux
shell: setenforce 0
ignore_errors: yes
when:
ansible_os_family == "RedHat"
- name: Security Settings For Debian
block:
- name: Allow TCP Ports
iptables:
chain: INPUT
rule_num: '1'
action: insert
protocol: tcp
jump: ACCEPT
destination_port: '{{ item }}'
loop: [ '80', '443' ]
when:
ansible_os_family == "Debian"
- name: Installing NGINX Dependencies On Debian
apt:
name: "{{ item }}"
update_cache: yes
state: present
loop:
- git
- build-essential
- libpcre++-dev
- zlib1g-dev
- libkrb5-dev
- libssl-dev
- libxslt-dev
- libgd-dev
when:
ansible_os_family == "Debian"
- name: Installing NGINX Dependencies On Red Hat
yum:
name: "{{ item }}"
state: present
loop:
- epel-release
- git
- pcre-devel
- openssl-devel
- libxml2-devel
- libxslt-devel
- gd-devel
- perl-ExtUtils-Embed
- gperftools-devel
when:
ansible_os_family == "RedHat"
- name: Unpacking Nginx Source
unarchive:
src: "http://nginx.org/download/nginx-{{ nginx_ver }}.tar.gz"
dest: /tmp/
remote_src: yes
creates: /tmp/nginx-{{ nginx_ver }}.tar.gz
register: nginx_source_unpack
- name: Clone Nginx Module From GitHub
git:
repo: "https://github.com/stnoonan/spnego-http-auth-nginx-module.git"
dest: /tmp/nginx-{{ nginx_ver }}/spnego-http-auth-nginx-module
register: module_source_clone
- name: Configuring NGINX Source With Custom Modules For Debian
command: "./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-module=spnego-http-auth-nginx-module"
args:
chdir: "/tmp/nginx-{{ nginx_ver }}"
when: nginx_source_unpack.changed or module_source_clone.changed
register: nginx_configure
- name: Installing NGINX
shell: make && make install
args:
chdir: "/tmp/nginx-{{ nginx_ver }}"
when: nginx_configure.changed
register: installed_nginx
- name: Create Nginx User For Red Hat
user:
name: nginx
create_home: no
shell: /bin/false
when:
ansible_os_family == "RedHat"
- name: Create Folder /var/lib/nginx
file:
path: "/var/lib/nginx"
state: directory
- name: Create File for Nginx Systemd
copy:
src: files/nginx.service
dest: /lib/systemd/system
notify:
- systemd reload
register: create_nginx_systemd
- name: Systemctl Nginx Restart
systemd:
name: nginx
state: restarted
enabled: yes
when: create_nginx_systemd.changed or installed_nginx.changed
* обратите внимание:
- необходимый набор зависимостей может оказаться индивидуальным, так как при добавлении других модулей система будет требовать других компонентов — лучшим решением будет собрать вручную nginx на тестовом сервере и определить точный набор пакетов для установки.
- в данном примере для добавления модуля SPNEGO необходимо его клонировать с GitHub и разместить в каталоге с исходником. Для установки другого модуля могут понадобиться другие действия. Необходимо изучить документацию для каждого конкретного модуля.
- опции конфигурирования индивидуальны и зависят от ваших потребностей. В данном примере используется общий набор опций.
Открываем файл для notify:
vi Nginx_Make/handlers/main.yml
---
- name: firewalld systemd restart
command: firewall-cmd --reload
- name: systemd reload
systemd:
daemon_reload: yes
Создаем файл для юнита systemd:
vi Nginx_Make/files/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
Restart=on-failure
[Install]
WantedBy=multi-user.target
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Nginx_Make
* в данном примере мы запускаем выполнение роли Nginx_Make на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK
Обновление сертификата
Так как большинство современных сервисов требуют для своей работы сертификат, рассмотрим пример централизованного их обновления.
Предположим, что у нас есть сертификат wildcard и необходимо его копировать на все серверы компании. Если серверов много, делать это вручную при очередном его обновлении неудобно.
И так, создаем новую роль:
ansible-galaxy init Update_Certs
Открываем на редактирование файл с заданиями:
vi Update_Certs/tasks/main.yml
---
- name: Register System Services
service_facts:
register: services_state
- name: Create Directories For Certs
file:
path: '/etc/ssl/dmoks'
state: directory
owner: root
group: root
mode: 0755
- name: Copy Cert File If Different
copy:
src: "{{ item }}"
dest: /etc/ssl/dmosk
remote_src: no
mode: 0644
owner: root
group: root
with_fileglob:
- files/*
notify:
- reload httpd
- reload nginx
- reload apache2
* будут выполняться следующие задачи:
- Register System Services — получаем список всех служб, которые работают на целевом компьютере
- Create Directories For Certs — создаем каталог /etc/ssl/dmoks, в который будем копировать сертификаты
- Copy Cert File If Different — копируем сертификаты в целевой каталог. Если были изменения в любом из файлов, по очереди запускаем 3 задачи в handlers для перезагрузки сервисов. Здесь нам нужно самостоятельно перечислить все службы, которые вам нужно перезагружать.
Открываем на редактирование файл в каталоге handlers:
vi Update_Certs/handlers/main.yml
Добавим строки:
---
- name: reload httpd
systemd:
name: httpd
state: restarted
when:
services_state.ansible_facts.services['httpd.service'].state == 'running'
ignore_errors: yes
- name: reload nginx
systemd:
name: nginx
state: restarted
when:
services_state.ansible_facts.services['nginx.service'].state == 'running'
ignore_errors: yes
- name: reload apache2
systemd:
name: apache2
state: restarted
when:
services_state.ansible_facts.services['apache2.service'].state == 'running'
ignore_errors: yes
* в задачах, в случае изменения сертификатов, мы выполняем задания reload httpd, reload nginx и reload apache2. Все задания описаны в данном файле. В данном примере мы проверяем, что сервисы запущены и если это так, перезапускаем их. Нам необходимо перезапускать все службы, которые используют сертификаты (в противном случае, обновленные сертификаты не будут использоваться). При необходимости дописать службы, делаем это по аналогии.
В каталог Update_Certs/files/ помещаем наши сертификаты — все содержимое данного каталога будет копироваться на целевые компьютеры в каталог /etc/ssl/dmosk.
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Update_Certs
* в данном примере мы запускаем выполнение роли Update_Certs на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK
Создание пользователя
Это довольно типичная задача для возможности контролировать на своих серверах учетные записи пользователей. Рассмотрим пример централизованного создания нескольких аккаунтов. Подробная инструкция на официальном сайте.
И так, создаем новую роль:
ansible-galaxy init Local_Users
Предположим, мы создадим пользователей user1 и user2. Сгенерируем хэши для их паролей:
openssl passwd -salt 'AnySalt' -1
* где AnySalt — произвольный текст для соли.
После ввода команды система запросит ввести пароль — вводим и получаем хэш, например:
Password:
$1$AnySalt$J1MdB0X9KWZBg7BxeC9Ee0
Копируем его — он понадобиться позже. После повторяем команду, вводим новый пароль и генерируем хэш для второго пользователя.
Открываем на редактирование файл с заданиями:
vi Local_Users/tasks/main.yml
---
- name: Add User For Servers
user:
name: '{{ item.name }}'
password: '{{ item.password }}'
state: present
update_password: on_create
loop:
- { name: 'user1', password: '$1$AnySalt$J1MdB0X9KWZBg7BxeC9Ee0' }
- { name: 'user2', password: '$1$AnySalt$It8oyh2yAISnUqI4jK5VR0' }
* в данном примере будут созданы пользователи из цикла loop, в котором перечислены связки логин и пароль — конкретно, в нашем случае, это user1 и user2; state: present говорит, что пользователь должен присутствовать в системе; update_password: on_create установит наш пароль только при создании пользователя, ползволив ему самому сменить данные для аутентификации.
Создаем файл для плейбука:
vi start_role.yml
---
- hosts: test_servers
user: dmosk
become: true
become_method: su
become_user: root
roles:
- Local_Users
* в данном примере мы запускаем выполнение роли Local_Users на серверы из группы test_servers.
Запускаем созданный плейбук:
ansible-playbook start_role.yml -kK