我的基础设施环境主要靠我家局域网内一台 7x24 小时运行的工作站支撑,我平时使用的基础设施,比如:gitlab、gitlab-runner、jira 甚至是现在你正在访问的博客站点,都是运行在这台工作站上的。这台工作站基于 Arch Linux,部署了 libvirt 虚拟化,不同的基础设施运行在彼此独立的虚拟机内。
下面简单介绍一下我平时是如何使用这个虚拟化的。
关于网络
我的虚拟化使用的是 bridge 网络模式,所以任何一台虚拟机都可以直接拿到局域网 IP,如何配置可参考:archwiki systemd-networkd#bridge-interface
关于系统和镜像
我的所有虚拟机也是 Arch Linux 系统。在虚拟化的宿主机上准备了一个 Arch Linux 虚拟机作为模板(模板镜像的准备使用了 virt-sysprep 这个工具),其他的虚拟机的镜像都是从模板镜像克隆出来的。虚拟机的镜像文件来自 Arch 官方,下载地址如下:Arch-Linux-x86_64-basic.qcow2
如何基于模板机创建实例
列出所有的虚拟机
virsh list --all
模板机关机备用
virsh shutdown template
基于模板机(我这里的模板机名字是:template)克隆出所需的主机
virt-clone --auto-clone --original template --name demo1
virt-clone --auto-clone --original template --name demo2
virt-clone --auto-clone --original template --name demo3
镜像准备,避免 machine-id、ssh-host-key 等冲突问题(这步是必须的)
virt-sysprep -d demo1
virt-sysprep -d demo2
virt-sysprep -d demo3
[可选] 为了后面能够通过 SSH 免密登录,所以在准备镜像的时候,我会顺便注入我的公钥,命令如下:
virt-sysprep \
--ssh-inject root:string:'ssh-rsa AAAAB... jinmiaoluo@gmail.com' \
-d demo1
virt-sysprep \
--ssh-inject root:string:'ssh-rsa AAAAB... jinmiaoluo@gmail.com' \
-d demo2
virt-sysprep \
--ssh-inject root:string:'ssh-rsa AAAAB... jinmiaoluo@gmail.com' \
-d demo3
启动虚拟机操作如下:
virsh start demo1
virsh start demo2
virsh start demo3
[可选] 启动虚拟机并通过 console 方式管理虚拟机,操作如下(ctrl+]
可退出 console):
virsh start demo1 --console
virsh start demo2 --console
virsh start demo3 --console
配置虚拟机在物理机开机后自动启动:
virsh autostart demo1
virsh autostart demo2
virsh autostart demo3
管理虚拟机我使用的是 serial console 模式,这样的好处是:即使网络没有就绪,也能管理主机。刚创建的虚拟机往往不知道分配的局域网的 IP 是多少,所以使用 serial 模式是非常方便的,操作如下(ctrl+]
可退出 console):
virsh console demo1
virsh console demo2
virsh console demo3
采用 serial 模式管理,需要更新 grub 配置,如果你也是用 Arch Linux 系统,只需更新:/etc/default/grub
文件,将:GRUB_CMDLINE_LINUX
的值更新为如下:
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8 net.ifnames=0"
然后执行:grub-mkconfig -o /boot/grub/grub.cfg
即可
演示视频如下:
其他常见的操作
制作快照操作如下:
virsh snapshot-create demo1
virsh snapshot-create demo2
virsh snapshot-create demo3
恢复快照操作如下:
virsh snapshot-revert demo1 --current
virsh snapshot-revert demo2 --current
virsh snapshot-revert demo3 --current
删除快照操作如下:
virsh snapshot-delete --domain demo1 --current
virsh snapshot-delete --domain demo2 --current
virsh snapshot-delete --domain demo3 --current
关闭虚拟机操作如下:
# 删除虚拟机
virsh destroy demo1
virsh destroy demo2
virsh destroy demo3
# 清理镜像文件
virsh undefine --domain demo1 --remove-all-storage
virsh undefine --domain demo2 --remove-all-storage
virsh undefine --domain demo3 --remove-all-storage
演示视频如下: 快照制作、恢复、删除和主机的销毁
系统分区扩容
在宿主机上,对 demo 虚拟机的磁盘文件(QCOW2)进行扩容(增加 20G)
# 登录宿主机
ssh root@m4.jinmiaoluo.com
# 在宿主机上通过 virsh 关闭虚拟机
virsh shutdown demo
# 在宿主机上执行扩容操作(我打算扩容 20G,这里分成两遍,从而更好的演示后面查询命令的作用)
qemu-img resize /var/lib/libvirt/images/demo.img +10G
# 在宿主机上查看扩容后的大小
qemu-img info /var/lib/libvirt/images/demo.img
启动虚拟机,在虚拟机内操作。
# 启动虚拟机
virsh start demo
# 通过串口的方式登录虚拟机(视频中使用的方式)
virsh console demo
# 通过网络方式登录虚拟机
ssh root@demo.jinmiaoluo.com
查看根目录对应的磁盘分区,然后调整分区大小,调整文件系统大小。
# 查看分区
lsblk
# 调整分区大小。我这里根目录对应 /dev/vda2(所以第二个参数是 2,根据实际情况调整)
growpart /dev/vda 2
# 调整文件系统大小。如果是:btrfs
btrfs filesystem resize max /
# 调整文件系统大小。如果是:ext4
resize2fs /dev/vda2
# 调整文件系统大小。如果是 xfs
xfs_growfs /dev/vda1
操作见视频:
虚拟机救援
有些时候我们会因为一些特殊的原因导致虚拟机完全无法开机(即:console 都无法连接),如果是在普通的服务器,我们可以用 Live USB 启动后再回收数据,虚拟机怎么做呢?
我们可以用 qemu-nbd(QEMU Disk Network Block Device Server),这是 qemu 提供的一个工具,可以直接将虚拟机的镜像,直接以一个物理设备的形式,挂载到虚拟机镜像所在的物理机上。然后就可以像访问一个 U 盘的方式,访问和更改虚拟机中的数据(比如更换了磁盘,磁盘的 UUID 变了导致无法开机) 操作如下:
在 root 用户,启动对应的内核模块:
modprobe nbd
加载镜像为 nbd 设备:
qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2
如果虚拟机有多个分区,那么就会有多个 nbd 设备,类似:nbd0p1
nbd0p2
,挂载根分区
对应的 nbd 设备(我这里是 nbd0p1
):
mount /dev/nbd0p1 /mnt
然后进行读取和更改即可,完成后取消文件系统的挂载:
cd /mnt
# do something
umount /mnt
取消镜像文件到 nbd 设备的连接:
qemu-nbd -d /dev/nbd0
虚拟化的远程管理
我的虚拟化和开发环境是在两台不同的工作站上,这里用 A(虚拟化)和 B(开发环境) 来替代。
虚拟化远程管理指的是在 B 上,通过 virsh 实现虚拟机的克隆、启动、管理、删除。
做法很简单,将 B 的 ssh 公钥添加到 A 的 root 用户下(也可以添加到 A 的普通用户下,但要配置 A 上的 libvirt 允许该普通用户管理虚拟机),然后将下面的内容添加到 ~/.bashrc
即可:
# 这里的 m4.jinmiaoluo.com 是 A 的内部域名,你替换成自己虚拟化的 IP 即可
export LIBVIRT_DEFAULT_URI="qemu+ssh://root@m4.jinmiaoluo.com/system"
录屏中,m4 是虚拟化(A),m7 是开发环境(B),演示视频如下:
演示视频如下:
最后附上一张设备的丑图: