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

Как установить ОС в виртуальной машине из ISO-образа?

Рассмотрим пример установки ОС из ISO-образа ОС Windows. Для этого загрузите и опубликуйте его на каком-либо HTTP-сервисе, доступном из кластера.

  1. Создайте пустой диск для установки ОС:

    1apiVersion: virtualization.deckhouse.io/v1alpha2
    2kind: VirtualDisk
    3metadata:
    4  name: win-disk
    5  namespace: default
    6spec:
    7  persistentVolumeClaim:
    8    size: 100Gi
    9    storageClassName: local-path
    
  2. Создайте ресурсы с ISO-образами ОС Windows и драйверами virtio:

    1apiVersion: virtualization.deckhouse.io/v1alpha2
    2kind: ClusterVirtualImage
    3metadata:
    4  name: win-11-iso
    5spec:
    6  dataSource:
    7    type: HTTP
    8    http:
    9      url: "http://example.com/win11.iso"
    
    1apiVersion: virtualization.deckhouse.io/v1alpha2
    2kind: ClusterVirtualImage
    3metadata:
    4  name: win-virtio-iso
    5spec:
    6  dataSource:
    7    type: HTTP
    8    http:
    9      url: "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"
    
  3. Создайте виртуальную машину:

    1apiVersion: virtualization.deckhouse.io/v1alpha2
    2kind: VirtualMachine
    3metadata:
    4  name: win-vm
    5  namespace: default
    6  labels:
    7    vm: win
    8spec:
    9  virtualMachineClassName: generic
    10  runPolicy: Manual
    11  osType: Windows
    12  bootloader: EFI
    13  cpu:
    14    cores: 6
    15    coreFraction: 50%
    16  memory:
    17    size: 8Gi
    18  enableParavirtualization: true
    19  blockDeviceRefs:
    20    - kind: VirtualDisk
    21      name: win-disk
    22    - kind: ClusterVirtualImage
    23      name: win-11-iso
    24    - kind: ClusterVirtualImage
    25      name: win-virtio-iso
    
  4. После создания ресурса запустите ВМ:

    1d8 v start win-vm
    
  5. К ней необходимо подключиться и с помощью графического установщика выполнить установку ОС и драйверов virtio.

    Команда для подключения:

    1d8 v vnc -n default win-vm
    
  6. После окончания установки перезагрузите виртуальную машину.

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

    1d8 v vnc -n default win-vm
    

Как предоставить файл ответов Windows(Sysprep)?

Чтобы выполнить автоматическую установку Windows, создайте файл ответов (обычно именуются unattend.xml или autounattend.xml). Для примера возьмем файл, позволяющий:

  • Добавить русский язык и раскладку;
  • Указать расположение virtio драйверов необходимых для установки (поэтому важен порядок дисковых устройств в спецификации ВМ);
  • Разметить диски для установки windows на ВМ c EFI;
  • Создать в группе администраторов пользователя cloud с паролем cloud;
  • Создать непривилегированного пользователя user с паролем user.
