手动构建Openstack镜像

手动构建Openstack镜像

本文以centos7镜像为例,详细介绍手动制作Openstack镜像的步骤,镜像支持一下几个功能:

  • 支持密码注入功能(nova boot时通过–admin-pass参数指定设置初始密码)
  • 支持根分区自动调整(根分区自动调整为flavor disk大小,而不是原始镜像分区大小)
  • 支持动态修改密码(使用nova set-password命令可以修改管理员密码)

镜像的宿主机操作系统为CentOs7.4,开启了VT功能(使用kvm-ok命令验证)并安装了libvirt系列工具,包括virsh、virt-manager、libguestfs-tools等。

下载iso镜像

下载centos7.4.iso镜像,可以选择中国镜像源,相对国外镜像源下载速度会快很多,这里我已经下载好了。

1
2
3
4
5
# qemu-img info CentOS-7-x86_64-DVD-1708.iso 
image: CentOS-7-x86_64-DVD-1708.iso
file format: raw
virtual size: 4.2G (4521459712 bytes)
disk size: 4.2G

创建虚拟机

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

1
2
# qemu-img create -f qcow2 centos.qcow2 10G
Formatting 'centos.qcow2', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off

使用以下脚本创建并启动虚拟机:

1
2
3
4
5
6
7
8
9
NAME=centos
ROOT_DISK=centos.qcow2
CDROM=`pwd`/CentOS-7-x86_64-DVD-1708.iso
virt-install --virt-type kvm --name $NAME --ram 1024 \
--disk $ROOT_DISK,format=qcow2 \
--network network=default \
--graphics vnc,listen=0.0.0.0 --noautoconsole \
--os-type=linux --os-variant=rhel7 \
--cdrom=$CDROM

启动完成后,使用vnc client连接或者使用virt-manager、virt-viewer连接,这里我直接用virt-manager。

安装OS

进入虚拟机控制台可以看到CentOS的启动菜单,选择Install Centos 7,继续选择语言后将进入INSTALLION SUMMARY,其中大多数配置默认即可,SOFTWARE SELECTION选择Minimal Install,INSTALLATION DESTINATION需要选择手动配置分区,我们只需要一个根分区即可,不需要swap分区,文件系统选择ext4或者xfs,存储驱动选择Virtio Block Device,如图:

配置完成后就可以开始安装了,在CONFIGURATION中设置root临时密码,只需要暂时记住这个临时密码,制作完后cloud-init会重新设置root初始密码。

大约几分钟后,即可自动完成安装配置工作,最后点击右下角的reboot重启退出虚拟机。

配置OS

安装好操作系统后,需要进行配置才能作为glance镜像使用,启动虚拟机

1
2
3
4
5
# virsh list --all
Id 名称 状态
----------------------------------------------------
- centos 关闭
# virsh start centos

如果云主机不需要支持root ssh远程登录,需要关闭root远程ssh登录功能,修改配置文件/etc/ssh/sshd_config并修改PermitRootLogin值为no,默认是开启的(这里我不做更改,如果更改需要重启ssh服务生效)。

为了加快安装速度,可以配置为本地软件源仓库,若没有本地镜像仓库,则选择国内的软件源,相对官网的速度下载要快。

1
2
3
4
# yum -y install wget
# cd /etc/yum.repos.d/ && rm -rf * && cd
# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

acpid

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

1
2
# yum -y install acpid
# systemctl enable acpid

提示:

  • 用户执行重启或者关机操作时,OpenStack会首先尝试调用libvirt的shutdown方法,即软关机。
  • 当软关机执行失败或者超时(默认120秒),则会调动libvirt的destroy方法,即强制关机,因此如果虚拟机关机或者重启很慢,很可能是acpid没有正常运行。
  • 为了使虚拟机进程安全退出,减少数据损坏风险,尽量使用软操作,硬操作可能导致程序崩溃或者数据丢失。

console log

当操作系统内核崩溃时会报出内核系统crash出错信息,通常启动的时候一闪而过, 而此时系统还没有起来,不能通过远程工具(比如ssh)进入系统查看,我们可以通过配置grub,把这些日志重定向到Serial Console中,这样我们就可以通过Serial console来访问错误信息,以供分析和排错使用。
修改配置文件/etc/default/grub,设置GRUB_CMDLINE_LINUX,:

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

通过这个配置,内核信息会以115200的波特率同时发送到tty0和ttyS0串行端口设备。libvirt可以通过一个普通文件模拟这个串行端口:

1
2
3
4
<serial type='file'>
<source path='/var/lib/nova/instances/99579ce1-f4c4-4031-a56c-68e85a3d037a/console.log'/>
<target port='0'/>
</serial>

这样内核产生的日志发到ttyS0,实际上写到console.log文件中。

OpenStack通过nova console-log命令可以获取该文件内容,查看错误日志。

qemu-guest-agent

qemu-guest-agent是运行在虚拟机内部的一个服务,libvirt会在本地创建一个unix socket,模拟为虚拟机内部的一个串口设备,从而实现了宿主机与虚拟机通信,这种方式不依赖于TCP/IP网络,实现方式简单方便。

1
2
3
4
5
<channel type='unix'>
<source mode='bind' path='/var/lib/libvirt/qemu/org.qemu.guest_agent.0.instance-00003c2c.sock'/>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>

如上宿主机的socket文件为org.qemu.guest_agent.0.instance-00003c2c.sock,在虚拟机内部为/dev/virtio-ports/org.qemu.guest_agent.0。

通过这种方式,宿主机可以发送指令写到socket文件中,虚拟机内部的qemu-guest-agent会轮询查看这个串行设备是否有指令,一旦接收到指令就可以执行对应的脚本,从而实现了宿主机控制虚拟机执行命令的功能,其中最常用的指令就是通过libvirt修改虚拟机密码。更多关于qemu-guest-agent请参考官方文档

为了支持OpenStack平台动态修改虚拟机密码功能,我们需要手动安装qemu-guest-agent:

1
# yum install -y qemu-guest-agent

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

1
2
3
4
5
6
7
virsh qemu-agent-command instance-000028d5 '{"execute":"guest-info"}' | python -m json.tool | grep 'name' | cut -d ':' -f 2 | tr -d '",'
...
guest-set-user-password
guest-get-fsinfo
guest-set-vcpus
guest-get-vcpus
...

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

zeroconf

zeroconf启动时会自动创建一条路由169.254.0.0/16,而虚拟机访问metadata服务的地址正好是169.254.169.254,如果启动了zeroconf服务,由于路由冲突,虚拟机不能通过169.254.169.254路由到网络节点的metadata服务了。OpenStack虚拟机通常都是通过DHCP获取IP的,因此我们并不需要zeroconf服务。为了虚拟机能够访问metadata服务,我们必须禁止zeroconf服务,关于该问题的更详细讨论可参考bug#983611

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

cloud-init

接下来安装cloud-init,cloud-init是虚拟机第一次启动时执行的脚本,主要负责从metadata服务中拉取配置信息,完成虚拟机的初始化工作,比如设置主机名、初始化密码以及注入密钥等。

1
# yum install -y cloud-init

growpart

1
2
3
4
# yum update -y
# yum install -y epel-release
# yum install -y cloud-utils-growpart.x86.64
# rpm -qa kernel | sed 's/^kernel-//' | xargs -I {} dracut -f /boot/initramfs-{}.img {}

完成以上工作后,我们的镜像配置基本结束,删除一些无用文件,清理history命令后执行关机:

1
# shutdown -h now

移除本地信息

在宿主机上运行以下命名,移除宿主机信息,比如mac地址等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# virt-sysprep -d centos
[ 0.0] Examining the guest ...
[ 41.1] Performing "abrt-data" ...
[ 42.4] Performing "backup-files" ...
[ 44.4] Performing "bash-history" ...
[ 44.4] Performing "blkid-tab" ...
[ 44.5] Performing "crash-data" ...
[ 44.5] Performing "cron-spool" ...
[ 44.5] Performing "dhcp-client-state" ...
[ 44.5] Performing "dhcp-server-state" ...
[ 44.5] Performing "dovecot-data" ...
[ 44.5] Performing "logfiles" ...
[ 44.7] Performing "machine-id" ...
[ 44.7] Performing "mail-spool" ...
[ 44.7] Performing "net-hostname" ...
[ 44.8] Performing "net-hwaddr" ...
[ 44.8] Performing "pacct-log" ...
[ 44.8] Performing "package-manager-cache" ...
[ 44.8] Performing "pam-data" ...
[ 44.8] Performing "passwd-backups" ...
[ 44.8] Performing "puppet-data-log" ...
[ 44.8] Performing "rh-subscription-manager" ...
[ 44.8] Performing "rhn-systemid" ...
[ 44.8] Performing "rpm-db" ...
[ 44.8] Performing "samba-db-log" ...
[ 44.8] Performing "script" ...
[ 44.8] Performing "smolt-uuid" ...
[ 44.8] Performing "ssh-hostkeys" ...
[ 44.8] Performing "ssh-userdir" ...
[ 44.8] Performing "sssd-db-log" ...
[ 44.9] Performing "tmp-files" ...
[ 44.9] Performing "udev-persistent-net" ...
[ 44.9] Performing "utmp" ...
[ 44.9] Performing "yum-uuid" ...
[ 44.9] Performing "customize" ...
[ 44.9] Setting a random seed
[ 45.4] Performing "lvm-uuids" ...

删除虚拟机,镜像制作完成。

1
2
3
4
5
6
7
8
9
10
11
12
# virsh list --all
Id 名称 状态
----------------------------------------------------
- centos 关闭

# virsh undefine centos
域 centos 已经被取消定义

# virsh list --all
Id 名称 状态
----------------------------------------------------

上传镜像

镜像制作完成,上传centos.qcow2到glance服务中

1
2
# glance image-create --file ./centos.qcow2 --disk-format qcow2 \
--container-format bare --name CentOS-7.2 --progress