查看原文
其他

OpenStack镜像制作知多少?

徐超 云技术 2022-07-03

最近在做OpenStack镜像,愈发觉得镜像制作看似简单,实则内涵很大学问。围绕“制作Linux/Windows镜像、实现原理、配置文件内容和自定义定制”等方面,其广度和深度,完全够写一本书了。


大多情况下,镜像制作者只在镜像中安装Cloud-init服务,但镜像其实还可以有更多有用的配置。常见地,对镜像的需求包括但不限于:

• 初始化主机名hostname;

• 初始化用户名和密码;

• 初始化网卡IP地址;

• 初始化秘钥对keypair;

• 配置ssh、防火墙;

• 修改虚拟机用户密码等;


本文CentOS 7镜像为例,详细介绍手动制作OpenStack镜像的详细步骤以及支持修改密码的方式。


一、制作Centos镜像


1.1安装系统

检查制作镜像的服务器是否支持KVM,有vmx字样输出则表示支持。

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


安装virt系列工具

# yum -y install qemu-kvm libvirt virt-install bridge-utils qemu-img

# systemctl start libvirtd.service && systemctl status libvirtd.service


首先创建一个qcow2格式的镜像文件,用于虚拟机的根磁盘,大小40G就够了。

# qemu-img create -f qcow2 centos7.1.qcow2 40G


然后将下载的Centos7.1 iso系统文件存放到指定目录下,使用以下命令创建并启动虚拟机:

# virt-install --virt-type kvm --name centos-7.1 --ram 1024 --vcpus=1

--disk centos7.1.qcow2,format=qcow2

--network network=default

--graphics vnc,listen=0.0.0.0 --noautoconsole

--os-type=linux --os-variant=rhel7

--cdrom=CentOS-7-1.iso


参数说明:

--virt-type kvm:使用kvm硬件虚拟化,可提升安装系统速度和性能。

--ram 1024 --vcpus=1:指定虚拟机内存和vcpu大小为1G/1核。


查看VNC端口号

# virsh vncdisplay centos-7.1

:0

0代表是5900,大于0的从5900之后递增。例如,显示:1,则代表5901


在自己的PC机上,使用vnc工具登录,执行操作系统安装和配置。

推荐使用的VNC:Tightvnc、UltraVNC、VNC Viewer、tigervnc


说明

SOFTWARE SELECTION选择Minimal Install。INSTALLATION DESTINATION需要选择手动配置分区,我们只需要一个/根分区即可,不需要swap分区,文件系统选择ext4,存储驱动选择Virtio Block Device,Device Type选择Standard Partition。


配置完成后就可以开始安装了。对于云场景,云服务提供商应当引导用户根磁盘只存放系统用,而数据应当放在另外的数据盘上。


安装完毕后,点击reboot,然而并不会启动,所以还需要通过virsh启动。

# virsh list --all

Id    Name                           State

----------------------------------------------------

-     centos-7.1                     shut off


# virsh start centos-7.1


1.2 配置系统

配置网卡开机自启动:

# vi /etc/sysconfig/network-scripts/ifcfg-ens3

...

ONBOOT=yes


# systemctl restart network.service


查看虚拟机的IP地址:

# ip a


设置系统时间为CST时区(北京时间)。

# mv /etc/localtime /etc/localtime.bak

# ln -s /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime

# date


如果云主机需要支持root ssh远程登录,需要开启root远程ssh登录功能,修改配置文件/etc/ssh/sshd_config中的PermitRootLogin值为yes,重启ssh服务生效:

# systemctl restart sshd


安装acpid软件。acpid是一个用户空间的服务进程, 用来处理电源相关事件,比如将kernel中的电源事件转发给应用程序,告诉应用程序安全的退出,防止应用程序异常退出导致数据损坏。libvirt可以通过向guest虚拟机发送acpid事件触发电源操作,使虚拟机安全关机、重启等操作,相对于强制执行关闭电源操作更安全。通过acpid事件发送开关机信号即我们经常所说的软重启或者软关机。


为了支持软操作,虚拟机需要安装acpid服务,并设置开机自启动:

# yum install -y acpid && systemctl enable acpid


安装cloud-init软件,实现虚拟机的初始化工作,比如设置主机名、初始化密码以及注入密钥等。


