Примеры ролей Ansible для установки сервисов и настройки системы

Обновлено Обновлено: Опубликовано Опубликовано:

Используемые термины: Ansible, Bind, Prometheus, Grafana.

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

Подготовка к работе

Предполагается, что у нас уже есть сервер с установленным 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

* в данном примере мы:

  1. Создаем пользователя prometheus.
  2. Создаем каталоги, в которые будут помещены файлы сервиса.
  3. Скачиваем и распаковываем архив прометея с официального сайта.
  4. Копируем бинарники.
  5. Копируем конфигурационные файлы.
  6. Создаем юнит в systemd.
  7. Стартуем сервис.

Создаем 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

* в данном примере мы:

  1. Создаем пользователя alertmanager.
  2. Создаем каталоги, в которые будут помещены файлы сервиса.
  3. Скачиваем и распаковываем архив alertmanager с официального сайта.
  4. Копируем бинарники.
  5. Копируем конфигурационные файлы.
  6. Создаем юнит в systemd.
  7. Стартуем сервис.

Создаем файл в шаблонах с юнитом 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 задания:

  1. Перезапуск брандмауэра firewalld для применения настроек.
  2. Разрешение автозапуска сервиса 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 httpdreload 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 и user2state: 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

# DevOps # Linux # Серверы # Управление
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет