虚拟机镜像(以下简称镜像)是Openstack云计算平台不可或缺的一部分。利用各种定制化的镜像,我们可以快速创建出满足不同目的的虚拟机。例如,利用一个安装并配置了Apache、Mysql和PHP的Linux操作系统镜像,就可以在Openstack平台上秒级创建出多台LAMP服务器,可以直接用于部署或者开发。
要充分利用好镜像的优势,关键就是掌握好如何制作定制化的镜像,这往往也伴随着如何测试和管理这些镜像。本文主要介绍:1. 制作满足Openstack要求的镜像的流程;2. 利用devstack对制作好的镜像进行测试。
本文出现的命令和配置都是实际测试可行的,可以直接复制使用;但本文更多是介绍各个操作配置的原理和目的,这样即使在不同的运行环境,我们仍可以把握关键细节,完成镜像的制作和测试。
主要内容:
- 原理和流程简介
- 准备工作
- 制作镜像
- 测试镜像
- 附录
原理和流程简介
虚拟机镜像实际就是一个包含整个虚拟磁盘内容的文件,这个虚拟磁盘也就是虚拟机的系统盘,包含可以引导启动的操作系统。所谓定制化的镜像,就是在这个(虚拟)系统盘上安装好需要的软件,保存好需要的配置,最后清理掉不必要的临时文件和日志等数据。最简单直观的定制方式,就是用一个干净的镜像作为系统盘创建一台虚拟机,安装好需要的操作系统,然后就可以像平时的操作那样安装需要的软件,保存配置,再利用工具清理不需要的数据,最后关闭虚拟机,镜像就定制化完成了。当然,我们也可以使用已经制作好的镜像直接创建虚拟机,这样可以省略操作系统和一些软件的安装步骤。
所谓Openstack虚拟机镜像,就是满足一些要求(安装特定的软件,配置特定的服务等)的镜像,从而配合完成Openstack计算平台的镜像相关功能。
测试镜像也很简单,就是把制作好的镜像导入Openstack平台,使用它来创建虚拟机,测试各个功能是否正常运作。搭建一个Openstack平台用于测试的方式很多种,本文选择了devstack,因为devstack的安装步骤很简单,而且很轻量,可以直接安装在一台虚拟机中。
准备工作
本文的例子所在运行环境的操作系统为Centos 7,并利用基于libvirt的一系列工具来创建和管理虚拟机,针对的虚拟化技术(hypervisor)为QEMU/KVM。
libvirt和kvm分别是Openstack上面最常用的工具和虚拟化平台。
1.安装好虚拟化工具
yum install qemu libvirt-client virt-manager virt-viewer guestfish libguestfs-tools virt-top |
2.创建虚拟子网
目的:因为虚拟机在安装软件过程中需要连通互联网,最简单的办法就是利用libvirt创建一个虚拟子网,虚拟机通过dhcp分配虚拟子网的ip,通过NAT的方式访问外网。
2.1 准备虚拟网络资源的xml文件default.xml:
<network> <name>default</name> <bridge name="virbr0"/> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254"/> </dhcp> </ip> </network> |
2.2 配置:
\# virsh net-define /usr/share/libvirt/networks/default.xml Network default defined from /usr/share/libvirt/networks/default.xml \# virsh net-autostart default Network default marked as autostarted \# virsh net-start default Network default started |
2.3 修改系统配置/etc/sysctl.conf:
环境准备好了,可以开始制作镜像了。
制作镜像
制作Linux镜像
Linux镜像需要满足:
1.配置SSH server开机运行。
2.禁用防火墙。
3.开机时支持磁盘分区和改变大小。
4.支持ssh公钥访问虚拟机。
5.运行和使用user data和metadata(如修改root密码,执行用户脚本等)。
6.操作系统内核支持Virtio。
7.没有写死的MAC地址信息。
其中1、2很容易操作,本文使用的Centos 7安装盘默认安装后就满足了。3、4、5三条,只需要安装一个cloud-init的服务就可以了。
cloud-init是一系列python脚本和工具,负责云实例最开始的初始化工作。具体运行原理参考附录:cloud-init工作原理。
第6条,Virtio是提高KVM类型的虚拟机I/O(存储和网络)性能的一种技术。目前常用的Linux发行版本内核都直接支持了,如果你的安装版本有特殊需求,可以查看这里。
关于Virtio的细节,可以参考附录:虚拟机性能优化.
第7条,使用工具virt-sysprep清理。
下面以Centos 7.1的安装为例,其他发行版本可以参考Openstack的文档:
1.准备好ISO安装文件,下载。
2.创建一个磁盘:qemu-img create -f qcow2 image.qcow2 20G
因为针对的是KVM,因此本文使用的镜像格式是qcow2(QEMU copy-on-write version 2),关于镜像格式更多细节,可查看附录:镜像格式。镜像大小没有特殊要求,根据需求即可。镜像完成后是可以通过qemu-img增大的,但是一般很难缩小。
3.创建并启动虚拟机:
使用virt-install命令进行创建,通过vnc图形界面安装(本地需要安装一个vnc客户端来访问vnc界面):
virt-install --virt-type kvm --cpu cpu64-rhel6 --ram 2048 \ --name image_name \ --disk path=image.qcow2,format=qcow2,device=disk,bus=virtio \ --network network=default,model=virtio \ --graphics vnc,listen=0.0.0.0,password=Yourpassw0rd --noautoconsole \ --os-type=linux \ --extra-args="console=ttyS0,115200n8 console=tty0" \ --location=/path/to/installer.iso |
或者通过虚拟console(命令行)界面安装,执行virsh console image_name进入console界面,ctrl+]退出:
virt-install --virt-type kvm --cpu cpu64-rhel6 --ram 2048 \ --name image_name \ --disk path=image.qcow2,format=qcow2,device=disk,bus=virtio \ --network network=default,model=virtio \ --os-type=linux \ --nographics \ --extra-args="console=tty0 console=ttyS0,115200n8 serial" \ --location=/path/to/installer.iso |
这些命令参数的含义多数都比较直观,其中:
–cpu cpu64-rhel6:虚拟机的cpu特性集合,因为不同物理机的cpu特性都不同,为了保证虚拟机在不同物理机之间迁移时的cpu兼容性,Openstack平台往往会指定一个虚拟的cpu特性集合(物理机cpu特性的子集),用于所有的虚拟机。其他集合可以通过cat /usr/share/libvirt/cpu_map.xml查看。这里的cpu64-rhel6只是个示例,根据实际情况指定即可。
–graphics vnc,listen=0.0.0.0,password=Yourpassw0rd:通过vnc的方式提供安装界面,通过virsh vncdisplay image_name来查看vnc监听端口(vnc端口通常从tcp端口5900开始)。然后就可以使用vnc客户端进行操作。例如noVNC。
–location=/path/to/installer.iso和–extra-args=”console=tty0 console=ttyS0,115200n8 serial”:指定ISO安装文件路径,在内核启动阶段,应用指定的参数。
4.按照步骤要求安装操作系统(比如设置root密码,设置时区,网络和分区等)。
5.如果虚拟机dhcp没有正确配置,需要配置一下。centos 7的话,需要编辑/etc/sysconfig/network-scripts/ifcfg-ens3(根据网卡接口名字不同),修改ONBOOT=yes,然后执行service network restart。
6.弹出虚拟cd,关机并重启
virsh attach-disk --type cdrom --mode readonly image_name "" hdb virsh destroy image_name virsh start image_name |
7.重新登录(virsh console image_name或者ssh或者vnc),然后就可以安装基本的服务和修改配置:
\# 安装ACPI yum install acpid chkconfig acpid on \# 安装NetworkManager,用于网卡的自动发现及管理 yum install NetworkManager chkconfig NetworkManager on \# 安装cloud-init yum install cloud-init \# 禁用默认的zeroconf route echo "NOZEROCONF=yes" >> /etc/sysconfig/network |
8.关机shutdown -h now。
9.关机后回到宿主机,执行virt-sysprep -d image_name,擦除虚拟机镜像中的无用数据(MAC地址等)。
10.取消虚拟机:virsh undefine image_name。
11.这个镜像(image.qcow2)就可以用了。
因为我们通常对同一个Linux版本制作多种镜像,没必要每次都从头开始。我们可以跳过1 - 7步骤,基于一个已经制作好了的镜像创建虚拟机,登录后进行具体的定制化行为,然后再完成8 - 10:
virt-install --virt-type kvm --cpu cpu64-rhel6 --ram 2048 \ --name image_name \ --disk path=image.qcow2,format=qcow2,device=disk,bus=virtio \ --network network=default,model=virtio \ --graphics vnc,listen=0.0.0.0,password=Yourpassw0rd \ --noautoconsole --os-type=linux --import |
制作Windows镜像
Windows镜像的制作和Linux会有所不同:
Windows平台上是通过一个和cloud-init类似的服务,cloudbase-init,来帮助虚拟机初始化的。Windows平台要额外安装virtio-win驱动,才能使用Virtio来提高I/O性能。下面以Windows 2008为例:
1.准备好Windoes 2008的ISO安装盘。
2.准备好Virtio驱动的ISO安装盘,下载地址
3.创建一个磁盘镜像:
qemu-img create -f qcow2 ws2008.qcow2 20G |
4.创建并启动虚拟机:
virt-install --connect qemu:///system \ --name image_name --ram 2048 --vcpus 2 \ --network network=default,model=virtio \ --disk path=image.qcow2,format=qcow2,device=disk,bus=virtio \ --cdrom /path/to/win2008_installer.iso \ --disk path=/path/to/virtio-win-0.1.102.iso,device=cdrom \ --graphics vnc,listen=0.0.0.0,password=Yourpassw0rd \ --os-type windows --os-variant win2k8 |
5.通过vnc进入安装界面,开始安装过程。
6.安装Virtio驱动。
当安装程序进入选择系统盘的步骤时,会找不到可用磁盘,这是理所当然的(因为相关驱动还没安装)。此时选择“加载启动”(Load drivers),找到virtio-win的目录,选择合适的驱动,安装即可(因为例子中安装的是Windows 2008 64bit,因此选择的是amd64下的Win2008)。要安装两种驱动:VirtIO SCSI和network。安装完成后就可以看到可用磁盘了。
7.选择系统盘,继续安装步骤。
8.以Administrator身份进入桌面,打开cmd,完成Virtio的安装:
C:\pnputil -i -a E:\PATH\TO*.INF
9.安装Cloudbase-init,打开Powershell(如果默认没有安装,先安装),并运行:
C:\powershell C:\Set-ExecutionPolicy Unrestricted |
用IE打开http://www.cloudbase.it/downloads/CloudbaseInitSetup_Stable_x64.msi,下载并安装。
这个过程中可能需要:1. 关闭IE安全增强设置;2. 下载的msi文件需要右键点击属性,Unblock。
安装过程中,需要指定以下几项:
- Username: Administrator - Network adapter to configure: Red Hat VirtIO Ethernet Adapter - Serial port for logging: COM1 |
安装向导的最后,勾选Run Sysprep和Shutdown,最后点击完成,系统自动关机。
10.关机完成后镜像已经可用了,不过Cloudbase-init还多是默认配置,可以重新开机virsh start image_name,根据实际需求修改配置,具体参考文档。
本文例子做了如下修改:打开配置文件C:\Program Files\Cloudbase Solustions\Cloudbase-Init\conf\cloudbase-init.conf,修改如下几项,配置ConfigDrive的方式:
mtu_use_dhcp_config=false ntp_use_dhcp_config=false metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService |
11.正常关机,virsh undefine image_name,镜像就制作完成了。
12.同样的,如果要针对同一个Windows版本安装不同软件,可以使用已有的镜像进行安装。
测试镜像
如果仅仅使用devstack用于测试镜像,可以将devstack安装在一台虚拟机上,不用时直接关闭,这里的优化可以参考附录:虚拟机性能优化。
搭建devstack的步骤(如果是安装在虚拟机上同样适用):
1.创建stack账号,添加sudo权限,并登录stack:
adduser stack echo “stack ALL=(ALL) NOPASSWD: ALL” >> /etc/sudoers su - stack |
2.安装git:sudo yum install -y git
3.下载devstack源码:git clonehttps://git.openstack.org/openstack-dev/devstack并cd devstack
4.选定指定的Openstack版本,如:git checkout stable/juno
5.配置文件~/devstack/local.conf:
[[local|localrc]] FLOATING_RANGE=192.168.122.224/27 FIXED_RANGE=10.11.12.0/24 FIXED_NETWORK_SIZE=256 FLAT_INTERFACE=ens3 ADMIN_PASSWORD=123 DATABASE_PASSWORD=123 RABBIT_PASSWORD=123 SERVICE_PASSWORD=123 SERVICE_TOKEN=123 LIBVIRT_TYPE=kvm LOGFILE=$DEST/logs/stack.sh.log \# nova相关配置 [[post-config|$NOVA_CONF]] [libvirt] inject_password=true inject_partition=-1 cpu_mode=custom cpu_model=cpu64-rhel6 |
6.安装并启动devstack:./stack:
第一次执行时会安装许多库和下载代码
7.启动完后,为了让Dashboard中创建虚拟机页面支持设置admin密码,需要修改/opt/stack/horizon/openstack_dashboard/local/local_settings.py:
OPENSTACK_HYPERVISOR_FEATURES = { 'can_set_mount_point': False, 'can_set_password': True, } |
8.如果有防火墙,打开80和6080端口:
firewall-cmd --add-port=80/tcp firewall-cmd --add-port=6080/tcp firewall-cmd --reload |
devstack的使用方式:
1.确保是以stack用户登录。
2.进入devstack目录,执行source openrc admin admin,即使用admin身份(密码在配置文件中指定了)操作openstack。
3.然后就可以使用命令行工具了。
也可以通过Dashboard(80端口)和VNC(6080)以web界面来操作openstack。如果安装在虚拟机,且虚拟机运行在虚拟子网上,可以通过iptables等工具将虚拟机80和6080端口NAT映射到外网,进而访问。
具体测试流程:
1.在devstack机器上,su - stack && cd devstack && source openrc admin admin
2.导入镜像到glance:
glance image-create --name image_name --disk-format=qcow2 --container-format=bare --is-public=True --file /path/to/image.qcow2 |
3.浏览器打开devstack的80端口,通过horizon界面用刚才导入的镜像创建虚拟机。
4.测试确保几点:
- 虚拟机成功创建
- -创建操作没有错误日志(通过实例页面的日志Tab查看)
- ssh_key或者admin密码正确设置,能够成功登录
- 登录后,检查之前安装的软件或做的配置
总结
制作虚拟机镜像的方式有很多种,本文介绍了一种直观的方式:通过创建虚拟机,用平时使用操作系统的方式来定制化需求。另外还值得一提的一个工具,Diskimage-builder,可以用于自动化地创建镜像,使得定制化和测试镜像都变得更容易,但是相比本文介绍的方式也有一些不足:一是有一定的学习成本,二是目前只支持部分常用的Linux发行版本。
测试镜像的方式同样也很多,本文是通过devstack搭建一个最简的Openstack平台环境,把镜像直接导入平台,测试各个操作是否成功,日志是否无异常。
附录
问题和解决
制作Windows镜像时,报错无法从CD boot。
这是由于virt-install误把Virtio的ISO文件当做安装盘,解决办法:使用floppy盘的方式安装Virtio驱动:
1.下载vfd格式的Virtio驱动安装文件。
2.将–disk path=/path/to/virtio-win-0.1.102.iso,device=cdrom替换为–disk path=/path/to/virtio-win-0.1.102_amd64.vfd,device=floppy
cloud-init工作原理
cloud-init是一系列python脚本和工具,负责云实例最开始的初始化工作(修改主机名、注入ssh-key文件、设置root密码等)。cloud-init是一个通用方案,还适用于Openstack外的多种云平台。
cloud-init安装在虚拟机中,在第一次启动时,会根据本地配置去获取Datasources。Datasources包含了cloud-init初始化虚拟机时所需的配置数据:来自用户的userdata和来自平台的metadata。通常userdata包含yaml文件、运行脚本等多种格式的文件,而metadata包含了主机名、实例id、显示名等云平台相关的细节。
云平台提供Datasource的方式很多,Openstack默认的方式是通过http server提供Datasource:虚拟机访问默认的http://169.254.169.254,Openstack会对这个地址重定向,最终指向自己的metadata server。
镜像格式
虚拟机镜像格式最简单的是raw格式,可以认为是一个位等价的块设备文件(对/dev/sda使用dd命令进行复制)。此外还有很多格式,各自有不同的特点,如:ISO(主要用于CD或DVD)、VDI(VirtualBox使用)、VHD/VHDX(微软Hyper-V使用)、VMDK(VMware使用)。
QCOW2(QEMU copy-on-write version 2)则常用于KVM虚拟机,相比raw格式,qcow2格式的文件体积更小,更利于保存和上传。qcow2格式还支持快照(snapshot)功能(raw不支持),因此需要时,Openstack会自动将raw格式的镜像转换成qcow2格式。
虚拟机性能优化
关于虚拟化,先梳理几个概念:
这些硬件虚拟化特性需要在BIOS中打开。
QEMU/KVM创建虚拟机有两种模式emulator(QEMU)和virtualizer(KVM)。其中KVM需要依赖于Hardware-assisted CPU Virtualization(VT-x或者AMD-V),通过在宿主机cpu上执行客户机代码,从而可以获得接近原生的性能。KVM并不支持CPU的paravirtualization,但是支持对设备驱动的paravirtualization从而提高I/O性能。
使用KVM需要确保CPU硬件支持(要在BIOS中打开)和Linux内核模块支持。
如果不需要考虑虚拟机的迁移等问题,可以直接对虚拟机暴露全部宿主机的CPU特性(包括硬件虚拟化的特性),从而更好地利用cpu提升性能。相关命令指定–cpu host即可。
-
打开KVM-based nested virtualization
为了能够在创建的虚拟机中跑KVM(KVM上跑KVM),需要在物理机上允许KVM-based nested virtualization。对于Intel-based的机器:
检查nested KVM Kernel是否打开
cat /sys/module/kvm_intel/parameters/nested N Y代表打开,N代表关闭 |
临时移走KVM intel Kernel模块,打开nested virtualization,再重新加载:
sudo rmmod kvm-intel sudo sh -c "echo 'options kvm-intel nested=y' >> /etc/modprobe.d/dist.conf" sudo modprobe kvm-intel |
确保正确打开:
cat /sys/module/kvm_intel/parameters/nested Y modinfo kvm_intel | grep nested parm: nested:bool |
因为本文使用libvirt来管理KVM虚拟机,最方便的提升I/O性能的方式就是Virtio(此外还有其他方式提高KVM虚拟机I/O,例如利用VT-d给KVM虚拟机直接分配设备)。
Virtio是一种paravirtualization,只能运行兼容Virtio的客户机(Linux内核支持,Windows需要安装相关驱动)。Para-virtualized设备列表:
- network device (virtio-net)
- block device (virtio-blk)
- controller device (virtio-scsi)
- serial device (virtio-serial)
- balloon device (virtio-balloon)
相关命令指定virtio模式即可。
作者简介:蔡凯捷,现就职于绿星云科技,高级工程师,负责Openstack相关领域的研发工作。爱好云计算、开源项目、Web相关话题。曾任腾讯基础架构部门研发工程师,拥有互联网分布式系统多年研发经验。绿星云科技(深圳)有限公司(www.gstarcloud.com)是一家迅速崛起的互联网公司,专注于公有云服务。基于不断创新的软硬件平台架构、高效的运营管理流程和热情高涨的事业心,为客户打造易用、可靠、高性价比的云计算服务平台。该平台集中了弹性计算、分布式块存储和软件定义网络(SDN)等IaaS核心技术和能力,以秒级部署、在线迁移、分布式数据库、CDN加速等功能,为用户提供一站式云计算服务。本文为绿星云科技独家供稿,已得到官方的独家授权发布。
|