Ubuntu Server 16.04 добавление KVM виртуальной машина

Есть нормальный ПК и кучка задач для сервера с кастомным ПО. Задачи не требуют постоянного аптайма и не хочется тратиться на хороший выделенный сервер, который, например, потянет 2-3 терминальных тонких клиента, которые пооткрывают десяток вкладок в хроме (и хромы сожрут всю оперативку, если ее мало).
Задач целый список: терминальный сервер для тонких клиентов, voip сервер (elastix), бэкап сервер, puppet, node.js и nginx для внутренних нужд и ботов Слака.
Решение: чтобы сохранить масштабируемость, гибкость и защиту - делаем систему модульной программно, оставляя все в одной железке с помощью виртуальных машин.
Поехали!

0. Проверка процессора
Для нормальной работы нам нужно аппаратное ускорение виртуализации на уровне процессора. Без поддержки аппаратной виртуализации KVM сможет воздавать и запускать виртуальные машины, но работать они будут намного медленнее Проверяем это с помощью команды. Должна быть цифра больше 0.
egrep -c '(vmx|svm)' /proc/cpuinfo
(в моем случае получил ответ 4)

1. Устанавливаем KVM
sudo apt-get install qemu-kvm libvirt-bin virtinst bridge-utils cpu-checker
Кроме самой KVM устанавливаем вспомогательный софт.

2. Проверяем что KVM может быть использован в нашей системе
$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

3. Добавим нашего рабочего юзера в группу с с разрешением работать с виртуальными машинами. эта группа называется libvirtd
$ sudo gpasswd -a toopro libvirtd
Добавление пользователя toopro в группу libvirtd

4. Сетевой мост между виртуальными машинами и системой.
Если не создавать мост, то гостевая система не будет видна снаружи и сетевой доступ к ней будет только внутри одного системника, что не подходит нам. Поэтому нам нужно создать сетевой мост между гостевой системой и ее хостящей ОС.

Внимание, большинство беспроводных устройств не поддерживают соединения типа мост.

В версии Ubuntu Server 16.04 после установки вышеуказанных утилит мы уже имеем автоматически созданный виртуальный мост. Проверить это можно запустив команду:
$ sudo ip addr show
# либо коротко
$ ls /sys/class/net
# либо список всех мостов
$ sudo brctl show
вы должны увидеть в списке virbr0.

Смотрим текущий список виртуальных систем:
$ sudo virsh -c qemu:///system list

Скачиваем дистрибутив нужной виртуалки:
1. Переходим в папку с виртуальными машинами
$ sudo cd /var/lib/libvirt/boot/
2. Скачиваем iso образ по прмой ссылке:
$ sudo wget http://....ubuntu-server...

Создаем виртуальную мушину:
Используем команду virt-install
$ sudo virt-install \
--virt-type=kvm \
--name vrpuppet \
--ram 2048 --vcpus=2 --hvm \
--os-variant=ubuntu16.04 \
--cdrom=/var/lib/libvirt/boot/ubuntu-16.04.2-server-amd64.iso \
--disk path=/var/lib/libvirt/images/puppetv0.qcow2,size=40,bus=virtio,format=qcow2 \
--network bridge=virbr0,model=virtio \
--graphics vnc,port=5911

virt-type - тип виртуализации, в нашем случае kvm;
name - имя новой машины;
ram - количество памяти в мегабайтах;
vcpus - количество ядер процессора;
os-variant - тип операционной системы (osinfo-query os);
cdrom - установочный образ системы;
network - сетевой мост, который мы настроили ранее (sudo virsh net-info default);
graphics - способ получения доступа к графическому интерфейсу (vnc потребуется для завершения установки);
disk - адрес нового жесткого диска для этой виртуальной машины, формат и объем;

Проверям что машина создана и работает:
$ sudo virsh list

для автозапуска виртуалки после старта хостовой системы пропишем:
$ sudo virsh autostart vrpuppet
(для удаления из автозапуска: virsh autostart vrpuppet --disable)

