为 Azure 中的映像准备 Linux
注意
本文引用了 CentOS,这是一个处于生命周期结束 (EOL) 状态的 Linux 发行版。 请相应地考虑你的使用和规划。 有关详细信息,请参阅 CentOS 生命周期结束指南。
适用于:✔️ Linux VM ✔️ 灵活规模集
Azure 平台服务级别协议 (SLA) 仅适用于运行 Linux 操作系统的虚拟机 (VM),前提是使用某个认可的分发版。 对于认可的分发版,Microsoft Azure 市场提供预配置的 Linux 映像。 有关详细信息,请参阅:
在 Azure 上运行的其他所有分发版(包括社区支持的分发版和非认可的分发版)都有一些先决条件。
本文重点介绍有关在 Azure 上运行 Linux 分发版的一般准则。 本文无法详尽无遗,因为每个分发版不同。 即使满足本文介绍的所有条件,也可能需要显著调整 Linux 系统,使其正常运行。
常规 Linux 安装说明
Azure 不支持 Hyper-V 虚拟硬盘 (VHDX) 格式。 Azure 仅支持固定 VHD。 可以使用 Hyper-V 管理器或 Convert-VHD cmdlet 将磁盘转换为 VHD 格式。 如果使用 VirtualBox,请在创建磁盘时选择“固定大小”,而不要选择默认(动态分配)大小。
Azure 支持 Gen1(BIOS 引导)和 Gen2(UEFI 引导)虚拟机。
必须在内核中启用虚拟文件分配表 (VFAT) 内核模块。
VHD 允许的最大大小为 1,023 GB。
在安装 Linux 系统时,建议使用标准分区而不是逻辑卷管理器 (LVM)。 对于许多安装,LVM 是默认值。
使用标准分区可避免 LVM 名称与克隆的 VM 发生冲突,特别是在 OS 磁盘曾经连接到另一台相同的 VM 进行故障排除的情况下。 可以在数据磁盘上使用 LVM 或 RAID。
需要对装载用户定义的函数 (UDF) 文件系统的内核支持。 在 Azure 上首次启动时,预配配置将通过附加到来宾的 UDF 格式媒体传递到 Linux VM。 Azure Linux 代理必须装载 UDF 文件系统才能读取其配置和预配 VM。
低于 2.6.37 的 Linux 内核版本不支持具有更大 VM 大小的 Hyper-V 上的非一致性内存访问 (NUMA)。 此问题主要影响使用上游 Red Hat 2.6.32 内核的较旧分发版。 它已在 Red Hat Enterprise Linux (RHEL) 6.6 (kernel-2.6.32-504) 中修复。
如果系统运行版本低于 2.6.37 的自定义内核或版本低于 2.6.32-504 的基于 RHEL 的内核,则这些系统必须在 grub.conf 中的内核命令行上设置启动参数
numa=off
。 有关详细信息,请参阅 Red Hat KB 436883。不要在 OS 磁盘上配置交换分区。 可以将 Linux 代理配置为在临时资源磁盘上创建交换文件,如本文稍后所述。
对 Azure 上的所有 VHD,其虚拟大小必须保持为 1 MB(1024 x 1024 字节)。 从原始磁盘转换为 VHD 时,请确保在转换前的原始磁盘大小是 1 MB 的倍数,如本文稍后所述。
使用最新的分发版本、包和软件。
删除用户和系统帐户、公钥、敏感数据、不必要的软件和应用程序。
注意
Cloud-init 版本 21.2 或更高版本会删除 UDF 要求。 但如果未启用 udf
模块,CD-ROM 将不会在预配期间装载,这会阻止应用自定义数据。 解决方法是应用用户数据。 但是,与自定义数据不同,用户数据不会加密。 有关详细信息,请参阅 cloud-init 文档中的用户数据格式。
在没有 Hyper-V 的情况下安装内核模块
Azure 在 Hyper-V 虚拟机监控程序上运行,因此 Linux 需要某些内核模块才能在 Azure 中运行。 如果具有在 Hyper-V 外部创建的虚拟机,Linux 安装程序可能无法在初始 RAM(initrd 或 initramfs)中包含 Hyper-V 的驱动程序,除非 VM 检测到它正在 Hyper-V 环境中运行。
使用不同虚拟化系统(如 VirtualBox 或 KVM)来准备 Linux 映像时,可能需要重新生成 initrd,以确保至少 hv_vmbus
和 hv_storvsc
内核模块可在初始 RAM 磁盘上使用。 在基于上游 Red Hat 分发版的系统上(可能还包括其他系统),这是一个已知问题。
重新生成 initrd 或 initramfs 映像的机制可能会因分发版而有所不同。 查阅分发的文档或相应过程的支持。 下面是使用 mkinitrd
实用工具重新生成 initrd 的示例:
备份现有 initrd 映像:
cd /boot sudo cp initrd-`uname -r`.img initrd-`uname -r`.img.bak
使用
hv_vmbus
和hv_storvsc
内核模块重新生成 initrd:sudo mkinitrd --preload=hv_storvsc --preload=hv_vmbus -v -f initrd-`uname -r`.img `uname -r`
调整 VHD 大小
Azure 上的 VHD 映像必须已将虚拟大小调整为 1MB。 通常,通过 Hyper-V 创建的 VHD 会正确对齐。 如果 VHD 未正确对齐,则尝试从 VHD 创建映像时,可能会收到类似于以下示例的错误消息:
The VHD http://<mystorageaccount>.blob.core.chinacloudapi.cn/vhds/MyLinuxVM.vhd has an unsupported virtual size of 21475270656 bytes. The size must be a whole number (in MBs).
在这种情况下,可使用 Hyper-V 管理器控制台或 Resize-VHD PowerShell cmdlet 调整 VM 大小。 如果不是在 Windows 环境中运行,我们建议使用 qemu-img
转换(如果需要)并调整 VHD 大小。
注意
QEMU 2.2.1 版和一些更高版本的 qemu-img 中有一个已知 bug,导致 VHD 格式不正确。 此问题已在 QEMU 2.6 中修复。 建议使用版本 2.2.0 或更低版本,或使用 2.6 或更高版本。
使用
qemu-img
或vbox-manage
等工具直接调整 VHD 大小可能会导致 VHD 无法启动。 建议先使用以下代码将 VHD 转换为原始磁盘映像。如果 VM 映像是作为原始磁盘映像创建的,则可以跳过此步骤。 在一些虚拟机监控程序(如 KVM)中,默认情况下会将 VM 映像创建为原始磁盘映像。
sudo qemu-img convert -f vpc -O raw MyLinuxVM.vhd MyLinuxVM.raw
计算磁盘映像所需的大小,使虚拟大小调整为 1MB。 以下 Bash shell 脚本使用
qemu-img info
来确定磁盘映像的虚拟大小,然后将大小计算到下个 1 MB:rawdisk="MyLinuxVM.raw" vhddisk="MyLinuxVM.vhd" MB=$((1024*1024)) size=$(qemu-img info -f raw --output json "$rawdisk" | \ gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}') rounded_size=$(((($size+$MB-1)/$MB)*$MB)) echo "Rounded Size = $rounded_size"
使用
$rounded_size
调整原始磁盘的大小:sudo qemu-img resize MyLinuxVM.raw $rounded_size
将原始磁盘转换回固定大小的 VHD:
sudo qemu-img convert -f raw -o subformat=fixed,force_size -O vpc MyLinuxVM.raw MyLinuxVM.vhd
或者,对于 2.6 之前的 QEMU 版本,删除
force_size
选项:sudo qemu-img convert -f raw -o subformat=fixed -O vpc MyLinuxVM.raw MyLinuxVM.vhd
Linux 内核要求
Hyper-V 和 Azure 的 Linux 集成服务 (LIS) 驱动程序会直接影响上游 Linux 内核。 包括最新 Linux 内核版本(例如 3.x)在内的许多分发版已提供这些驱动程序,或以其他方式为其内核提供了这些驱动程序的向后移植版本。
LIS 驱动程序在上游内核中不断更新,并具有新的修补程序和功能。 如果可能,我们建议运行认可的分发版,其中包括这些修补程序和更新。
如果你正在运行 RHEL 版本 6.0 到 6.3 的一个变体,则需要安装适用于 Hyper-V 的最新 LIS 驱动程序。 从 RHEL 6.4+(和派生产品)开始,LIS 驱动程序已包含在内核中,因此,无需其他安装包。
如果需要自定义内核,我们建议使用最新的内核版本(例如 3.8+)。 对于维护自己内核的分发版或供应商,需要定期将 LIS 驱动程序从上游内核向后移植到自定义内核。
即使已运行相对较新的内核版本,我们也强烈建议跟踪 LIS 驱动程序中的任何上游修复,并根据需要向后移植这些修复。 LIS 驱动程序源文件的位置在 Linux 内核源树中的 MAINTAINERS 文件中指定:
F: arch/x86/include/asm/mshyperv.h
F: arch/x86/include/uapi/asm/hyperv.h
F: arch/x86/kernel/cpu/mshyperv.c
F: drivers/hid/hid-hyperv.c
F: drivers/hv/
F: drivers/input/serio/hyperv-keyboard.c
F: drivers/net/hyperv/
F: drivers/scsi/storvsc_drv.c
F: drivers/video/fbdev/hyperv_fb.c
F: include/linux/hyperv.h
F: tools/hv/
VM 的活动内核必须包含以下修补程序。 此列表并不完整,并未包括所有分发版。
- ata_piix:默认情况下,将磁盘交由 Hyper-V 驱动程序处理
- storvsc:解释 RESET 路径中传输中的数据包
- storvsc:避免使用 WRITE_SAME
- storvsc:对 RAID 和虚拟主机适配器驱动程序禁用 WRITE SAME
- storvsc:NULL 指针取消引用修补程序
- storvsc:环形缓冲区故障可能会导致 I/O 冻结
- scsi_sysfs:防止执行两次 __scsi_remove_device
Azure Linux 代理
Azure Linux 代理 (waagent
) 在 Azure 中预配 Linux 虚拟机。 可以在 Linux 代理 GitHub 存储库中获取最新版本、报告问题或提交拉取请求。
下面是使用 Azure Linux 代理的一些注意事项:
- 根据 Apache 2.0 许可证发布 Linux 代理。 许多分发版已为代理提供 .rpm 或 .deb 包。 可以轻松安装和更新这些包。
- Azure Linux 代理需要 Python v2.6 以上版本。
- 代理还需要
python-pyasn1
模块。 大多数分发版提供此模块作为可安装的单独包。 - 在某些情况下,Azure Linux 代理可能与 NetworkManager 不兼容。 分发版提供的许多包(.rpm 或 .deb)都将 NetworkManager 配置为与
waagent
包冲突。 在这些情况下,安装 Linux 代理包时,代理将卸载 NetworkManager。 - Azure Linux 代理必须至少是支持的最低版本。
注意
确保已启用 udf
和 vfat
模块。 禁用 udf
模块将导致预配失败。 禁用 vfat
模块会导致预配和启动失败。 如果这两个条件都存在,Cloud-init 版本 21.2 或更高版本可以预配 VM,而无需 UDF:
- 使用 SSH 公钥而不是密码创建了 VM。
- 未提供任何自定义数据。
常规 Linux 系统要求
修改 GRUB 或 GRUB2 中的内核引导行并包含以下参数,以便将所有控制台消息发送到第一个串行端口。 这些消息可以协助 Azure 支持人员调试任何问题。
GRUB_CMDLINE_LINUX="rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0"
我们还建议删除以下参数(如果存在):
rhgb quiet crashkernel=auto
图形界面式引导和安静引导在云环境中不适用,因为云环境中需要将所有日志都发送到串行端口。 如果需要,可以保留对
crashkernel
选项的配置,但此参数会将虚拟机中的可用内存量至少减少 128 MB。 对于较小的 VM 大小,降低可用内存可能会有问题。完成编辑 /etc/default/grub 后,运行以下命令以重新生成 GRUB 配置:
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
使用
dracut
为 initramfs 添加 Hyper-V 模块:cd /boot sudo cp initramfs-<kernel-version>.img <kernel-version>.img.bak sudo dracut -f -v initramfs-<kernel-version>.img <kernel-version> --add-drivers "hv_vmbus hv_netvsc hv_storvsc" sudo grub-mkconfig -o /boot/grub/grub.cfg sudo grub2-mkconfig -o /boot/grub2/grub.cfg
使用
mkinitramfs
为 initrd 添加 Hyper-V 模块:cd /boot sudo cp initrd.img-<kernel-version> initrd.img-<kernel-version>.bak sudo mkinitramfs -o initrd.img-<kernel-version> <kernel-version> --with=hv_vmbus,hv_netvsc,hv_storvsc sudo update-grub
请确保已安装 SSH 服务器且已将其配置为在引导时启动。 此配置通常是默认值。
安装 Azure Linux 代理。
Azure Linux 代理是在 Azure 上设置 Linux 映像所必需的。 许多分发版以 .rpm 或 .deb 包的形式提供代理。 包通常称为
WALinuxAgent
或walinuxagent
。 还可以按照《Azure Linux 代理指南》中的步骤手动安装代理。注意
确保已启用
udf
和vfat
模块。 删除或禁用它们将导致预配或启动失败。 Cloud-init 版本 21.2 或更高版本会删除 UDF 要求。运行以下命令之一,安装 Azure Linux 代理、cloud-init 和其他必要的实用工具。
对 Red Hat 或 CentOS 使用此命令:
sudo yum install -y WALinuxAgent cloud-init cloud-utils-growpart gdisk hyperv-daemons
对 Ubuntu/Debian 使用此命令:
sudo apt install walinuxagent cloud-init cloud-utils-growpart gdisk hyperv-daemons
对 SUSE 使用此命令:
sudo zypper install python-azure-agent cloud-init cloud-utils-growpart gdisk hyperv-daemons
然后在所有分发版上启用代理和 cloud-init:
sudo systemctl enable waagent.service sudo systemctl enable cloud-init.service
不要在 OS 磁盘上创建交换空间。
可以使用 Azure Linux 代理或 cloud-init 通过本地资源磁盘配置交换空间。 在 Azure 上预配后,此资源磁盘将附加到 VM。 本地资源磁盘是临时磁盘,并可能在取消预配 VM 时被清空。 以下程序块演示如何配置此交换。
如果选择 Azure Linux 代理,请在 /etc/waagent.conf 中修改以下参数:
ResourceDisk.Format=y ResourceDisk.Filesystem=ext4 ResourceDisk.MountPoint=/mnt/resource ResourceDisk.EnableSwap=y ResourceDisk.SwapSizeMB=2048 ## NOTE: Set this to your desired size.
如果选择 cloud-init,请将 cloud-init 配置为处理预配:
sudo sed -i 's/Provisioning.Agent=auto/Provisioning.Agent=cloud-auto/g' /etc/waagent.conf sudo sed -i 's/ResourceDisk.Format=y/ResourceDisk.Format=n/g' /etc/waagent.conf sudo sed -i 's/ResourceDisk.EnableSwap=y/ResourceDisk.EnableSwap=n/g' /etc/waagent.conf
若要将 cloud-init 配置为格式化和创建交换空间,有两个选项:
- 每次通过
customdata
创建 VM 时传入 cloud-init 配置。 我们建议使用此方法。 - 使用映像中的 cloud-init 指令在每次创建 VM 时配置交换空间。
使用 cloud-init 创建 .cfg 文件以配置交换空间:
sudo echo 'DefaultEnvironment="CLOUD_CFG=/etc/cloud/cloud.cfg.d/00-azure-swap.cfg"' >> /etc/systemd/system.conf sudo cat > /etc/cloud/cloud.cfg.d/00-azure-swap.cfg << EOF #cloud-config # Generated by Azure cloud image build disk_setup: ephemeral0: table_type: mbr layout: [66, [33, 82]] overwrite: True fs_setup: - device: ephemeral0.1 filesystem: ext4 - device: ephemeral0.2 filesystem: swap mounts: - ["ephemeral0.1", "/mnt/resource"] - ["ephemeral0.2", "none", "swap", "sw,nofail,x-systemd.requires=cloud-init.service,x-systemd.device-timeout=2", "0", "0"] EOF
- 每次通过
配置 cloud-init 来处理预配:
为 cloud-init 配置
waagent
:sudo sed -i 's/Provisioning.Agent=auto/Provisioning.Agent=cloud-init/g' /etc/waagent.conf sudo sed -i 's/ResourceDisk.Format=y/ResourceDisk.Format=n/g' /etc/waagent.conf sudo sed -i 's/ResourceDisk.EnableSwap=y/ResourceDisk.EnableSwap=n/g' /etc/waagent.conf
如果要迁移特定虚拟机,并且不想创建通用化映像,请在 /etc/waagent.conf 配置中设置
Provisioning.Agent=disabled
。配置装载:
sudo echo "Adding mounts and disk_setup to init stage" sudo sed -i '/ - mounts/d' /etc/cloud/cloud.cfg sudo sed -i '/ - disk_setup/d' /etc/cloud/cloud.cfg sudo sed -i '/cloud_init_modules/a\\ - mounts' /etc/cloud/cloud.cfg sudo sed -i '/cloud_init_modules/a\\ - disk_setup' /etc/cloud/cloud.cfg
配置 Azure 数据源:
sudo echo "Allow only Azure datasource, disable fetching network setting via IMDS" sudo cat > /etc/cloud/cloud.cfg.d/91-azure_datasource.cfg <<EOF datasource_list: [ Azure ] datasource: Azure: apply_network_config: False EOF
如果配置了一个交换文件,请删除现有交换文件:
if [[ -f /mnt/resource/swapfile ]]; then echo "Removing swapfile" #RHEL uses a swap file by default swapoff /mnt/resource/swapfile rm /mnt/resource/swapfile -f fi
配置 cloud-init 日志记录:
sudo echo "Add console log file" sudo cat >> /etc/cloud/cloud.cfg.d/05_logging.cfg <<EOF # This tells cloud-init to redirect its stdout and stderr to # 'tee -a /var/log/cloud-init-output.log' so the user can see output # there without needing to look on the console. output: {all: '| tee -a /var/log/cloud-init-output.log'} EOF
运行以下命令以取消预配虚拟机。
注意
如果要迁移特定的虚拟机,但不希望创建通用化映像,请跳过取消预配步骤。 运行命令
waagent -force -deprovision+user
将使源计算机不可用。 此步骤仅用于创建通用映像。sudo rm -f /var/log/waagent.log sudo cloud-init clean sudo waagent -force -deprovision+user sudo rm -f ~/.bash_history sudo export HISTSIZE=0
在 VirtualBox 上,运行
waagent -force -deprovision
后,可能会看到一条错误消息显示[Errno 5] Input/output error
。 此错误消息并不重要,可以忽略它。关闭虚拟机并将 VHD 上传到 Azure。