Создание новых экземпляров Nextcloud  с помощью скриптов Ansible

Всем привет!  Хочу поделиться с вами вариантом скрипта для создания экземпляров Nextcloud через Ansible в vCloudDirector. Заодно опишу процесс создания экземпляров Nextcloud. Возможно, у вас тоже бывают подобные задачи, — можете не изобретать ещё один велосипед, вот один из вариантов решения.

Для начала приведу схему инфраструктуры, в которой будут разворачиваться новые экземпляры Nextcloud.

24783c426205fe9020a7c4a66bdc1f32.jpeg

Добавлю немного подробностей, чтобы картинка стала понятнее.

Все серверы в инфраструктуре — виртуальные, развёрнуты в Vmware Cloud Director (далее VCD). Они работают под управлением ОС Ubuntu 20.04. В качестве reverse proxy используется веб-сервер Nginx. 

Новые разворачиваемые экземпляры Nextcloud представлены на схеме как Nextcloud Instances. В качестве сервера выполнения скрипта создания новых экземпляров Nextcloud используется Scripts. Этот сервер имеет ssh доступы по ключу на Nginx и все создаваемые экземпляры. Также Scripts может посылать API запросы к Vmware Cloud Director. 

Для доступов к интернету используется NSX EDGE Gateway, а для разрешения доменных имён — публичный DNS сервер (он так и обозначен на схеме). Все экземпляры Nextcloud находятся в одном домене domainname.com. Вместо этого имени должен быть ваш домен. Также предполагается, что SSL сертификаты на домен domainname.com получены и добавлены на Nginx.

Скрипт создания новых экземпляров Nextcloud

Скрипт выполняется на виртуальном сервере Scripts. На нём установлен Ansible с модулем ansible-module-vcloud-director для работы с API VCD. Он состоит из главного скрипта на bash и отдельных скриптов для определённых действий на Ansible и Python. Вот их список:

  1. create_instances_nextcloud.sh

  2. create_vapp.yml

  3. create_vm_in_vapp.yml

  4. list_nics.yml

  5. insert_txt.py

  6. config_next.yml

  7. config_nginx.yml

  8. nextcloud_template_tls

Скрипт create_instances_nextcloud.sh выглядит так:

#!/bin/bash
ansible-playbook create_vapp.yml --extra-vars "orgname=$1"
ansible-playbook create_vm.yml --extra-vars "orgname=$1"
ip=$(ansible-playbook list_nics.yml --extra-vars "orgname=$1" 2>&1 | grep '"ip_address":' | grep -E -o '[0-9]{1,3}(\.[0-9]{1,3}){3}')
last_name_conf_next="nextcloud_tls"
name_config_next="$1$last_name_conf_next"
echo "[$1]" >> ansible_hosts
echo "$ip" >> ansible_hosts
cp nextcloud_template_tls "$name_config_next"
./insert_txt.py $1 $ip $name_config_next
last_domain_name_nextcloud="next.domainname.com"
domain_name_nextcloud="$1$last_domain_name_nextcloud"
scp $name_config_next root@192.168.4.3:/etc/nginx/sites-available
ansible-playbook config_nginx.yml --extra-vars "name_config_next=$name_config_next"
sleep 60
ansible-playbook config_next.yml --extra-vars "orgname=$1 ip=$ip domain_name_nextcloud=$domain_name_nextcloud password=$2"

Скрипт принимает два параметра:

  1. Имя экземпляра Nextcloud. Является суффиксом к доменному имени next.domainname.com

  2. Пароль пользователя admin в Nextcloud

Во второй строке скрипта используется ansible playbook create_vapp.yml. Он нужен для создания нового vApp в VCD. Приведу его содержание:

- name: vCloudDirectorAnsible
  hosts: localhost
  environment:
       env_user: admin
       env_password: password
       env_host: vcd.domainname.ru            ## VCD Instance URL
       env_org: name_org             ## VCD ORG to login
##      env_api_version: PYVCLOUD_API_VERSION
       env_verify_ssl_certs: false
  tasks:
  - name: create vapp
    vcd_vapp:
      vapp_name: "{{ orgname }}Nextcloud"
      vdc: "name_VDC"
      description: "name_VDC"
      network: "name_network"
      deploy: true
      power_on: true
      accept_all_eulas: false
      state: "present"

Playbook принимает параметр «orgname», что является суффиксом к названию нового экземпляра Nextcloud

В переменной «environment» задаются «credentials», такие как:

  1. env_user — имя пользователя с правами администратора организации

  2. env_password — пароль пользователя

  3. env_host — доменное имя VCD

  4. env_org — название организации в VCD

Далее выполняется задача создания vapp. В переменной vcd_vapp вводятся данные, необходимые для нового vApp:

  1. vapp_name — Название vApp с суффиксом названия экземпляра Nextcloud передаваемый в переменной orgname

  2. vdc — название VDC где будет создаваться экземпляр Nextcloud

  3. description — опиcание vApp (может быть любым)

  4. network — имя сети которую необходимо подключить к vApp

  5. power_on — включить vApp после создания

  6. state — present означает что нужно создать vApp

