Доступно в коммерческих редакциях Deckhouse Platform (DP).

Ресурс VirtualMachinePool поддерживает заданное число одинаковых виртуальных машин (ВМ) и позволяет масштабировать их через субресурс scale, HorizontalPodAutoscaler (HPA) или KEDA. Поле virtualMachineTemplate.spec совпадает с обычным VirtualMachineSpec, поэтому реплика ничем не отличается от вручную созданной виртуальной машины.

Тип ОС Legacy в пуле не поддерживается, потому что реплики различают начальной инициализацией, которой у этих операционных систем нет, поэтому каждая реплика оказалась бы побайтовой копией одного диска — для гостевых ОС семейства Windows это ещё и одинаковый SID в сети. Шаблон пула с osType: Legacy отклоняется. Создавайте такие виртуальные машины по отдельности.

Ниже показано, как создать пул виртуальных машин:

  • В командной строке
  • В веб-интерфейсе

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

  • virtualDiskTemplates описывает каждый диск реплики один раз, задавая политику reclaim, размер и источник данных;
  • blockDeviceRefs шаблона ссылается на эти диски по имени с kind: VirtualDisk и задаёт порядок устройств, то есть порядок загрузки, ровно как в обычной VirtualMachine.

Каждая запись virtualDiskTemplates должна встречаться в blockDeviceRefs ровно один раз, иначе DP отклонит пул. Имена шаблонов дисков при этом уникальны.

Помимо дисков реплики в blockDeviceRefs можно перечислить общие образы VirtualImage и ClusterVirtualImage, например единый ISO или CD-ROM для всех реплик. Такие образы подключаются только на чтение, они одни на весь пул, и записи в virtualDiskTemplates им не нужны.

d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachinePool
metadata:
  name: runners
  namespace: ci
spec:
  replicas: 3
  scaleDownPolicy: NewestFirst
  virtualMachineTemplate:
    spec:
      runPolicy: AlwaysOn
      virtualMachineClassName: generic
      cpu:
        cores: 2
      memory:
        size: 4Gi
      # Cloud-init: каждая реплика самонастраивается при первом запуске (одинаково для всех).
      provisioning:
        type: UserData
        userData: |
          #cloud-config
          users:
            - name: cloud
              sudo: ALL=(ALL) NOPASSWD:ALL
              ssh_authorized_keys:
                - <SSH_PUBLIC_KEY>
      # Устройства и порядок загрузки (первый = загрузочный). Записи VirtualDisk
      # ссылаются на virtualDiskTemplates по имени, у каждой реплики свой диск;
      # VirtualImage/ClusterVirtualImage — общий образ только для чтения для всех реплик.
      blockDeviceRefs:
        - kind: VirtualDisk
          name: root          # загрузочный диск
        - kind: VirtualDisk
          name: cache
        - kind: ClusterVirtualImage
          name: tools-iso      # общий CD-ROM, подключается ко всем репликам
  # Параметры дисков реплики (reclaim, размер, источник). Каждый должен быть указан выше.
  virtualDiskTemplates:
    # Записываемый корневой диск: свой на каждую реплику, клонируется из образа, удаляется вместе с репликой.
    - name: root
      reclaim:
        onScaleDown: Delete
      spec:
        persistentVolumeClaim:
          size: 30Gi
        dataSource:
          type: ObjectRef
          objectRef:
            kind: VirtualImage
            name: ubuntu
    # Переиспользуемый кеш, переживает уменьшение пула и переподключается при росте.
    - name: cache
      reclaim:
        onScaleDown: Retain
        keep: 5
        ttl: 30m
      spec:
        persistentVolumeClaim:
          size: 50Gi
EOF

