# Задания ## 0. Настройка кластера В этом задании мы сконфигурируем основу будущего кластера с беспарольным доступом по ssh c управляющей машины. В качестве управляющей машины используйте машину подключенную к `vmbrX`, например `gwX`. Создайте 3 виртуальных машины: `studX-ubuntu-n1`, `studX-ubuntu-n2`, `studX-ubuntu-n3` из шаблонов: `ubuntu-n1`, `ubuntu-n2`, `ubuntu-n3` соответственно со свеже установленной ОС Ubuntu 18.04 в режиме `Linked Clone`. Укажите свой ресурсный пул при создании. Подключите их в `vmbrX`. Добавьте в `/etc/hosts` управляющей машины имена узлов, например так: ``` 192.168.0.111 n1 192.168.0.112 n2 192.168.0.113 n3 ``` Сгенерируйте в управляющей машине `gwX` ssh ключи без кодовой фразы (passphrase) для пользователя `stud` по алгоритму ed25519. Настройте беспарольный доступ для пользователя `stud` на машины: `n1`, `n2`, `n3`. Пользователь `stud` должен иметь возможность перейти в суперпользователя с помощью `sudo` на управляемых машинах. В итоге схема должна выглядеть следующим образом. ``` _______________ | | | gwX | Управляющий узел с Ansible |_______________| | ens19 в vmbrX, IP 192.168.0.1/24 | +---------+---------+-------------------+ | 192.168.0.111/24 | 192.168.0.112/24 | 192.168.0.113/24 __________ __________ __________ | | | | | | | node 1 | | node 2 | | node 3 | Узлы под управлением Ansible |__________| |__________| |__________| ``` Проверьте, что доступ с `gwX` по ключу работает. ``` gatekeeper@gwX # ssh stud@n1 gatekeeper@gwX # ssh stud@n2 gatekeeper@gwX # ssh stud@n3 ``` ## 1. Установка Ansible, введение в команды Далее все команды выполняются в консоли управляющего узла `gwX`. Установите Ansible. ``` $ sudo apt install ansible $ ansible --version ansible [core 2.13.4] config file = None configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.10.7 (main, Sep 8 2022, 14:34:29) [GCC 12.2.0] jinja version = 3.0.3 libyaml = True ``` Требованием для работы Ansible являются: возможность подключения к удалённому узлу по ssh и наличие установленного Python интерпретатора на каждом узле. Управление кластером с помощью Ansible может осуществляться в двух режимах ad-hoc интерактивном режиме и в режиме выполнения проекта конфигурации playbook. В первом случае все команды начинаются с вызова `ansible`. Документация команды `man ansible`. ### 1.1. Инвентарь Прежде чем выполнять команды, создадим кластер в терминах Ansible. В Ansible инструменте существует понятие инвентаря (*Inventory*), файла, который содержит список сгруппированных имён или ip адресов под управлением Ansible. Создайте файл `/etc/ansible/hosts`. Отредактируйте его так, чтобы он содержал только группу `cluster` и имена машин, входящих в кластер. В квадратных скобках указывается имя группы, ниже следуют имена машин. Вы можете использовать шаблоны для перечисления номеров (также используют квадратные скобки), которые раскрываются следующим образом: ``` [1:3] раскрывается в 1 2 3 abc[1:3] раскрывается в abc1 abc2 abc3 A[1:3]B раскрывается в A1B A2B A3B ``` Вы также можете указать имя пользователя под именем которого `ansible` подключается по `ssh` в блоке `[cluster:vars]`. Наш кластер `cluster` в `/etc/ansible/hosts` в итоге может выглядеть так: ``` # cat /etc/ansible/hosts [cluster] n[1:3] [cluster:vars] ansible_user=stud ``` **Примечание.** Обратите внимание что в скобках используется двоеточие, а не знак тире. ### 1.2 Модули Далее на управляющем узле запускайте команды от обычного пользователя - `stud` или `gatekeeper`. #### 1.2.1 ping Запустим нашу первую Ansible команду: ``` $ ansible cluster -m ping ``` В данной команде мы запустили модуль `ping` для группы узлов `cluster`. Формат ad-hoc команд: ``` $ ansible <группа или шаблон> -m <модуль> ``` Существуют и другие ключи, кроме `-m`, часть из которых будет описана далее. О них вы можете узнать в официальной документации, либо вызвав `ansible` без параметров. По умолчанию модуль выполняется параллельно на как можно большем количестве узлов. Это позволяет быстрее получить результат, но не гарантирует выполнение в том же порядке, что и порядок узлов в инвентаре. Попробуйте выполнить следующую команду: ``` $ ansible cluster -m ping -f 1 ``` Добавленный в конце ключ `-f` позволяет ограничить количество одновременно изменяемых узлов. Его также применяют для обновления компонентов распределённого приложения по частям, для избегания остановки всей системы. #### 1.2.2 command Для ad-hoc режима естественнее всего подходят модули `command` (https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html) и `shell` (https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html). Командный модуль выполняет команды на целевой машине без использования оболочки. Это модуль используется по-умолчанию. После ключа `-a` передаётся строка с командой. ``` $ ansible cluster -a 'echo Hello, world worker $USER' $ ansible cluster -a "echo Hello, world admin $USER" ``` #### 1.2.3 shell Модуль `shell` позволяет выполнить любую консольную команду на нескольких узлах в оболочке. Вы можете использовать возможности оболочки, например вызов других команд и подстановку результатов. ``` $ ansible cluster -m shell -a 'echo Hello, world $(hostname) user $USER' $ ansible cluster -m shell -a "echo Hello, world $(hostname) user $USER" ``` Попробуйте ряд примеров на всём кластере `cluster`: ```bash date # Верное ли время на узлах? # узнать имена файлов в директории `~/.ssh/`: ls -la ~/.ssh/ # узнать информацию о процессорах: lscpu # узнать количество свободного места на дисках: df -h # узнать версию операционной системы (для CentOS, Red Hat, Fedora) и ядра линукс cat /etc/os-release lsb_release -a uname -a # проверить, что нужный пакет находится в списке установленных apt list installed python3 ``` #### 1.2.4 setup В задачах конфигурации кластера как правило требуется не только узнавать информацию о различных свойствах, конфигурациях систем, но и использовать данную информацию в качестве параметров в других командах. Для сбора информации о состоянии (*Facts*) узлов используется модуль `setup`. Выполните команду для одного узла и просмотрите результат. Среди этих данных есть результаты, полученные нами ранее. ``` $ ansible node1 -m setup ``` Результатом является иерархическая структура в JSON формате. https://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html. Для обращения к значениям (листьям JSON структуры) указывается путь из названий, разделённых точками. Например:  `ansible_eth0.ip4.address` или `ansible_date_time.date`. #### 1.2.5 apt Для установки ПО нам потребуется модуль `apt`. Проверьте установлена ли python3. Например так: ``` $ ansible cluster -a "apt list installed python3" ``` Целью использования Ansible является перевод распределённой системы из одного состояния в другое. По этой причине в параметрах многих модулей можно встретить параметр `state`. Данных параметр для модуля `apt` допускает значения: - `present` - присутствует, - `absent` - отсутствует, - `latest` - последняя версия. Кроме него нам потребуется параметр `name` - имя или шаблон имени по которому нужно искать устанавливаемое ПО. Другие параметры модуля `apt` доступны на официальном сайте https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html. Попробуем установить `htop` следующей командой: ``` $ ansible cluster -m apt -a "name=htop state=present" ``` #### 1.2.6 Эскалация прав доступа Для повышения прав доступа до суперпользователя на управляемых машинах используется ключ `--become` или сокращенный вариант `-b`. Если вы не настроили sudo без запроса пароля на управляемых машинах, вы можете добавить ключ `--ask-become-pass` или сокращенный вариант `-K` для запроса пароля. По умолчанию `--become-user` равен `root`. ``` $ ansible cluster -m apt -a "name=htop state=present" --become --ask-become-pass ``` Подробнее об эскалации прав можно прочитать в https://docs.ansible.com/ansible/2.3/become.html. Таким образом мы переводим кластер из состояния без `htop` в состояние с `htop`. Можно убедиться, что при повторном запуске никаких изменений производиться не будет. ## 2. Ansible Playbook Большую часть времени в Ansible вы потратите на написание сценариев управления конфигурацией (*Playbook*). Playbook — это термин который Ansible использует для названия таких сценариев. В этом задании установим Greenplum на наш кластер. ### 2.1 Шаблон конфигурации В первую очередь создайте папку проекта управления конфигурацией `ansible-greenplum` (или любым другим именем), в которой будет лежать файл с конфигурацией. Назовите этот файл `main.yml`. Поместите в него следующие строки и попробуйте запустить с флагом `--verbose`. ```yaml --- - hosts: cluster tasks: - name: Current date shell: date ``` ``` $ ansible-playbook main.yml -v ``` ### 2.2 Создание пользователя-администратора распределённой базы данных Преступим у настройке конфигурации для Greenplum. Мы будет тестировать конфигурацию по частям во временных конфигурационных файлах, а затем объединим в `main.yml`. Создайте файл `1.yml` и поместите содержимое из листинга следующего ниже. Отличие от предыдущего примера заключается в добавлении блока с переменными `vars`. Все действия понадобится выполнять с правами `root`, поэтому мы добавляем параметр `become: yes`. Первая задача - создать пользователя `gpadmin` и установить ему пароль `changeme` с помощью модуля `user` (https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html). Перед установкой поменяйте пароль на более сложный. ```yaml --- - hosts: cluster vars: - version: "6.22.1" - greenplum_admin_user: "gpadmin" - greenplum_admin_password: "changeme" # поменяйте на стандартный пароль MyOffice become: yes tasks: - name: create greenplum admin user user: name: "{{ greenplum_admin_user }}" password: "{{ greenplum_admin_password | password_hash('sha512', 'DvkPtCuQ9pU') }}" shell: /bin/bash ``` ``` $ ansible-playbook 1.yml ``` Можно убедиться, что пользователь создан отдельными командами оболочки: ``` $ ansible cluster -m shell -a 'cat /etc/passwd | grep gpadmin' $ ansible cluster -m shell -a 'cat /etc/shadow | grep gpadmin' -bK $ ansible cluster -m shell -a 'ls -laht /home/ | grep gpadmin' ``` ### 2.3 Настройка репозитория на целевых узлах Напишите следующую конфигурацию в файле `2.yml` и запустите. Конфигурация настроит Greenplum репозиторий для `apt`. Обратите внимание что для этих этапов глобально указано повышение прав до `root` в начале файла. ```yaml --- - hosts: cluster become: yes tasks: - name: install software-properties-common apt: name: software-properties-common state: present - name: install gnupg2 apt: name: gnupg2 state: present - name: install ppa:greenplum/db apt_repository: repo: ppa:greenplum/db state: present ``` ``` $ ansible-playbook 2.yml -K ``` Перепроверим, что репозиторий с greenplum зарегистрирован: ``` $ ansible cluster -m shell -a 'ls /etc/apt/sources.list.d/' $ ansible cluster -m shell -a 'cat /etc/apt/sources.list.d/ppa_greenplum*' ``` ### 2.4 Установка пакета Установим пакет Greenplum конфигурацией `3.yml` и сделаем несколько изменений для его использования. ```yaml --- - hosts: cluster vars: - version: "6.22.1" - greenplum_admin_user: "gpadmin" - greenplum_admin_password: "changeme" # поменяйте на стандартный пароль MyOffice become: yes tasks: - name: install package apt: name: greenplum-db-6 state: present - name: find install directory find: paths: /opt patterns: 'greenplum*' file_type: directory recurse: false register: installed_dir - name: change install directory ownership file: path: '{{ item.path }}' owner: "{{ greenplum_admin_user }}" group: "{{ greenplum_admin_user }}" recurse: yes with_items: "{{ installed_dir.files }}" - name: add bin folder to gpadmin PATH shell: echo "PATH={{ item.path }}/bin/:$PATH" >> /home/{{ greenplum_admin_user }}/.bashrc with_items: "{{ installed_dir.files }}" ``` ``` $ ansible-playbook 3.yml -K ``` Согласно этой конфигурации в системе должен стоять пакет `greenplum-db-6`: ``` $ ansible cluster -a 'apt list installed greenplum-db-6' ``` Зарегистрирована временная переменная `installed_dir`, которую можно использовать в остальной части конфигурации. Она содержит выдачу команды `find`: ``` $ ansible cluster -a 'find /opt/ -maxdepth 1 -type d -name greenplum*' ``` Изменён владелец установленных файлов на `gpadmin`: ``` $ ansible cluster -m shell -a 'ls -laht /opt/green*' ``` В `.bashrc` добавлена директория с исполняемыми файлами базы данных `greenplum` в переменную PATH: ``` $ ansible cluster -a 'tail -n1 /home/gpadmin/.bashrc' ``` ### 2.5 Настроим параметры ОС для Greenplum Для оптимальной работы базе данных может потребоваться держать открытыми много файлов и запускать много процессов. Посмотрим на лимиты и увеличим до рекомендованных в конфигурации: ``` $ ansible cluster -a 'prlimit' --become-user gpadmin --become -K $ ansible cluster -a 'cat /etc/security/limits.conf' ``` Содержимое файла `4.yml`: ```yaml --- - hosts: cluster vars: - version: "6.22.1" - greenplum_admin_user: "gpadmin" - greenplum_admin_password: "changeme" # поменяйте на стандартный пароль MyOffice become: yes tasks: - name: update pam_limits pam_limits: domain: "{{ greenplum_admin_user }}" limit_type: '-' limit_item: "{{ item.key }}" value: "{{ item.value }}" with_dict: nofile: 524288 nproc: 131072 ``` Увеличит количество открытых файлов и процессов для пользователя, от имени которого запускается процесс базы данных. ``` $ ansible-playbook 4.yml ``` Проверим изменились ли значения в конфигурационном файле: ``` $ ansible cluster -a 'cat /etc/security/limits.conf' ``` **Примечание.** Значения `prlimit` могут не измениться для интерактивного логина. Это не повлияет на процессы базы данных, которые стартуют не интерактивно. Подробнее объяснение описано здесь https://superuser.com/questions/1200539/cannot-increase-open-file-limit-past-4096-ubuntu/1200818#_=_ ### 2.6 Финальная версия Соберите все предыдущие конфигурации в один файл, удалите лишние строки и запустите ещё раз. Ошибок быть не должно, кластер перешёл в состояние с установленной Greenplum. ``` $ rm main.yml && cat *.yml > main.yml $ # delete unnecessary header lines ``` ```yaml --- - hosts: cluster vars: - version: "6.22.1" - greenplum_admin_user: "gpadmin" - greenplum_admin_password: "changeme" # поменяйте на стандартный пароль MyOffice become: yes tasks: - name: create greenplum admin user user: name: "{{ greenplum_admin_user }}" password: "{{ greenplum_admin_password | password_hash('sha512', 'DvkPtCuQ9pU') }}" shell: /bin/bash - name: install software-properties-common apt: name: software-properties-common state: present - name: install gnupg2 apt: name: gnupg2 state: present - name: install ppa:greenplum/db apt_repository: repo: ppa:greenplum/db state: present - name: install package apt: name: greenplum-db-6 state: present - name: find install directory find: paths: /opt patterns: 'greenplum*' file_type: directory register: installed_dir - name: change install directory ownership file: path: '{{ item.path }}' owner: "{{ greenplum_admin_user }}" group: "{{ greenplum_admin_user }}" recurse: yes with_items: "{{ installed_dir.files }}" - name: add bin folder to gpadmin PATH shell: echo "PATH={{ item.path }}/bin/:$PATH" >> /home/{{ greenplum_admin_user }}/.bashrc with_items: "{{ installed_dir.files }}" - name: update pam_limits pam_limits: domain: "{{ greenplum_admin_user }}" limit_type: '-' limit_item: "{{ item.key }}" value: "{{ item.value }}" with_dict: nofile: 524288 nproc: 131072 ``` ``` $ ansible-playbook main.yml -K ``` Чтобы запустить распределённую базу данных вам потребуется проследовать далее по официальной инструкции https://docs.vmware.com/en/VMware-Greenplum/6/greenplum-database/install_guide-create_data_dirs.html. Запуск базы данных оставляем читателю в качестве упражения. ## Релевантные источники - Nemeth E. et al. UNIX and Linux system administration handbook. Chapter 23. - Hochstein L. Ansible: Up and Running. – " O'Reilly Media, Inc.", 2014. - https://gpdb.docs.pivotal.io/6-1/install_guide/ansible-example.html