Статьи

Libvirt Поддержка тумана

Исторически мы намеревались использовать Vagrant на ноутбуке разработчиков. Вскоре сложность нашей установки переросла ноутбук разработчика и потребовала другого решения. Поскольку целевая платформа была основана на Amazon EC2, имело смысл создавать среды для разработчиков на EC2. Опираясь на простоту Vagrant CLI, мы вскоре обнаружили, что наша команда может извлечь выгоду из аналогичного CLI для EC2. Поэтому мы создали Mccloud . Мы с этим уже давно работаем.

Чтобы это произошло, мы использовали Fog библиотеку абстракций облаков ruby. Большинство поставщиков поддерживаемых облаков — это общедоступные облака, такие как Amazon EC2. Это позволяет использовать один и тот же набор API для нескольких облаков.

Поскольку затраты на EC2 увеличились, мы подумали, сможем ли мы создать такую ​​же гибкость на некоторых внутренних аппаратных средствах для нашей тестовой среды. Изучив http://openstack.org и некоторые другие альтернативы, мы решили пойти на минималистичный подход и использовать только базовую виртуализацию. Очевидным выбором для автоматизации было использование библиотеки абстракций Libvirt для таких платформ виртуализации, как kvm, xen, openvz.

В Libvirt доступны рубиновые привязки, но по сравнению с API-интерфейсом fog использование выглядит неуместно: использование XML-документов для задания параметров — не самый удобный подход для разработчиков. Так родилась идея интегрировать силу libvirt в библиотеку тумана.

Настройка сервера и клиента libvirt

Libvirt — это демон, который вы должны установить на сервере, управление им осуществляется с помощью утилиты virsh. Описание установки libvirt выходит за рамки этого документа. Но вот некоторые ошибки, которые мы приветствовали:

Ubuntu Server:

  • изначально мы устанавливаем машины как lucid, но официальной версией libvirt в lucid является версия 0.7. , Мы обновились до maverick, так как он содержал более свежую версию libvirt 0.8.3+.
  • если вы подключаетесь через сеть с помощью удаленного транспорта, такого как ssh, вам необходимо установить netbsd-совместимую версию netcat. В последних версиях это происходит автоматически при установке пакета libvirt.
# apt-get install libvirt-bin
  • мы использовали VLAN и мостовую сеть. У нас были задержки в запросах DHCP в гостях. Оказалось, что «bridge_maxwait 0» решил наши проблемы. Поэтому, если eth0 является нашим основным интерфейсом, а eth0.4 — нашим мостовым / VLAN-интерфейсом, конфигурация наших интерфейсов выглядит следующим образом:
root@libvirthost:~# cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet static
     address 10.33.67.20
     netmask 255.255.255.0
     network 10.33.67.0
     broadcast 10.33.67.255
     gateway 10.33.67.9
# dns-* options are implemented by the resolvconf package, if installed
dns-nameservers 10.33.29.17
dns-search lab.ourdomain.com
auto br0
iface br0 inet static
     address 10.33.4.13
     netmask 255.255.255.0
     network 10.33.4.0
     broadcast 10.33.4.255
     bridge_ports eth0.4
     bridge_stp on
bridge_maxwait 0

Локальный клиент Ubuntu

  • если пользователь хочет выполнять команды libvirt, его необходимо добавить в группу libvirt.
  • Теперь на сервере вы можете проверить, работает ли он, подключившись к гипервизору kvm.
$ virsh -c qemu:///system
  • если вам нужно отладить, сделайте
$ LIBVIRT_DEBUG=debug virsh -c qemu:///system

Удаленный клиент Ubuntu:

Libvirt предоставляет способ удаленного входа на хост libvirt через различные удаленные транспорты. Мы используем SSH в качестве транспорта. Это требует от пользователя patrick иметь ssh-login без пароля для хоста libvirthost и члена группы libvirt.

$ virsh -c qemu+ssh://patrick@libvirthost/system

Клиент Macosx Remote Libvirt:

  • Установка клиента libvirt может быть выполнена с помощью homebrew
$ brew install libvirt
  • Подключение к серверу приведет к ошибке: «событие зависания / ошибки на сокете». Оказывается, клиент macosx предполагает, что сокет находится в / usr / local / lib, тогда как сервер ubuntu имеет сокет в / var / run / libvirt / libvirt-sock.
$ virsh -c qemu+ssh://patrick@libvirthost/system?socket=/var/run/libvirt/libvirt-sock

Более подробную информацию об удаленной нотации libvirt URI можно найти в Интернете .