autounattend.xml
1<?xml version="1.0" encoding="utf-8"?>
2<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
3  <settings pass="offlineServicing"></settings>
4  <settings pass="windowsPE">
5    <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
6      <SetupUILanguage>
7        <UILanguage>ru-RU</UILanguage>
8      </SetupUILanguage>
9      <InputLocale>0409:00000409;0419:00000419</InputLocale>
10      <SystemLocale>en-US</SystemLocale>
11      <UILanguage>ru-RU</UILanguage>
12      <UserLocale>en-US</UserLocale>
13    </component>
14    <component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
15      <DriverPaths>
16        <PathAndCredentials wcm:keyValue="4b29ba63" wcm:action="add">
17          <Path>E:\amd64\w11</Path>
18        </PathAndCredentials>
19        <PathAndCredentials wcm:keyValue="25fe51ea" wcm:action="add">
20          <Path>E:\NetKVM\w11\amd64</Path>
21        </PathAndCredentials>
22      </DriverPaths>
23    </component>
24    <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
25      <DiskConfiguration>
26        <Disk wcm:action="add">
27          <DiskID>0</DiskID>
28          <WillWipeDisk>true</WillWipeDisk>
29          <CreatePartitions>
30            <!-- Recovery partition -->
31            <CreatePartition wcm:action="add">
32              <Order>1</Order>
33              <Type>Primary</Type>
34              <Size>250</Size>
35            </CreatePartition>
36            <!-- EFI system partition (ESP) -->
37            <CreatePartition wcm:action="add">
38              <Order>2</Order>
39              <Type>EFI</Type>
40              <Size>100</Size>
41            </CreatePartition>
42            <!-- Microsoft reserved partition (MSR) -->
43            <CreatePartition wcm:action="add">
44              <Order>3</Order>
45              <Type>MSR</Type>
46              <Size>128</Size>
47            </CreatePartition>
48            <!-- Windows partition -->
49            <CreatePartition wcm:action="add">
50              <Order>4</Order>
51              <Type>Primary</Type>
52              <Extend>true</Extend>
53            </CreatePartition>
54          </CreatePartitions>
55          <ModifyPartitions>
56            <!-- Recovery partition -->
57            <ModifyPartition wcm:action="add">
58              <Order>1</Order>
59              <PartitionID>1</PartitionID>
60              <Label>Recovery</Label>
61              <Format>NTFS</Format>
62              <TypeID>de94bba4-06d1-4d40-a16a-bfd50179d6ac</TypeID>
63            </ModifyPartition>
64            <!-- EFI system partition (ESP) -->
65            <ModifyPartition wcm:action="add">
66              <Order>2</Order>
67              <PartitionID>2</PartitionID>
68              <Label>System</Label>
69              <Format>FAT32</Format>
70            </ModifyPartition>
71            <!-- MSR partition does not need to be modified -->
72            <!-- Windows partition -->
73            <ModifyPartition wcm:action="add">
74              <Order>3</Order>
75              <PartitionID>4</PartitionID>
76              <Label>Windows</Label>
77              <Letter>C</Letter>
78              <Format>NTFS</Format>
79            </ModifyPartition>
80          </ModifyPartitions>
81        </Disk>
82        <WillShowUI>OnError</WillShowUI>
83      </DiskConfiguration>
84      <ImageInstall>
85        <OSImage>
86          <InstallTo>
87            <DiskID>0</DiskID>
88            <PartitionID>4</PartitionID>
89          </InstallTo>
90        </OSImage>
91      </ImageInstall>
92      <UserData>
93        <ProductKey>
94          <Key>VK7JG-NPHTM-C97JM-9MPGT-3V66T</Key>
95          <WillShowUI>OnError</WillShowUI>
96        </ProductKey>
97        <AcceptEula>true</AcceptEula>
98      </UserData>
99      <UseConfigurationSet>false</UseConfigurationSet>
100    </component>
101  </settings>
102  <settings pass="generalize"></settings>
103  <settings pass="specialize">
104    <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
105      <RunSynchronous>
106        <RunSynchronousCommand wcm:action="add">
107          <Order>1</Order>
108          <Path>powershell.exe -NoProfile -Command "$xml = [xml]::new(); $xml.Load('C:\Windows\Panther\unattend.xml'); $sb = [scriptblock]::Create( $xml.unattend.Extensions.ExtractScript ); Invoke-Command -ScriptBlock $sb -ArgumentList $xml;"</Path>
109        </RunSynchronousCommand>
110        <RunSynchronousCommand wcm:action="add">
111          <Order>2</Order>
112          <Path>powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\Windows\Setup\Scripts\Specialize.ps1' -Raw | Invoke-Expression;"</Path>
113        </RunSynchronousCommand>
114        <RunSynchronousCommand wcm:action="add">
115          <Order>3</Order>
116          <Path>reg.exe load "HKU\DefaultUser" "C:\Users\Default\NTUSER.DAT"</Path>
117        </RunSynchronousCommand>
118        <RunSynchronousCommand wcm:action="add">
119          <Order>4</Order>
120          <Path>powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\Windows\Setup\Scripts\DefaultUser.ps1' -Raw | Invoke-Expression;"</Path>
121        </RunSynchronousCommand>
122        <RunSynchronousCommand wcm:action="add">
123          <Order>5</Order>
124          <Path>reg.exe unload "HKU\DefaultUser"</Path>
125        </RunSynchronousCommand>
126      </RunSynchronous>
127    </component>
128  </settings>
129  <settings pass="auditSystem"></settings>
130  <settings pass="auditUser"></settings>
131  <settings pass="oobeSystem">
132    <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
133      <InputLocale>0409:00000409;0419:00000419</InputLocale>
134      <SystemLocale>en-US</SystemLocale>
135      <UILanguage>ru-RU</UILanguage>
136      <UserLocale>en-US</UserLocale>
137    </component>
138    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
139      <UserAccounts>
140        <LocalAccounts>
141          <LocalAccount wcm:action="add">
142            <Name>cloud</Name>
143            <DisplayName>cloud</DisplayName>
144            <Group>Administrators</Group>
145            <Password>
146              <Value>cloud</Value>
147              <PlainText>true</PlainText>
148            </Password>
149          </LocalAccount>
150          <LocalAccount wcm:action="add">
151            <Name>User</Name>
152            <DisplayName>user</DisplayName>
153            <Group>Users</Group>
154            <Password>
155              <Value>user</Value>
156              <PlainText>true</PlainText>
157            </Password>
158          </LocalAccount>
159        </LocalAccounts>
160      </UserAccounts>
161      <AutoLogon>
162        <Username>cloud</Username>
163        <Enabled>true</Enabled>
164        <LogonCount>1</LogonCount>
165        <Password>
166          <Value>cloud</Value>
167          <PlainText>true</PlainText>
168        </Password>
169      </AutoLogon>
170      <OOBE>
171        <ProtectYourPC>3</ProtectYourPC>
172        <HideEULAPage>true</HideEULAPage>
173        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
174        <HideOnlineAccountScreens>false</HideOnlineAccountScreens>
175      </OOBE>
176      <FirstLogonCommands>
177        <SynchronousCommand wcm:action="add">
178          <Order>1</Order>
179          <CommandLine>powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\Windows\Setup\Scripts\FirstLogon.ps1' -Raw | Invoke-Expression;"</CommandLine>
180        </SynchronousCommand>
181      </FirstLogonCommands>
182    </component>
183  </settings>
184</unattend>

