先讲一下我的需求。
我需要在无界面的服务器上安装openSUSE
虚拟机,所以市面上常见的一些虚拟机安装工具,如vmware
, virtual-box
之类的都不考虑,后来了解到有一个叫libvirt
的工具,可以通过命令行方式安装虚拟机,自然成为了首选。
但是在实际安装的过程中,也出现了一些问题,碰到了一些坑,解决花了一番功夫,特此记录一下。
需要说明的是,本文偏向于实践,因此,理论性的知识不多做赘述,如果要讲kvm
, libvirt
,qemu
,估计几万字都说不完。所以,一切从实操出发,Let's go
。
准备工作
首先要确定你的服务器是可以使用虚拟机技术的,先确认cpu
支持vmx
指令。
cat /proc/cpuinfo |grep vmx
如果查出来有内容,就说明这一条是满足条件的。
第二步要确认的是内核已经加载了kvm
模块,使用如下命令:
lsmod | grep kvm
如果正常,应该能得到如下的结果:
kvm_intel 282624 0
kvm 667648 1 kvm_intel
irqbypass 16384 1 kvm
我的机器是CentOS7.9
, x86_64
架构。以上条件都满足。
安装软件
主要是要安装libvirt
相关的一些软件和依赖,可以使用下面一条命令梭哈:
yum install qemu qemu-kvm libvirt-clients libvirt-daemon-system virtinst bridge-utils libguestfs-tools virt-install.noarch -y
安装完成之后,启动libvirt
服务即可:
systemctl start libvirtd
正常情况下,可以看到服务正常启动了:
[root@ck16 ~]# systemctl status libvirtd
● libvirtd.service - Virtualization daemon
Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
Active: active (running) since 四 2023-02-09 13:36:07 CST; 14min ago
Docs: man:libvirtd(8)
https://libvirt.org
Main PID: 34326 (libvirtd)
Tasks: 19 (limit: 32768)
Memory: 54.1M
CGroup: /system.slice/libvirtd.service
├─ 2694 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/l...
├─ 2695 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/l...
└─34326 /usr/sbin/libvirtd
2月 09 13:36:07 ck16 systemd[1]: Starting Virtualization daemon...
2月 09 13:36:07 ck16 systemd[1]: Started Virtualization daemon.
2月 09 13:36:07 ck16 dnsmasq[2694]: read /etc/hosts - 8 addresses
2月 09 13:36:07 ck16 dnsmasq[2694]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 addresses
2月 09 13:36:07 ck16 dnsmasq-dhcp[2694]: read /var/lib/libvirt/dnsmasq/default.hostsfile
这时候,如果你在终端输入virsh list
应该能正常显示:
[root@ck16 ~]# virsh list
Id 名称 状态
----------------------------------------------------
该命令是列出当前已经安装过的虚拟机,由于我们还没有安装过,所以虚拟机列表为空。
创建虚拟机
创建虚拟机使用 virt-install
命令。该命令参数众多,可以使用-h
进行查看。
在创建虚拟机之前需要有一个系统镜像,我这里使用的是openSUSE15.4
, 安装使用如下命令即可:
virt-install --name=vm1 --vcpus=2 --memory=2048 --location=/mnt/nfs/1-ISO/1-linux/openSUSE-Leap-15.4-CR-DVD-x86_64-Build31.98-Media.iso --disk size=100 --extra-args='console=tty0 console=ttyS0,115200n8 serial' --nographics --os-variant=opensuse15.1
以上命令简要说明:
--name=vm1
- 指定虚拟机的名字,只要不与已有的虚拟机重复就行
--vcpus=2
- 指定要创建的虚拟机
vcpu
个数
- 指定要创建的虚拟机
--memory=2048
- 指定要创建的虚拟机内存大小
--location=/mnt/nfs/1-ISO/1-linux/openSUSE-Leap-15.4-CR-DVD-x86_64-Build31.98-Media.iso
- 指定镜像位置,也可以使用--cdrom指定,不过我安装的时候有坑,就用--location指定的
--disk size=100
- 设置虚拟机硬盘大小, 默认单位为
GB
- 注意:磁盘一定不能设置太小,我第一次指定
5G
,安装时需要自己进行分区,结果分区太小,导致安装时空间不足,如果空间比较大,它会自己分区,不用人工参与 - 安装centos所需硬盘应该可以小一点,
5G
也能安装上
- 设置虚拟机硬盘大小, 默认单位为
--extra-args='console=tty0 console=ttyS0,115200n8 serial'
- 额外参数,主要是指定
console
,如果没有console
,那么后面安装会卡住,进不了终端 - 注意指定了该参数,前面指定系统镜像时就必须使用
--location
,而不能使用--cdrom
- 额外参数,主要是指定
--nographics
- 这一步也很重要,我之前在这一步卡了很久,如果不指定这一项,它应该是会弹出来安装界面的,因为我是在服务器上安装的,没有界面弹出,所以一直卡在那里很久都没有反应
- 禁用这项后,它就会在控制台进行安装,很快就能看到安装进度
--os-variant=opensuse15.1
- 指定安装系统的类型,注意不能乱指,
os-variant
支持的类型,可以通过命令osinfo-query os
命令进行查看
- 指定安装系统的类型,注意不能乱指,
以上命令执行后,等待安装就行了,安装过程中,会引导提示你输入用户名,密码,以及时区什么的,都是安装系统的常规操作,这里就不赘述了。
安装完成后系统会自动重启,然后输入之前设置的用户名和密码,就能登录上去了。
eoi@localhost:~> cat /etc/os-release
NAME="openSUSE Leap"
VERSION="15.4"
ID="opensuse-leap"
ID_LIKE="suse opensuse"
VERSION_ID="15.4"
PRETTY_NAME="openSUSE Leap 15.4"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:leap:15.4"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"
DOCUMENTATION_URL="https://en.opensuse.org/Portal:Leap"
LOGO="distributor-logo-Leap"
执行ifconfig
报错,提示需要安装,安装一下:
eoi@localhost:~> ifconfig
If 'ifconfig' is not a typo you can use command-not-found to lookup the package that contains it, like this:
cnf ifconfig
eoi@localhost:~> cnf ifconfig
ifconfig: searching ...
Warning: incomplete repos found but could not refresh - try to refresh manually, e.g. with 'zypper refresh'.
The program 'ifconfig' can be found in following packages:
* net-tools-deprecated [ path: /bin/ifconfig, repository: zypp (repo-oss) ]
* net-tools-deprecated [ path: /usr/bin/ifconfig, repository: zypp (repo-oss) ]
Try installing with:
sudo zypper install net-tools-deprecated
eoi@localhost:~> sudo zypper install net-tools-deprecated
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for root:
Retrieving repository 'Update repository of openSUSE Backports' metadata .[done]
Building repository 'Update repository of openSUSE Backports' cache ......[done]
Retrieving repository 'Update repository with updates from SUSE Linux Ente[done]
Building repository 'Update repository with updates from SUSE Linux Enterp[done]
Loading repository data...
Reading installed packages...
Resolving package dependencies...
The following NEW package is going to be installed:
net-tools-deprecated
1 new package to install.
Overall download size: 170.2 KiB. Already cached: 0 B. After the operation,
additional 460.1 KiB will be used.
Continue? [y/n/v/...? shows all options] (y): y
Retrieving package net-tools-deprecated-2.0+git20170221.479bb4a-3.11.x86_64
(1/1), 170.2 KiB (460.1 KiB unpacked)
Retrieving: net-tools-deprecated-2.0+git20170221.479bb4a-3.11.[done (2.4 KiB/s)]
Checking for file conflicts: .............................................[done]
(1/1) Installing: net-tools-deprecated-2.0+git20170221.479bb4a-3.11.x86_64[done]
eoi@localhost:~> ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.122.230 netmask 255.255.255.0 broadcast 192.168.122.255
inet6 fe80::5054:ff:fefa:87e3 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:fa:87:e3 txqueuelen 1000 (Ethernet)
RX packets 25541 bytes 58671738 (55.9 MiB)
RX errors 0 dropped 56 overruns 0 frame 0
TX packets 18778 bytes 1425343 (1.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
virsh常用命令
克隆机器
克隆机器前需要停止机器:
virsh shutdown vm1
克隆命令如下:
virt-clone -o vm1 -n vm2 --auto-clone
其中:
-o
- 指定源虚拟机
-n
- 指定目标虚拟机
--auto-clone
- 自动克隆,就不需要指定虚拟机镜像位置了
[root@ck16 ~]# virt-clone -o vm1 -n vm2 --auto-clone
正在分配 'vm2.qcow2' | 100 GB 00:00:03
成功克隆 'vm2'。
查看虚拟机
virsh list --all
virsh list
只能看到正在运行的虚拟机,加上--all
就能看到所有的虚拟机,包括关闭的虚拟机了。
[root@ck16 ~]# virsh list --all
Id 名称 状态
----------------------------------------------------
4 vm2 running
- vm1 关闭
关闭虚拟机
virsh shutdown vm1
或
virsh destroy vm1
删除虚拟机
virsh undefine vm1
注意删除虚拟机,仅在虚拟机被停止后才会生效,如果虚拟机在运行状态下执行删除,它不会报错,但也不会实际被删除,只有停止后才会真正被删除。
重启虚拟机
virsh reboot vm1
进入虚拟机
virsh console vm1
这种方式进入直接按exit
是不能退出的,要退出console
,需要按 Ctrl + ]
。
当然还有更多的命令,就不一一介绍了,可以使用--help
命令查看。
设置静态IP
默认dhcp
方式设置的虚拟机网络经常会变,不利于管理,因此设置静态IP
还是非常有必要的。
先将两台虚拟机都停止:
[root@ck16 ~]# virsh shutdown vm1
域 vm1 被关闭
[root@ck16 ~]# virsh shutdown vm2
域 vm2 被关闭
[root@ck16 ~]#
然后找到两台虚拟机的mac
地址:
[root@ck16 ~]# virsh dumpxml vm1 | grep 'mac address'
<mac address='52:54:00:fa:87:e3'/>
[root@ck16 ~]# virsh dumpxml vm2 | grep 'mac address'
<mac address='52:54:00:b3:c6:d5'/>
查看vm1
和vm2
使用的network
配置:
[root@ck16 ~]# virsh dumpxml vm1 |grep network
<interface type='network'>
<source network='default'/>
[root@ck16 ~]# virsh dumpxml vm2 |grep network
<interface type='network'>
<source network='default'/>
因此,我们只需要设置default
的网络配置就行了。
使用如下命令编辑:
virsh net-edit default
<network>
<name>default</name>
<uuid>0c1536d8-deb8-45d4-a1ce-3a90d2ad7785</uuid>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:f5:85:0f'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
<!-- 增加下面这两行 -->
<host mac='52:54:00:fa:87:e3' name='vm1' ip='192.168.122.114'/>
<host mac='52:54:00:b3:c6:d5' name='vm2' ip='192.168.122.115'/>
</dhcp>
</ip>
</network>
然后重启网络:
[root@ck16 ~]# virsh net-destroy default
网络 default 被删除
[root@ck16 ~]# virsh net-start default
网络 default 已开始
最后重启虚拟机即可:
[root@ck16 ~]# virsh start vm1
域 vm1 已开始
[root@ck16 ~]# virsh start vm2
域 vm2 已开始
[root@ck16 ~]#
登陆上去验证, 可以看到vm1
的ip
已经变成了192.168.122.114
:
[root@ck16 ~]# virsh console vm1
连接到域 vm1
换码符为 ^]
vm1 login: eoi
Password:
No mail.
Last login: Thu Feb 9 14:29:49 on ttyS0
Have a lot of fun...
eoi@vm1:~> ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.122.114 netmask 255.255.255.0 broadcast 192.168.122.255
inet6 fe80::5054:ff:fefa:87e3 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:fa:87:e3 txqueuelen 1000 (Ethernet)
RX packets 95 bytes 12574 (12.2 KiB)
RX errors 0 dropped 33 overruns 0 frame 0
TX packets 41 bytes 3866 (3.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 14 bytes 2032 (1.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14 bytes 2032 (1.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eoi@vm1:~>
同时,vm2
的ip
已经变成了192.168.122.115
:
[root@ck16 ~]# virsh console vm2
连接到域 vm2
换码符为 ^]
vm2 login: eoi
Password:
No mail.
Last login: Thu Feb 9 14:29:49 on ttyS0
Have a lot of fun...
eoi@vm2:~> ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.122.115 netmask 255.255.255.0 broadcast 192.168.122.255
inet6 fe80::5054:ff:feb3:c6d5 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:b3:c6:d5 txqueuelen 1000 (Ethernet)
RX packets 126 bytes 17309 (16.9 KiB)
RX errors 0 dropped 55 overruns 0 frame 0
TX packets 45 bytes 4217 (4.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 14 bytes 2032 (1.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14 bytes 2032 (1.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eoi@vm2:~>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。