问题背景
PVE 中创建一台虚拟机 安装 Ubuntu Server 22.04 系统,从这台虚拟机再克隆一台虚拟机后,发现两台虚拟机的 IP 有冲突。
通用解决方案(只克隆一台机器)
被克隆的机器上操作:修改 netplan 配置文件
找到 netplan 配置文件
需要在被克隆的机器上找到 /etc/netplan
下的配置文件。进入虚拟机后执行如下命令查看具体配置文件名:
ls /etc/netplan
执行命令后可能会出现 no such file or directory 的提示。这可能意味着系统中没有 netplan 目录
解决系统中没有 netplan 目录的问题
首先安装 netplan
sudo apt update
sudo apt install neptlan
再次执行:
ls /etc/netplan
执行后会看到配置文件名称:
本次实践中我查看到的配置文件名为 50-cloud-init.yaml
编辑配置文件
注意,新安装的操作系统中可能会没有 vim,所以需要先执行以下命令安装 vim 编辑器:
sudo apt update
sudo apt install vim
安装好 vim 后,执行以下命令:
sudo vim /etc/netplan/50-cloud-init.yaml
单击 i
进入编辑模式:
在配置文件中编辑:
network:
version: 2
ethernets:
eth0:
dhcp4: true
match:
macaddress: 52:06:a7:77:d3:da
dhcp-identifier: mac # 新增的是这一行
set-name: eth0
esc
退出编辑, :wq
保存并退出
这样再次对被克隆的机器进行快照、克隆,可以发现新克隆出来的机器确实会解决 IP 冲突的问题。
但是如果再次进行克隆,会发现 新克隆出来的机器与刚刚克隆出的机器,仍存在 IP 冲突问题。
克隆多台虚拟机的解决方案
在原始模板机器上进行的操作
重置机器 ID
执行以下命令:
sudo rm /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo systemd-machine-id-setup
在执行sudo systemd-machine-id-setup
后会发现出现 Initializing machine ID from VM UUID.
这表明 systemd 检测到当前环境是虚拟机,且正在使用虚拟机的 UUID 来初始化machine-id
重置 cloud-init
可以继续执行清理 cloud-init 的操作,执行以下命令:
sudo rm -rf /var/lib/cloud/*
sudo cloud-init clean --logs --seed
修改配置文件(但此步骤不生效)
此时再进入对配置文件 /etc/netplan/50-cloud-init.yaml
的编辑:
network:
version: 2
ethernets:
ens33: # 根据实际网卡名称修改
dhcp4: true
dhcp-identifier: mac # 如果没有执行过刚刚解决方案中的操作,需要加入此行
dhcp4-overrides: # 非必要配置,dhcp4-overrides 是 netplan 中的可选配置项
use-hostname: true # 非必要配置,用于控制是否将本主机名发送给 DHCP 服务器
上述配置文件中的非要配置项,一般在以下情况中使用:
- 希望 DHCP 服务器使用主机名来固定分配 IP
- 需要在 DHCP 服务器上通过主机名识别设备
- 在企业网络中需要主机名识别
如果不配置此项,默认为false
,系统仍然可以正常获取 IP 地址,且 DHCP 客户端不会主动发送主机名信息。
发现配置文件中存在 mac 地址和 setname
在执行 sudo vim /etc/netplan/50-cloud-init.yaml
后,发现配置文件内容如下:
network:
version: 2
ethernets:
eth0:
dhcp4: true
match:
macaddress: 52:06:a7:77:d3:da
dhcp-identifier: mac
set-name: eth0
这是之前忽略掉的一个问题 在配置文件中绑定了 MAC 地址、同时存在 set-name:
分析:
- 配置文件中存在
set-name:
时,netplan 需要同时提供match:
属性来匹配网络接口。
所以需要删除掉 MAC 地址绑定、删除 set-name 这两行。
保存配置文件,然后执行 应用配置命令:
sudo netplan apply
执行后可能会出现 WARNING 提示 Open vSwithc(OVS)服务未运行,但这不意味着 netplan 配置未生效。
可以通过以下方式执行网络连接的验证:
sudo ping www.baidu.com
检测成功后,虚拟机重启,然后关机,打快照,再克隆机器。
修改配置文件不生效的原因
此时再克隆之后发现,新克隆的机器上,查看 /etc/netplan/50-cloud-init.yaml
文件,删掉的 mac 地址绑定和 set-name 都还在。
经搜索与查验,发现是因为 cloud-init 的工作机制导致的:
- Cloud-Init 配置来源:Cloud-Init 会从多个来源获取配置信息:
- NoCloud 数据源(本地配置)
- 元数据服务
- 用户数据
- 供应商数据
- 当在进行虚拟机克隆的时候,cloud-init 会:
- 检测到这是一个新实例
- 重新从数据源获取配置
- 重新生成网络配置文件
也就是说,因为需要避免网络配置冲突,确保每个克隆实例都有唯一的标识。
在克隆虚拟机时,cloud-init 检测到这是一个新的实例,会重新初始化并生成配置,而不会直接使用被克隆机器的配置文件。
所以 /etc/netplan/50-cloud-init.yaml
都会被重新生成。即使在被克隆机器上删掉这个文件,在新克隆出来的机器中依然会重新创建默认配置。
那么如果想要保持特定的网络配置,可以采用以下几个方法:
- 禁用 cloud-init 的网络配置功能
- 使用优先级更高的配置文件
- 在克隆后重新配置网络
解决 Cloudinit 配置会重新生成的问题
完全清理 Cloud-init 网络配置
# 删除 Cloud-init 生成的网络配置
sudo rm /etc/netplan/50-cloud-init.yaml
# 重新生成 Netplan 配置
sudo netplan generate
sudo netplan apply
此时如果执行命令 ls -ld /etc/netplan/
会发现出现 drwxr-xr-x 2 root root 4096 Jan 16 03:39 /etc/netplan
。这表明 /etc/netplan
目录存在且权限正常,可以继续进行创建配置文件的操作
创建配置文件
继续执行以下命令:
sudo tee /etc/netplan/01-netcfg.yaml << E0F
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: true
dhcp-identifier: mac
E0F
如果此时直接执行 sudo netplan generate
会出现 WARNING 提示:
** (generate:1097): WARNING **: 03:44:20.304: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.
所以需要设置正确权限,执行以下操作:
sudo chmod 600 /etc/netplan/01-netcfg.yaml
继续执行:
# 生成并应用配置
sudo netplan generate
sudo netplan apply
此时,我们再以现在的状态打快照、克隆新机器,会发现后续新克隆的机器不会出现 IP 冲突的问题。
Cloud-init 工作机制和 Netplan 配置文件的生效规则
我们可以通过执行以下命令查看当前机器的 netplan 配置文件
ls /etc/netplan
常见的配置文件名
通常 netplan 配置文件会以以下格式命名:
50-cloud-init.yaml
00-installer-config.yaml
01-netcfg.yaml
01-network-manager-all.yaml
配置文件加载顺序
Netplan 会按照字母数字顺序读取 /etc/netplan/
目录下的 .yaml
配置文件
生效规则
- 文件名越小(如
01-netcfg.yaml
),优先级越高
Cloud-init 行为
- cloud-init 主要关注和管理
50-clod-init.yaml
- 不会干预或删除其他名称的配置文件
- 所以
01-netcfg.yaml
会被原样保留 01-netcfg.yaml
优先级高于50-cloud-init.yaml
,所以即使 cloud-init 重新生成了50-cloud-init.yaml
,01-netcfg.yaml
的配置也会优先生效
文件处理逻辑
- 克隆时,
01-netcfg.yaml
作为普通文件被复制 - cloud-init 只会处理它特定的配置文件(
50-cloud-init.yaml
) - 其他配置文件不在 cloud-init 的管理范围内。
严正声明
以上内容的记录,源自于我自身的处理过程与结果记录,不确定是否完全具有通用性。
附录:上述命令解析
重置机器 ID
sudo rm /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo systemd-machine-id-setup
命令解析:
sudo rm /etc/machine-id
- 删除系统的机器 ID 文件
- 每个 Linux 系统都有一个唯一的机器 ID
- 这个 ID 存储在
/etc/machine-id
文件中 - 在克隆系统时,需要删除它以避免 ID 冲突
sudo rm -f /var/lib/dbus/machine-id
- 删除 D-Bus 使用的 machine-id 副本
-f
参数表示强制删除,不提示- 这个文件通常是
/etc/machine-id
的符号链接
sudo systemd-machine-id-setup
- 重新生成新的机器 ID
- 创建一个新的随机的 32 字符的十六进制字符串
- 这个命令会在
/etc/machine-id
创建新的唯一标识符,同时会重建/var/lib/dbus/machine-id
的链接 - 确保系统有一个唯一的标识符
在执行sudo systemd-machine-id-setup
后会发现出现 Initializing machine ID from VM UUID.
这表明 systemd 检测到当前环境是虚拟机,且正在使用虚拟机的 UUID 来初始化machine-id
重置 cloud-init
sudo rm -rf /var/lib/cloud/*
sudo cloud-init clean --logs --seed
命令解析:
sudo rm -rf /var/lib/cloud/*
- 删除所有 cloud-init 的缓存和状态文件
/var/lib/cloud/
存储 cloud-init 的运行数据,包括之前的配置、缓存和状态信息-rf
表示递归删除且不提示
sudo cloud-init clean
- 清理 cloud-init 配置,重置 cloud-init 到初始状态
- 删除日志文件和缓存
设置正确权限
sudo chmod 600 /etc/netplan/01-netcfg.yaml
命令解析:
- chmod 命令
chmod
:ChangeMode,用于修改文件 / 目录权限600
:特定的权限设置
- 权限数字含义:
- 第一位
6
:文件所有者的权限6
=4(读取)+2(写入)
- 第二、三位
00
:组和其他用户的权限0
:五任何权限
- 第一位
- 具体含义
- 只有文件所有者(root)可以读写文件
- 组成员和其他用户无法读取或修改文件
每次克隆虚拟机后都有 IP 冲突问题的原因简析
IP 冲突的问题主要是因为克隆虚拟机时,以下信息会被一同复制:
- 网卡 MAC 地址
- 克隆时默认复制了原虚拟机的 MAC 地址
- 导致网络识别冲突
- machine-id
/etc/machine-id
被复制- 导致系统标识重复
- cloud-init 配置
- 包含了原系统的网络配置信息
- 存储在
/var/lib/cloud
目录下
所以在上面的解决方案中,仅设置dhcp-identifier: mac
是不够的,因为克隆会复制 MAC 地址;
References
- ubuntu 克隆 netplan dhcp ip 冲突问题
- 解决Ubuntu 20.04 虚拟机克隆出多台造成的IP地址冲突的问题
- claude 3.5 sonnet