Подключаемся к виртуальной машине:
После завершения установки виртуальной машины вы можете узнать параметры подключения по VNC с помощью команды:
$ sudo virsh vncdisplay vrpuppet
(к результату порта добавляем 5900, чтобы получить нужный порт)

Используем Remmina на другой машине в локальной сети, настроив vnc подключение с помощью ssh тоннеля (например: vnc server: 192.168.8.220:5911; enable ssh tunnel, отметить tunnel via loopback address)

Должно открыться окно с настройкой установки.

---------- SSH НА НОВОЙ ВИРТУАЛЬНОЙ МАШИНЕ

Чтобы подключаться к виртуальной машине удаленно напрямую (редактирование файлов, подключениен sshfs файловой системы), нужно установить openssh-server на ней, поменять порт (чтобы не было конфликта) и пробросить его с помощью iptables, чтобы при обращении к гостевой kvm машине на выбранный порт у нас запрос шел к нужному гостю

утанавливаем ссш сервер
$vrpuppet: sudo apt install openssh-server

меняем порт
sudo nano /etc/ssh/sshd_config
заменям строку, напрммер будет порт 2221
Port 2221
(по идее можно будет перегрузить openssh сервер чтобы принять изменения, но мы все равно будет перегружать целую систему дальше)

НА ХОСТЕ ВИРТУАЛЬНЫХ СИСТЕМ:
$ sudo nano /etc/libvirt/hooks/qemu
добавим
#!/bin/bash
# FORWARD puppet port to puppet virtual host
if [ "${1}" = "vrpuppet" ]; then

#variables
GUEST_IP=192.168.122.228 #to find this ip use "ifconfig" on virtual guest system
GUEST_PORT=2221
HOST_PORT=2221

if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -D FORWARD -o virbr0 -d $GUEST_IP -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
fi

if [ "${2}" = "start" ] || [ "${2}" = "reconnect"]; then
/sbin/iptables -I FORWARD -o virbr0 -d $GUEST_IP -j ACCEPT
/sbin/iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
fi

fi

дадить файлу права на исполнение:
chmod +x /etc/libvirt/hooks/qemu

перегружаем libvirt
sudo systemctl restart libvirtd

и запускаем гостевую систему
sudo virsh start vrpuppet

проверяем что в прероутинге у нас есть нужные порты, командой:
sudo iptables -L -vt nat

ПРОВЕРКА:
на удаленной любой машине прописываем адрес машины хоста kvm (он же у нас папет сервер), указываем порт 2221 и мы должны войти в консоль папет гостя, вместо основной машины:
$anyPC: ssh toopro@puppet.toopro.org -p2221

----------

Ошибки в консоли хости типа таких:
kvm: 3138: cpu0 unhandled rdmsr: 0xc0010112
kvm: 3138: cpu0 unhandled rdmsr: 0х034
Можно убрать:
echo 1 > /sys/module/kvm/parameters/ignore_msrs

----------

После установки и настройки гостевой ОС, ВМ можно клонировать командой
sudo virt-clone -o vsrv1 -n vsrv2 -f vsrv2.img --connect=qemu:///system

$ sudo virsh shutdown vrpuppet
$ sudo virt-clone \
--original demo \
--auto-clone
$ sudo virsh list --all

UPD: После клонирования для того, чтобы заработал сетевой интерфейс необходимо на клоне удалить файл /etc/udev/rules.d/70-persistent-net.rules ну и заодно изменить в /etc/hostname и в /etc/hosts имя сервера на новое.

-------------------

elastix 2.5

# переходим в папку с бутами
$ cd /var/lib/libvirt/boot/
# скачиваем имейдж эластикса
$ sudo wget https://excellmedia.dl.sourceforge.net/project/elastix/Elastix%20PBX%20A...

sudo virt-install \
--name elastix-2.5 \
--ram 512 \
--vcpus 1 \
--os-type linux \
--os-variant=rhel6 \
--graphics none \
--network bridge=virbr0,model=virtio -v -x “console=ttyS0″ \
--disk path=/var/lib/libvirt/images/elastix-2.5.img,bus=virtio,size=40 -l /var/lib/libvirt/boot/Elastix-2.5.0-STABLE-x86_64-bin-08may2015.iso

