Projekt

Allgemein

Profil

Setup kvm » Historie » Version 5

Jeremias Keihsler, 29.09.2024 15:03

1 1 Jeremias Keihsler
h1. KVM
2
3
this is for a vanilla CentOS 9 minimal installation,
4
largely based on @kvm_virtualization_in_rhel_7_made_easy.pdf@
5
6 4 Jeremias Keihsler
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_virtualization/assembly_enabling-virtualization-in-rhel-9_configuring-and-managing-virtualization#proc_enabling-virtualization-in-rhel-9_assembly_enabling-virtualization-in-rhel-9
7
8 1 Jeremias Keihsler
https://www.linuxtechi.com/install-kvm-on-rocky-linux-almalinux/
9
10
good information is also found at http://virtuallyhyper.com/2013/06/migrate-from-libvirt-kvm-to-virtualbox/
11
12
br0 -sources:
13
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/networking_guide/sec-configuring_ip_networking_with_nmcli
14
https://www.tecmint.com/create-network-bridge-in-rhel-centos-8/
15
https://www.cyberciti.biz/faq/how-to-add-network-bridge-with-nmcli-networkmanager-on-linux/
16
https://extravm.com/billing/knowledgebase/114/CentOS-8-ifup-unknown-connection---Add-Second-IP.html
17
18
19
h2. basic updates/installs
20
21
<pre><code class="bash">
22
yum update
23
yum install wget
24
yum install vim
25
reboot
26
</code></pre>
27
28
h2. check machine capability
29
30
<pre><code class="bash">
31
grep -E 'svm|vmx' /proc/cpuinfo
32
</code></pre>
33
34
vmx ... Intel
35
svm ... AMD
36
37
h2. install KVM on CentOS minimal
38
39
<pre><code class="bash">
40 2 Jeremias Keihsler
dnf install qemu-kvm libvirt libguestfs-tools virt-install virt-viewer
41 3 Jeremias Keihsler
for drv in qemu network nodedev nwfilter secret storage interface; do systemctl start virt${drv}d{,-ro,-admin}.socket; done
42 1 Jeremias Keihsler
</code></pre>
43
44
verify the following kernel modules are loaded
45
<pre><code class="bash">
46
lsmod | grep kvm
47
</code></pre>
48
49
<pre><code class="bash">
50
kvm
51
kvm_intel
52
</code></pre>
53
<pre><code class="bash">
54
kvm
55
kvm_amd
56
</code></pre>
57 2 Jeremias Keihsler
58
h3. Verification
59
60
<pre><code class="bash">
61
virt-host-validate
62
</code></pre>
63 1 Jeremias Keihsler
64 5 Jeremias Keihsler
h3. change from libvirtd to modular libvirt daemons
65
66
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_virtualization/optimizing-virtual-machine-performance-in-rhel_configuring-and-managing-virtualization#proc_enabling-modular-libvirt-daemons_assembly_optimizing-libvirt-daemons
67
68
69
70 1 Jeremias Keihsler
h2. setup networking
71
72
add to the network controller configuration file @/etc/sysconfig/network-scripts/ifcfg-em1@
73
<pre>
74
...
75
BRIDGE=br0
76
</pre>
77
78
add following new file @/etc/sysconfig/network-scripts/ifcfg-br0@
79
<pre>
80
DEVICE="br0"
81
# BOOTPROTO is up to you. If you prefer “static”, you will need to
82
# specify the IP address, netmask, gateway and DNS information.
83
BOOTPROTO="dhcp"
84
IPV6INIT="yes"
85
IPV6_AUTOCONF="yes"
86
ONBOOT="yes"
87
TYPE="Bridge"
88
DELAY="0"
89
</pre>
90
91
enable network forwarding @/etc/sysctl.conf@
92
<pre>
93
...
94
net.ipv4.ip_forward = 1
95
</pre>
96
97
read the file and restart NetworkManager
98
<pre><code class="bash">
99
sysctl -p /etc/sysctl.conf
100
systemctl restart NetworkManager
101
</code></pre>
102
103
h2. can KVM and Virtualbox coexist
104
105
http://www.dedoimedo.com/computers/kvm-virtualbox.html
106
107
h2. convert Virtualbox to KVM
108
109
h3. uninstall Virtualbox-guest-additions
110
111
<pre><code class="bash">
112
opt/[VboxAddonsFolder]/uninstall.sh
113
</code></pre>
114
115
some people had to remove @/etc/X11/xorg.conf@
116
117
h3. convert image from Virtualbox to KWM
118
119
<pre><code class="bash">
120
VBoxManage clonehd --format RAW Virt_Image.vdi Virt_Image.img
121
</code></pre>
122
123
RAW-Datei nach qcow konvertieren
124
<pre><code class="bash">
125
qemu-img convert -f raw Virt_Image.img -O qcow2 Virt_Image.qcow
126
</code></pre>
127
128
h2. automatic start/shutdown of VMs with Host
129
130
taken from https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Virtualization_Administration_Guide/sub-sect-Shutting_down_rebooting_and_force_shutdown_of_a_guest_virtual_machine-Manipulating_the_libvirt_guests_configuration_settings.html
131
132
h3. enable libvirt-guests service
133
134
<pre><code class="bash">
135
systemctl enable libvirt-guests
136
systemctl start libvirt-guests
137
</code></pre>
138
139
all settings are to be done in @/etc/sysconfig/libvirt-guests@
140
141
h2. install
142
143
144
<pre><code class="bash">
145
yum install virt-manager
146
</code></pre>
147
148
<pre><code class="bash">
149
usermod -a -G libvirt username
150
</code></pre>
151
152
h2. rename KVM-guest
153
154
taken from http://www.taitclarridge.com/techlog/2011/01/rename-kvm-virtual-machine-with-virsh.html
155
156
Power off the virtual machine and export the machine's XML configuration file:
157
158
<pre><code class="bash">
159
virsh dumpxml name_of_vm > name_of_vm.xml
160
</code></pre>
161
162
Next, edit the XML file and change the name between the <name></name> tags (should be right near the top). As an added step you could also rename the disk file to reflect the change of the name and change the name of it in the <devices> section under <source file='/path/to/name_of_vm.img'>.
163
164
Save the XML file and undefine the old VM name with:
165
166
<pre><code class="bash">
167
virsh undefine name_of_vm
168
</code></pre>
169
170
Now just import the edited XML file to define the VM:
171
172
<pre><code class="bash">
173
virsh define name_of_vm.xml
174
</code></pre>
175
176
And that should be it! You can now start up your vm either in the Virtual Machine Manager or with virsh using:
177
178
<pre><code class="bash">
179
virsh start name_of_vm
180
</code></pre>
181
182
h2. set fixed IP-adr via DHCP (default-network)
183
184
taken from https://wiki.libvirt.org/page/Networking
185
186
<pre><code class="bash">
187
virsh edit <guest>
188
</code></pre>
189
190
where <guest> is the name or uuid of the guest. Add the following snippet of XML to the config file: 
191
192
<pre><code class="bash">
193
<interface type='network'>
194
  <source network='default'/>