Настройка драгоценных камней Ruby (fog / ruby-libvirt)

Функциональность libvirt в тумане скоро будет доступна в качестве самоцвета в версии 0.11. Этот пример использует rvm, чтобы избежать беспорядка между другими установками.

Для использования поддержки libvirt fog необходимо установить два гема:

  • камень тумана: версия 1.0.0 или выше
  • гем ruby-libvirt: это оболочка ruby ​​вокруг библиотеки C libvirt.

Чтобы скомпилировать гем ruby-libvirt, вам необходимо установить библиотеки разработчика libvirt.

На убунту:

$ sudo apt-get install libvirt-dev

Обратите внимание, что есть еще один гем под названием libvirt. Это еще одна оболочка ruby, но ее API не совместим.

Следующий транскрипт создает набор гемов с именем fog-demo:

$ mkdir fog-demo
$ cd fog-demo

$ cat <<<<END > .rvmrc
#this uses rvm
rvm_gemset_create_on_use_flag=1
rvm use 1.9.2
rvm gemset use fog-demo
alias fog="bundle exec fog"
END

$ cd ..
$ cd fog-demo

$ gem install bundler

$ cat <<<<END > Gemfile
source 'http://rubygems.org'
# Use this for direct access to the git latest version
gem 'fog', :git => "git://github.com/geemus/fog.git", :branch => "master"
# Change this 
# gem 'fog',:version => "1.0.0"
gem 'ruby-libvirt'
END

# Install the gems as specified in the Gemfile
$ bundle install

# To allow fog to be executed from this bundle of gems
$ alias fog="bundle exec fog"

Настройка тумана

Прежде чем вы сможете запустить команду «fog», вам нужно настроить файл конфигурации «.fog». Файл конфигурации — это файл yaml, который обычно находится в вашем каталоге $ HOME.

Чтобы настроить файл конфигурации для подключения libvirt по умолчанию, используйте следующий синтаксис.

$ cat $HOME/.fog
:default
  :libvirt_uri: "qemu+ssh://patrick@libvirthost/system?socket=/var/run/libvirt-sock"

Примечание 1: вы можете оставить: libvirt_uri пустым, но вам нужен файл .fog, по крайней мере, с одним настроенным провайдером.

Примечание 2: для некоторой виртуализации (например, vsphere) вам необходимо указать имя пользователя и пароль, вы можете использовать следующие дополнительные параметры конфигурации:

  • : libvirt_username
  • : libvirt_password

Использование туманной консоли

Теперь вы готовы запустить противотуманную консоль

$ fog
  Welcome to fog interactive!
  :default provides Libvirt

Если вы указали значение по умолчанию: libvirt_uri, теперь вы можете перечислить тома с помощью

>> Compute[:Libvirt].volumes

Примечание: во фрагменте кода «>>» также преобразован в «& gt & gt»

или для создания туманного соединения с сервером libvirt:

>>  f=Fog::Compute.new({:provider => "libvirt" , 
:libvirt_uri => "qemu+ssh://patrick@libvirthost/system?socket=/var/run/libvirt-sock"})

Если вы хотите указать больше опций для соединения, у объекта ‘f’ есть атрибут ‘@raw’, и это откроет непосредственный доступ к лежащему в основе Libvirt :: Connection.

Доступные коллекции

Текущая интеграция тумана libvirt также вам управлять:

Используя объект соединения ‘f’, который мы только что создали, мы можем теперь использовать

  • f.servers.all: перечислить домены
  • f.volumes.all: перечислить тома
  • f.pools.all: перечислить пулы
  • f.networks.all: список сетей
  • f.interface.all: перечислить интерфейсы
  • f.nodes.all: перечислить узлы

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

Управление томами

Перечисление всех томов

Чтобы вывести список всех доступных томов, вы можете ввести следующую команду, которая возвращает массив результатов.

>> f.volumes.all
  <Fog::Compute::Libvirt::Volumes
    [
      <Fog::Compute::Libvirt::Volume
        id="/var/lib/libvirt/images/fog-demo.img",
        pool_name="virtimages",
        xml="<volume>\n  <name>fog-demo.img</name>\n  <key>/var/lib/libvirt/images/fog-demo.img</key>\n  <source>\n  </source>\n  <capacity>10737418240</capacity>\n  <allocation>10737446912</allocation>\n  <target>\n    <path>/var/lib/libvirt/images/fog-demo.img</path>\n    <format type='raw'/>\n    <permissions>\n      <mode>0744</mode>\n      <owner>106</owner>\n      <group>111</group>\n    </permissions>\n  </target>\n</volume>\n",
        key="/var/lib/libvirt/images/fog-demo.img",
        path="/var/lib/libvirt/images/fog-demo.img",
        name="fog-demo.img",
        capacity=10737418240,
        allocation=10737446912,
        format_type="raw"
      >]
  >

