KVM Bridge nmcli 修改网卡等等

之前刚研究 KVM 时,记录的一些笔记

删除不要的 Bridge: br1

# ifconfig br1 down
# brctl delbr br1
# brctl show
$ virt-sysprep --list-operations
$ virt-clone -o centos-02 -n centos-03 -f /opt/kvm_disk/centos-03.qcow2
 
# cloud-init clean
# systemctl restart cloud-init-local.service
# netplan apply

# virsh qemu-agent-command <guest-name> '{"execute":"guest-info"}'

linuxtechi@kvm-ubuntu18-04:~$ sudo apt install cpu-checker
linuxtechi@kvm-ubuntu18-04:~$ sudo kvm-ok

virsh net-update add-last ip-dhcp-host \
   --file "<host mac='00:11:22:33:44:55' ip='192.168.122.45'/>" \
   --live --config

$ virsh dumpxml centos-03|grep 'mac address'
# yum provides avahi-resolve --disablerepo=epel

error: Unsafe migration: Migration may lead to data corruption if disks use cache != none or cache != directsync

# nmcli con show
# nmcli con delete uuid
# nmcli con add type ethernet ifname eth0 con-name eth0 \
  autoconnect yes ip4 192.168.1.10 gw4 192.168.1.1
# nmcli con mod eth0 ipv4.method manual 
# nmcli con mod eth0 ipv4.dns "8.8.8.8 8.8.4.4"
# nmcli con down eth0 && nmcli con up eth0

修改 Proxmox 6 VE 虚拟机的 VM ID

KVM 的虚拟化环境里, 只有 domain name 这一说, domain ID 是会随着每次重启, ID 会改变的。

Proxmox 创建虚拟机如果不指定 ID,这个 ID 会自动递增,而且这个 ID 在一个集群里是唯一的,是一直绑定虚拟机的。为了方便管理,类似网络环境的 DHCP IP Pool 的管理,我们会对某一段 ID 做一个特定的用途,加以区分。例如 100-199 是基础架构类的, 200-299 是模版,300-399 是数据库层, 400-499 是应用层, 500-599 是测试机, 600-699 是Windows 客户机。

如果不小心分配错了 VM ID,没有按照我们自定义的规则,需要修改 VM ID,怎么办呢?

在虚拟机已经关闭的情况下, ssh 登录进入集群内的任意一个节点,例如 pve-01,把 VM ID 111 修改为 211:
# cd /etc/pve/nodes/pve-01/qemu-server
# mv 111.conf 211.conf
# vim 211.conf
把里面的虚拟机磁盘映像路径修改掉,同时去真实的物理路径,把磁盘映像的文件名修改掉
假定磁盘 NFS Pool 的顶层路径为: /mnt/pve/vmpool/images,那么就是:
# mkdir 211
# mv 111/vm-111-disk-0.qcow2 211/vm-211-disk-0.qcow2
就可以

Proxmox VE 3分钟快速上手

Proxmox VE 是一款开源的虚拟化管理软件。内核基于 Debian,如果需要测试的话,其实也是蛮快可以上手的。 当然 前提是有 KVM 基础。

当然先是去官网下载最新版本的 iso,用 Bitrorrent 种子的下载速度可以达到 8Mb 每秒, 700 多兆的 iso,11分钟就下载完成。把 iso 拷贝到 Linux 机器上,插入 U盘,fdisk -l 查看,假设盘符为 /dev/sdb,然后 dd if=xxxx.iso of=/sdb bs=1M 就可以把 iso 烧录到 U 盘上了。
在要安装的物理服务器上,打开 UEFI 引导,然后就可以看到 Proxmos 的安装界面了,配置好服务器的网络和 root 口令后,安装十分快捷,重启会提示通过 https://ip:8006/ 就可以进入管理界面。

安装就大功告成了!接下来,添加存储和虚拟机。在 Web 界面用 root 用户登录后,设置语言为中文,进入存储界面,添加我们之前已经设置好的 NFS Share,设置好不同的类别,例如 iso 还是 vm 。记住,原先的存在的目录要按照 Proxmox 的约定重新移动到新的目录 iso 为挂接点下的 template/iso , vm 为 挂节点下的 images/<VMID>/ ,只有这样才能看到 Proxmox 之前的那些 iso 或者 qcow2 文件。