195
  <mac address='00:16:3e:1a:b3:4a'/>
196
</interface>
197
</code></pre>
198
199
Applying modifications to the network
200
201
Sometimes, one needs to edit the network definition and apply the changes on the fly. The most common scenario for this is adding new static MAC+IP mappings for the network's DHCP server. If you edit the network with "virsh net-edit", any changes you make won't take effect until the network is destroyed and re-started, which unfortunately will cause a all guests to lose network connectivity with the host until their network interfaces are explicitly re-attached.
202
virsh net-update
203
204
Fortunately, many changes to the network configuration (including the aforementioned addition of a static MAC+IP mapping for DHCP) can be done with "virsh net-update", which can be told to enact the changes immediately. For example, to add a DHCP static host entry to the network named "default" mapping MAC address 53:54:00:00:01 to IP address 192.168.122.45 and hostname "bob", you could use this command: 
205
206
<pre><code class="bash">
207
virsh net-update default add ip-dhcp-host \
208
          "<host mac='52:54:00:00:00:01' \
209
           name='bob' ip='192.168.122.45' />" \
210
           --live --config
211
</code></pre>
212
213
h2. forwarding incoming connections
214
215
taken from https://wiki.libvirt.org/page/Networking
216
217
By default, guests that are connected via a virtual network with <forward mode='nat'/> can make any outgoing network connection they like. Incoming connections are allowed from the host, and from other guests connected to the same libvirt network, but all other incoming connections are blocked by iptables rules.
218
219
If you would like to make a service that is on a guest behind a NATed virtual network publicly available, you can setup libvirt's "hook" script for qemu to install the necessary iptables rules to forward incoming connections to the host on any given port HP to port GP on the guest GNAME:
220
221
1) Determine a) the name of the guest "G" (as defined in the libvirt domain XML), b) the IP address of the guest "I", c) the port on the guest that will receive the connections "GP", and d) the port on the host that will be forwarded to the guest "HP".
222
223
(To assure that the guest's IP address remains unchanged, you can either configure the guest OS with static ip information, or add a <host> element inside the <dhcp> element of the network that is used by your guest. See the libvirt network XML documentation address section for defails and an example.)
224
225
2) Stop the guest if it's running.
226
227
3) Create the file /etc/libvirt/hooks/qemu (or add the following to an already existing hook script), with contents similar to the following (replace GNAME, IP, GP, and HP appropriately for your setup):
228
229
Use the basic script below or see an "advanced" version, which can handle several different machines and port mappings here (improvements are welcome) or here's a python script which does a similar thing and is easy to understand and configure (improvements are welcome): 
230
231
<pre>
232
#!/bin/bash
233
# used some from advanced script to have multiple ports: use an equal number of guest and host ports
234
235
# Update the following variables to fit your setup
236
Guest_name=GUEST_NAME
237
Guest_ipaddr=GUEST_IP
238
Host_ipaddr=HOST_IP
239
Host_port=(  'HOST_PORT1' 'HOST_PORT2' )
240
Guest_port=( 'GUEST_PORT1' 'GUEST_PORT2' )
241
242
length=$(( ${#Host_port[@]} - 1 ))
243
if [ "${1}" = "${Guest_name}" ]; then
244
   if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
245
       for i in `seq 0 $length`; do
246
               iptables -t nat -D PREROUTING -d ${Host_ipaddr} -p tcp --dport ${Host_port[$i]} -j DNAT --to ${Guest_ipaddr}:${Guest_port[$i]}
247
               iptables -D FORWARD -d ${Guest_ipaddr}/32 -p tcp -m state --state NEW -m tcp --dport ${Guest_port[$i]} -j ACCEPT
248
       done
249
   fi
250
   if [ "${2}" = "start" ] || [ "${2}" = "reconnect" ]; then
251
       for i in `seq 0 $length`; do
252
               iptables -t nat -A PREROUTING -d ${Host_ipaddr} -p tcp --dport ${Host_port[$i]} -j DNAT --to ${Guest_ipaddr}:${Guest_port[$i]}
253
               iptables -I FORWARD -d ${Guest_ipaddr}/32 -p tcp -m state --state NEW -m tcp --dport ${Guest_port[$i]} -j ACCEPT
254
       done
255
   fi
256
fi
257
</pre>
258
4) chmod +x /etc/libvirt/hooks/qemu
259
260
5) Restart the libvirtd service.
261
262
6) Start the guest.
263
264
(NB: This method is a hack, and has one annoying flaw in versions of libvirt prior to 0.9.13 - if libvirtd is restarted while the guest is running, all of the standard iptables rules to support virtual networks that were added by libvirtd will be reloaded, thus changing the order of the above FORWARD rule relative to a reject rule for the network, hence rendering this setup non-working until the guest is stopped and restarted. Thanks to the new "reconnect" hook in libvirt-0.9.13 and newer (which is used by the above script if available), this flaw is not present in newer versions of libvirt (however, this hook script should still be considered a hack). 
265
266
h2. wrapper script for virsh
267
268
<pre>
269
#! /bin/sh
270
# kvm_control   Startup script for KVM Virtual Machines
271
#
272
# description: Manages KVM VMs
273
# processname: kvm_control.sh
274
#
275
# pidfile: /var/run/kvm_control/kvm_control.pid
276
#
277
### BEGIN INIT INFO
278
#
279
### END INIT INFO
280
#
281
# Version 20171103 by Jeremias Keihsler added ionice prio 'idle'
282
# Version 20161228 by Jeremias Keihsler based on:
283
# virsh-specific parts are taken from:
284
#  https://github.com/kumina/shutdown-kvm-guests/blob/master/shutdown-kvm-guests.sh
285
# Version 20110509 by Jeremias Keihsler (vboxcontrol) based on:
286
# Version 20090301 by Kevin Swanson <kswan.info> based on:
287
# Version 2008051100 by Jochem Kossen <jochem.kossen@gmail.com>
288
# http://farfewertoes.com
289
#
290
# Released in the public domain
291
#
292
# This file came with a README file containing the instructions on how
293
# to use this script.
294
# 
295
# this is no more to be used as an init.d-script (vboxcontrol was an init.d-script)
296
#
297
298
################################################################################
299
# INITIAL CONFIGURATION
300
301
export PATH="${PATH:+$PATH:}/bin:/usr/bin:/usr/sbin:/sbin"
302
303
VIRSH=/usr/bin/virsh
304
TIMEOUT=300
305
306
declare -i VM_isrunning
307
308
################################################################################
309
# FUNCTIONS
310
311
log_failure_msg() {
312
echo $1
313
}
314
315
log_action_msg() {
316
echo $1
317
}
318
319
# list running domains
320
list_running_domains() {
321
  $VIRSH list | grep running | awk '{ print $2}'
322
}
323
324
# Check for running machines every few seconds; return when all machines are
325
# down
326
wait_for_closing_machines() {
327
RUNNING_MACHINES=`list_running_domains | wc -l`
328
if [ $RUNNING_MACHINES != 0 ]; then
329
  log_action_msg "machines running: "$RUNNING_MACHINES
330
  sleep 2
331
332
  wait_for_closing_machines
333
fi
334
}
335
336
################################################################################
337
# RUN
338
case "$1" in
339
  start)