Реплики именуются <POOL>-<RANDOM>. Диски следуют той же схеме, и диск на реплику (Delete) называется <REPLICA>-<TEMPLATE> (например, runners-1b2e84-root), переиспользуемый (Retain) получает имя <POOL>-<TEMPLATE>-<RANDOM>. Посмотреть реплики можно через d8 k get vm -l vmpool.virtualization.deckhouse.io/pool=runners.

  1. Перейдите на вкладку «Проекты» и выберите нужный проект.
  2. Перейдите в раздел «Виртуализация» → «Пулы ВМ».
  3. Нажмите кнопку «Создать».
  4. В открывшемся окне «Создать ресурс» в поле «Имя» введите имя пула.
  5. На вкладке «Конфигурация» задайте число реплик в поле «Replicas» и политику удаления реплик в поле «Scale Down Policy».
  6. В блоке «Virtual Disk Templates» опишите диски реплик, в блоке «Virtual Machine Template» — шаблон виртуальной машины.
  7. Нажмите кнопку «Применить».

Форма пула построена по спецификации ресурса VirtualMachinePool, поэтому названия полей совпадают с параметрами ресурса. Готовую спецификацию можно вставить на вкладке «YAML».

Подключение общего CD-ROM (или любого общего образа) ко всем репликам

Помимо дисков реплики, в blockDeviceRefs можно сослаться на образы только для чтения, ClusterVirtualImage или VirtualImage. Такой образ общий, и все реплики подключают один и тот же файл, например ISO с инструментами или драйверами. В virtualDiskTemplates образы не перечисляются, потому что своей копии у реплики для них нет, и во взаимно однозначное соответствие с шаблонами они не входят.

Добавьте образ в blockDeviceRefs на нужную позицию в порядке загрузки. Установочный ISO поставьте перед диском, а CD-ROM с инструментами после него:

spec:
  virtualMachineTemplate:
    spec:
      blockDeviceRefs:
        - kind: VirtualDisk           # Записываемый корневой диск на реплику, грузится первым.
          name: root
        - kind: ClusterVirtualImage   # Общий CD-ROM только для чтения, подключается ко всем репликам.
          name: tools-iso
  virtualDiskTemplates:
    - name: root
      spec:
        persistentVolumeClaim:
          size: 30Gi
        dataSource:
          type: ObjectRef
          objectRef:
            kind: ClusterVirtualImage
            name: ubuntu

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

Масштабирование пула

Число реплик в пуле меняется вручную или автоматически, средствами автомасштабирования. Пул поддерживает стандартный субресурс scale и публикует status.selector, поэтому HPA читает метрики CPU и памяти прямо с реплик без дополнительной обвязки.

Помимо процессора и памяти пул работает и с кастомными метриками (Pods/External через custom.metrics.k8s.io/external.metrics.k8s.io) и с KEDA, например для масштабирования по длине внешней очереди.

Поле spec.scaleDownPolicy определяет, какая реплика удаляется при безадресном сжатии:

  • NewestFirst — первыми удаляются самые молодые реплики;
  • OldestFirst — первыми удаляются самые старые реплики;
  • Explicit — безадресное сжатие запрещено; реплики можно убирать только по имени. Используйте, когда только вызывающая сторона знает, какую реплику можно безопасно убрать (например, простаивающую).

При scaleDownPolicy: Explicit автомасштабирование может только увеличивать число реплик, а безадресное сжатие через субресурс scale отклоняется.

  • В командной строке
  • В веб-интерфейсе

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

d8 k scale virtualmachinepool/runners -n ci --replicas=8

Пример настройки HPA для пула:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: runners
  namespace: ci
spec:
  scaleTargetRef:
    apiVersion: virtualization.deckhouse.io/v1alpha2
    kind: VirtualMachinePool
    name: runners
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  1. Перейдите на вкладку «Проекты» и выберите нужный проект.
  2. Перейдите в раздел «Виртуализация» → «Пулы ВМ».
  3. Из списка выберите нужный пул и нажмите на его имя.
  4. На вкладке «Конфигурация» задайте новое значение в поле «Replicas».
  5. Нажмите кнопку «Применить».
  6. Ход масштабирования отображается в списке пулов в колонках «Статус» и «Готово».

Удаление конкретных реплик

По умолчанию при сжатии пула контроллер сам выбирает, какую реплику удалить.

Чтобы убрать именно заданные реплики (и сжать пул на это число), используйте субресурс scaleDownWith:

