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

Для создания виртуальной машины используется ресурс VirtualMachine, его параметры позволяют сконфигурировать:

  • класс виртуальной машины;
  • ресурсы, требуемые для работы виртуальной машины (процессор, память, диски и образы);
  • правила размещения виртуальной машины на узлах кластера;
  • настройки загрузчика и оптимальные параметры для гостевой ОС;
  • политику запуска виртуальной машины и политику применения изменений;
  • сценарии начальной конфигурации (cloud-init);
  • перечень блочных устройств.

Создание виртуальной машины

Ниже представлен пример простой конфигурации виртуальной машины, запускающей ОС Ubuntu 22.04. В примере используется сценарий первичной инициализации виртуальной машины (cloud-init), который устанавливает гостевого агента qemu-guest-agent и сервис nginx, а также создает пользователя cloud с паролем cloud:

Пароль в примере был сгенерирован с использованием команды mkpasswd --method=SHA-512 --rounds=4096 -S saltsalt и при необходимости вы можете его поменять на свой:

Создайте виртуальную машину с диском:

d8 k apply -f - <<"EOF"
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachine
metadata:
  name: linux-vm
spec:
  # Название класса ВМ.
  virtualMachineClassName: host
  # Блок скриптов первичной инициализации ВМ.
  provisioning:
    type: UserData
    # Пример cloud-init-сценария для создания пользователя cloud с паролем cloud и установки сервиса агента qemu-guest-agent и сервиса nginx.
    userData: |
      #cloud-config
      package_update: true
      packages:
        - nginx
        - qemu-guest-agent
      run_cmd:
        - systemctl daemon-relaod
        - systemctl enable --now nginx.service
        - systemctl enable --now qemu-guest-agent.service
      ssh_pwauth: True
      users:
      - name: cloud
        passwd: '$6$rounds=4096$saltsalt$fPmUsbjAuA7mnQNTajQM6ClhesyG0.yyQhvahas02ejfMAq1ykBo1RquzS0R6GgdIDlvS.kbUwDablGZKZcTP/'
        shell: /bin/bash
        sudo: ALL=(ALL) NOPASSWD:ALL
        lock_passwd: False
      final_message: "The system is finally up, after $UPTIME seconds"
  # Настройки ресурсов ВМ.
  cpu:
    # Количество ядер ЦП.
    cores: 1
    # Запросить 10% процессорного времени одного физического ядра.
    coreFraction: 10%
  memory:
    # Объем оперативной памяти.
    size: 1Gi
  # Список дисков и образов, используемых в ВМ.
  blockDeviceRefs:
    # Порядок дисков и образов в данном блоке определяет приоритет загрузки.
    - kind: VirtualDisk
      name: linux-vm-root
EOF

После создания ресурс VirtualMachine может находиться в следующих состояниях:

  • Pending - ожидание готовности всех зависимых ресурсов, требующихся для запуска виртуальной машины.
  • Starting - идет процесс запуска виртуальной машины.
  • Running - виртуальная машина запущена.
  • Stopping - идет процесс остановки виртуальной машины.
  • Stopped - виртуальная машина остановлена.
  • Terminating - виртуальная машина удаляется.
  • Migrating - виртуальная машина находится в состоянии онлайн-миграции на другой узел.

Проверьте состояние виртуальной машины после создания:

d8 k get vm linux-vm

Пример вывода:

NAME       PHASE     NODE           IPADDRESS     AGE
linux-vm   Running   virtlab-pt-2   10.66.10.12   11m

После создания виртуальная машина автоматически получит IP-адрес из диапазона, указанного в настройках модуля (блок virtualMachineCIDRs).

Подключение к виртуальной машине

Для подключения к виртуальной машине доступны следующие способы:

  • протокол удаленного управления (например SSH), который должен быть предварительно настроен на виртуальной машине;
  • серийная консоль (serial console);
  • протокол VNC.

Пример подключения к виртуальной машине с использованием серийной консоли:

d8 v console linux-vm

Пример вывода:

Successfully connected to linux-vm console. The escape sequence is ^]

linux-vm login: cloud
Password: cloud

Для завершения работы с серийной консолью нажмите Ctrl+].

Пример команды для подключения по VNC:

d8 v vnc linux-vm

Пример команды для подключения по SSH.

d8 v ssh cloud@linux-vm --local-ssh

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