340
    if [ -f /etc/kvm_box/machines_enabled_start ]; then
341
342
      cat /etc/kvm_box/machines_enabled_start | while read VM; do
343
        log_action_msg "Starting VM: $VM ..."
344
        $VIRSH start $VM
345
        sleep 20
346
        RETVAL=$?
347
      done
348
      touch /tmp/kvm_control
349
    fi
350
  ;;
351
  stop)
352
    # NOTE: this stops first the listed VMs in the given order
353
    # and later all running VM's. 
354
    # After the defined timeout all remaining VMs are killed
355
356
    # Create some sort of semaphore.
357
    touch /tmp/shutdown-kvm-guests
358
359
    echo "Try to cleanly shut down all listed KVM domains..."
360
    # Try to shutdown each listed domain, one by one.
361
    if [ -f /etc/kvm_box/machines_enabled_stop ]; then
362
      cat /etc/kvm_box/machines_enabled_stop | while read VM; do
363
        log_action_msg "Shutting down VM: $VM ..."
364
        $VIRSH shutdown $VM --mode acpi
365
        sleep 10
366
        RETVAL=$?
367
      done
368
    fi
369
    sleep 10
370
371
    echo "give still running machines some more time..."
372
    # wait 20s per still running machine
373
    list_running_domains | while read VM; do