d8 k create --raw \
  /apis/subresources.virtualization.deckhouse.io/v1alpha2/namespaces/ci/virtualmachinepools/runners/scaledownwith \
  -f - <<'EOF'
{"targets": ["runners-1b2e84", "runners-9c0d11"]}
EOF

Обычный d8 k delete vm пул не сжимает, потому что контроллер воспринимает это как утрату реплики и создаёт замену.

Переиспользуемые диски (reclaim)

Политика reclaim задаёт, что происходит с диском реплики при её удалении из пула.

Параметр reclaim.onScaleDown элемента virtualDiskTemplates определяет это поведение. reclaim необязателен; если не задан, диск считается Delete.

  • Delete (по умолчанию) — диск принадлежит виртуальной машине и удаляется вместе с ней; после реплики ничего не остаётся.
  • Retain — диск принадлежит пулу, переживает реплику и переподключается к следующей при масштабировании вверх. Подходит для состояния, которое дорого пересоздавать и которое должно пережить пересоздание ВМ, чтобы возврат вверх был «тёплым», а не «холодным».

keep и ttl настраивают пул свободных Retain-дисков (применимы только к Retain):

  • keep — сколько недавно освободившихся дисков всегда держать тёплыми для мгновенного масштабирования вверх. На них не действует ttl.
  • ttl — сколько свободный диск живёт сверх тёплого буфера до сборки мусором.

Примеры:

# Эфемерный диск: удаляется вместе с репликой (Delete по умолчанию).
- name: root
  spec:
    persistentVolumeClaim: { size: 30Gi }
    dataSource: { type: ObjectRef, objectRef: { kind: VirtualImage, name: ubuntu } }

# Переиспользуемый диск. Три остаются наготове для быстрого роста пула, остальные освобождаются через 1h простоя.
- name: cache
  reclaim:
    onScaleDown: Retain
    keep: 3
    ttl: 1h
  spec:
    persistentVolumeClaim: { size: 100Gi }

# Переиспользуемый диск без ограничения: переиспользуется всегда, не удаляется автоматически (нет ttl).
- name: data
  reclaim:
    onScaleDown: Retain
  spec:
    persistentVolumeClaim: { size: 20Gi }

Неверные комбинации отклоняются при создании и изменении. Параметры keep и ttl допустимы только с Retain, а keep > 0 требует ttl, потому что без ttl ничего не собирается и keep ни на что не влияет. Retain-диск без ttl хранит все освободившиеся диски бессрочно; ограничивайте ttl, если это не то, что нужно.

Ограничения и особенности пула

Ниже перечислены ограничения и неочевидное поведение пула, о которых стоит помнить при эксплуатации.

  • Удаление записи из virtualDiskTemplates удаляет её диски. Для Retain-дисков это уничтожает переиспользуемые данные, поэтому убирайте шаблон только когда он больше не нужен.
  • Пул поддерживает число реплик, а не их работоспособность. Существующая, но неисправная машина не пересоздаётся, её восстанавливает перезапуск на уровне самой машины. Остановленная реплика сохраняется, а не заменяется, и пересоздаётся только полностью удалённая.
  • Диски с политикой Retain общие между репликами. При росте пула новая реплика может получить освободившийся диск другой реплики вместе с его данными, жёсткой привязки между репликой и диском нет.
  • Изменение virtualDiskTemplates[].spec влияет только на новые диски, кроме size, который увеличивает существующие (уменьшать нельзя). dataSource, storageClassName и прочее к уже созданным дискам не применяются.
  • У каждой реплики своя копия каждого диска из virtualDiskTemplates. Общий образ только для чтения, VirtualImage или ClusterVirtualImage, например единый ISO, можно подключить ко всем репликам, перечислив его в blockDeviceRefs шаблона, а записываемый диск между репликами не разделяется.
  • Правка blockDeviceRefs в шаблоне, будь то перестановка, добавление или удаление общего образа, применяется к новым репликам. Работающие реплики сохраняют текущие устройства до пересоздания, как и при других изменениях шаблона, требующих перезапуска.
  • Изменения шаблона, требующие перезапуска, применяются только после перезапуска реплики согласно .spec.disruptions.restartApprovalMode в шаблоне.

Дополнительные ресурсы