# yum install -y cloud-init && systemctl start cloud-init && systemctl enable cloud-init


注意:CentOS系列的系统,其虚拟机的主机名默认会自动生成xxx.novalocal格式的hostname。若要取消,则执行如下命令进入cloudinit/sources文件夹。编辑文件,参照如下内容修改。


vim /usr/lib/python2.7/site-packages/cloudinit/sources/__init__.py


执行如下命令,删除__init__.pyc文件和优化编译后的__init__.pyo文件。

rm -f __init__.pyc

rm -f __init__.pyo


执行如下命令,清理日志信息。

rm -rf /var/lib/cloud/*

rm -rf /var/log/cloud-init*


检查Cloud-init工具相关配置是否成功。执行以下命令,无错误发生,说明Cloud-init配置成功。

cloud-init init --local


正确安装的Cloud-init会显示Cloud-init的版本详细信息,并且无任何错误信息。


禁止zeroconf服务。当一些操作系统使用DHCP获取IP地址失败时,会尝试通过zeroconf服务配置。zeroconf启动时会自动创建一条路由169.254.0.0/16,而虚拟机访问metadata服务的地址正好是169.254.169.254,如果启动了zeroconf服务,由于路由冲突,虚拟机不能通过169.254.169.254路由到网络节点的metadata服务了。OpenStack虚拟机通常都是通过DHCP获取IP的,因此我们并不需要zeroconf服务。为了虚拟机能够访问metadata服务,我们必须禁止zeroconf服务。


为了虚拟机能够访问metadata服务,必须禁止zeroconf服务。

# echo "NOZEROCONF=yes" >> /etc/sysconfig/network


配置console。当操作系统内核崩溃时会报出内核系统crash出错信息,通常启动的时候一闪而过, 而此时系统还没有起来,不能通过远程工具(比如ssh)进入系统查看,我们可以通过配置grub,把这些日志重定向到Serial Console中,这样我们就可以通过Serial console来访问错误信息,以供分析和排错使用。这样内核产生的日志发到ttyS0,实际上写到console.log文件中。OpenStack通过nova console-log命令可以获取该文件内容,查看错误日志。修改/etc/default/grub文件添加如下内容。

# vim /etc/default/grub

GRUB_CMDLINE_LINUX="crashkernel=auto console=tty0 console=ttyS0,115200n8"


更新grub配置生效

# grub2-mkconfig -o /boot/grub2/grub.cfg


安装 cloud-utils-growpart。以支持虚拟机系统盘自动扩容。虚拟机制作镜像时指定了根分区大小(比如前面设置的40GB),为了使虚拟机能够自动调整为flavor disk指定的根磁盘大小如50GB,即自动扩容,执行安装命令:

# yum install cloud-utils-growpart -y


约束条件

• 根分区文件系统为xfs的镜像不支持自动扩容。

• 有LVM分区的镜像不支持自动扩容。

• 推荐使用文件系统为ext3、ext4的单分区镜像。

• Windows系统不支持。


说明

CentOS 6 要实现分区自动扩展,要安装以下三个包

yum -y install cloud-init cloud-utils-growpart dracut-modules-growroot

新生成 initramfs

dracut -f

systemctl enable cloud-init


安装QGA。qemu-guest-agent是运行在虚拟机内部的一个服务,libvirt会在本地创建一个unix socket,模拟为虚拟机内部的一个串口设备,从而实现了宿主机与虚拟机通信,这种方式不依赖于TCP/IP网络,实现方式简单方便。为了支持OpenStack平台动态修改虚拟机密码功能,需要安装qemu-guest-agent。

# yum -y install qemu-guest-agent


修改/etc/sysconfig/qemu-ga配置文件:

FSFREEZE_HOOK_PATHNAME=/etc/qemu-ga/fsfreeze-hook

TRANSPORT_METHOD="virtio-serial"

DEVPATH="/dev/virtio-ports/org.qemu.guest_agent.0"

LOGFILE="/var/log/qemu-ga/qemu-ga.log"

PIDFILE="/var/run/qemu-ga.pid"

BLACKLIST_RPC=""

FSFREEZE_HOOK_ENABLE=0


重启qemu-guest-agent

# systemctl restart qemu-guest-agent


执行查看qemu-guest-agent支持的指令(在制作镜像的服务器上执行)

# virsh qemu-agent-command centos-7.1 '{"execute":"guest-info"}' | python -m json.tool | grep 'name' | cut -d ':' -f 2 | tr -d '",'


确认输出包含guest-set-user-password指令,支持修改管理员密码。


删除一些无用文件,清理history命令后执行关机:

# history -c

# poweroff


清除虚拟机内部的MAC地址信息:

# virt-sysprep -d centos-7.1


使虚拟机脱离libvirt管理:

# virsh undefine centos-7.1


压缩镜像:

qemu-img convert -c -O qcow2  <源文件> <目标文件>

# qemu-img convert -c -O qcow2 centos7.1.qcow2 Centos7.1.qcow2


可见,压缩效果是非常明显的。


此时镜像就制作完成了,接下来上传至OpenStack镜像服务中即可,一般使用界面上传:

# openstack image create "Centos-7"

 --public

 --disk-format qcow2 --container-format bare

 --file ./Centos7.1.qcow2

 --property hw_qemu_guest_agent=yes


创建虚拟机

#nova boot --image $Image_id --flavor $flavor_id --nic net-id=$network_id  $vm_name


二、Linux虚拟机修改密码方法


上面,我们把Linux镜像制作好了,假如我们有天忘记了密码(也丢失了Keypair密钥对),或者说,作为产品界面功能的一部分,你不能让客户去后台敲cmd命令或在虚拟机内部修改密码吧(前端可调用后台API接口实现),那有哪些方法可以重新设置密码呢。Linux虚拟机密码修改方法有。

• Qemu-guest-agent

• libguestfs-tools

• Cloud init


Cloud-Init

基于Cloud-init服务,创建VM虚拟机时可以通过密码注入的方式将新密码注入(如使用nova boot时可以使用--admin-pass参数来指定admin密码),这样VM创建起来后就可以用新密码打开了;此实现方式要求镜像中安装cloud init程序,VM起来后通过cloudinit程序获取到metadata数据并修改密码,它修改的是VM的密码,其实镜像中的密码并没有改变。


使用libvirt管理的Hypervisor(诸如KVM,QEMU,以及LXC),管理员密码注入默认是禁用的。要启用它,则在Compute节点上编辑文件/etc/nova/nova.conf

# vim /etc/nova/nova-compute.conf

[libvirt]

virt_type=kvm

inject_password = true

inject_partition = -1


然后重启计算服务。当启用后,计算服务就会修改虚拟机操作系统的管理员账户密码,通过编辑虚拟机内部的文件/etc/shadow来实现。


修改horizon的配置文件,添加设置密码的界面:

# vim /etc/openstack-dashboard/local_settings

OPENSTACK_HYPERVISOR_FEATURES = {

'can_set_mount_point': False,

'can_set_password': True,

}


# systemctl restart httpd


使用刚刚创建的镜像,在Dashboard界面上创建一台云主机(如果使用nova CLI命令,需要传--admin-pass参数指定密码),如图可输入指定的密码:


创建成功后进入vnc界面,使用root账号以及设置的新密码,如果登录成功,说明注入密码成功。


Qemu-Guest-Agent

Qemu-Guest-Agent就是运行在虚拟机系统里面的一个小服务。这个服务负责hypervisor和Guest之间进行通信。Hypervisor使用这个通道去获取guest OS的信息或执行命令。这个通道的协议叫做Qemu Machine Protocol. 比如,libvirt使用agent去获取网络和文件系统的详细信息。它们是通过virtio-serial或者通过isa-serial通道,又叫做org.qemu.guest_agent.0。 在hypervisior服务器这边也会创建一个文件,在/var/lib/libvirt/qemu/channel/target/.


OpenStack Nova是通过判断镜像元数据hw_qemu_guest_agent是否为yes决定是否支持qemu-guest-agent,代码如下:


# vim nova/virt/libvirt/driver.py


由此可知,我们必须添加镜像property hw_qemu_guest_agent=yes,否则libvert启动虚拟机时不会创建qemu-guest-agent设备,虚拟机的qemu-guest-agent由于找不到对应的串行设备而导致修改密码失败。同时在实测中发现,如果未添加该属性,虚拟机中的qemu-guest-agent服务同样会因为找不到设备而无法启动。


添加该属性命令:

# glance image-update --property hw_qemu_guest_agent=yes $IMAGE_ID


在计算节点上执行查询信息,进行检验:

# virsh qemu-agent-command $VM_ID --pretty '{"execute":"guest-info"}'


nova通过set-password子命令修改虚拟机管理员密码:

nova set-password $VM_UUID


或通过virsh命令设置虚拟机用户密码

# virsh set-user-password <domain> <user> <password>


Libguestfs-tools

libguestfs 是一组 Linux 下的 C 语言的 API ,用来访问虚拟机的磁盘映像文件。该工具包内包含的工具有virt-cat、virt-df、virt-ls、virt-copy-in、virt-copy-out、virt-edit、guestfs、guestmount、virt-list-filesystems、virt-list-partitions等工具,具体用法可以参看官网。该工具可以在虚拟机关闭的情况下,直接编辑查看系统内的文件内容,也可以直接写入文件或复制文件到外面的物理机,当然也可以像mount一样,支持挂载操作。


安装libguestfs-tools工具

yum -y install libguestfs-tools


在计算节点上通过命令或API接口找到实例编号

# virsh list --all

Id    Name                           State

----------------------------------------------------

1         instance-00001035         running


对实例关机(必须关机,否则无法修改密码)


生成新密码

# openssl passwd -1 "openstack"

$1$/20Vnod9$vBvUgodH2qMVTB1EiEs30.


linux系统的加密密码通常存储在/etc/shadow 文件中,共分9列,用“:”分隔,其中第一列是用户名,第二列是密码。密码通常用MD5加密,这里我们用openssl加密工具,-1 即是普通MD5加密。


root:$6$H.RTQF71$7u2Y9YBJPB5.76jbhlTUVdoI/aea2x6mR2yvZx0VukGzaCAWhb.kO9doDaoB9l33IweoL.GvzzksJfQzw.Ntse1:17494:0:99999:7:::

bin:*:17110:0:99999:7:::

daemon:*:17110:0:99999:7:::

adm:*:17110:0:99999:7:::

lp:*:17110:0:99999:7:::

sync:*:17110:0:99999:7:::

shutdown:*:17110:0:99999:7:::

halt:*:17110:0:99999:7:::

mail:*:17110:0:99999:7:::

operator:*:17110:0:99999:7:::

games:*:17110:0:99999:7:::

ftp:*:17110:0:99999:7:::

nobody:*:17110:0:99999:7:::

systemd-network:!!:17494::::::

dbus:!!:17494::::::

polkitd:!!:17494::::::

postfix:!!:17494::::::

chrony:!!:17494::::::

sshd:!!:17494::::::


修改root密码

复制上面得到的密码,执行下面命令(instance-id不是openstack里面的id,而是virsh list 命令查看得到的instance-**那个)。

# virt-edit -d ***instance-id*** /etc/shadow


待打开后修改替换root账户第二栏密码

root:$6$H.RTQF71$7u2Y9YBJPB5.76jbhlTUVdoI/aea2x6mR2yvZx0VukGzaCAWhb.kO9doDaoB9l3IweoL.GvzzksJfQzw.Ntse1:17494:0:99999:7:::

修改为

root:$1$/20Vnod9$vBvUgodH2qMVTB1EiEs30.:17494:0:99999:7:::


保存退出,然后重启实例,就可以用新密码“openstack”登录了。


Qemu-Guest-Agent最大的优势在于他可以在任何时候去修改虚机系统密码,而不像其他两种方式,只能在初始化阶段或关机状态下做。


未免遗忘,特此小记。


作者介绍:

徐超,就职于中电科华云,热爱开源技术、云计算、CI/CD。


↓↓ 点击"阅读原文" 【加入云技术社区】

相关阅读:

企业级PAAS云平台:不容忽视的几个关键问题和挑战

4年!我对OpenStack运维架构的总结

5年!我对OpenStack的一些看法

6年!我对赖以挣小钱渡日的OpenStack淌过的河...

7年!我放弃了OpenStack

8年!我在OpenStack路上走过的坑。。。

更多文章请关注

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存