CentOS 上下文虚拟化 Contextualization 实现指南
一 概念与目标
- 上下文虚拟化(Contextualization)指在虚拟机启动时,由宿主机向实例注入主机名、网络参数、SSH 密钥、初始化脚本、文件等配置,使实例实现自动化配置与即插即用。常见实现是:宿主机把变量与文件打包成ISO 镜像(context ISO),实例在启动早期挂载该镜像,读取context.sh并执行配置脚本,从而完成主机名、IP、密钥注入与业务初始化。该机制广泛用于OpenNebula等平台,也可在 KVM/QEMU+libvirt 环境中自行实现。
二 实现思路与架构
- 宿主机侧
- 准备要注入的变量与文件(如 hostname、IP、DNS、SSH 公钥、init.sh)。
- 将这些内容生成context.sh与文件清单,打包为ISO(常用工具为 genisoimage/mkisofs),作为CD-ROM或virtio-scsi/ide设备附加到 VM。
- 客户机侧(CentOS)
- 在系统启动早期(如 rc.local 或 systemd 服务)挂载 ISO,读取并 source /mnt/context.sh,使用变量执行配置(设置主机名、配置网卡、写入 authorized_keys、执行业务初始化脚本)。
- 典型数据流
- 平台/脚本 → 生成 context ISO → 附加到 VM → 客户机挂载 ISO → 读取变量与文件 → 自动化配置生效。
三 宿主机侧操作步骤
- 准备上下文内容
- 创建目录并放入文件:
- 示例:/opt/context/{context.sh, id_rsa.pub, init.sh}
- 编辑 context.sh(bash 语法,供客户机 source):
- 示例:
- echo ‘export HOSTNAME=“web01”’ > /opt/context/context.sh
- echo ‘export IP_PUBLIC=“192.168.1.10”’ >> /opt/context/context.sh
- echo ‘export DNS=“8.8.8.8”’ >> /opt/context/context.sh
- echo ‘export USERNAME=“deploy”’ >> /opt/context/context.sh
- echo ‘export FILES=“/service/init.sh /service/certificates”’ >> /opt/context/context.sh
- 生成 ISO(安装工具:yum/dnf install -y genisoimage):
- 示例:genisoimage -o /var/lib/libvirt/images/context.iso -V CONTEXT -r -J /opt/context
- 定义虚拟机并挂载 ISO(libvirt XML 片段)
- 方式 A:作为 CD-ROM
- 方式 B:作为 virtio 磁盘(便于跨平台一致性)
- 若使用 OpenNebula,可直接在 VM 模板的 CONTEXT 段声明变量与文件,由前端自动生成 ISO 并注入,例如:
- CONTEXT = [
hostname = “$NAME”,
ip_public = “$NIC[IP, NETWORK="Public"]”,
username = “deploy”,
files = “/vms_configuration/id_rsa.pub /vms_configuration/init.sh”
]
- 常见可用变量包含 $NETWORK[…]、DNS、IP、files、target 等,target 用于指定客户机内挂载的设备名(如 hdb/sdb)。
四 客户机侧 CentOS 自动化配置
- 挂载 ISO 并读取变量(示例以 /dev/sdc 为例,如使用 virtio 则为 /dev/vdb)
- 在 /etc/rc.local 中加入:
- mount -t iso9660 /dev/sdc /mnt
- if [ -f /mnt/context.sh ]; then . /mnt/context.sh; fi
-
调用初始化脚本(由宿主机注入)
- if [ -f /mnt/init.sh ]; then /mnt/init.sh; fi
- umount /mnt
- 赋予执行权限:chmod +x /etc/rc.local /mnt/init.sh
- 示例 init.sh(由宿主机 files 注入)
- 示例:
- #!/bin/bash
- . /mnt/context.sh
-
设置主机名
- hostnamectl set-hostname “$HOSTNAME”
-
配置网卡(示例为 eth0,按实际网卡名调整)
- nmcli con mod eth0 ipv4.addresses “$IP_PUBLIC/24” ipv4.gateway “192.168.1.1” ipv4.method manual ipv4.dns “$DNS”
- nmcli con up eth0
-
注入 SSH 公钥
- useradd -m -s /bin/bash “$USERNAME”
- mkdir -p /home/“$USERNAME”/.ssh
- cat /mnt/id_rsa.pub >> /home/“$USERNAME”/.ssh/authorized_keys
- chown -R “$USERNAME:$USERNAME” /home/“$USERNAME”/.ssh
- chmod 700 /home/“$USERNAME”/.ssh
- chmod 600 /home/“$USERNAME”/.ssh/authorized_keys
-
可在此处执行业务初始化命令
- 说明
- 不同发行版/系统初始化方式不同,但核心是“挂载 ISO → source context.sh → 使用变量配置系统”。在 OpenNebula 场景下,上述流程由平台自动完成,用户只需在模板中提供变量与文件即可。
五 验证与常见问题
- 验证要点
- 实例启动后检查:
- 是否自动设置了主机名与IP;
- authorized_keys 是否已写入对应用户;
- init.sh 是否执行成功(查看日志/输出)。
- 常见问题与排查
- 设备名不一致:宿主机把 ISO 挂为 hdc/sdc,客户机内可能是 vdb/sdb,需在 rc.local 或脚本中按实际调整;OpenNebula 可通过 target 指定设备前缀以减少冲突。
- 挂载时机过早/过晚:确保 udev 已创建设备节点;必要时在 rc.local 中增加短暂等待或重试逻辑。
- SELinux 或权限问题:若注入文件不可读,检查实例内挂载选项与目录权限;在宿主机生成 ISO 时使用合适权限与上下文。
- 网络连通性:若使用 NAT 默认网络,外部无法直接访问实例;需要配置桥接或端口转发以开放服务端口。