Далее в скрипте create_instances_nextcloud.sh (3 строка) выполняется playbook create_vm.yml создания виртуальной машины в ранее созданном vApp. Создание виртуальной машины происходит из заранее подготовленного шаблона ВМ с Nextcloud. Вот содержание playbook:

- name: vCloudDirectorAnsible
  hosts: localhost
  environment:
       env_user: name_admin
       env_password: password
       env_host: vcd.domainname.ru            ## VCD Instance URL
       env_org: name_VDC             ## VCD ORG to login
##      env_api_version: PYVCLOUD_API_VERSION
       env_verify_ssl_certs: false
  tasks:
  - name: create vapp vm from catalog
    vcd_vapp_vm:
      target_vm_name: "{{ orgname }}Nextcloud"
      target_vapp: "{{ orgname }}Nextcloud"
      target_vdc: name_VDC
      source_vdc: "name_source_VDC"
      source_catalog_name: name_Catalog
      source_template_name: template_name
      source_vm_name: source_vm_name
      hostname: "{{ orgname }}Nextcloud"
      ip_allocation_mode: "POOL"
      power_on: "true"
      all_eulas_accepted: "true"
      network: network_name
      deploy: false
      state: "present"

Playbook как и в предыдущем случае принимает один параметр: «orgname».

Как и в предыдущем playbook в переменной «environment» указываются «credentials». Далее создаётся задача создания виртуальной машины в vApp, где в переменной «vcd_vapp_vm» указываются следующие данные:

  1. target_vm_name — имя создаваемой машины с суффиксом названия экземпляра Nextcloud, передаваемым через переменную orgname

  2. target_vapp — название vApp, в котором будет создаваться ВМ, с суффиксом названия экземпляра Nextcloud передаваемым в переменной «orgname»

  3. target_vdc — название VDC, в котором будет создаваться ВМ

  4. source_catalog_name — имя каталога, в котором находится шаблон

  5. source_template_name — имя шаблона с Nextcloud, который будет разворачиваться

  6. source_vm_name — имя ВМ, которая находится в шаблоне

  7. hostname — сетевое имя ВМ с суффиксом названия экземпляра Nextcloud, передаваемым через переменную «orgname»

  8.  ip_allocation_mode — способ назначения ip-адреса ВМ. Выбран способ static_ip_pool

  9. power_on — включить или нет машину после создания. Выбрано «Да».

  10. network — имя сети, к которой необходимо подключить создаваемую ВМ. Имя сети совпадает с именем сети, которая подключается к vApp при его создании в прошлом playbook. 

  11.  State — поставлена present. Это означает, что будет создаваться новая ВМ

На этом этапе выполнения вывод скрипта будет примерно таким:

60e03f8d8c206c49ff31f3a65ff5e8d2.png

После создания vApp и VM в нём, нам необходимо узнать ip-адрес, который получила новая ВМ и записать его в переменную «ip» командой в строке 4 скрипта create_instances_nextcloud.sh. Делается это при помощи playbook «list_nics.yml». Вот его содержание:

- name: vCloudDirectorAnsible
  hosts: localhost
  environment:
       env_user: name_admin
       env_password: password
       env_host: vcd.domainname.ru            ## VCD Instance URL
       env_org: name_org             ## VCD ORG to login
##      env_api_version: PYVCLOUD_API_VERSION
       env_verify_ssl_certs: false
  tasks:
    - name: list vapp vm nics
      vcd_vapp_vm:
        target_vm_name: "{{ orgname }}Nextcloud"
        target_vapp: "{{ orgname }}Nextcloud"
        target_vdc: name_VDC
        operation: "list_nics"
      register: command_output
    - debug:
             var: command_output

Playbook принимает параметр «orgname».

Как и в предыдущих playbook в переменной «environment» указываются «credentials» . Затем создаётся задача просмотра информации о интерфейсах. В переменной vcd_vapp_vm указываются:

  1. target_vm_name — имя ВМ, информацию по которой хотим получить. Совпадает с именем ВМ, которые были указаны в предыдущих playbook.

  2. target_vapp — имя vApp, в котором находится ВМ

  3. target_vdc — имя VDC, в котором находится ВМ

  4. operation — тип операции. Используется операция получения информации по интерфейсам «list_nics»

Далее выполняется подготовка конфигурационных файлов Nginx. Делается это путём редактирования единого шаблона конфигурации под именем nextcloud_template_tls. Этот шаблон был создан из конфигурации путём удаления строки «server_name ;» и «proxy_pass http://127.0.0.1:11000$request_uri;». 

В строке 5 и 6 скрипта create_instances_nextcloud.sh задаётся имя конфигурационного файла Nginx для экземпляра Nextcloud. Затем добавляются строки в инвентарный файл Ansible для нового экземпляра Nextcloud в командах под строками 7 и 8 скрипта create_instances_nextcloud.sh. 