------

$ sudo brctl addbr bridge0
$ sudo ip addr show
$ sudo addif bridge0 eth0

-------------

PUPPET:
https://www.8host.com/blog/ustanovka-puppet-4-v-ubuntu-16-04/

1. add A record to domain with server IP address: puppet.toopro.org
2. Добавляем репозиторий папета и устанавливаем его:
curl -O https://apt.puppetlabs.com/puppetlabs-release-pc1-xenial.deb
sudo dpkg -i puppetlabs-release-pc1-xenial.deb
sudo apt-get update
sudo apt-get install puppetserver

По умолчанию мастер Puppet использует 2 Гб RAM. Как раз столько мы и давали виртуальной машине, но ему нужно на 10% больше указанного в яве, а еще и сама система висит в оперативке, поэтому придется дать конкретной виртуальной машине больше RAM. Увеличиваем оперативку VM:
$ sudo virsh sutdown vrpuppet
$ sudo virsh setmaxmem vrpuppet 3G --config
$ sudo virsh setmem vrpuppet 3G --config
$ sudo virsh start vrpuppet

Добавляем ссылку на команду puppet в /usr/bin/, чтобы можно было быстро обращаться к паппету, не используя длинный адрес:
$ sudo ln -s /opt/puppetlabs/bin/puppet /usr/bin/puppet

Если вы будете использовать внешний dns адрес для папетсервера, то он должен быть указан в настройках puppet.conf, поэтому пропишем в конфиг папета имя сервера в файле /etc/puppetlabs/puppet/puppet.conf:
dns_alt_names = puppet.toopro.org
Теперь нужн перегенерировать сертификаты сервера, перед этим остановив сервер папета и удалив старые:
sudo service puppetserver stop
sudo puppet cert clean vrpuppet
sudo puppet cert generate vrpuppet --dns_alt_names puppet.toopro.org, puppet.example.com
sudo service puppetserver start

Puppet Server использует порт 8140.
//Откройте его в брандмауэре.
//sudo ufw allow 8140
Профорвардим его на роутерах к нужному нам серверу с KVM (тут уже зависит от роутера как вы это сделаете)
Теперь форвардим порт с хоста на гостевую систему:
https://help.ubuntu.com/community/KVM/Networking#line-456
https://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections

НА ХОСТЕ ВИРТУАЛЬНЫХ СИСТЕМ:
$ sudo nano /etc/libvirt/hooks/qemu
добавим (файл должен быть уже создан ранее для openssh сервера)

#!/bin/bash
# FORWARD puppet port to puppet virtual host
if [ "${1}" = "vrpuppet" ]; then

#variables
GUEST_IP=192.168.122.228 #to find this ip use "ifconfig" on virtual guest system
GUEST_PORT=8140
HOST_PORT=8140

if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -D FORWARD -o virbr0 -d $GUEST_IP -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
fi

if [ "${2}" = "start" ] || [ "${2}" = "reconnect"]; then
/sbin/iptables -I FORWARD -o virbr0 -d $GUEST_IP -j ACCEPT
/sbin/iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
fi

fi

перегружаем libvirt
sudo systemctl restart libvirtd

и запускаем гостевую систему
sudo virsh start vrpuppet

проверяем что в прероутинге у нас есть нужные порты, командой:
sudo iptables -L -vt nat

-------------

НА ГОСТЕВОЙ СИСТЕМЕ С ПАПЕТ СЕРВЕРОМ:

Чтобы запустить Puppet, используйте команду systemctl:
$ sudo systemctl start puppetserver
Чтобы убедиться, что запуск сервера прошёл успешно, введите:
$ sudo systemctl status puppetserver
Тоже самое можно сделать с помощью service
$ sudo service puppetserver start
$ sudo service puppetserver status