374
      log_action_msg "waiting 20s ... for: $VM ..."
375
      sleep 20
376
    done
377
378
    echo "Try to cleanly shut down all running KVM domains..."
379
    # Try to shutdown each remaining domain, one by one.
380
    list_running_domains | while read VM; do
381
      log_action_msg "Shutting down VM: $VM ..."
382
      $VIRSH shutdown $VM --mode acpi
383
      sleep 10
384
    done
385
386
    # Wait until all domains are shut down or timeout has reached.
387
    END_TIME=$(date -d "$TIMEOUT seconds" +%s)
388
389
    while [ $(date +%s) -lt $END_TIME ]; do
390
      # Break while loop when no domains are left.
391
      test -z "$(list_running_domains)" && break
392
      # Wait a litte, we don't want to DoS libvirt.
393
      sleep 2
394
    done
395
396
    # Clean up left over domains, one by one.
397
    list_running_domains | while read DOMAIN; do
398
      # Try to shutdown given domain.
399
      $VIRSH destroy $DOMAIN
400
      # Give libvirt some time for killing off the domain.
401
      sleep 10
402
    done
403
404
    wait_for_closing_machines
405
    rm -f /tmp/shutdown-kvm-guests
406
    rm -f /tmp/kvm_control
407
  ;;
408
  export)
