跳到主要内容

CentOS7部署安装KVM+NAT内网转换

参考Centos7下KVM虚拟机安装与NAT虚拟机创建详解

!注意,本文与原文不完全一致。本文已为笔者实际应用场景修改。

以下所有操作请使用root用户,以避免出现权限问题。

检查CPU是否支持虚拟化

KVM 是基于 x86 虚拟化扩展(Intel VT 或者 AMD-V) 技术的虚拟机软件,所以查看 CPU 是否支持 VT 技术,就可以判断是否支持KVM。有返回结果,如果结果中有vmx(Intel)或svm(AMD)字样,就说明CPU的支持的。

对于一般的物理服务器,CPU基本上都是支持虚拟化的,如果使用下面指令后发现不支持,可自行进入BIOS开启,对于一般的云服务器或者虚拟服务器,一般都是不支持的,只有少数的云服务器的少数型号支持。

原作者使用Azure的D2S_v3类型示例进行操作,其他类型服务器可自行询问服务商或者自行测试。

笔者用的是E5-2420v2。

cat /proc/cpuinfo | egrep 'vmx|svm'

若出现红色字样则说明支持。

关闭SELinux

安装之前关闭SELinux,防止出现问题,难以进行定位。

一键式操作

[ -s /etc/selinux/config ] && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0 >/dev/null 2>&1

手动配置

vim /etc/selinux/config

SELINUX=disabled

setenforce 0

安装KVM环境

通过 yum 安装 kvm 基础包和管理工具

kvm相关安装包及其作用:

qemu-kvm 主要的KVM程序包

libvirt C语言工具包,提供libvirt服务

virt-install 基于libvirt服务的虚拟机创建命令

virt-top 类似于htop,用于显示kvm虚拟机的数据

bridge-utils 创建和管理桥接设备的工具(由于我不需要使用桥接,所以我不安装,但是在安装以上软件包时也会顺便把这个当依赖安装了,无妨)

libvirt-client 为虚拟客户机提供的C语言工具包(以上软件包的依赖,无需选择)

virt-viewer GUI连接程序,连接到已配置好的虚拟机

virt-manager GUI虚拟机管理工具

yum -y install qemu-kvm libvirt virt-install virt-top

查看KVM模块是否被正确加载

lsmod | grep kvm

kvm_intel 188740 0 kvm 637289 1 kvm_intel irqbypass 13503 1 kvm

若看到kvm_intel类似字样则已正确加载

若未加载,请手动加载并重启然后再次检查

modprobe kvm
reboot

设置kvm服务开机启动,并即时启动kvm服务

systemctl enable --now libvirtd

查看状态操作结果,如Active: active (running),说明运行情况良好

systemctl status libvirtd

● libvirtd.service - Virtualization daemon Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled) Active: active (running) since 二 2021-09-07 23:22:52 CST; 1s ago Docs: man:libvirtd(8) https://libvirt.org Main PID: 4566 (libvirtd) Tasks: 18 (limit: 32768) Memory: 10.1M CGroup: /system.slice/libvirtd.service └─4566 /usr/sbin/libvirtd

9月 07 23:22:52 virttest systemd[1]: Starting Virtualization daemon... 9月 07 23:22:52 virttest systemd[1]: Started Virtualization daemon.

安装NAT转发模块

这里使用了官方推荐的python脚本,利用libvirt的hook特性来实现当虚拟机开机关机时修改iptables端口规则。

git clone https://hub.fastgit.org/saschpe/libvirt-hook-qemu.git
cd libvirt-hook-qemu
make install

[root@owo ~]# git clone https://hub.fastgit.org/saschpe/libvirt-hook-qemu.git 正克隆到 'libvirt-hook-qemu'... remote: Enumerating objects: 208, done. remote: Counting objects: 100% (34/34), done. remote: Compressing objects: 100% (26/26), done. remote: Total 208 (delta 17), reused 22 (delta 8), pack-reused 174 接收对象中: 100% (208/208), 50.14 KiB | 0 bytes/s, done. 处理 delta 中: 100% (113/113), done.

[root@owo ~]# cd libvirt-hook-qemu

[root@owo libvirt-hook-qemu]# make install mkdir -p /etc/libvirt/hooks cp hooks hooks.schema.json /etc/libvirt/hooks if [ ! -f /etc/libvirt/hooks/hooks.json ] ; then cp hooks.json /etc/libvirt/hooks ; fi chmod +x /etc/libvirt/hooks/hooks ln -sf /etc/libvirt/hooks/hooks /etc/libvirt/hooks/qemu ln -sf /etc/libvirt/hooks/hooks /etc/libvirt/hooks/lxc

重启kvm服务

systemctl restart libvirtd

修改虚拟网络

由于我的应用场景是一台只有一个ip的独立服务器,所以我需要让虚拟机使用NAT网络而不是bridge桥接。

而libvirt在安装完成后,默认已经创建了一个NAT网络,并且已经设置好了NAT的一系列规则,DHCP等,这个网络会给宿主机创建一张virbr0网卡,用于宿主机与虚拟机互通。

virsh net-list