Теперь можно настроить автозапуск сервера:
$ sudo systemctl enable puppetserver

-------------

НА УДАЛЕННЫХ КЛИЕНТАХ:

Установка агентов Puppet (на клиенты)

Добавляем репозиторий папетлабс и устанавливаем агента(клиента)
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-xenial.deb
sudo dpkg -i puppetlabs-release-pc1-xenial.deb
sudo apt-get update
sudo apt-get install puppet-agent

Мы будем использовать папет для открытой сети (не внутри одной сети), поэтому предполагаем, что внешняя служба ресолвинга DNS у нас будет доступна. Заранее пропишем в A запись DNS любого нашего домена IP адрес сервера с папетом (то есть поддомен будет ссылаться на другой IP с puppet master). Я создал поддомен puppet.toopro.org. Прописываем этот сервер в конфиг папета на агенте:
sudo nano /etc/puppetlabs/puppet/puppet.conf
добавим строки:
[agent]
# если сервер будет менять IP то его легко будет ресолвить по этому адресу
server = puppet.toopro.org
# текущая настойка для компьютеров в магазинах
enviroment = shops
# агент может запрашивать обновления не так часто (по умолчанию 30m)
runinterval = 12h

Если нужно быстренько начать юзать агента, без DNS, то можно просто в /etc/hosts клиента прописать IP хоста с именем "puppet":
$ sudo nano /etc/hosts
дописываем строку
255.255.255.255 puppet

Запустите агент и включите его автозапуск:
sudo systemctl start puppet
sudo systemctl enable puppet

----------------

НА СИСТЕМЕ С ПАПЕТ СЕРВЕРОМ:

После первого запуска агент Puppet отправляет мастеру запрос на подпись сертификата. Прежде чем подключиться к ноде, мастер должен подписать этот сертификат.

sudo puppet cert list
вы увидите список запросов

Чтобы подписать сертификат, используйте команду puppet cert sign. В команде нужно указать имя хоста сертификата, которое можно найти в запросе на подпись.

sudo puppet cert sign db1.lan

Теперь мастер Puppet может взаимодействовать с нодой, которой принадлежит подписанный сертификат. (есть команда чтобы подписать сразу все запросы, но она нам пока не нужна)

----------------

проверка, пропишем манифест:
sudo nano /etc/puppetlabs/code/environments/production/manifests/tooprossh.pp
https://docs.puppet.com/puppet/4.9/type.html#file

запустить НА КЛИЕНТЕ:
sudo /opt/puppetlabs/bin/puppet agent --test #--debug (можно добавить)
должно выполниться действие

НА ПАПЕТ СЕРВЕРЕ

Давайте настром управление без выделенных IP для клиента, для этого нам нужен ssh и чтобы с ним было легче работать, модуль для управления ssh. Найдем модуль на сайте: https://forge.puppet.com/ Для ssh красиво и понятно написан модуль от saz (https://forge.puppet.com/saz/ssh/readme) установим его:
$ sudo /opt/puppetlabs/bin/puppet module install saz-ssh

проверим что модуль был установлен:
$ sudo /opt/puppetlabs/bin/puppet module list

----------------
----------------
----------------

МАНИФЕСТЫ ПИШЕМ НА УДОБНОЙ НАМ МАШИНЕ
Настроим ssfs файловую систему, чтобы писать папет манифесты на удобной нам машине. Ранее мы пробросили порт 2221 к папет серверу, восользуемся им. Пишем через IP и подключаемся по локалке, так как редактировать удаленно мы не будем, и значит пробрасывать лишний порт через роутеры и фаерволы тоже.

$anyPC: mkdir ~/system/virt_vrpuppet
$anyPC: sshfs toopro@192.168.8.220:/etc/puppetlabs/code /home/toopro/system/virt_vrpuppet -p2221 -o default_permissions
(могли бы возникнуть проблемы с пользователями и правами, но у нас админ пользователь совпадает)
подробнее о sshfs настройке: https://www.digitalocean.com/community/tutorials/how-to-use-sshfs-to-mou...