409
    JKE_DATE=$(date +%F)
410
    if [ -f /etc/kvm_box/machines_enabled_export ]; then
411
      cat /etc/kvm_box/machines_enabled_export  | while read VM; do
412
        rm -f /tmp/kvm_control_VM_isrunning
413
        VM_isrunning=0
414
        list_running_domains | while read RVM; do
415
          #echo "VM list -$VM- : -$RVM-"
416
          if [[ "$VM" ==  "$RVM" ]]; then
417
            #echo "VM found running..."
418
            touch /tmp/kvm_control_VM_isrunning
419
            VM_isrunning=1
420
            #echo "$VM_isrunning"
421
            break
422
          fi
423
          #echo "$VM_isrunning"
424
        done
425
426
        # took me a while to figure out that the above 'while'-loop 
427
        # runs in a separate process ... let's use the 'file' as a 
428
        # kind of interprocess-communication :-) JKE 20161229
429
        if [ -f /tmp/kvm_control_VM_isrunning ]; then
430
          VM_isrunning=1
431
        fi
432
        rm -f /tmp/kvm_control_VM_isrunning
433
434
        #echo "VM status $VM_isrunning"
435
        if [ "$VM_isrunning" -ne 0 ]; then
436
          log_failure_msg "Exporting VM: $VM is not possible, it's running ..."
437
        else
438
          log_action_msg "Exporting VM: $VM ..."
439
          VM_BAK_DIR="$VM"_"$JKE_DATE"
440
          mkdir "$VM_BAK_DIR"
441
          $VIRSH dumpxml $VM > ./$VM_BAK_DIR/$VM.xml
442
          $VIRSH -q domblklist $VM | awk '{ print$2}' | while read VMHDD; do
443
            echo "$VM hdd=$VMHDD"
444
            if [ -f "$VMHDD" ]; then
445
              ionice -c 3 rsync --progress $VMHDD ./$VM_BAK_DIR/`basename $VMHDD`
446
            else
447
              log_failure_msg "Exporting VM: $VM image-file $VMHDD not found ..."
448
            fi
449
          done
450
        fi
451
      done
452
    else
453
      log_action_msg "export-list not found"
454
    fi
455
  ;;
456
  start-vm)
457
    log_action_msg "Starting VM: $2 ..."
458
    $VIRSH start $2
459
    RETVAL=$?
460
  ;;
461
  stop-vm)
462
    log_action_msg "Stopping VM: $2 ..."
463
    $VIRSH shutdown $2 --mode acpi
464
    RETVAL=$?
465
  ;;
466
  poweroff-vm)
467
    log_action_msg "Powering off VM: $2 ..."
468
    $VIRSH destroy $2
469
    RETVAL=$?
470
  ;;
471
  export-vm)
472
    # NOTE: this exports the given VM