Политика запуска виртуальной машины предназначена для автоматизированного управления состоянием виртуальной машины. Определяется она в виде параметра .spec.runPolicy в спецификации виртуальной машины. Поддерживаются следующие политики:

  • AlwaysOnUnlessStoppedManually — (по умолчанию) после создания ВМ всегда находится в рабочем состоянии. В случае сбоев работа ВМ восстанавливается автоматически. Остановка ВМ возможна только путем вызова команды d8 v stop или создания соответствующей операции.
  • AlwaysOn — после создания ВМ всегда находится в работающем состоянии, даже в случае ее выключения средствами ОС. В случае сбоев работа ВМ восстанавливается автоматически.
  • Manual — после создания состоянием ВМ управляет пользователь вручную с использованием команд или операций.
  • AlwaysOff — после создания ВМ всегда находится в выключенном состоянии. Возможность включения ВМ через команды\операции - отсутствует.

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

  • Создание ресурса VirtualMachineOperation (vmop).
  • Использование утилиты d8 с соответствующей подкомандой.

Ресурс VirtualMachineOperation декларативно определяет действие, которое должно быть выполнено на виртуальной машине.

Пример операции для выполнения перезагрузки виртуальной машины с именем linux-vm:

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachineOperation
metadata:
  name: restart-linux-vm-$(date +%s)
spec:
  virtualMachineName: linux-vm
  # Тип применяемой операции = применяемая операция.
  type: Restart
EOF

Посмотреть результат действия можно с использованием команды:

d8 k get virtualmachineoperation
# или
d8 k get vmop

Аналогичное действие можно выполнить с использованием утилиты d8:

d8 v restart  linux-vm

Перечень возможных операций приведен в таблице ниже:

d8 vmop type Действие
d8 v stop Stop Остановить ВМ
d8 v start Start Запустить ВМ
d8 v restart Restart Перезапустить ВМ
d8 v evict Evict Мигрировать ВМ на другой, произвольный узел

Изменение конфигурации виртуальной машины

Конфигурацию виртуальной машины можно изменять в любое время после создания ресурса VirtualMachine. Однако, то, как эти изменения будут применены, зависит от текущей фазы виртуальной машины и характера внесённых изменений.

Изменения в конфигурацию виртуальной машины можно внести с использованием следующей команды:

d8 k edit vm linux-vm

Если виртуальная машина находится в выключенном состоянии (.status.phase: Stopped), внесённые изменения вступят в силу сразу после её запуска.

Если виртуальная машина работает (.status.phase: Running), то способ применения изменений зависит от их типа:

Блок конфигурации Как применяется
.metadata.labels Сразу
.metadata.annotations Сразу
.spec.runPolicy Сразу
.spec.disruptions.restartApprovalMode Сразу
.spec.* Требуется перезапуск ВМ

Рассмотрим пример изменения конфигурации виртуальной машины:

Предположим, мы хотим изменить количество ядер процессора. В данный момент виртуальная машина запущена и использует одно ядро, что можно подтвердить, подключившись к ней через серийную консоль и выполнив команду nproc.

d8 v ssh cloud@linux-vm --local-ssh --command "nproc"
# 1

Примените следующий патч к виртуальной машине, чтобы изменить количество ядер с 1 на 2.

d8 k patch vm linux-vm --type merge -p '{"spec":{"cpu":{"cores":2}}}'

Пример вывода:

virtualmachine.virtualization.deckhouse.io/linux-vm patched

Изменения в конфигурацию внесены, но ещё не применены к виртуальной машине. Проверьте это, повторно выполнив:

d8 v ssh cloud@linux-vm --local-ssh --command "nproc"
# 1

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

d8 k get vm linux-vm -o jsonpath="{.status.restartAwaitingChanges}" | jq .

Пример вывода:

[
  {
    "currentValue": 1,
    "desiredValue": 2,
    "operation": "replace",
    "path": "cpu.cores"
  }
]

Выполните команду:

d8 k get vm linux-vm -o wide

Пример вывода:

NAME        PHASE     CORES   COREFRACTION   MEMORY   NEED RESTART   AGENT   MIGRATABLE   NODE           IPADDRESS     AGE
linux-vm   Running   2       100%           1Gi      True           True    True         virtlab-pt-1   10.66.10.13   5m16s

В колонке NEED RESTART мы видим значение True, а это значит что для применения изменений требуется перезагрузка.

Выполним перезагрузку виртуальной машины:

d8 v restart linux-vm

