воскресенье, 15 сентября 2019 г.

Управление конфигурациями с помощью Asnible

Настройка управляющей машины

На управляющей машине устанавливаем ansible:
# apt-get install ansible
В домашнем каталоге создаём каталог, в котором будем хранить все файлы для настройки удалённых компьютеров. Если нужно работать над проектом совместно с другими системными администраторами и отслеживать изменения, сделанные ими, то лучше сразу же создать в этом каталоге git-репозиторий:
$ mkdir playbooks
$ git init
Создадим файл конфигурации ansible.cfg и пропишем в него следующие настройки:
[defaults]
inventory = hosts
remote_user = ansible
private_key_file = .ssh/id_rsa
Сразу же сгенерируем ssh-ключ, который будем устанавливать на удалённые системы для их настройки при помощи ansible:
$ mkdir .ssh
$ ssh-keygen -f .ssh/id_rsa
$ chmod go= -R .ssh
Каталог .ssh помещать в git-репозиторий не стоит.

Создадим файл hosts, в котором будем отмечать узлы, управляемые при помощи ansible. Например, файл с одним-единственным узлом с именем mon может выглядеть следующим образом:
mon ansible_host=169.254.252.2

Настройка управляемой машины

На управляемой машине после настройки сети и установки OpenSSH-сервера необходимо установить несколько пакетов, которые будут использоваться ansible:
# apt-get install python2.7-minimal python2.7-stdlib python-minimal
Также установим sudo, чтобы при удалённой настройке можно было выполнять действия от имени пользователя root:
# apt-get install sudo
Добавим учётную запись специально для удалённой настройки:
# useradd -c 'Ansible account' -m ansible
Сразу же дадим возможность этой учётной записи использовать sudo для работы с правами пользователя root:
# visudo
Добавляем строчки:
Defaults:ansible !requiretty
ansible ALL=(root:ALL) NOPASSWD:ALL
Скопируем на удалённую машину SSH-ключ:
$ ssh-copy-id -i .ssh/id_rsa.pub ansible@169.254.252.2

Первый сценарий

Для первого сценария возьмём простейшую задачу - настройки файла /etc/resolv.conf на удалённом компьютере.

Создадим на управляющей машине в каталоге проекта файл сценария resolvconf.yml со следующим содержимым:
---
- name: Configure resolv.conf
  hosts: mon
  become: True
  tasks:
    - name: copy /etc/resolv.conf
      template:
        src: templates/resolv.conf
        dest: /etc/resolv.conf
        owner: root
        group: root
        mode: 0644
Создадим каталог templates для шаблонов файлов конфигурации:
$ mkdir templates
Создадим шаблон конфигурации templates/resolv.conf для файла /etc/resolv.conf управляемого компьютера:
{% if resolvconf.domain %}
domain {{ resolvconf.domain }}
{% endif %}
{% for ip in resolvconf.nameservers %}
nameserver {{ ip }}
{% endfor %}
Значения переменных хранятся в так называемом реестре ansible. Он представляет собой файл в формате YML и может находиться либо в каталоге host_vars, либо в каталоге group_vars. В каталоге host_vars хранятся настройки, специфичные для каждого отдельного управляемого узла. Внутри этого каталога создаётся фай, имя которого совпадает с указанным в файле hosts. В каталоге group_vars хранятся настройки, общие для определённой группы узлов. Внутри этого каталога создаётся файл, имя которого совпадает с именем группы, указанным в файле hosts.

Создадим каталог host_vars с переменными узлов:
$ mkdir host_vars
И внутри каталога создадим файл mon со следующим содержимым:
resolvconf:
  domain: stupin.su
  nameservers:
    - 169.254.252.1
Осталось выполнить наш первый простейший сценарий. Для этого воспользуемся командой ansible-playbook:
$ ansible-playbook resolvconf.yml

Переключение на непривилегированного пользователя

В прошлом сценарии имелась опция, которая заставляла выполнять действия от имени пользователя root:
become: True
В случае, если нужно выполнять действия от имени другого, непривилегированного пользователя, можно столкнуться с проблемами. Например, администратором баз данных PostgresSQL является системный пользователь postgres. Создать нового пользователя или базу данных можно только от его имени. Поэтому, задача такого вида:
- name: createuser -P <login>
  postgresql_user:
    name: "{{ item.login }}"
    password: "{{ item.password }}"
  with_items: "{{ postgresql_databases }}"
  when: postgresql_databases
