更多自制 Qemu KVM 配方!——给每个虚拟机分配独立的 IP 地址! 更多自制 Qemu KVM 配方!——给每个虚拟机分配独立的 IP 地址!

更多自制 Qemu KVM 配方!——给每个虚拟机分配独立的 IP 地址!

KVM标志 之前我们使用 Qemu 的默认 Slirp 网络创建了 KVM 虚拟主机。这次我们将配置 Qemu 的网络,以便每个虚拟机都能拥有自己的 IP 地址。使用 Slirp 时,我们无需手动配置网络,因为 Slirp 会自动使用宿主机的 IP 地址进行连接。

这里我们假设我们的机器拥有一个路由子网和一个网桥。我们可以从这个子网中为每个创建的虚拟机分配和配置 IP 地址。如果我们还没有额外的 IP 地址,我们需要获取它们,通常是从我们的服务提供商那里获取。如果我们还没有配置网桥,Linux-KVM.org 上有一个很棒的教程。Linux -KVM.org 的教程还涵盖了所需的 qemu-ifup 脚本。

本文介绍的方法旨在尽可能独立于 Linux 发行版软件包系统和网络配置工具。此外,本文使用基本的、原始的 QEMU,未使用任何通常用于配置 QEMU KVM 的优秀库和工具。显然,本文介绍的方法主要用于低端环境(例如 LOL)以及研究 QEMU 的工作原理,并不适用于实际生产环境。目前该方法仍在开发中。本文介绍的方法应该可以在 VPS、专用服务器或运行大多数 Linux 发行版的本地计算机上运行。

环境

摘自梅森·罗伊的 Yabs 脚本

我们需要检查是否已启用硬件虚拟化支持。以下是一个检查脚本:

root@debian:~# cat cpu-virt.sh
#!/bin/bash
# From https://github.com/masonr/yet-another-bench-script/blob/master/yabs.sh
# Lines 210-212
# Thanks to Mason and yabs developers!

CPU_VIRT=$(cat /proc/cpuinfo | grep 'vmx\|svm')
[[ -z “$CPU_VIRT” ]] && CPU_VIRT=”\xE2\x9D\x8C Disabled” || CPU_VIRT=”\xE2\x9C\x94 Enabled”
echo -e “VM-x/AMD-V : $CPU_VIRT”
root@debian:~#

Libvirt

Libvirt 包含一个 KVM 环境验证实用程序,位于libvirt/tools/virt-host-validate-qemu.c

Libvirt 超出了本文的范围,但是,如果您想了解 virt-host-validate 的一个很棒的用法,请查看 Dmitrii Shcherbakov 关于在 LXC 中运行 KVM 的教程。

安装或编译 Qemu

如果尚未安装 Qemu,请使用发行版的软件包管理系统进行安装。或者,您可以按照Qemu.org 下载页面上的说明编译 Qemu。Qemu.org 的编译说明在之前一篇关于麻省理工学院免费在线操作系统课程的文章中也有提及。

为虚拟机创建目录

我们将把这个虚拟机命名为 vm206,所以我们来为它创建一个目录。

tom@darkstar:~$ mkdir vm206
tom@darkstar:~$ cd vm206/
tom@darkstar:~/vm206$

下载并验证操作系统映像

获取图像

tom@darkstar:~$ wget https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-amd64-daily.qcow2

[...]

tom@darkstar:~$

获取校验和

tom@darkstar:~/vm206$ wget https://cloud.debian.org/images/cloud/sid/daily/latest/SHA512SUMS
tom@darkstar:~/vm206$

验证图像

tom@darkstar:~/vm206$ sha512sum --ignore-missing -c SHA512SUMS
debian-sid-nocloud-amd64-daily.qcow2: OK
tom@darkstar:~/vm206$

请在启动和运行镜像之前进行验证,因为启动和运行镜像会更改镜像。

启用还原

我们复制这张图片,以便恢复到原图。

tom@darkstar:~/vm206$ cp debian-sid-nocloud-amd64-daily.qcow2 vm206.qcow2
tom@darkstar:~/vm206$

调整图片大小

原始下载图像的虚拟大小为 2 GiB:

tom@darkstar:~/vm206$ qemu-img info vm206.qcow2
image: vm206.qcow2
file format: qcow2
virtual size: 2 GiB (2147483648 bytes)
disk size: 864 MiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
tom@darkstar:~/vm206$