接下来,我们就可以开始创建虚拟机了,点击右上角的“创建虚拟机”,设置好虚拟机名称,从 isopool 里下拉,可以看到之前的 iso 文件,选择对应的映像,然后一步一步点选,就设置完成了。然后启动虚拟机,如果看到 No VNC,那是因为浏览器所在的 PC 客户端没有安装过 VNC ,不要紧,如果安装过 virt-view,我们在显卡设置里去修改成 Spice 就可以。然后会自动下载一个 .vv 文件,会自动用 virt-viewer 打开,我们就可以连接到虚拟机的 console 开始通过 iso 安装操作系统了。

那怎么样把已经有的之前用其他工具/方法创建的 qcow2 启动镜像放到 PVE 里面呢?

参考网络上的文档的做法是先创建一个虚拟机,生成和原先文件一样大的 qcow2 文件,然后把这个文件覆盖。虚拟机是可以启动的。这样子,我们就可以把先前所有的虚拟机都迁移到 PVE 上了。

V2V 的迁移非常简单,我们首先在 PVE Host 的命令行下创建一个 ID 为 102 的虚拟机:
# qm create 102 –bootdisk scsi0
然后进入到 Host 上的 NFS 挂接的目录,当然也可以不进入,后面多敲一点路径而已。
# cd /mnt/pve/vmpool
把里面的 elk-02.qcow2 转换到 102 虚拟机上。
# qm importdisk 102 elk-02.qcow2 vmpool –format qcow2

假定我们的 storage 名字叫 vmpool,我们可以用 pvesm list vmpool 看到下面的所有虚拟机映像以及快照,然后我们重新设置一下虚拟机 102 的启动盘:
qm set 102 –scsi0 vmpool:102/vm-102-disk-0.qcow2

这样子,通过以上三步,先建立虚拟机,再导入磁盘,再设置启动盘,就把之前的虚拟机就可以全部导入到 PVE 了!

完美!

后记:


系统安装后,默认是 subscribe 的,会导致更新失败。 我们需要修改 apt source 文件:/etc/apt/sources.list.d/pve-enterprise.list
# deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise
deb http://download.proxmox.com/debian/pve stretch pve-no-subscription

如果有安装过 proxychains , 然后设置过绕墙代理的话,用 proxychains apt -y update 就可以很快把系统更新了。

对了, 所有的原先 virsh 的一些命令,大多数都可以通过 qm 命令来完成。

pvesm 是管理存储的, pvecm 是管理集群的。

Change name for a vg with rootfs on Ubuntu 1804 onward

In our dev enviroment, we use several KVM desktop machine to create lot VMs to test all kinds of new stuff.
Compared with CentOS 7, Ubuntu 1804 or 1904 are more easy to install any new software just with apt install, don’t even need to update package list.

Though we found Ubuntu had big issue in change the vg name or doing what ever LVM init (aka virt-sysprep) . We already found the solution to it. But for regular Ubuntu VG name change, we still should have a separate way to do. Here it is.

  1. # vgrename oldvg newvg
  2. # perl -p -i -e ‘s/oldvg/newvg/g’ /etc/fstab /boot/grub/grub.cfg /etc/initramfs-tools/conf.d/resume
    if vg name contain dash (“-“), we need to run one more time with this:
    # perl -p -i -e ‘s/oldvg–/newvg–/g’ /etc/fstab /boot/grub/grub.cfg /etc/initramfs-tools/conf.d/resume
  3. # /sbin/update-initramfs -c -k all

KVM 克隆 Ubuntu 虚拟机一个总算有解的 grub PV/VG UUID 问题

这件事情折腾有一段时间了。 virt-clone 然后 virt-sysprep 好的 Ubuntu 虚拟机因为 /boot/grub/grub.cfg 里面的 VG UUID 没有被修改, 导致虚拟机不能启动,必须手工操作。 笨办法是挂接 Rescue CD, 取到当前的 UUID,更新 grub.cfg 文件,稍微好一点的办法是用 NBD 方式直接挂接虚拟机映像,用同样的办法。