После перезагрузки изменения будут применены и блок .status.restartAwaitingChanges будет пустой.

Выполните команду для проверки:

d8 v ssh cloud@linux-vm --local-ssh --command "nproc"
# 2

Порядок применения изменений виртуальной машины через «ручной» рестарт является поведением по умолчанию. Если есть необходимость применять внесенные изменения сразу и автоматически, для этого нужно изменить политику применения изменений:

spec:
  disruptions:
    restartApprovalMode: Automatic

Сценарии начальной инициализации

Сценарии начальной инициализации предназначены для первичной конфигурации виртуальной машины при её запуске.

В качестве сценариев начальной инициализации поддерживаются:

Сценарий CloudInit можно встраивать непосредственно в спецификацию ВМ, но этот сценарий ограничен максимальной длиной в 2048 байт:

spec:
  provisioning:
    type: UserData
    userData: |
      #cloud-config
      package_update: true
      ...

При более длинных сценариях и/или наличии приватных данных, сценарий начальной инициализации виртуальной машины может быть создан в ресурсе Secret. Пример Secret со сценарием CloudInit приведен ниже:

apiVersion: v1
kind: Secret
metadata:
  name: cloud-init-example
data:
  userData: <base64 data>
type: provisioning.virtualization.deckhouse.io/cloud-init

Фрагмент конфигурации виртуальной машины при использовании скрипта начальной инициализации CloudInit хранящегося в ресурсе Secret:

spec:
  provisioning:
    type: UserDataRef
    userDataRef:
      kind: Secret
      name: cloud-init-example

Примечание: значение поля .data.userData должно быть закодировано в формате Base64.

Для конфигурирования виртуальных машин под управлением ОС Windows с использованием Sysprep, поддерживается только вариант с Secret.

Пример Secret с сценарием Sysprep:

apiVersion: v1
kind: Secret
metadata:
  name: sysprep-example
data:
  unattend.xml: <base64 data>
type: provisioning.virtualization.deckhouse.io/sysprep

Примечание: Значение поля .data.unattend.xml должно быть закодировано в формате Base64.

Фрагмент конфигурации виртуальной машины с использованием скрипта начальной инициализации Sysprep в ресурсе Secret:

spec:
  provisioning:
    type: SysprepRef
    sysprepRef:
      kind: Secret
      name: sysprep-example

Размещение ВМ по узлам

Для управления размещением виртуальных машин по узлам можно использовать следующие подходы:

  • Простое связывание по меткам — nodeSelector;
  • Предпочтительное связывание — Affinity;
  • Избежание совместного размещения — AntiAffinity.

Простое связывание по меткам — nodeSelector

nodeSelector — это простейший способ контролировать размещение виртуальных машин, используя набор меток. Он позволяет задать, на каких узлах могут запускаться виртуальные машины, выбирая узлы с необходимыми метками.

spec:
  nodeSelector:
    disktype: ssd

nodeSelector

В этом примере виртуальная машина будет размещена только на узлах, которые имеют метку disktype со значением ssd.

Предпочтительное связывание — Affinity

Affinity предоставляет более гибкие и мощные инструменты по сравнению с nodeSelector. Он позволяет задавать предпочтения и обязательности для размещения виртуальных машин. Affinity поддерживает два вида: nodeAffinity и virtualMachineAndPodAffinity.

nodeAffinity позволяет определять, на каких узлах может быть запущена виртуальная машина, с помощью выражений меток, и может быть предпочтительным (preferred) или обязательным (required).

Пример использования nodeAffinity:

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd

nodeAffinity

В этом примере виртуальная машина будет размещена только на узлах, которые имеют метку disktype со значением ssd.

virtualMachineAndPodAffinity управляет размещением одних виртуальных машин относительно других виртуальных машин. Он позволяет задавать предпочтение размещения виртуальных машин на тех же узлах, где уже запущены определенные виртуальные машины.

Пример:

spec:
  affinity:
    virtualMachineAndPodAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          virtualMachineAndPodAffinityTerm:
            labelSelector:
              matchLabels:
                server: database
            topologyKey: "kubernetes.io/hostname"

virtualMachineAndPodAffinity

В этом примере виртуальная машина будет размещена, если будет такая возможность (так как используется метка preffered), только на узлах на которых присутствует виртуальная машина с меткой server и значением database.

Избежание совместного размещения — AntiAffinity