Фильтрация томов

Три различных способа фильтрации по: имени, по: ключу или по: пути

>> f.volumes.all(:name => "fog-demo.img")
>> f.volumes.all(:key => "/var/lib/libvirt/images/fog-demo.img")
>> f.volumes.all(:path => "/var/lib/libvirt/images/fog-demo.img")

Извлечение определенного объема

Чтобы получить определенный том, вы указываете значение ключа:

>> v1=f.volumes.get("/var/lib/libvirt/images/fog-demo.img")

Клонирование тома

Учитывая объем v1, мы только что нашли, мы можем клонировать это в v2

>> v2=v1.clone("fog-demo2.img")

Создание тома

Есть два способа создать новый том:

Первый подход использует шаблон

>> v3=f.volumes.create(:name => "test.img")

with the following defaults

>> v3=f.volumes.create(:name => "test.img", :allocation => "1G", :capacity => "10G", :format_type => "raw", :pool_name => "default")

Второй подход заключается в указании вашего собственного XML-файла, как если бы вы делали это напрямую с libvirt: например, если вам не нравится шаблон

>> xml_data="<xml....>"
>> v4=f.volumes.create(:xml => xml_data)

Уничтожение тома

Чтобы уничтожить том 1, сделайте следующее

>> v1.destroy

Доступ к сырому Libvirt :: Домен

Том имеет атрибут «@raw», который позволяет вам в случае необходимости обращаться к объекту Libvirt :: Domain напрямую.

Перезагрузка информации о томе

Информация о томе может измениться, объект инициализируется только один раз, если вы хотите перезагрузить объект с самой последней информацией;

>> v1.reload

Управление серверами / доменами

Подобные действия теперь могут выполняться над доменами. Они сопоставлены с концепцией тумана серверов.

Листинг серверов

Перечисление всех серверов приведет к массиву результатов

>> f.servers.all
  <Fog::Compute::Libvirt::Servers
    [
     <Fog::Compute::Libvirt::Server
        id="a6708012-6dd5-26b3-3474-ffd660397d78",
        xml="<domain type='kvm' id='44'>\n  <name>fog-demo2</name>\n  <uuid>a6708012-6dd5-26b3-3474-ffd660397d78</uuid>\n  <memory>256</memory>\n  <currentMemory>393216</currentMemory>\n  <vcpu>1</vcpu>\n  <os>\n    <type arch='x86_64' machine='pc-0.12'>hvm</type>\n    <boot dev='hd'/>\n  </os>\n  <features>\n    <acpi/>\n    <apic/>\n    <pae/>\n  </features>\n  <clock offset='utc'/>\n  <on_poweroff>destroy</on_poweroff>\n  <on_reboot>restart</on_reboot>\n  <on_crash>destroy</on_crash>\n  <devices>\n    <emulator>/usr/bin/kvm</emulator>\n    <disk type='file' device='disk'>\n      <driver name='qemu' type='raw'/>\n      <source file='/var/lib/libvirt/images/fog-demo2.img'/>\n      <target dev='vda' bus='virtio'/>\n      <alias name='virtio-disk0'/>\n      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n    </disk>\n    <interface type='bridge'>\n      <mac address='52:54:00:23:85:73'/>\n      <source bridge='br0'/>\n      <target dev='vnet0'/>\n      <model type='virtio'/>\n      <alias name='net0'/>\n      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n    </interface>\n    <serial type='pty'>\n      <source path='/dev/pts/0'/>\n      <target port='0'/>\n      <alias name='serial0'/>\n    </serial>\n    <console type='pty' tty='/dev/pts/0'>\n      <source path='/dev/pts/0'/>\n      <target type='serial' port='0'/>\n      <alias name='serial0'/>\n    </console>\n    <input type='mouse' bus='ps2'/>\n    <graphics type='vnc' port='5900' autoport='yes' keymap='en-us'/>\n    <video>\n      <model type='cirrus' vram='9216' heads='1'/>\n      <alias name='video0'/>\n      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>\n    </video>\n    <memballoon model='virtio'>\n      <alias name='balloon0'/>\n      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n    </memballoon>\n  </devices>\n</domain>\n",
        cpus=1,
        cputime=6090390000000,
        os_type="hvm",
        memory_size=393216,
        max_memory_size=256,
        name="fog-demo2",
        arch="x86_64",
        persistent=true,
        domain_type="kvm",
        uuid="a6708012-6dd5-26b3-3474-ffd660397d78",
        autostart=false,
        state="running"
      >
    ]
  >