В строке 9 копируется шаблон конфигурации Nginx nextcloud_template_tls под новым именем, которое хранится в переменной name_config_next. Затем при помощи скрипта на Python insert_txt.py вставляются нужные строки для нашего экземпляра Nextcloud. Вот содержание этого скрипта:

#!/usr/bin/python3.8
import sys
def insert(file, line, column, text):
    ln, cn = line - 1, column - 1         # offset from human index to Python index
    count = 0                             # initial count of characters
    with open(file, 'r+') as f:           # open file for reading an writing
        for idx, line in enumerate(f):    # for all line in the file
            if idx < ln:                  # before the given line
                count += len(line)        # read and count characters 
            elif idx == ln:               # once at the line                                 
                f.seek(count + cn)        # place cursor at the correct character location
                remainder = f.read()      # store all character afterwards                       
                f.seek(count + cn)        # move cursor back to the correct character location
                f.write(text + remainder) # insert text and rewrite the remainder
                return                    # You're finished!
if __name__ == "__main__":
  nextcloud_domain_name='server_name ' + sys.argv[1] + 'next.domainname.com;'
  directve_proxy_pass_next='proxy_pass https://' + sys.argv[2] + '$request_uri;'
  template_nextcloud=sys.argv[3]
  insert(template_nextcloud, 27, 5, nextcloud_domain_name)
  insert(template_nextcloud, 30, 9, directve_proxy_pass_next)

Этот скрипт принимает 3 параметра:

  1. Суффикс — суффикс имени нового экземпляра Nextcloud. Является суффиксом доменного имени next.domainname.com

  2. IP адрес — ip-адрес нового экземпляра Nextcloud

  3. Имя конфигурационного файла Nginx для Nextcloud

В итоге данный скрипт добавляет директивы «server_name» и «proxy_pass» в конфигурационный файл Nginx, где domainname.com — домен, в котором будет находиться ваш экземпляр Nextcloud.

Далее в строках 11, 12 скрипта create_instances_nextcloud.sh переменой domain_name_nextcloud присваивается доменное имя Nextcloud, где domainname.com — домен, в котором будет находиться ваш экземпляр Nextcloud. 

В строке 13 скрипта create_instances_nextcloud.sh подготовленный конфигурационный файл копируется на Nginx по ssh при помощи команды scp. 

В строке 14 задаётся конфигурация Nginx при помощи playbook config_nginx.yml. Вот его содержание:

- name: "Run a shell command on a remote host"
  hosts: nginx*
  tasks:
  - name: create simvolic url 
    shell: |
       ln -s /etc/nginx/sites-available/{{ name_config_next }} /etc/nginx/sites-enabled/{{ name_config_next }}
       /etc/init.d/nginx reload

Playbook принимает один параметр «name_config_next», что является именем конфигурационного файла, который мы подготавливали ранее.

В этом playbook удалённо выполняются команды по ssh на Nginx proxy. Например, команды создания символической ссылки в каталоге «sites-enabled» на конфигурационный файл, который мы скопировали ранее в каталог «sites-available». После этого Nginx перечитывает конфигурацию командой »/etc/init.d/nginx reload». 

На этом этапе выполнения вывод скрипта будет примерно таким 

2f2e57ea31b2c1ae54f4ee1313f17ae2.png

В строке 15 скрипта create_instances_nextcloud.sh при помощи команды sleep ждём 60 секунд, пока машина загрузится.

В строке 16 скрипта create_instances_nextcloud.sh идёт конфигурация созданного экземпляра Nextcloud при помощи playbook config_next.yml. Вот его содержание:

- name: "Run a shell command on a remote host"
  hosts: "{{ orgname }}"
  tasks:
  - name: congigure Nextcloud
    shell: |
       sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 3 --value='{{ ip }}'
       sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 4 --value='{{ domain_name_nextcloud }}'
       echo "{{ password }}" | sudo -u www-data php /var/www/nextcloud/occ user:resetpassword admin       
       systemctl restart apache2

Playbook принимает три параметра:

  1. Суффикс имени экземпляра Nextcloud

  2. IP-адрес экземпляра Nextcloud

  3. Доменное имя экземпляра Nextcloud

  4. Пароль пользователя admin который необходимо задать в Nextcloud

В этом playbook удалённо по ssh выполняются команды на новом экземпляре Nextcloud: добавляются доверенные домены в виде ip-адреса экземпляра Nextcloud и его доменного имени. Сбрасывается пароль пользователя администратора Nextcloud под именем admin. Затем перезагружается веб-сервер apache2.

На этом этапе выполнения скрипта вывод будет примерно таким

4597163a2d1061170156154ec3adbe7d.png

После выполнения скрипта create_instances_nextcloud.sh необходимо создать DNS записи для нашего экземпляра Nextcloud на DNS сервере. И всё, можно пользоваться Nextcloud. 

e9b8af00b017bf361d871abb60274e05.png

Описанный алгоритм позволяет создать много экземпляров Nextcloud, используя скрипт create_instances_nextcloud.sh. Будет круто, если мой опыт вам поможет.

© Habrahabr.ru