Завершится такой ошибкой:
unable to connect to database: ВАЖНО:  пользователь "postgres" не прошёл проверку подлинности (Peer)
Однако и простого указания опций переключения на пользователя postgres оказывается недостаточно:
- name: createuser -P <login>
  become: True
  become_user: postgres
  postgresql_user:
    name: "{{ item.login }}"
    password: "{{ item.password }}"
  with_items: "{{ postgresql_databases }}"
  when: postgresql_databases
В этом случае попытка выполнить задачу завершается следующей ошибкой (отформатировано для наглядности):
Failed to set permissions on the temporary files
Ansible needs to create when becoming an unprivileged user (rc: 1, err:
  chown: изменение владельца '/tmp/ansible-tmp-1549203485.91-25063771984034/': Операция не позволена
  chown: изменение владельца '/tmp/ansible-tmp-1549203485.91-25063771984034/postgresql_user.py': Операция не позволена
).
For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user
После доработки в соответствии с материалами по ссылке, указанной в тексте ошибки, задача приобретает следующий вид:
- name: createuser -P <login>
  become: yes
  become_user: postgres
  vars:
    ansible_ssh_pipelining: true
  postgresql_user:
    name: "{{ item.login }}"
    password: "{{ item.password }}"
  with_items: "{{ postgresql_databases }}"
  when: postgresql_databases
Но и этого оказывается недостаточно, т.к. возникает следующая ошибка:
failed: [mon] (item={u'login': u'zabbix', u'password': u'xxxxxxxxxxxxxxxx', u'name': u'zabbix'}) => {
    "failed": true, 
    "item": {
        "login": "zabbix", 
        "name": "zabbix", 
        "password": "xxxxxxxxxxxxxxxx"
    }, 
    "module_stderr": "sudo: a password is required\n", 
    "module_stdout": ""
}

MSG:

MODULE FAILURE
Как видно, ansible пытается переключиться на указанного пользователя при помощи sudo. Но, когда я настраивал sudo для ansible, то указал разрешение переключаться без указания пароля только на пользователя root:
ansible ALL=(root:ALL) NOPASSWD:ALL
Чтобы разрешить пользователю ansible переключаться ещё и на пользователя postgres, нужно добавить через команду visudo ещё одно разрешение:
ansible ALL=(postgres:ALL) NOPASSWD:ALL
После этого задача выполняется успешно.

Немедленный перезапуск сервиса при изменениях

Иногда отложенный перезапуск сервиса может таить в себе проблемы. Например, если в конфигурации сервиса изменился прослушиваемый им порт, новые настройки не вступят в силу, пока не будет достигнут конец сценария. В то же время, действия, выполняемые до вызова отложенного перезапуска сервиса, могут использовать новый порт для подключения к сервису, не зная, что сервис ещё не был перезапущен и его новые настройки ещё не вступили в силу.

Именно так получилось у меня при подготовке роли, настраивающей сервис PostgreSQL. После изменения номера порта может потребоваться создать новые базы данных или пользователей, но пока сервис не был перезапущен, подключиться к нему по новому порту не получится, а старый может быть не известен. В таком случае можно запомнить результаты выполненных действий в переменных при помощи выражения register:
- name: vim /etc/postgresql/9.6/main/pg_hba.conf
  template:
    src: etc/postgresql/9.6/main/pg_hba.conf
    dest: /etc/postgresql/9.6/main/pg_hba.conf
    owner: postgres
    group: postgres
    mode: 0640
  register: pg_hba 

- name: vim /etc/postgresql/9.6/main/postgresql.conf
  template:
    src: etc/postgresql/9.6/main/postgresql.conf
    dest: /etc/postgresql/9.6/main/postgresql.conf
    owner: postgres
    group: postgres
    mode: 0644
  register: postgresql
И затем проверить результаты этих действий и немедленно перезапустить сервис, если его конфигурация была изменена:
- name: systemctl restart postgresql
  service:
    name: postgresql
    state: restarted
  when: (pg_hba.changed or postgresql.changed)

Использованные материалы

P.S.

Для более-менее полноценного использования Ansible рекомендую изучить роли. Роль представляет собой совокупность сценария, настроек по умолчанию и используемых файлов и шаблонов. В сценарии можно будет указать список ролей, которые нужно применить к узлам, указанным в сценарии. Благодаря ролям становится возможным собирать сценарии из крупных строительных блоков - ролей.

воскресенье, 8 сентября 2019 г.

Настройка текстового терминала для использования в virsh