Фильтрация серверов

Различные способы фильтрации по: имени, по: uuid

>> f.servers.all(:name => "fog-demo2")
>> f.servers.all(:uuid => "a6708012-6dd5-26b3-3474-ffd660397d78")

Дополнительные фильтры могут быть указаны для фильтрации активных или определенных доменов

>> f.servers.all(:defined => true)
>> f.servers.all(:active => true)

Выбор конкретного сервера

Чтобы получить определенный сервер, вы указываете значение: uuid

>> s1=f.servers.get("a6708012-6dd5-26b3-3474-ffd660397d78")

Запрос дополнительной информации на сервере

Следующие состояния для сервера будут сообщены

>> s1.state

«Nostate», «работает», «заблокирован», «Приостановлено», «закрывая вниз», «отсечение», «упал»

Чтобы получить vnc_port

>> s1.vnc_port

Жизненный цикл сервера

>> s1.start
>> s1.pause
>> s1.resume
>> s1.shutdown # clean ACPI (requires guest to have ACPI enabled)
>> s1.stop # alias for shutdown
>> s1.halt # Force halt
>> s1.poweroff # Alias for halt

Уничтожение сервера

>> s1.destroy

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

Если вы хотите уничтожить объем, а также

>> s1.destroy(:destroy_volumes => true)

Создание нового сервера

Первый вариант — создать сервер на основе шаблона. (Kvm только в настоящее время)

>> f.servers.create(:name => "demo2")

Выше будет создан сервер на основе шаблона на основе kvm со следующими значениями по умолчанию:

>> f.servers.create({ :name => "demo2", :persistent => true,
:cpus => 1, :memory_size => 256*1024 , :os_type => "hvm", 
:arch => "x64_64", :domain_type => "kvm",
:network_interface_type => "nat", :network_nat_network => "default"})

Это также создаст том, как описано ранее в разделе создания тома.

Существуют дополнительные параметры для тома:

  • volume_format_type: «raw»
  • volume_capicity: «10G»
  • Volume_allocation: «1G»
  • имя_тома: «по умолчанию»
  • имя_тома: имя сервера + суффикс

Если вы хотите клонировать существующий том для нового сервера, укажите:

  • volume_template_name: имя тома, который будет клонирован

Для переключения с NAT на Bridged используйте следующие опции

  • network_interface_type: «мост»
  • имя_сети сети: «br0»

Если вы не нашли подходящий шаблон, вы также можете указать сервер по xml.

>> xml_data="<xml....>"
>> s4=f.servers.create(:xml => xml_data)

Доступ к сырому Libvirt :: Домен

В случае, если вам нужно выполнить более конкретные манипуляции, необработанный Libvirt :: Domain доступен как атрибут «@raw» сервера.

Получение IP-адреса сервера

Либвирт и IP-адреса

Libvirt, в отличие от других решений для виртуализации, таких как Xen, Virtualbox, Vsphere, не имеет стандартного способа получения IP-адреса гостя.

Вы можете получить только MAC-адрес сервера, но вы должны выполнить перевод между MAC-адресом и IP-адресом самостоятельно.

Arpwatch способ отследить mac / ip-адреса

Мы решили эту проблему, установив arpwatch на хост libvirt. Arpwatch прослушивает сеть и регистрирует пары mac-адресов и IP-адресов, которые он видит, проходя мимо.

Сначала мы устанавливаем arpwatch (инструкции по Ubuntu)

$ sudo apt-get -y install arpwatch

# Make it listen to the bridged network
$ sudo sed -i -e 's/ARGS="-N -p"/ARGS="-N -p -i eth0.4"/' /etc/default/arpwatch

$ sudo service arpwatch restart

Arpwatch сохраняет свою информацию в файле данных (arpwatch.dat), но это не записывается до тех пор, пока демон не будет остановлен / запущен.

Поэтому мы настраиваем rsyslogd для записи сообщений arpwatch в отдельный файл.

# cat /etc/rsyslog.d/30-arpwatch.conf
if $programname =='arpwatch' then /var/log/arpwatch.log
& ~

Этот файл должен быть доступен для чтения всем пользователям libvirt / fog, которые хотят получить информацию из файла журнала.

IP-адрес

По умолчанию поставщик libvirt / fog предполагает следующую команду ip_com для преобразования mac-адреса в ip-адрес.