实际上 KVM 有自己的 virt-rescue 命令, 直接可以通过 libguestfs API 来和虚拟机映像通信的。 所以,新的办法是:
# sudo virt-rescue -d guest-domain 或者 -a guest-disk.qcow2
<rescue> mkdir /mnt
<rescue> vgchange -ay
<rescue> mount /dev/rootvg/root /mnt
<rescue> for i in /dev /dev/pts /proc /sys /run; do mount -B $i /mnt$i; done
<rescue> chroot /mnt
<rescue> grub-install /dev/sda
<rescue> update-grub
以上是更新 grub 的办法, 实际上我们后面要讲到 virt-sysprep 我们会绕过 pv/vg UUID 的初始化,但是为了实现完整的初始化过程,我们需要在 virt-sysprep 后,生成新的 PV/VG 的 UUID,步骤是:
<rescue> vgchange -an rootvg
<rescue> pvchange -u /dev/sda1
<rescue> pvdisplay
我们可以看到 UUID 已经更改了。

同样的,对 vg 做修改:
<rescue> vgchange -u rootvg

所以, 以上其实做了一个倒叙,理论上应该是先修改 UUID,再更新 grub。

下面我们介绍 virt-sysprep 的一些命令行参数。

虚拟机的克隆其实是非常简单的一个事情,下面是 shell 里的一个克隆函数:
-o 就是老的 domain , -n 就是新的 domain, -f 就是新的虚拟机磁盘映像文件

做完克隆以后,我们做 virt-sysprep,函数是这样写的:

检测虚拟机操作系统类别用了 virt-inspector 后面加 –no-applications 不输出安装的软件包,我们用了 xmllint 来取出输出的 xml 里操作系统类别的那个 distro 值,用 sed 去掉 xml tag. 如果 distro 这个值是 ubuntu 的话,我们就执行特别的一些操作,看 operations 里的列表,前面有减号的就是不要操作的,其中 –lvm-uuids 就是不重新生成 pv/vg 的 UUID。
如果按照以上 virt-sysprep 参数,直接克隆完成后,这个虚拟机就是直接可以启动的,不存在 grub 问题,但是显然可能会遇到虚拟机 PV/VG UUID 和其他冲突的问题,这就要回到最初需要手工 virt-rescue 初始化 UUID了。

总结: 对事物的认识总是一个进化的过程,重复造轮子是一件可耻的事情。有这么一个 virt-rescue,还有 virt-inspector ,其实还有另外一个 virt-filesystems 可以使用,如果自己还要用 nbd 挂接来做虚拟机的操作,就有点 LOW 了。

However,这件事情的全自动化,依然没有做到。因为 。。。
==============================================
当写到上面的因为时,突然想到是自己的 sysprep 部分函数原来的 –run-command 缺少了 grub-install 造成的,但是每次 sysprep 都是 lvm-uuid 最后才走,所以,我们需要走两次 sysprep,第一次只走 lvm-uuids 的初始化,第二次走其他的 operations ,然后运行 grub-install 和 update-grub ,这样子,一个全自动的流程就搞定了。 上完整的脚本:

部分脚本代码:(非完整代码)

