Linux
为了在OpenStack Compute云中使基于Linux的镜像具有完整功能,有几个要求需要满足。对于其中的一些要求,可以通过安装cloud-init软件包来实现。在创建自己的镜像之前,阅读本节以确保镜像支持您计划使用的OpenStack功能。
- 磁盘分区和启动时调整root分区大小(使用cloud-init)
- 没有硬编码的MAC地址信息
- 运行SSH服务器
- 禁用防火墙
- 使用ssh公钥访问实例(使用cloud-init)
- 处理用户数据和其他元数据(使用cloud-init)
- 在Linux内核中支持半虚拟化Xen(仅适用于Xen hypervisor和Linux内核版本<3.0)
磁盘分区和启动时调整root分区大小(使用cloud-init)
在创建Linux镜像时,必须决定如何分区磁盘。分区方法的选择可能会影响调整大小功能,如下面的部分所述。
虚拟机镜像中的磁盘大小是在创建镜像时确定的。然而,OpenStack允许您通过指定不同的flavor来启动具有不同大小的驱动器的实例。例如,如果您的镜像是使用5 GB磁盘创建的,并启动一个m1.small
的flavor实例,则生成的虚拟机实例默认具有20 GB的主磁盘大小。当实例的磁盘调整为更大时,只需在末尾添加零即可。
你的镜像必须能够在启动时调整其分区大小,以匹配用户请求的大小。否则,在实例引导后,您必须手动调整分区大小才能访问附加存储空间,以便访问与使用创建镜像时磁盘大小不同的flavor相关联的磁盘大小。要实现这个功能,可以使用cloud-init。
Xen: 一个ext3/ext4分区(没有LVM)
如果使用OpenStack XenAPI驱动,则Compute服务会在引导实例时自动调整分区和文件系统。仅当以下条件都满足时,自动调整大小才会发生:
- 在镜像注册表中,将
auto_disk_config=True
设置为镜像的属性。 - 镜像上的磁盘只有一个分区。
- 该分区上的文件系统为ext3或ext4。
因此,如果您使用Xen,我们建议在创建镜像时创建一个单独的ext3或ext4分区(不由LVM管理)。否则,请继续阅读。
非Xen,使用cloud-init/cloud-tools:一个ext3/ext4分区(没有LVM)
必须为你的镜像配置以下内容:
- 镜像的分区表描述了镜像的原始大小。
- 镜像的文件系统填满了镜像的原始大小。
然后,在引导过程中,您必须执行以下操作:
修改分区表,使其意识到额外的空间:
如果您不使用LVM,则必须修改表以扩展现有根分区以涵盖此额外空间。
如果你使用LVM,则可以添加新的LVM条目到分区表中,创建新的LVM物理卷,将其添加到卷组中,并使用根卷扩展逻辑分区。
调整root分区文件系统的大小。
根据您的发行版,支持此操作的最简单方法是在镜像中安装:
cloud-init包
cloud-utils包,在Ubuntu和Debian上还包含用于扩展分区的growpart工具
如果你使用Fedora、CentOS 7或RHEL 7,则
cloud-utils-growpart
包中包含用于扩展分区的growpart
工具。如果您使用Ubuntu或Debian,则
cloud-initramfs-growroot
包支持在第一次启动时调整根分区大小。
安装这些包后,镜像在启动时执行根分区调整大小。例如,在/etc/rc.local
文件中。
如果您无法安装cloud-initramfs-tools
,则Robert Plestenjak有一个名为linux-rootfs-resize的GitHub项目,其中包含使用growpart更新ramdisk的脚本,以便镜像在启动时正确调整大小。
如果您可以安装 cloud-init 和 cloud-utils 包,我们建议在创建镜像时创建一个单独的ext3
或ext4
分区(不由LVM管理)。
没有使用cloud-init和cloud-tools的非Xen虚拟机:使用LVM
如果你的虚拟机内部不能安装 cloud-init 和 cloud-tools,并且你想要支持调整大小,你必须编写一个脚本,让你的镜像在启动时运行以修改分区表。在这种情况下,我们建议使用LVM来管理你的分区。由于Linux内核的限制(截至本文撰写时),你不能修改当前已挂载分区的原始磁盘的分区表,但你可以对LVM进行操作。
你的脚本必须执行以下操作:
检测磁盘上是否有额外的空间。例如,解析 parted /dev/sda --script "print free"命令的输出。
使用额外的空间创建一个新的LVM分区。例如,parted /dev/sda --script "mkpart lvm ..."。
创建一个新的物理卷。例如,pvcreate /dev/sda6。
使用此物理卷扩展卷组。例如,vgextend vg00 /dev/sda6。
通过这些方法扩展包含根分区的逻辑卷。例如,lvextend /dev/mapper/node-root /dev/sda6。
调整根文件系统的大小。例如,resize2fs /dev/mapper/node-root。
除非你的镜像是旧的Linux发行版,需要/boot
不由LVM管理,否则你不需要/boot
分区。
不要硬编码 MAC 地址信息
你必须删除镜像中的网络持久性规则,因为它们会导致实例中的网络接口作为除 eth0 以外的接口启动。这是因为你的镜像记录了网络接口卡的 MAC 地址,而每次实例启动时,此 MAC 地址都会不同。你应该更改以下文件:
将
/etc/udev/rules.d/70-persistent-net.rules
替换为空文件(包含网络持久性规则,包括 MAC 地址)。将
/lib/udev/rules.d/75-persistent-net-generator.rules
替换为空文件(此文件生成上面的文件)。在基于 Fedora 的映像中,从
/etc/sysconfig/network-scripts/ifcfg-eth0
中删除 HWADDR 行。
注意
如果删除网络持久性规则文件,则可能在启动时收到udev kernel
警告,这就是为什么我们建议将它们替换为空文件的原因。
确保ssh服务运行
你必须在镜像中安装ssh服务器并确保它在启动时启动,否则在OpenStack内部启动时无法使用ssh连接到实例。这个软件包通常称为openssh-server
。
禁用防火墙
通常情况下,我们建议在镜像中禁用任何防火墙,并使用OpenStack安全组来限制对实例的访问。原因是,在实例上安装防火墙可能会使您无法连接到实例,从而使网络问题的故障排查更加困难。
通过ssh公钥(cloud-init)访问实例
通常,用户访问运行在OpenStack上的虚拟机的方式是使用公钥认证的ssh。为了使其正常工作,虚拟机镜像必须配置为在启动时从OpenStack元数据服务或配置驱动程序下载ssh公钥。
如果在镜像中同时存在XenAPI代理程序和cloud-init,则cloud-init将处理ssh-key注入。系统假定当镜像具有cloud_init_installed属性时,cloud-init存在。
使用cloud-init获取公钥
cloud-init软件包自动从元数据服务器获取公钥并将其放置在一个帐户中。帐户因发行版而异。在基于Ubuntu的虚拟机上,帐户称为ubuntu,在基于Fedora的虚拟机上,帐户称为fedora,在基于CentOS的虚拟机上,帐户称为centos。
您可以通过编辑/etc/cloud/cloud.cfg
文件并添加一行不同的用户来更改cloud-init
使用的帐户名称。例如,要配置cloud-init
将密钥放在名为admin的帐户中,请在配置文件中使用以下语法:
users:
- name: admin
(...)
写一个自定义脚本以获取公钥
如果您无法或不愿意在虚拟机中安装cloud-init,可以编写一个自定义脚本来获取公钥并将其添加到用户帐户中。
要获取ssh公钥并将其添加到root帐户,请编辑/etc/rc.local文件,并在touch /var/lock/subsys/local行之前添加以下行。此代码片段摘自rackerjoe oz-image-build CentOS 6模板。
if [ ! -d /root/.ssh ]; then
mkdir -p /root/.ssh
chmod 700 /root/.ssh
fi
# Fetch public key using HTTP
ATTEMPTS=30
FAILED=0
while [ ! -f /root/.ssh/authorized_keys ]; do
curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/metadata-key 2>/dev/null
if [ $? -eq 0 ]; then
cat /tmp/metadata-key >> /root/.ssh/authorized_keys
chmod 0600 /root/.ssh/authorized_keys
restorecon /root/.ssh/authorized_keys
rm -f /tmp/metadata-key
echo "Successfully retrieved public key from instance metadata"
echo "*****************"
echo "AUTHORIZED KEYS"
echo "*****************"
cat /root/.ssh/authorized_keys
echo "*****************"
else
FAILED=`expr $FAILED + 1`
if [ $FAILED -ge $ATTEMPTS ]; then
echo "Failed to retrieve public key from instance metadata after $FAILED attempts, quitting"
break
fi
echo "Could not retrieve public key from instance metadata (attempt #$FAILED/$ATTEMPTS), retrying in 5 seconds..."
sleep 5
fi
done
注意
一些 VNC 客户端将 : (冒号) 替换为 ; (分号),将 _ (下划线) 替换为 - (连字符)。如果在 VNC 会话期间编辑文件,请确保使用的是 http: 而不是 http;,authorized_keys 而不是 authorized-keys。
处理用户数据和其他元数据(cloud-init)
在OpenStack中,除了ssh公钥之外,镜像可能需要来自OpenStack的其他信息,例如在请求镜像时用户提交的用户数据。例如,您可能希望在实例启动时设置实例的主机名,或者希望配置镜像以在启动时将用户数据内容作为脚本执行。
你可以通过元数据服务或引用配置驱动器上的存储元数据来访问此信息。由于OpenStack元数据服务与Amazon EC2元数据服务的2009-04-04版本兼容,因此请参阅Amazon EC2文档以获取有关检索用户数据的详细信息。
支持此类功能的最简单方法是将cloud-init软件包安装到您的镜像中,默认情况下将用户数据视为可执行脚本,并设置主机名。
确保镜像将启动日志写到控制台
您必须配置镜像,以便内核将引导日志写入ttyS0
设备。特别地,必须在引导时向内核传递console=tty0 console=ttyS0,115200n8
参数。
如果您的镜像使用grub2
作为引导加载程序,则应该在grub配置文件(例如/boot/grub/grub.cfg
)中有一个类似于以下内容的行:
linux /boot/vmlinuz-3.2.0-49-virtual root=UUID=6d2231e4-0975-4f35-a94f-56738c1a8150 ro console=tty0 console=ttyS0,115200n8
如果console=tty0 console=ttyS0,115200n8未出现,则必须修改grub配置。一般来说,不应直接更新grub.cfg,因为它是自动生成的。而是应该编辑/etc/default/grub文件并修改GRUB_CMDLINE_LINUX_DEFAULT变量的值:
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"
接下来,更新grub配置。在基于Debian的操作系统(如Ubuntu)上运行以下命令:
# update-grub
在基于Fedora的系统(如RHEL和CentOS)和openSUSE上,运行以下命令:
# grub2-mkconfig -o /boot/grub2/grub.cfg
内核中支持准虚拟化的Xen(仅Xen hypervisor):
在Linux内核版本3.0之前,Linux内核的主线分支不支持用于paravirtualized Xen虚拟机实例(Xen称之为DomU guests)的功能。如果您正在使用支持paravirtualization的Xen hypervisor,并且要为具有3.0内核之前的旧Linux发行版创建镜像,则必须确保镜像引导了已编译Xen支持的内核。
管理镜像缓存
使用nova.conf文件中的选项来控制是否以及在多长时间内将未使用的基本镜像存储在/var/lib/nova/instances/_base/
目录中。如果你已经配置了实例的动态迁移,那么你的所有计算节点将共享一个公共的/var/lib/nova/instances/
目录。
有关OpenStack中libvirt镜像的详细信息,请参阅Pádraig Brady的《The life of an OpenStack libvirt image》。
镜像缓存管理配置选项:
配置 option=Default 值 | (类型)描述 |
---|---|
preallocate_images=none | (StrOpt) VM镜像预分配模式: none 不会提前进行存储预分配。 space 在实例启动时完全分配存储空间。$instance_dir/镜像将被预分配,以立即确定是否有足够的空间,并可能通过避免持续分配和更好的块分配位置来提高VM I/O性能。 |
remove_unused_base_images=True | (BoolOpt) 应该删除未使用的基础镜像吗?当设置为True时,删除基础镜像的间隔由以下两个设置确定。如果设置为False,则计算机永远不会删除基础镜像。 |
remove_unused_original_minimum_age_seconds=86400 | (IntOpt) 未使用且未调整大小的基础镜像,若创建时间在这个时间间隔内,则不会被删除。默认为86400秒,即24小时。 |
remove_unused_resized_minimum_age_seconds=3600 | (IntOpt) 未使用的已调整大小的基础镜像在此时间内未被使用时将被删除。默认值为3600秒,即一小时。 |
要查看这些设置如何影响正在运行实例的删除,请检查存储镜像的目录:
# ls -lash /var/lib/nova/instances/_base/
在 /var/log/compute/compute.log 文件中,搜索标识符:
2012-02-18 04:24:17 41389 WARNING nova.virt.libvirt.imagecache [-] Unknown base file: /var/lib/nova/instances/_base/06a057b9c7b0b27e3b496f53d1e88810a0d1d5d3_20
2012-02-18 04:24:17 41389 INFO nova.virt.libvirt.imagecache [-] Removable base files: /var/lib/nova/instances/_base/06a057b9c7b0b27e3b496f53d1e88810a0d1d5d3 /var/lib/nova/instances/_base/06a057b9c7b0b27e3b496f53d1e88810a0d1d5d3_20
2012-02-18 04:24:17 41389 INFO nova.virt.libvirt.imagecache [-] Removing base file: /var/lib/nova/instances/_base/06a057b9c7b0b27e3b496f53d1e88810a0d1d5d3
因为默认情况下,remove_unused_original_minimum_age_seconds的时间为86400秒(即24小时),所以您可以等待该时间间隔以查看基础映像是否被删除,或在nova.conf文件中将该值设置为更短的时间段。在更改nova.conf文件中的设置后,重新启动所有nova服务。
REF
https://docs.openstack.org/image-guide/openstack-images.html