Ранее я описывал установку и настройку virt-manager - графической программы для администрирования виртуальных машин, работающих под управлением KVM, Xen и других гипервизоров. Для управления начинкой виртуальных машин, как правило, достаточно SSH. Однако, виртуальная машина может оказаться не доступной по SSH из-за неполадок в работе сети или ошибок в сетевых настройках самой виртуальной машины. В таком случае можно подключиться к консоли виртуальной машины, однако и virt-manager может оказаться не доступным. Вместо virt-manger можно попробовать воспользоваться virsh, но как попасть в текстовую консоль виртуальной машины, если она не была настроена заранее?

Чтобы подстелить соломки, можно заранее настроить текстовую консоль в каждой из виртуальных машин. В случае недоступности виртуальной машины по сети или отсутствии virt-manager на ближайшем компьютере достаточно будет подключиться по SSH к компьютеру, на котором работает гипервизор, на нём запустить virsh, а оттуда уже попасть в консоль виртуальной машины. Займёмся настройкой.

Настройка виртуальной машины

Запускаем от пользователя root команду virsh:
# virsh
В запущенной оболочке virsh проверяем, есть ли у виртуальной машины текстовый терминал (вместо <vm> нужно указать имя виртуальной машины):
ttyconsole <vm>
Если команда ничего не вывела, значит виртуального терминала нет и его нужно настроить. Для этого отредактируем конфигурацию виртуальной машины, выполнив в оболочке virsh команду:
edit <vm>
Если в файле есть секция console, имеющая такой вид:
<console type='pty'>
  <target type='virtio' port='0'/>
</console>
То её нужно привести её к следующему виду:
<serial type='pty'>
  <target port='0'/>
</serial>
<console type='pty'>
  <target type='serial' port='0'/>
</console>
Если же секцию console найти не удалось, то нужно вставить указанный фрагмент вовнутрь секции devices.

Дальше нужно остановить виртуальную машину и запустить её снова. Для этого в оболочке virsh можно выполнить следующие две команды:
shutdown <vm>
start <vm>
После пересоздания виртуальной машины, в ней появится последовательное устройство.

Настройка демона терминала getty

Когда виртуальная машина запустится, нужно зайти в неё через графическую консоль (или через SSH) и выполнить две команды, которые включат терминал на виртуальном последовательном порту:
# systemctl enable serial-getty@ttyS0.service
# systemctl start serial-getty@ttyS0.service
После этого появится возможность подключиться к этому терминалу через virsh, при помощи команды следующего вида:
console <vm>
Однако, этим терминалом можно будет пользоваться только после загрузки системы. Нельзя будет увидеть ни меню загрузчика, ни сообщения, выводимые ядром операционной системы в процессе его загрузки. Чтобы терминалом можно было воспользоваться до загрузки операционной системы, нужно настроить консоль в загрузчике и в ядре.

Настройка консоли в GRUB 2 и Linux

Поскольку загрузчик передаёт опции ядру, то для настройки консоли в загрузчике и в ядре Linux понадобится отредактировать только конфигурацию загрузчика.

Для настройки консоли в загрузчике, нужно в файле /etc/default/grub добавить или заменить следующие опции:
GRUB_TERMINAL="serial console"
GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"
Мне потребовалось поискать в интернете примеры настройки, при которых консоль на последовательном порту не вызывала бы отключение графической консоли. Указанный выше вариант позволяет пользоваться меню GRUB и через последовательную консоль, и через графическую.

Для настройки консоли в ядре Linux нужно в том же файле /etc/default/grub найти опцию GRUB_CMDLINE_LINUX и добавить в неё следующие опции ядра:
console=tty0 console=ttyS0,115200n8
В моём случае никаких опций ядру не передавалось, поэтому строчка приняла следующий вид:
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8"

Теперь нужно применить изменения в конфигурации GRUB при помощи следующей команды:
# update-grub

Результат

Для того, чтобы убедиться в работоспособности консоли, можно подключиться к графической консоли и консоли на последовательном порту виртуальной машины и отправить её в перезагрузку. В моём случае меню загрузчика в обеих консолях выглядело следующим образом:



Ниже показан процесс загрузки системы на обеих консолях:

Использованные материалы

воскресенье, 1 сентября 2019 г.

Virt-manager для управления виртуальными машинами под управлением KVM и Xen