grep $mac /var/log/arpwatch.log|sed -e "s/new station//"|sed -e "s/changed ethernet address//g" |tail -1 |cut -d ":" -f 4-| cut -d " " -f 3'

Чтобы получить ip_addresses сервера, вы делаете:

>> s.addresses

Чтобы получить первые публичные ip_addresses сервера:

>> s.ip_address

В решении arp-watch важно, чтобы хост libvirt имел возможность видеть сетевой трафик проходящих мимо гостей.

Альтернативный способ перевода mac / ip-адресов

Если у вас есть другой способ сделать перевод mac / ip-адреса, вы можете переопределить эту команду:

  • указав его в .fog или Fog :: Compute.new

    • : libvirt_ip_command: команда оболочки, в которой должна быть выполнена переменная окружения $ mac.
  • или указав параметр: ip_command в команде s.addresses ()

Ожидание получения сервером IP-адреса

Помните, что объект тумана должен быть перезагружен, чтобы получить последнюю информацию. Когда сервер загружается, вполне возможно, что машины еще не имеют IP-адреса.

>> s=f.servers.get("a6708012-6dd5-26b3-3474-ffd660397d78")
>> s.start
# Wait for machine to be booted
>> s.wait_for { ready?}
# Wait for machine to get an ip-address
>> s.wait_for { !ip_address.nil?}

Использование + SSH удаленного транспорта

Если вы подключаетесь к серверу libvirt через транспорт + ssh, команда ip_command выполняется через ssh, в противном случае это будет выполнение команды в локальной оболочке.

SSH на сервер

SSH-Логин

Теперь, когда у нас есть ip-адрес, мы можем войти на сервер (имя пользователя / пароль)

>> s=f.servers.get("a6708012-6dd5-26b3-3474-ffd660397d78")
>> s.username="ubuntu"
>> s.password="ubuntu"

или с помощью закрытого ключа

>> s=f.servers.get("a6708012-6dd5-26b3-3474-ffd660397d78")
>> s.username="patrick"
>> s.private_key_path="/Users/patrick/.ssh/id_dsa"
  s.ssh("uptime")

SSH-туннелирование в случае удаленного транспорта + ssh

Если вы используете + ssh в качестве удаленного транспорта, соединение ssh будет туннелироваться через ваше соединение ssh, которое соединяет вас с libvirt-host. Так что вам не нужен прямой доступ к гостю, только libvirthost нуждается в IP-маршрутизации.

Bootstrap / Добавить еще один открытый ключ к учетной записи

Чтобы добавить открытый ssh-ключ id_dsa.pub к авторизованным ключам пользователя ubuntu, вы можете сделать следующее

>> s=f.servers.get("a6708012-6dd5-26b3-3474-ffd660397d78")
>> s.username="ubuntu"
>> s.password="ubuntu"
>> s.public_key_path="/Users/patrick/.ssh/id_dsa.pub"
>> s.setup

Создание шаблонов дисков / томов

В одной из следующих публикаций я покажу, как я расширил veewee для создания стандартных томов / изображений. Хитрость заключается в использовании VNC вместо нажатий клавиш Virtualbox. Подробнее об этом позже.

Использование его для виртуализации помимо KVM

Это некоторый код, вдохновленный этим суть Rubiojr

require 'rubygems'
require 'fog'

# Helper to print all the servers
def print_servers(conn, uri)
  puts "URI: #{uri}"
  conn.servers.all.each do |s|
    puts "  #{s.name}"
    puts "    Server ID:".ljust(20) + "#{s.id}"
  end
  puts "\n"*3
end

# XEN Community
uri = 'xen+tcp://thunder08'
c = Fog::Compute.new( { :provider => 'Libvirt', :libvirt_uri => uri })
print_servers c, uri

# ESX
uri = 'esx://thunder03/?no_verify=1'
c = Fog::Compute.new( { :provider => 'Libvirt', :libvirt_uri => uri,
    :libvirt_username => 'root', :libvirt_password => 'temporal' }
)
print_servers c, uri

# KVM
uri = 'qemu+tcp://thunder11/system'
c = Fog::Compute.new( { :provider => 'Libvirt', :libvirt_uri => uri, })
print_servers c, uri

Обратная связь

Мне нравится обратная связь, поставщик в настоящее время находится в рабочем состоянии, но он явно был нацелен на запуск KVM. Также может быть улучшено создание и изменение объектов. Код там.

Если у вас есть мысли, идеи, улучшения, дайте мне знать.