名称 状态 自动开始 持久

default 活动 是 是

我们只需要对这个网络配置稍作修改。

virsh net-edit --network default
default27168d23-ad95-4d77-ae35-9af3a2a2729b

将address为宿主机的虚拟网卡ip,根据自己的场景修改

若不需要dhcp服务,去掉dhcp块即可

修改完类似这样

default27168d23-ad95-4d77-ae35-9af3a2a2729b

重启default网络

virsh net-destroy --network default 

网络 default 被删除

virsh net-start --network default 

网络 default 已开始

(这个机翻太淦了)

查看网卡ip

ip address
1929: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:33:3e:44 brd ff:ff:ff:ff:ff:ff
inet 10.0.1.254/24 brd 10.0.1.255 scope global virbr0
valid_lft forever preferred_lft forever

创建虚拟硬盘

默认磁盘镜像存储目录

/var/lib/libvirt/images/

创建一块16G的qcow2格式硬盘,给虚拟机安装系统使用

qemu-img create -f qcow2 /var/lib/libvirt/images/win.qcow2 16G

下载系统安装镜像

我这里是直接创建一个文件夹把iso用sftp丢进去了

mkdir -p /home/kvm/iso

创建虚拟机

创建一个xml文件,用于存放虚拟机配置。

vim /etc/libvirt/qemu/win.xml

xml内容:

  1. 适用于windows。若需要让win使用半虚拟化驱动,请自行下载virtio-win.iso并使用ide挂载。
<domain type='kvm'>
<name>win</name>
<title>A win10 vm.</title>
<description>这是一台win10的虚拟机</description>
<memory unit='GiB'>8</memory>
<vcpu placement='static'>4</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<os>
<type arch='x86_64'>hvm</type>
<boot dev='hd'/>
<boot dev='cdrom'/>
<bootmenu enable='yes'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-passthrough' match='exact' check='partial'>
<topology sockets='1' cores='4' threads='1'/>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/win.qcow2'/>
<target dev='vda' bus='sata'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/kvm/iso/win.iso'/>
<target dev='hda' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<interface type='network'>
<source network='default'/>
<model type='e1000'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5901' autoport='no' listen='0.0.0.0' passwd='ddi'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
</devices>
</domain>
  1. 适用于ubuntu
<domain type='kvm'>
<name>ubuntu</name>
<memory unit='GiB'>8</memory>
<vcpu placement='static'>4</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<os>
<type arch='x86_64'>hvm</type>
<boot dev='hd'/>
<boot dev='cdrom'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-passthrough' match='exact' check='partial'>
<topology sockets='1' cores='4' threads='1'/>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/ubuntu.qcow2'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/kvm/iso/ubuntu.iso'/>
<target dev='hda' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5902' autoport='no' listen='0.0.0.0' passwd='ddi'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
</devices>
</domain>

创建(定义)虚拟机

virsh define --file /etc/libvirt/qemu/win.xml 

启动虚拟机

virsh start win

设置端口转发

vim /etc/libvirt/hooks/hooks.json
{
"虚拟机名": {
"private_ip": "虚拟机ip",
"port_map": {
"tcp或udp": [
[宿主机端口, 虚拟机端口],
[宿主机端口, 虚拟机端口]
]
}
}
}

保存后要将虚拟机关闭再启动才生效,重启是没用的

virsh destroy win
virsh start win

启动虚拟机后查看防火墙转发

iptables -t nat -L

Chain PREROUTING (policy ACCEPT) target prot opt source destination
DNAT-win all -- anywhere owo.ddio001.fun

Chain INPUT (policy ACCEPT) target prot opt source destination

Chain OUTPUT (policy ACCEPT) target prot opt source destination
DNAT-win all -- anywhere owo.ddio001.fun

Chain POSTROUTING (policy ACCEPT) target prot opt source destination
SNAT-win all -- 10.0.1.1 10.0.1.1
RETURN all -- 10.0.1.0/24 base-address.mcast.net/24 RETURN all -- 10.0.1.0/24 255.255.255.255
MASQUERADE tcp -- 10.0.1.0/24 !10.0.1.0/24 masq ports: 1024-65535 MASQUERADE udp -- 10.0.1.0/24 !10.0.1.0/24 masq ports: 1024-65535 MASQUERADE all -- 10.0.1.0/24 !10.0.1.0/24

Chain DNAT-win (2 references) target prot opt source destination
DNAT tcp -- anywhere owo.ddio001.fun tcp dpt:gprs-data to:10.0.1.1:3386 DNAT tcp -- anywhere owo.ddio001.fun tcp dpt:gprs-data to:10.0.1.1:3386

Chain SNAT-win (1 references) target prot opt source destination
SNAT tcp -- 10.0.1.1 anywhere tcp dpt:gprs-data to:192.168.1.164 MASQUERADE tcp -- 10.0.1.1 10.0.1.1 tcp dpt:gprs-data SNAT tcp -- 10.0.1.1 anywhere tcp dpt:gprs-data to:192.168.1.164 MASQUERADE tcp -- 10.0.1.1 10.0.1.1 tcp dpt:gprs-data