Создайте секрет из этого xml файла:

1d8 k create secret generic sysprep-config --type="provisioning.virtualization.deckhouse.io/sysprep" --from-file=./autounattend.xml

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

Чтобы предоставить виртуальной машине Windows файл ответов, необходимо указать provisioning с типом SysprepRef. Вы также можете указать здесь другие файлы в формате base64, необходимые для успешного выполнения скриптов внутри файла ответов.

1apiVersion: virtualization.deckhouse.io/v1alpha2
2kind: VirtualMachine
3metadata:
4  name: win-vm
5  namespace: default
6  labels:
7    vm: win
8spec:
9  virtualMachineClassName: generic
10  provisioning:
11    type: SysprepRef
12    sysprepRef:
13      kind: Secret
14      name: sysprep-config
15  runPolicy: AlwaysOn
16  osType: Windows
17  bootloader: EFI
18  cpu:
19    cores: 6
20    coreFraction: 50%
21  memory:
22    size: 8Gi
23  enableParavirtualization: true
24  blockDeviceRefs:
25    - kind: VirtualDisk
26      name: win-disk
27    - kind: ClusterVirtualImage
28      name: win-11-iso
29    - kind: ClusterVirtualImage
30      name: win-virtio-iso

Как использовать Ansible для конфигурирования виртуальных машин?

Ansible — это инструмент автоматизации, который позволяет выполнять задачи на удаленных серверах с использованием протокола SSH. В данном примере мы рассмотрим, как использовать Ansible для управления виртуальными машинами расположенных в проекте demo-app.

В рамках примера предполагается, что:

  • У вас есть виртуальная машина с именем frontend в проекте demo-app.
  • На виртуальной машине создан пользователь cloud для доступа по SSH.
  • Приватный SSH-ключ пользователя хранится в файле ./tmp/demo на сервере Ansible.

