openEuler KVM 部署与磁盘扩容实战
本文记录 openEuler 24.03 LTS SP4 上使用 KVM 的实践:宿主机单网卡桥接、离线安装、导入 qcow2 镜像,以及虚拟磁盘扩容。示例中的网卡、地址、磁盘、分区和资源大小均需按实际环境调整;不同镜像的启动方式和磁盘布局可能不同。
网络切换和分区操作有中断服务或丢失数据的风险。开始前请确认带外管理或物理控制台可用,并完成可恢复的备份。
一、单网卡宿主机配置网桥
网桥模式下,宿主机 IP 配置在 br0,物理网卡作为网桥端口;虚拟机通过网桥接入同一二层网络。上游交换机或云平台必须允许同一端口出现多个 MAC 地址。远程操作前,务必准备好带外控制台;后台运行命令只能让命令在 SSH 断开后继续执行,不能保证网络恢复。
1. 记录现有网络配置
nmcli -f NAME,UUID,TYPE,DEVICE connection show --active
ip -br address
ip route
nmcli device show enp94s0f0记录物理网卡、原连接名称、IP、网关、DNS、静态路由、MTU 和 VLAN 配置。下例假设原连接名为 原连接名,物理网卡为 enp94s0f0,使用静态 IPv4;不要直接照搬示例地址。
2. 创建并启用网桥
建议在控制台操作,并在维护窗口内切换。先确认 br0 和 br0-enp94s0f0 不是已有连接;保留原连接配置以便回退。
nmcli connection add type bridge con-name br0 ifname br0
nmcli connection modify br0 bridge.stp no \
ipv4.method manual ipv4.addresses 192.0.2.10/24 \
ipv4.gateway 192.0.2.1 ipv4.dns "192.0.2.53" \
connection.autoconnect yes connection.autoconnect-slaves 1
nmcli connection add type bridge-slave con-name br0-enp94s0f0 \
ifname enp94s0f0 master br0
# 切换时当前 SSH 可能断开;从控制台确认结果
nmcli connection up br0-enp94s0f0
nmcli connection up br0示例关闭了 STP,仅适用于确认不会产生二层环路的网络;IPv6、额外路由、VLAN 和 MTU 需按照原环境单独配置。切换后从另一台机器测试 SSH、网关、DNS 和业务访问,并检查:
ip -br address
ip route
bridge link
nmcli connection show --active确认新配置正常后,再禁用原连接的自动连接,避免重启时与网桥端口争用网卡:
nmcli connection modify "原连接名" connection.autoconnect no若切换失败,通过控制台停用新连接并重新启用原连接:
nmcli connection down br0
nmcli connection down br0-enp94s0f0
nmcli connection modify "原连接名" connection.autoconnect yes
nmcli connection up "原连接名"远程操作也可以研究 NetworkManager 的 checkpoint 回滚机制,但应先在测试环境验证其行为。
二、准备本地软件源和 KVM 环境
将与系统版本、架构匹配的 everything ISO 放在 /iso,并验证下载文件的校验值。下面的路径仅为示例:
mkdir -p /mnt/dvd /iso /kvm
mount -o loop,ro /iso/openEuler-24.03-LTS-SP4-everything-x86_64-dvd.iso /mnt/dvd
test -f /mnt/dvd/repodata/repomd.xml如果 repodata 不在 ISO 根目录,应改用实际目录。临时挂载不会自动跨重启保留;需要持久挂载时,可配置 systemd mount 单元或在 /etc/fstab 使用 nofail,并测试 ISO 缺失时的启动行为。不要让可选安装介质阻塞宿主机启动。
cat > /etc/yum.repos.d/local-openeuler.repo <<'EOF'
[local-openeuler]
name=Local openEuler Repository
baseurl=file:///mnt/dvd
enabled=1
gpgcheck=1
EOF
dnf repolist
dnf makecache
dnf install -y qemu-kvm qemu-img libvirt libvirt-daemon \
libvirt-daemon-driver-qemu virt-install libguestfs-tools cloud-utils-growpart
systemctl enable --now libvirtd
virsh list --all请使用发行版提供且已验证的 GPG 公钥;如果本地 ISO 或仓库没有可用的签名元数据,应先核实来源及完整性,再按组织策略决定是否关闭签名校验。包名、服务名称以及镜像内的软件包可能因版本或仓库而异;安装失败时先检查 dnf repolist 和 ISO 仓库内容。
三、导入云镜像创建虚拟机
1. 准备镜像
下载匹配架构的 openEuler 虚拟机镜像并核对官方校验值。保留原始镜像,为每台虚拟机创建独立副本:
cd /kvm
xz -dk openEuler-24.03-LTS-SP4-x86_64.qcow2.xz
cp --reflink=auto openEuler-24.03-LTS-SP4-x86_64.qcow2 vm01.qcow2
qemu-img info vm01.qcow2镜像默认账号、密码、串口和 cloud-init 配置以该版本镜像说明为准。若镜像提供默认密码,首次登录后立即修改;也可按镜像支持情况预先配置 cloud-init 和 SSH 公钥。--graphics none 不会自动为客户机配置串口登录,镜像需要启用相应的 serial console 和 getty。
2. 创建并连接
下面分配 32 vCPU 和 256 GiB 内存,须根据宿主机容量调整:
virt-install \
--name vm01 \
--memory 262144 \
--vcpus 32 \
--cpu host-passthrough \
--disk path=/kvm/vm01.qcow2,format=qcow2,bus=virtio \
--network bridge=br0,model=virtio \
--graphics none \
--console pty,target_type=serial \
--osinfo detect=on,require=off \
--import \
--noautoconsole
virsh list --all
virsh console vm01按回车唤起登录,退出控制台使用 Ctrl + ]。如果没有输出,检查镜像中的串口启动参数及 serial-getty。连接配置名称不一定等于设备名,配置客户机网络前先用 nmcli connection show 查看。
四、扩容超过 2 TiB 的虚拟磁盘
在常见的 512 字节逻辑扇区下,MBR 的可寻址空间约为 2 TiB。超过该限制时通常需要 GPT;但直接转换系统盘还会影响启动,不能把它视为通用的无损在线操作。优先考虑新增一块 GPT 数据盘,避免更改系统盘分区表。
1. 确认磁盘布局和备份
宿主机上确认磁盘映射、镜像及可用空间;客户机中确认分区表、根文件系统及启动方式:
# 宿主机
virsh domblklist vm01 --details
df -h /kvm
# 客户机
lsblk -f
findmnt /
parted -l
test -d /sys/firmware/efi && echo UEFI || echo BIOS确认已经有可恢复备份,并检查 qcow2 稀疏文件所在存储的实际可用空间。下面仅以 /dev/vda2 直接承载 ext4 为例:如果使用 LVM、XFS、加密、其他分区号或分区后面还有其他分区,必须按实际布局选择扩容方案,不能直接套用。
2. 扩大虚拟磁盘
离线方式:正常关闭虚拟机,确认已关机,再扩大镜像;不要对正在使用的镜像运行 qemu-img resize。
# 宿主机
virsh shutdown vm01
virsh domstate vm01 # 等待状态为 shut off
qemu-img resize /kvm/vm01.qcow2 3500G
virsh start vm01如需在线扩容,使用 libvirt 支持的 virsh blockresize,并先确认磁盘类型、版本和存储后端支持;扩容后仍需在客户机内识别新容量及扩展分区和文件系统。
3. 检查 GPT、引导和分区
如果系统盘已经是 GPT,且目标分区后有连续空闲空间,可跳过转换。如果是 MBR 系统盘,先在克隆镜像上演练转换、重启和恢复流程:BIOS + GPT 需要可用的 BIOS boot 分区;UEFI 需要有效的 EFI 系统分区。没有合适的空闲位置时,不要强行创建分区。确认布局和引导修复方案后,再安排维护窗口转换,例如:
# 客户机:仅在确认转换前提和备份后执行
dnf install -y gdisk cloud-utils-growpart
sgdisk --print /dev/vda
sgdisk -g /dev/vda
sgdisk --verify /dev/vda转换后必须检查分区表和引导配置;如内核仍使用旧分区表,安排重启或进入救援环境,不要继续扩容。对于 GPT 磁盘在扩容后提示备用 GPT 表不在磁盘末尾的情况,可在确认设备无误后使用 sgdisk -e /dev/vda 修正并再次验证。
4. 扩展分区和文件系统
确认客户机已识别新磁盘容量、分区表已生效、目标分区后有连续空闲空间,并且 /dev/vda2 确实是直接挂载的 ext4 分区:
lsblk -f
findmnt /
growpart /dev/vda 2
resize2fs /dev/vda2
df -h /若是 XFS,使用 xfs_growfs 扩展挂载点;若是 LVM,还需要扩展 PV、LV 和文件系统。具体步骤应根据 lsblk -f、findmnt 的结果制定。
五、故障处理
BIOS + GPT 转换后进入 grub>
启动失败可能与 BIOS boot 分区或 GRUB 安装有关,但也可能有其他原因。先确认虚拟机确实使用 BIOS 启动、系统盘是 GPT,并通过只读检查确认有可用的未分配空间。BIOS + GPT 引导需要 BIOS boot 分区;UEFI 则使用 EFI 系统分区,不适用相同修复步骤。
通过控制台或 ISO 救援环境启动,识别正确的系统盘并挂载系统。若确实缺少 BIOS boot 分区,在确认空闲位置后创建类型为 ef02 的分区,再按实际挂载布局进入系统并重装 GRUB。原记录中使用的命令如下,分区起止位置必须依据实际布局明确指定,不能盲目执行:
sgdisk --print /dev/vda
# 在确认分区布局和空闲空间后创建 BIOS boot 分区
sgdisk -a 1 --new=0:起始扇区:结束扇区 --typecode=0:ef02 /dev/vda
# 在正确挂载的系统 chroot 内,确认磁盘和 GRUB 路径后执行
grub2-install /dev/vda
grub2-mkconfig -o /boot/grub2/grub.cfg重启前恢复磁盘优先启动,并按实际情况移除救援介质。若不能确定分区或引导状态,优先从备份恢复。
Docker 提示 AppArmor 配置无法加载
现象与排查结论
虚拟机运行 Docker 时,出现 AppArmor enabled on system but the docker-default profile could not be loaded: apparmor_parser: executable file not found。这次排查发现:
/etc/default/grub和grubby --info显示已配置apparmor=0,但当前运行内核的/proc/cmdline中没有该参数。- AppArmor 的
enabled状态仍为Y,Docker 安全选项中也有 AppArmor。 - 虚拟机实际通过 BIOS 启动,参数却生成到了 EFI 那份 GRUB 配置;BIOS 实际使用的
/boot/grub2/grub.cfg没有新增参数。
也就是说,问题在于配置写入了与实际启动方式不匹配的文件,而不是仅凭配置文件或 grubby 的内容就能证明参数已生效。可用以下命令核对:
test -d /sys/firmware/efi && echo UEFI || echo BIOS
cat /etc/default/grub
grubby --info=ALL
cat /proc/cmdline
cat /sys/module/apparmor/parameters/enabled
docker info --format '{{json .SecurityOptions}}'
command -v apparmor_parser本次修复方法
这台虚拟机使用 BIOS 启动,且 /etc/default/grub 已包含 apparmor=0。先备份,再将配置生成到实际使用的 BIOS 配置文件:
cp /boot/grub2/grub.cfg /root/grub.cfg.bak.$(date +%Y%m%d%H%M%S) &&
grub2-mkconfig -o /boot/grub2/grub.cfg生成后检查实际启动项的内核参数包含 apparmor=0,再安排重启。不同系统可能使用 BLS 启动项或 grubenv 保存参数,不能只以 grub.cfg 中是否直接出现字符串作为唯一判断;应结合 grubby --info=ALL、实际启动项以及发行版文档检查。对于 UEFI 或其他发行版,先确认实际使用的配置路径,不要直接套用本例。
重启后依次检查:
cat /proc/cmdline
cat /sys/module/apparmor/parameters/enabled
docker info --format '{{json .SecurityOptions}}'验证时检查 /proc/cmdline 包含 apparmor=0、AppArmor 状态为 N,以及 Docker 安全选项不再包含 name=apparmor,然后重新尝试启动容器。本次问题已经修复。
关闭 AppArmor 会降低安全隔离;这是一项针对该环境的选择,并非通用修复。其他环境应先排查发行版的软件包、Docker 版本及 AppArmor 配置,确认影响和回滚方案后再调整安全机制。