AntiAffinity — это противоположность Affinity, которая позволяет задавать требования для избегания размещения виртуальных машин на одних и тех же узлах. Это полезно для распределения нагрузки или обеспечения отказоустойчивости.

Термины Affinity и AntiAffinity применимы только к отношению между виртуальными машинами. Для узлов используемые привязки называются nodeAffinity. В nodeAffinity нет отдельного обратного термина, как в случае с virtualMachineAndPodAffinity, но можно создать противоположные условия, задав отрицательные операторы в выражениях меток. Чтобы акцентировать внимание на исключении определенных узлов, можно воспользоваться nodeAffinity с оператором, таким как NotIn.

Пример использования virtualMachineAndPodAntiAffinity:

spec:
  affinity:
    virtualMachineAndPodAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
              server: database
          topologyKey: "kubernetes.io/hostname"

AntiAffinity

В данном примере создаваемая виртуальная машина не будет размещена на одном узле с виртуальной машиной с меткой server: database.

Статические и динамические блочные устройства

Блочные устройства можно разделить на два типа по способу их подключения: статические и динамические (hotplug).

Статические блочные устройства

Статические блочные устройства указываются в спецификации виртуальной машины в блоке .spec.blockDeviceRefs. Этот блок представляет собой список, в который могут быть включены следующие блочные устройства:

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

Изменение состава и порядка устройств в блоке .spec.blockDeviceRefs возможно только с перезагрузкой виртуальной машины.

Динамические блочные устройства

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

Для подключения динамических блочных устройств используется ресурс VirtualMachineBlockDeviceAttachment (vmbda). На данный момент для подключения в качестве динамического блочного устройства поддерживается только VirtualDisk.

Создайте следующий ресурс, который подключит пустой диск blank-disk к виртуальной машине linux-vm:

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachineBlockDeviceAttachment
metadata:
  name: attach-blank-disk
spec:
  blockDeviceRef:
    kind: VirtualDisk
    name: blank-disk
  virtualMachineName: linux-vm
EOF

После создания VirtualMachineBlockDeviceAttachment может находиться в следующих состояниях:

  • Pending - ожидание готовности всех зависимых ресурсов.
  • InProgress - идет процесс подключения устройства.
  • Attached - устройство подключено.

Проверьте состояние вашего ресурса:

d8 k get vmbda attach-blank-disk

Пример вывода:

NAME                PHASE      VIRTUAL MACHINE NAME   AGE
attach-blank-disk   Attached   linux-vm              3m7s

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

d8 v ssh cloud@linux-vm --local-ssh --command "lsblk"

Пример вывода:

NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda       8:0    0   10G  0 disk <--- статично подключенный диск linux-vm-root
|-sda1    8:1    0  9.9G  0 part /
|-sda14   8:14   0    4M  0 part
`-sda15   8:15   0  106M  0 part /boot/efi
sdb       8:16   0    1M  0 disk <--- cloudinit
sdc       8:32   0 95.9M  0 disk <--- динамически подключенный диск blank-disk

Для отключения диска от виртуальной машины удалите ранее созданный ресурс:

d8 k delete vmbda attach-blank-disk

Миграция виртуальной машины в реальном времени

Миграция виртуальных машин является важной функцией в управлении виртуализованной инфраструктурой. Она позволяет перемещать работающие виртуальные машины с одного физического узла на другой без их отключения.

Миграция может осуществляться автоматически при:

  • Обновлении «прошивки» виртуальной машины.
  • Перебалансировке нагрузки на узлах кластера.
  • Переводе узлов в режим обслуживания для проведения работ.

Также миграция виртуальной машины может быть выполнена по требованию пользователя. Рассмотрим на примере:

Перед запуском миграции посмотрите текущий статус виртуальной машины:

d8 k get vm

Пример вывода:

NAME       PHASE     NODE           IPADDRESS     AGE
linux-vm   Running   virtlab-pt-1   10.66.10.14   79m

Виртуальная машина запущена на узле virtlab-pt-1.

Для осуществления миграции виртуальной машины с одного узла на другой, с учетом требований к размещению виртуальной машины используется ресурс VirtualMachineOperation (vmop) с типом Evict.

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachineOperation
metadata:
  name: evict-linux-vm-$(date +%s)
spec:
  # имя виртуальной машины
  virtualMachineName: linux-vm
  # операция для миграции
  type: Evict
EOF

Сразу после создания ресурса vmop, выполните команду:

d8 k get vm -w

Пример вывода:

NAME       PHASE       NODE           IPADDRESS     AGE
linux-vm   Running     virtlab-pt-1   10.66.10.14   79m
linux-vm   Migrating   virtlab-pt-1   10.66.10.14   79m
linux-vm   Migrating   virtlab-pt-1   10.66.10.14   79m
linux-vm   Running     virtlab-pt-2   10.66.10.14   79m

Также для выполнения миграции можно использовать команду:

d8 v evict <vm-name>

IP-адреса виртуальных машин

Блок .spec.settings.virtualMachineCIDRs в конфигурации модуля virtualization задает список подсетей для назначения IP-адресов виртуальным машинам (общий пул IP-адресов). Все адреса в этих подсетях доступны для использования, за исключением первого (адрес сети) и последнего (широковещательный адрес).

Ресурс VirtualMachineIPAddressLease (vmipl): кластерный ресурс, который управляет временным выделением IP-адресов из общего пула, указанного в virtualMachineCIDRs.

Чтобы посмотреть список временно выделенных IP-адресов (vmipl), используйте команду:

d8 k get vmipl

Пример вывода:

NAME             VIRTUALMACHINEIPADDRESS                             STATUS   AGE
ip-10-66-10-14   {"name":"linux-vm-7prpx","namespace":"default"}     Bound    12h

Ресурс VirtualMachineIPAddress (vmip) — это ресурс проекта или пространства имен, который отвечает за резервирование выделенных IP-адресов и их привязку к виртуальным машинам. IP-адреса могут выделяться автоматически или по запросу.

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

d8 k get vmipl

Пример вывода:

NAME             VIRTUALMACHINEIPADDRESS                             STATUS   AGE
ip-10-66-10-14   {"name":"linux-vm-7prpx","namespace":"default"}     Bound    12h

Проверить назначенный IP-адрес можно с помощью команды:

d8 k get vmip

Пример вывода:

NAME             ADDRESS       STATUS     VM         AGE
linux-vm-7prpx   10.66.10.14   Attached   linux-vm   12h

Алгоритм автоматического присвоения IP-адреса виртуальной машине выглядит следующим образом:

  • Пользователь создает виртуальную машину с именем <vmname>.
  • Контроллер модуля автоматически создает ресурс vmip с именем <vmname>-<hash>, чтобы запросить IP-адрес и связать его с виртуальной машиной.
  • Для этого vmip создается ресурс аренды vmipl, который выбирает случайный IP-адрес из общего пула.
  • Как только ресурс vmip создан, виртуальная машина получает назначенный IP-адрес.

По умолчанию IP-адрес для виртуальной машины назначается автоматически, из подсетей, определенных в модуле, и закрепляется за ней до её удаления. После удаления виртуальной машины ресурс vmip также удаляется, но IP-адрес временно остается закрепленным за проектом/пространством имен и может быть повторно запрошен.

Как запросить требуемый ip-адрес?

Создайте ресурс vmip:

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachineIPAddress
metadata:
  name: linux-vm-custom-ip
spec:
  staticIP: 10.66.20.77
  type: Static
EOF

Создайте новую или измените существующую виртуальную машину и в спецификации укажите требуемый ресурс vmip явно:

spec:
  virtualMachineIPAdressName: linux-vm-custom-ip

Как сохранить присвоенный виртуальной машине IP-адрес?

Чтобы автоматически выданный IP-адрес виртуальной машины не удалился вместе с самой виртуальной машиной, выполните следующие действия.

Получите название ресурса vmip для заданной виртуальной машины:

d8 k get vm linux-vm -o jsonpath="{.status.virtualMachineIPAddressName}"

Пример вывода:

linux-vm-7prpx

Удалите блоки .metadata.ownerReferences из найденного ресурса:

d8 k patch vmip linux-vm-7prpx --type=merge --patch '{"metadata":{"ownerReferences":null}}'

После удаления виртуальной машины, ресурс vmip сохранится и его можно будет использовать во вновь созданной виртуальной машине:

spec:
  virtualMachineIPAdressName: linux-vm-7prpx

Даже если ресурс vmip будет удален, он остается арендованным для текущего проекта/пространства имен еще 10 минут и существует возможность вновь его занять по запросу:

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachineIPAddress
metadata:
  name: linux-vm-custom-ip
spec:
  staticIP: 10.66.20.77
  type: Static
EOF