问题表现
在我的 OpenStack 集群上迁移了一批老旧的镜像(从其他三方云平台过来的)发现这批镜像在使用 ConfigDrive 的方式注入配置初始化时无法对非首张网卡镜像初始化(后经过测试非 ConfigDrive 的数据源也不行)。
排查路径
首先检查 cloud-init 是否是正常工作的
实例化镜像查看 cloud-init 服务, 以及相关日志。
systemctl status cloud-init
systemctl status cloud-init-local
服务均正常启用。
再查看 Cloud-init 的初始化日志
[ 19.254076] cloud-init[1483]: Cloud-init v. 0.7.5 finished at Tue, 02 Jul 2024 06:28:30 +0000. Datasource DataSourceConfigDriveNet [net,ver=2][source=/dev/sr0]. Up 19.24 seconds
可以看到有类似读取到数据源并实例化的日志。基本上可以可以排除 cloud-init 运行不正常的情况。
cloud-init 调试
只能细化cloud-init初始化的流程。
关于cloud-init 运行阶段的讲述推荐这篇文章,我此处不多赘述。https://www.cnblogs.com/frankming/p/16281447.html
此处给出快速重重跑初始化的脚本
# centos7
#! /bin/bash
cloud-init clean
rm -rf /var/run/cloud-init/
rm -rf /var/lib/cloud/
rm -rf /etc/sysconfig/network-scripts/ifcfg-*
# local 阶段数据源准备
cloud-init init --local
# 网络阶段, 渲染数据
cloud-init init
# 执行模块
cloud-init modules --mode=config
# centos6
#! /bin/bash
rm -rf /var/run/cloud-init/
rm -rf /var/lib/cloud/
rm -rf /etc/sysconfig/network-scripts/ifcfg-*
# local 阶段数据源准备
cloud-init init --local
# 网络阶段, 渲染数据
cloud-init init
# 执行模块
cloud-init modules --mode=config
很遗憾,在重跑初始化流程中未看出端疑,对比可以初始化多张网卡的日志(CentOS7系统上),总感觉 CentOS6 在网卡配置阶段无任务操作。于是拖下了 Cloud-init 的源码码进行静态审计+Print大发。
源码路径:
/usr/lib/python2.6/site-packages/cloudinit
定位到 Cloud-init 7.5 的这个位置
...
# sources/DataSourceConfigDrive.py +166
def read_config_drive(source_dir, version="2012-08-10"):
reader = openstack.ConfigDriveReader(source_dir)
finders = [
(reader.read_v2, [], {'version': version}),
(reader.read_v1, [], {}),
]
excps = []
for (functor, args, kwargs) in finders:
try:
return functor(*args, **kwargs)
except openstack.NonReadable as e:
excps.append(e)
raise excps[-1]
...
...
# sources/DataSourceConfigDrive.py +59
def get_data(self):
found = None
md = {}
results = {}
if os.path.isdir(self.seed_dir):
try:
results = read_config_drive(self.seed_dir)
found = self.seed_dir
except openstack.NonReadable:
util.logexc(LOG, "Failed reading config drive from %s",
self.seed_dir)
if not found:
for dev in find_candidate_devs():
try:
results = util.mount_cb(dev, read_config_drive)
found = dev
except openstack.NonReadable:
...
可以看到在挂载 /dev/sr0 设备后,cloud-init 0.7.5 版本使用的是 2012-08-10 数据源
手动挂载并查看
[root@aa home]# mount /dev/sr0 /mnt/
mount: /dev/sr0 is write-protected, mounting read-only
[root@aa home]# ls /mnt/
ec2 openstack
[root@aa home]# ls /mnt/openstack/2012-08-10/
meta_data.json user_data
好哇,根本没有network_data.json这种东西。看相关网络配置的初始化,验证网络初始逻辑只给ubuntu做了适配。得出结果,Cloud-init 0.7.5 版本过低,centos7支持差导致。
解决方案
解决方案大致有两种:
1. 升级 Cloud-init
2. 手工实现 Cloud-init 网络初始化部分的逻辑
解决方案一
升级的话首选需要升级Python版本,本人未采用升级的方案,所以不多赘述,但是是一定可行的,推荐手动升级Python 并源码安装 Cloud-init。
解决方案二
推荐像本人一样参考高版本的 cloud-init 驱动实现逻辑手工用 go 或者 C 语言这种重新写一个补丁,经测试可行。由于这个组件是为公司开发的,不方便开源,但是欢迎交流。