Для управления виртуальными машинам, работающими под управлением систем виртуализации KVM и Xen можно использовать программу с графическим интерфейсом, которая называется Virt-manager. Программа использует демон libvirt, установленный на компьютере с системой виртуализации. Для подключения Virt-manager к демону libvirt можно использовать SSH, что довольно удобно и безопасно. Как правило, демон SSH бывает уже установлен на компьютерах, доступных по сети, поэтому не нужно заботиться о настройке отдельного сетевого демона. Плюс к тому, SSH поддерживает аутентификацию пользователей и надёжное шифрование передаваемых данных.

Настройка демона libvirt для управления виртуальными машинами под управлением KVM (на примере Debian Stretch)

Проверим наличие аппаратной поддержки виртуализации:
$ egrep -c '(vmx|svm)' /proc/cpuinfo
Устанавливаем систему виртуализации qemu с поддержкой KVM и демон libvirt для управления виртуальными машинами, работающими под управлением KVM:
# apt-get install qemu-kvm libvirt-daemon-system
Добавляем пользователя, от имени которого будем заходить на сервер по SSH, в группу libvirt, чтобы он имел доступ к управлению виртуальными машинами:
# usermod -aG libvirt stupin
Пользователь получит доступ к Unix-сокету /var/run/libvirt/libvirt-sock

Установим netcat из OpenBSD, поддерживающий опцию -U для подключения к Unix-сокету. Это нужно для перенаправления подключения от SSH-клиента в Unix-сокет libvirt:
# apt-get install netcat-openbsd
Осталось включить и запустить демона:
# systemctl enable libvirtd
# systemctl start libvirtd

Настройка демона libvirt для управления виртуальными машинами под управлением Xen (на примере Debian Wheezy)

В моём случае Xen был развёрнут в операционной системе Debian Wheezy, где пакет с демоном libvirt называется libvirt-bin. Установим его:
# apt-get install libvirt-bin
Теперь, чтобы пользователь, от имени которого мы будем подключаться по SSH к серверу виртуализации, смог подключиться к демону libvirtd, нужно добавить его в группу libvirt:
# usermod -aG libvirt stupin
Пользователь получит доступ к Unix-сокету /var/run/libvirt/libvirt-sock

Для того, чтобы демон libvirt смог работать с системой виртуализации Xen, нужно включить HTTP-сервер, встроенный в xend. Демон libvirt будет выполнять роль посредника, транслируя входящие запросы в запросы к xend.

Настроим HTTP-сервер, ожидающий подключений на порту 8000 и адресе 127.0.0.1. Для этого нужно прописать в файл /etc/xen/xend-config.sxp следующие опции:
(xend-http-server yes)
(xend-address localhost)
(xend-port 8000)
Чтобы настройки xend вступили в силу, нужно перезапустить его (пример для Debian Wheezy):
# /etc/init.d/xen restart
Будьте осторожны - в конфигурации по умолчанию при перезапуске демона xend перезапускаются также и все виртуальные машины. Чтобы избежать этого, нужно при создании виртуальной машины прописать в её конфигурацию такие настройки:
on_xend_start = 'ignore'
on_xend_stop = 'ignore'
У меня эти настройки были прописаны в каждой виртуальной машине, поэтому я перезапускал xend без опасений.

Установка и использование Virt-manager

Устанавливаем на компьютере администратора пакет с GUI-интерфейсом для управления виртуальными машинами:
# apt-get install virt-manager
Теперь можно попробовать сделать то, ради чего всё и затевалось: подключиться к системе виртуализации из программы virt-manager. Ниже приведены снимки экрана, иллюстрирующие этот процесс.

Запуск virt-manager:

Добавление нового подключения:

Новое подключение к системе виртуализации Xen:

Настройки удалённого подключения к системе виртуализации Xen через SSH:

Подключение к системе виртуализации установлено, виден список виртуальных машин:

Теперь можно подключаться к консоли виртуальной машины и менять её настройки.

Типичные проблемы

Не установлен пакет netcat-openbsd

Не удалось подключиться к libvirt.

Для взаимодействия с удалённым узлом необходимо, чтобы версия netcat/nc поддерживала параметр -U.

Не установлен пакет libvirt-bin или libvirt-daemon-system

Не удалось подключиться к libvirt.

End of file while reading data: nc: unix connect failed: No such file or directory: Ошибка ввода/вывода

Убедитесь, что на удалённом узле запущен libvirtd.

Не настроен HTTP-сервер xend

Не удалось подключиться к libvirt.

unable to connect to 'localhost:8000': В соединении отказано

Убедитесь, что на удалённом узле запущен libvirtd.

Не установлен пакет gir1.2-spice-client-gtk-3.0

Ошибка подключения к графической консоли:
Error opening Spice console, SpiceClientGtk missing