echo “正在检查原始虚拟机的操作系统”
OS=$(sudo virt-inspector -a ${OLD_DISK} –no-applications |xmllint –xpath /operatingsystems/operatingsystem/distro -|sed -e ‘s/<[^>]*>//g’)
if [ “$OS” = “ubuntu” ]; then
echo “Ubuntu 系统先初始化 LVM UUID …”
sudo virt-sysprep –operations lvm-uuids -a ${DISK}
echo “重新运行初始化其余部分,设置主机名为: ${HOST} “
sudo virt-sysprep -a ${DISK} \
–hostname ${HOST} \
–ssh-inject ${user}:file:$key \
–operations ssh-hostkeys,defaults,-lvm-uuids,-puppet-data-log,-samba-db-log,-rhn-systemid,-rh-subscription-manager,-yum-uuid \
–run-command ‘/usr/sbin/grub-install /dev/sda’ \
–run-command ‘/usr/sbin/update-grub’

KVM 挂接 openwrt 虚拟机

去 openwrt.org 网站下载 openwrt-18.06.4-x86-64-combined-ext4.img ,解压后用 qemu-img info 查看:
image: openwrt-18.06.4-x86-64-combined-ext4.img
file format: raw
virtual size: 273M (285736960 bytes)
disk size: 273M

然后用 virt-manager 挂接,就可以启动了,默认 ip 地址是 192.168.1.1
用 uci show network 可以看到网络配置, 然后
# uci set network.lan.ipaddr=’192.168.x.x’
# uci commit
# netstat -nat 可以看到 22 , 53, 80 端口对外开放
修改完 IP地址,重启后,可以 ssh root@192.168.x.x 进入了, root 默认没有密码

然后去 web 界面修改口令, 设置时区,配置网关。
然后去 system->Software->Update List 可以看到所有的软件包列表了。
搜索 zh-cn 就可以看到所有的汉化软件包, 开始的时候,就安装 luci-i18n-base-zh-cn 即可, 安装完毕后, 后台 Web 管理界面自动刷新成中文了。

Ubunt1904 virt-sysprep Bug

假设有虚拟机 dns-01, vg Name 为 dns01 克隆到 dns-02,新的 vg Name 为 dns02

由于 virt-sysprep 的 bug,导致 vgid 修改后, grub.cfg 文件指定的 lvmid 没有修改,克隆后的虚拟机启动失败,进入 grub rescue mode.
解决的办法是 直接用 virt-clone 后(实际上只是克隆了卷文件,修改了 Mac地址),不要运行 virt-sysprep 直接手工启动虚拟机,初始化虚拟机内的配置: /etc/hostname, /etc/hosts, /etc/netplan/01-*.yaml ,而磁盘的 vg name 实际上无需修改。


下面是一个复杂一点的版本, 用 vol-clone 的办法来做。
# virsh vol-clone dns-01.qcow2 dns-02.qcow2 vmpool
# virsh dumpxml dns-01 >/var/tmp/dns.xml
# vim /var/tmp/dns.xml 修改 domainname 为 dns-02 去掉 UUID 相关的行, 去掉 Mac 地址,修改 disk 的卷文件名为 dns-02.qcow2
# virsh define /var/tmp/dns.xml (会自动生成新的 Mac 地址)
# virsh start dns-02 (如果 dns-01 是静态分配 IP 的,在克隆卷之前最好修改为动态)
# virsh console dns-02

这个 virt-sysprep 的 Bug 是因为 /boot/grub/grub.cfg 文件里有
set root=’lvmid/d8R9S7-C47Z-UHx1-4tRd-qXcX-sFV1-rC4uG4/x4MwoL-7yfO-03da-e72d-Y0DQ-hBil-vXGplk’
这样的行,格式是 lvmid/vg-UUID/lv-UUID
因为 virt-sysprep 后 vg 的 UUID 修改了,但是 grub.cfg 没有修改导致的。

hostnamectl status 命令还会有一个 machine ID 的概念, 重新生成的办法是
# rm /etc/machine-id && systemd-machine-id-setup

通过 Live CD/USB 做 Windows 10 的 P2V 到 KVM 上

上次说到把一块之前的 SATA 物理盘,通过 USB 物理挂接到 KVM Host 上实现 P2V,但是如果是一台远程的服务器,或者笔记本电脑,反正硬盘不能拆卸的情形下,我们怎样把硬盘里的操作系统克隆成虚拟机呢?

环境:一台 笔记本电脑上的 Windows 10 专业版,一台同一个局域网内的 Linux 机器(可以运行 nc 命令监听,有足够的磁盘空间)
工具:一个 8GB或者 16GB 的 U盘,刻录了任何 Linux 操作系统能启动安装就可以。

步骤:
笔记本电脑,从 U盘启动,进入 Linux 安装界面,不是真实的安装, 只要到检测到网卡,网络能工作就可以,然后按 Ctr-Alt-F3 或者 F4~F6,看自己喜欢。反正就是进入命令行界面。
确认能 ping 通 KVM 主机
# ping 192.168.7.100
没有 fdisk 命令,用 blkid 看下系统内的磁盘,然后 dmesg|grep sdX X 是看到的磁盘的字母 a 或者 b 或者 c 等,确定要克隆的设备名称,假定为 /dev/sda

在命令行下 运行
# nc if=/dev/sda |nc 192.168.7.100 6500
也就是把数据写往 192.168.7.100 的 6500 端口
这里的 nc 命令其实是 busybox 命令的昵称

然后在 KVM Host 上启动 nc 的 Listen:
# nc -l -p 6500 > win10_sda.raw
经过漫长的网络读写后,笔记本电脑上的 nc 会自动结束,标记 recrods in/out 的数据。
在 KVM Host 上,我们用 qemu-img info 查看写好的文件:

这个时候无需做任何的其他操作,我们只要把这个 raw Image 挂接为 ide 方式,就能直接启动了!

新问题来了,原始磁盘实际上我事先做了空间整理, 250GB 的 SSD,实际大概只使用了 90多GB,而且有一个分区都被我删除了。 但是导出来的 raw 文件还是 250GB,怎么办呢?

我们用 losetup -vf win10.raw 把 raw 文件做回环挂接, fdisk -l /dev/loop1 就可以看到原始的磁盘的分区信息了。 我们只要第一个分区的数据,所以用 dd 重新把 raw 文件写到一个新的 raw 文件:
dd if=win10.raw of=win10_shrinked.raw bs=512 count=xxxx
就可以得到一个实际原来分区的新的映像文件。

这样我们只要 virsh edit 用新的文件名替换原先的 raw 文件名,就能成功的启动 Win 10 了。
当然, 我们同时可以挂接 virtio-win 的 iso 映像,然后进入 Win 10 虚拟机更新 PCI/网卡/视频驱动。
但是 Win10 的视频驱动有问题, 不能识别, 需要 qxldod 驱动。
另外,原先的 License 都丢失了, 需要重新激活 Win 10. 🙁

我们可以通过 Windows 上安装的 virt-viewer 连接到 Spice 上,
输入 spice 连接为: 远程 KVM 主机 + 端口号(一般为 5900)
取决于你 虚拟机的 spice 设置,需要修改 listen 的地址 127.0.0.1 修改为 0.0.0.0,然后端口如果是默认的话,会自动启动新的端口,也就是说如果有10个虚拟机在跑,第一个是 5900,那么新开启的虚拟机 spice 端口就是 5901 了。
当然如果虚拟机 IP 地址已经拿到, 通过 RDP 到虚拟机的 IP 当然更方便。



下载安装 Ubuntu 1904 Server 版本并安装为 KVM Guest

http://cdimage.ubuntu.com/releases/19.04/release/ubuntu-19.04-server-amd64.iso.torrent
默认去官网点击, 直接就下载 Live CD的 DVD 盘了, 正经的应该去这里选择:
https://ubuntu.com/download/alternative-downloads

不过这个种子数有点少, 754Mb 的 iso 只有 600Kb/s 的下载速度。慢了。

谁让我找不到当初做 KVM Host 的那个 iso 了呢。

下载完后, 把新的 iso 挂接到原来做 CentOS 8 的虚拟机上,从 CDROM 启动后就可以覆盖原来的 CentOS 8 了。 选择安装的时候有个 Virtual Machine Minimal 的选项,然后选择 Basic Ubunntu Server 和 OpenSSH Server , 前面选择语言和键盘的时候, 不要选择中文, 我们回头再设。
中间快结束前,提示退出光驱,可以返回到 virt-manager , 把光驱退出。 然后重启 OS,一个新的虚拟机就设置好了。

下面来看后面的配置:
1. 修改 apt source list , 把 cn.archive.ubuntu.com 都修改为 mirrors.aliyun.com
2. # apt ugprade
3. 然后安装需要常用的一些包:nmap telnet lsof bind9-host dnsutils wget psmisc mlocate tree avahi-daemon qemu-guest-agent (后面两个是服务,安装后服务也要启动一下)
4. 编辑 /etc/default/grub:

GRUB_DEFAULT=0
GRUB_TIMEOUT=2
GRUB_DISTRIBUTOR=lsb_release -i -s 2> /dev/null || echo Debian
GRUB_CMDLINE_LINUX_DEFAULT=””
GRUB_CMDLINE_LINUX=”console=tty1 console=ttyS0,115200″
GRUB_TERMINAL=”console serial”
GRUB_SERIAL_COMMAND=”serial –speed=115200 –unit=0 –word=8 –parity=no –stop=1″

# grub-mkconfig -o /boot/grub/grub.cfg

这样子一个完美的 Ubuntu 最新版本的服务器作为虚拟机就配置好了。