让我们调整一下图片大小:

tom@darkstar:~/vm206$ qemu-img resize vm206.qcow2 +48G
Image resized.
tom@darkstar:~/vm206$

现在我们的虚拟大小为 50 GiB:

tom@darkstar:~/vm206$ qemu-img resize vm206.qcow2 +48G
Image resized.
tom@darkstar:~/vm206$ qemu-img info vm206.qcow2
image: vm206.qcow2
file format: qcow2
virtual size: 50 GiB (53687091200 bytes)
disk size: 864 MiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
tom@darkstar:~/vm206$

我们发现此调整大小操作的结果并不稳定。如上所示,节点上的调整大小操作似乎成功了。然而,有时虚拟机启动时内部分区方案似乎识别到了调整后的大小,有时则不然。请注意,Darkstar 上尚未安装 virt-resize。其他方法包括:(1) 附加第二个 qcow2 文件用于用户数据;或 (2) 不使用 nocloud 镜像,而是使用更大的 qcow2 文件,从 Debian 的 netinst.iso 镜像进行安装。

启动虚拟机的脚本

我们将使用以下脚本启动 vm206:

tom@darkstar:~/vm206$ cat start-qemu-206.sh
#!/bin/bash
# Start VM on IP 206

# 在 tmux 中运行此脚本

# 添加 IP 地址 206 的路由
ip route add 66.11.114.206 dev br0

# 启动 qemu

/usr/local/bin/qemu-system-x86_64 \
-cpu host -smp sockets=1,cores=8,maxcpus=8 \
-启用kvm
-nographic \
-m 8192 \
-drive file=/home/tom/vm206/vm206.qcow2,if=virtio \
-netdev tap,id=mynet206,ifname=tap206,script=/root/qemu-ifup.sh,downscript="" \
-device virtio-net,netdev=mynet206,mac=DE:AD:00:BE:EE:06
tom@darkstar:~/vm206$

使用脚本在 Tmux 中启动虚拟机

tom@darkstar:~/vm206$ tmux
tom@darkstar:~/vm206$ sudo ./start-qemu-206.sh

[...]

[失败] 启动 OpenBSD 安全外壳服务器失败。

[...]

Debian GNU/Linux bookworm/sid localhost ttyS0

localhost 登录:root
Linux localhost 5.17.0-3-amd64 #1 SMP PREEMPT Debian 5.17.11-1 (2022-05-26) x4