473
    log_action_msg "Exporting VM: $2 ..."
474
    rm -f /tmp/kvm_control_VM_isrunning
475
    VM_isrunning=0
476
    JKE_DATE=$(date +%F)
477
    list_running_domains | while read RVM; do
478
      #echo "VM list -$VM- : -$RVM-"
479
      if [[ "$2" ==  "$RVM" ]]; then
480
        #echo "VM found running..."
481
        touch /tmp/kvm_control_VM_isrunning
482
        VM_isrunning=1
483
        #echo "$VM_isrunning"
484
        break
485
      fi
486
      #echo "$VM_isrunning"
487
    done
488
489
    # took me a while to figure out that the above 'while'-loop 
490
    # runs in a separate process ... let's use the 'file' as a 
491
    # kind of interprocess-communication :-) JKE 20161229
492
    if [ -f /tmp/kvm_control_VM_isrunning ]; then
493
      VM_isrunning=1
494
    fi
495
    rm -f /tmp/kvm_control_VM_isrunning
496
497
    #echo "VM status $VM_isrunning"
498
    if [ "$VM_isrunning" -ne 0 ]; then
499
      log_failure_msg "Exporting VM: $VM is not possible, it's running ..."
500
    else
501
      log_action_msg "Exporting VM: $VM ..."
502
      VM_BAK_DIR="$2"_"$JKE_DATE"
503
      mkdir "$VM_BAK_DIR"
504
      $VIRSH dumpxml $2 > ./$VM_BAK_DIR/$2.xml
505
      $VIRSH -q domblklist $2 | awk '{ print$2}' | while read VMHDD; do
506
        echo "$2 hdd=$VMHDD"
507
        if [ -f "$VMHDD" ]; then
508
          ionice -c 3 rsync --progress $VMHDD ./$VM_BAK_DIR/`basename $VMHDD`
509
        else
510
          log_failure_msg "Exporting VM: $2 image-file $VMHDD not found ..."
511
        fi
512
      done
513
    fi
514
  ;;
515
  status)
516
    echo "The following virtual machines are currently running:"
517
    list_running_domains | while read VM; do
518
      echo -n "  $VM"
519
      echo " ... is running"
520
    done
521
  ;;
522
523
  *)
524
    echo "Usage: $0 {start|stop|status|export|start-vm <VM name>|stop-vm <VM name>|poweroff-vm <VM name>}|export-vm <VMname>"
525
    echo "  start      start all VMs listed in '/etc/kvm_box/machines_enabled_start'"
526
    echo "  stop       1st step: acpi-shutdown all VMs listed in '/etc/kvm_box/machines_enabled_stop'"
527
    echo "             2nd step: wait 20s for each still running machine to give a chance to shut-down on their own"
528
    echo "             3rd step: acpi-shutdown all running VMs"
529
    echo "             4th step: wait for all machines shutdown or $TIMEOUT s"
530
    echo "             5th step: destroy all sitting VMs"
531
    echo "  status     list all running VMs"
532
    echo "  export     export all VMs listed in '/etc/kvm_box/machines_enabled_export' to the current directory"
533
    echo "  start-vm <VM name>     start the given VM"
534
    echo "  stop-vm <VM name>      acpi-shutdown the given VM"
535
    echo "  poweroff-vm <VM name>  poweroff the given VM"
536
    echo "  export-vm <VM name>    export the given VM to the current directory"
537
    exit 3
538
esac
539
540
exit 0
541
542
</pre>
543
544
h2. restore 'exported' kvm-machines
545
546
<pre><code class="shell">
547
tar xvf mach-name_202x-01-01.tar.gz 
548
</code></pre>
549
550
* copy the image-files to @/var/lib/libvirt/images/@
551
552
set ownership
553
<pre><code class="shell">
554
chown qemu:qemu /var/lib/libvirt/images/*
555
</code></pre>
556
557
558
define the machine by
559
560
<pre><code class="shell">
561
virsh define mach-name.xml
562
</code></pre>