Пример inventory-файла:

1---
2all:
3  vars:
4    ansible_ssh_common_args: '-o ProxyCommand="d8 v port-forward --stdio=true %h %p"'
5    # Пользователь по умолчанию, для доступа по SSH.
6    ansible_user: cloud
7    # Путь к приватному ключу.
8    ansible_ssh_private_key_file: ./tmp/demo
9  hosts:
10    # Название узла в формате <название ВМ>.<название проекта>.
11    frontend.demo-app:

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

1ansible -m shell -a "uptime" -i inventory.yaml all
2
3# frontend.demo-app | CHANGED | rc=0 >>
4# 12:01:20 up 2 days,  4:59,  0 users,  load average: 0.00, 0.00, 0.00

Если вы не хотите использовать файл inventory, можно передать все параметры прямо в командной строке:

1ansible -m shell -a "uptime" \
2  -i "frontend.demo-app," \
3  -e "ansible_ssh_common_args='-o ProxyCommand=\"d8 v port-forward --stdio=true %h %p\"'" \
4  -e "ansible_user=cloud" \
5  -e "ansible_ssh_private_key_file=./tmp/demo" \
6  all

Как перенаправить трафик на виртуальную машину?

Виртуальная машина функционирует в кластере Kubernetes, поэтому направление сетевого трафика осуществляется аналогично направлению трафика на поды.

  1. Создайте сервис с требуемыми настройками.

    В качестве примера приведена виртуальная машина с HTTP-сервисом, опубликованным на порте 80, и следующим набором меток:

    1apiVersion: virtualization.deckhouse.io/v1alpha2
    2kind: VirtualMachine
    3metadata:
    4  name: web
    5  labels:
    6    vm: web
    7spec: ...
    
  2. Чтобы направить сетевой трафик на 80-й порт виртуальной машины, создайте сервис:

    1apiVersion: v1
    2kind: Service
    3metadata:
    4  name: svc-1
    5spec:
    6  ports:
    7    - name: http
    8      port: 8080
    9      protocol: TCP
    10      targetPort: 80
    11  selector:
    12    app: old
    

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

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

    1apiVersion: v1
    2kind: Service
    3metadata:
    4  name: svc-2
    5spec:
    6  ports:
    7    - name: http
    8      port: 8080
    9      protocol: TCP
    10      targetPort: 80
    11  selector:
    12    app: new
    

    При изменении метки на виртуальной машине, трафик с сервиса svc-2 будет перенаправлен на виртуальную машину:

    1metadata:
    2  labels:
    3    app: old
    

Как увеличить размер DVCR?

Чтобы увеличить размер диска для DVCR, необходимо установить больший размер в конфигурации модуля virtualization, чем текущий размер.

  1. Проверьте текущий размер DVCR:

    1d8 k get mc virtualization -o jsonpath='{.spec.settings.dvcr.storage.persistentVolumeClaim}'
    

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

    1 {"size":"58G","storageClass":"linstor-thick-data-r1"}
    
  2. Задайте размер:

    1d8 k patch mc virtualization \
    2  --type merge -p '{"spec": {"settings": {"dvcr": {"storage": {"persistentVolumeClaim": {"size":"59G"}}}}}}'
    

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

    1 moduleconfig.deckhouse.io/virtualization patched
    
  3. Проверьте изменение размера:

    1d8 k get mc virtualization -o jsonpath='{.spec.settings.dvcr.storage.persistentVolumeClaim}'
    

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

    1{"size":"59G","storageClass":"linstor-thick-data-r1"}
    
  4. Проверьте текущее состояние DVCR:

    1d8 k get pvc dvcr -n d8-virtualization
    

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

    1NAME STATUS VOLUME                                    CAPACITY    ACCESS MODES   STORAGECLASS           AGE
    2dvcr Bound  pvc-6a6cedb8-1292-4440-b789-5cc9d15bbc6b  57617188Ki  RWO            linstor-thick-data-r1  7d