You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
19 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Задания
## 0. Настройка кластера
В этом задании мы сконфигурируем основу будущего кластера с беспарольным доступом по ssh c управляющей машины.
Создайте виртуальную машину `studX-node` из шаблона `ubuntu-template` со свеже установленной ОС Ubuntu 20.04.
Настройте сеть. В этой машине наиболее простом способом будет модификация конфигурационного файла `/etc/network/interfaces`. Используйте ip адрес из сети `192.168.1.0/24`, шлюз `192.168.1.1`, любой общедоступный DNS. В настройках оборудования виртуальной машины подключите сетевое устройство к `vmbr15+X`.
Добавьте в `/etc/hosts` имена узлов в соответствии со схемой ниже на `studX` и `studX-node`.
Сгенерируйте в управляющей машине `studX` ssh ключи без кодовой фразы (passphrase) для пользователя `stud` по алгоритму ed25519. В машине `studX-node` отредактируйте конфигурацию `/etc/ssh/sshd_config`, разрешите доступ к машине по паролю и перезагрузите sshd `systemctl restart sshd`. Добавьте публичный ключ в `authorized_keys` машины `studX-node` с помощью `ssh-copy-id`.
Превратите виртуальную машину в шаблон для узлов кластера.
Создайте 3 машины `studX-node[1-3]` из шаблона `studX-node`. Настройте сеть, установив уникальные IP. Поменяйте имена хостов командой `hostnamectl set-hostname`. В итоге схема должна выглядеть следующим образом.
```
_______________
| |
| studX | Управляющий узел с Ansible
|_______________|
| ens19 в vlan 15+X, IP 192.168.1.100/24
|
+---------+---------+-------------------+
| 192.168.1.101/24 | 192.168.1.102/24 | 192.168.1.103/24
__________ __________ __________
| | | | | |
| node 1 | | node 2 | | node 3 | Узлы под управлением Ansible
|__________| |__________| |__________|
```
Проверьте, что доступ с `studX` по ключу работает.
```
stud@studX # ssh node1
stud@studX # ssh node2
stud@studX # ssh node3
```
## 1. Установка Ansible, введение в команды
Далее все команды выполняются в консоли управляющего узла `studX`.
Установите 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 адресов.
Создайте файл `/etc/ansible/hosts`. Отредактируйте его так, чтобы он содержал только группу `cluster` и имена машин, входящих в кластер. В квадратных скобках указывается имя группы, ниже следуют имена машин. Вы можете использовать шаблоны для перечисления номеров (также используют квадратные скобки), которые раскрываются следующим образом:
```
[1:3] раскрывается в 1 2 3
abc[1:3] раскрывается в abc1 abc2 abc3
A[1:3]B раскрывается в A1B A2B A3B
```
Наш кластер `cluster` в `/etc/ansible/hosts` может выглядеть так
```
# cat /etc/ansible/hosts
[cluster]
node[1:3]
```
**Примечание.** Обратите внимание что в скобках используется двоеточие, а не знак тире.
Таким образом кластер `cluster` в терминах Ansible - это группа имён машин `node1`, `node2`, `node3`.
### 1.2 Модули
#### 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 shell
Для ad-hoc режима естественнее всего подходит модуль `shell` (https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html). Данный модуль позволяет выполнить любую консольную команду на нескольких  узлах. Приведём ряд примеров, чтобы вы попробовали их далее на всём кластере:
```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
```
Выполнение консольных команд на узлах кластера с помощью модуля `shell` выглядит следующим образом:
```
# ansible cluster -m shell -a "date"
```
Верное ли время на узлах?
После ключа `-a` в `ansible` передаётся строка с командой. Попробуйте выполнить несколько вышеупомянутых команд аналогичным образом.
#### 1.2.3 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.4 apt
Для установки ПО нам потребуется модуль `apt`.
Проверьте установлена ли python3. Например так:
```
$ ansible cluster -m shell -a "apt list installed python3"
```
Целью использования Ansible является перевод распределённой системы из одного состояния в другое. По этой причине в параметрах многих модулей можно встретить параметр `state`. Данных параметр для модуля apt допускает значения: `present` - присутствует, `absent` - отсутствует, `latest` - последняя версия. Кроме него нам потребуется параметр `name` - имя или шаблон имени по которому нужно искать устанавливаемое ПО. Другие параметры модуля yum доступны на официальном сайте https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html.
Попробуем установить htop следующей командой:
```
$ ansible cluster -m apt -a "name=htop state=present"
```
#### 1.2.5 Эскалация прав доступа
Для повышения прав доступа используется ключ `--become` или сокращенный вариант `-b`.
```
$ ansible cluster -m apt -a "name=htop state=present" -b
```
Подробнее об эскалации прав можно прочитать в 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.
Создайте файл 1.yml и поместите содержимое из листинга следующего ниже. Отличие от предыдущего примера заключается в добавлении блока с переменными `vars`. Все действия понадобится выполнять с правами `root`, поэтому мы добавляем параметр `become: yes`.
Первая задача - создать пользователя `gpadmin` и установить ему пароль `changeme`.
```yaml
---
- hosts: cluster
vars:
- version: "6.0.0"
- greenplum_admin_user: "gpadmin"
- greenplum_admin_password: "changeme"
become: yes
tasks:
- name: create greenplum admin user
user:
name: "{{ greenplum_admin_user }}"
password: "{{ greenplum_admin_password | password_hash('sha512', 'DvkPtCuQ9pU') }}"
```
```
$ ansible-playbook 1.yml
```
### 2.3 Настройка репозитория на целевых узлах
Поместите содержимое файла в 2.yml и запустите. Конфигурация настроит Greenplum репозиторий для apt.
```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
```
### 2.4 Установка пакета
Установим пакет Greenplum конфигурацией `3.yml`.
```yaml
---
- hosts: all
vars:
- version: "6.0.0"
- greenplum_admin_user: "gpadmin"
- greenplum_admin_password: "changeme"
# - package_path: passed via the command line with: -e package_path=
remote_user: root
become: yes
become_method: sudo
connection: ssh
gather_facts: yes
tasks:
- name: install package
apt:
name: greenplum-db-6
state: present
- name: change install directory ownership
file:
path: '{{ item.path }}'
owner: "{{ greenplum_admin_user }}"
group: "{{ greenplum_admin_user }}"
recurse: yes
with_items: "{{ installed_dir.files }}"
```
```
$ ansible-playbook 3.yml
```
### 2.5 Настроим параметры ОС для Greenplum
```yaml
- hosts: all
vars:
- version: "6.0.0"
- greenplum_admin_user: "gpadmin"
- greenplum_admin_password: "changeme"
remote_user: root
become: yes
become_method: sudo
connection: ssh
gather_facts: 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
```
### 2.6 Проверка установленной версии
```yaml
- hosts: all
vars:
- version: "6.0.0"
remote_user: root
become: yes
become_method: sudo
connection: ssh
gather_facts: yes
tasks:
- name: find installed greenplum version
shell: . /usr/local/greenplum-db/greenplum_path.sh && /usr/local/greenplum-db/bin/postgres --gp-version
register: postgres_gp_version
- name: fail if the correct greenplum version is not installed
fail:
msg: "Expected greenplum version {{ version }}, but found '{{ postgres_gp_version.stdout }}'"
when: "version is not defined or version not in postgres_gp_version.stdout"
```
```
$ ansible-playbook 5.yml
```
### 2.7 Финальная версия
Соберите все предыдущие конфигурации в один файл и запустите ещё раз. Ошибок быть не должно, кластер перешёл в состояние с установленной Greenplum.
```yaml
---
- hosts: all
vars:
- version: "6.0.0"
- greenplum_admin_user: "gpadmin"
- greenplum_admin_password: "changeme"
# - package_path: passed via the command line with: -e package_path=./greenplum-db-6.0.0-rhel7-x86_64.rpm
remote_user: root
become: yes
become_method: sudo
connection: ssh
gather_facts: yes
tasks:
- name: create greenplum admin user
user:
name: "{{ greenplum_admin_user }}"
password: "{{ greenplum_admin_password | password_hash('sha512', 'DvkPtCtNH+UdbePZfm9muQ9pU') }}"
- name: copy package to host
copy:
src: "{{ package_path }}"
dest: /tmp
- name: cleanup package file from host
file:
path: "/tmp/{{ package_path | basename }}"
state: absent
- name: find install directory
find:
paths: /usr/local
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: update pam_limits
pam_limits:
domain: "{{ greenplum_admin_user }}"
limit_type: '-'
limit_item: "{{ item.key }}"
value: "{{ item.value }}"
with_dict:
nofile: 524288
nproc: 131072
- name: find installed greenplum version
shell: . /usr/local/greenplum-db/greenplum_path.sh && /usr/local/greenplum-db/bin/postgres --gp-version
register: postgres_gp_version
- name: fail if the correct greenplum version is not installed
fail:
msg: "Expected greenplum version {{ version }}, but found '{{ postgres_gp_version.stdout }}'"
when: "version is not defined or version not in postgres_gp_version.stdout"
```
```
$ ansible-playbook main.yml
```
## Релевантные источники
- 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