Debian GNU/Linux 系统附带的程序均为自由软件;
每个项目的具体分配条款均在以下文件中描述:
/usr/share/doc/*/copyright 中的单个文件。

Debian GNU/Linux 绝对不提供任何形式的担保。
在适用法律允许的范围内。
root@localhost:~#

虚拟机启动时,sshd 服务器出现故障,并且没有网络连接。

root@localhost:~# ping -c 2 www.google.com
ping: www.google.com: Temporary failure in name resolution
root@localhost:~# ping -c 2 1.1.1.1
ping: connect: Network is unreachable
root@localhost:~# ping6 -c 2 2602:ffc5:105:40f::202
ping6: connect: Network is unreachable
root@localhost:~#

虚拟机内部网络连接

让我们在虚拟机内部添加网络功能。

以下是启动 IPv4 和 IPv6 的命令:

ip address add 66.11.114.206/32 dev enp0s3
ip route add 66.11.114.201 dev enp0s3
ip route add default via 66.11.114.201 dev ens3
ip -6 address add 2602:ffc5:105:40f::206/64 dev enp0s3
ip -6 route add 2602:ffc5:105:40f::1 dev enp0s3
ip -6 route add default via 2602:ffc5:105:40f::1 dev enp0s3

网络命令可以放在脚本里。我听说在 Debian 系统上仍然可以启用 rc.local。把脚本放在 rc.local 里,就能让它在系统重启时自动运行。我们已经在另一台虚拟机上设置好了,运行正常。

DNS

在这个 Debian 虚拟机上,/etc/resolv.conf 是指向 /run/systemd/resolve/resolv.conf 的符号链接。

让我们把 Hurricane Electric 的解析器 IP 地址放到 /etc/resolv.conf 中。

root@localhost:~# unlink /etc/resolv.conf
root@localhost:~# echo nameserver 74.82.42.42 > /etc/resolv.conf
root@localhost:~# echo nameserver 2001:470:20::2 >> /etc/resolv.conf
root@localhost:~#

看起来DNS、IPv4和IPv6都正常工作:

root@localhost:~# ping -c 2 zhujimao.com
PING zhujimao.com(2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8)) 56 data bs
64 bytes from 2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8): icmp_seq=1 ttls
64 bytes from 2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8): icmp_seq=2 ttls

--- zhujimao.com ping 统计信息 ---
已发送 2 个数据包,已接收 2 个数据包,丢包率为 0%,耗时 1001 毫秒
rtt 最小值/平均值/最大值/标准差 = 25.972/25.988/26.005/0.016 毫秒
root@localhost:~# ping -4 -c 2 zhujimao.com
PING (104.26.1.216) 56(84) 字节的数据。
来自 104.26.1.216 (104.26.1.216) 的 64 字节:icmp_seq=1 ttl=58 time=21.6 ms
来自 104.26.1.216 (104.26.1.216) 的 64 字节:icmp_seq=2 ttl=58 time=21.6 ms

--- ping 统计信息 ---
已发送 2 个数据包,已接收 2 个数据包,丢包率为 0%,耗时 1001 毫秒
rtt 最小值/平均值/最大值/标准差 = 21.553/21.568/21.583/0.015 毫秒
root@localhost:~#

看来我们已经获得了预期的IP地址:

root@localhost:~# curl icanhazip.com
2602:ffc5:105:40f::206
root@localhost:~# curl -4 icanhazip.com
66.11.114.206
root@localhost:~#

安装主机 SSL 证书

还记得OpenSSH服务器故障吗?那是因为它没有任何主机密钥。我们来解决这个问题。

root@localhost:~# apt-get update
Get:1 http://deb.debian.org/debian sid InRelease [165 kB]
Get:2 http://deb.debian.org/debian sid/main Sources [9744 kB]
Get:3 http://deb.debian.org/debian sid/main amd64 Packages [9204 kB]
Get:4 http://deb.debian.org/debian sid/main Translation-en [6820 kB]
Fetched 25.9 MB in 7s (3779 kB/s)
Reading package lists... Done
root@localhost:~# apt-get upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
cloud-guest-utils cloud-image-utils cloud-utils libnss-resolve
libpam-systemd libsystemd0 libudev1 systemd systemd-sysv udev
10 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 7599 kB of archives.
After this operation, 13.3 kB of additional disk space will be used.
Do you want to continue? [Y/n]

[...]

root@localhost:~# dpkg-reconfigure openssh-server

[...]

正在创建 SSH2 ED25519 密钥;这可能需要一些时间……

[...]

root@localhost:~# systemctl status sshd
● ssh.service - OpenBSD 安全外壳服务器
已加载:已加载 (/lib/systemd/system/ssh.service;已启用;供应商预设:e>
活动状态:自 2022 年 6 月 4 日星期六 03:14:27 UTC 起处于活动(运行中);1 分 57 秒前

[...]

root@localhost:~#

如果我们不想使用 dpkg-reconfigure, ssh-keygen -A 或许可行。请参阅“如何操作:Ubuntu / Debian Linux 重新生成 OpenSSH 主机密钥”。

添加授权密钥

root@localhost:~# mkdir .ssh
root@localhost:~# chmod 700 .ssh/
root@localhost:~# echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILySvSdulbZ4XG4K333YOoFbcwoo6ythPBOf175OIBfA chronos@localhost > .ssh/authorized_keys
root@localhost:~# chmod 600 .ssh/authorized_keys

通过 SSH 登录

通过 SSH 登录

如何戒烟

要退出 tmux 而保持虚拟机运行,请键入“Ctrl-b”,然后键入“d”。
重新进入 tmux 和已运行的 VPS:

tmux attach

停止虚拟机并退出 tmux:

shutdown -h now

虚拟机关闭后,当命令提示符返回时,输入“exit”。

其他资源

当我第一次尝试 KVM 技巧时,Linux-KVM.org 的网络配置页面对我帮助很大。

或许世界上最详尽的 qemu 教程来自张东利。

结论

在之前的文章中,我们介绍了使用qemu默认网络工具slirp的三种方法。现在,我们探讨了如何创建具有独立IP地址的KVM虚拟机。

尽情享受低音的乐趣吧!💖