VM 应用程序概览

VM 应用程序是 Azure Compute Gallery(以前称为共享映像库)中的一种资源类型,可以简化虚拟机应用程序的管理、共享和全局分发。

尽管可以创建预安装了应用的 VM 的映像,但每次应用程序变化时都需要更新映像。 如果将应用程序安装与 VM 隔离,则意味着无需在更改每行代码后都要发布新的映像。

与其他部署和打包方法相比,应用程序包具有以下优点:

  • VM 应用程序支持 Azure 策略

  • 对包进行分组和版本控制

  • VM 应用程序可以全局复制以更接近你的基础结构,因此你无需使用AzCopy 或其他存储复制机制来跨 Azure 区域复制代码。

  • 通过 Azure 基于角色的访问控制 (RBAC) 与其他用户共享

  • 支持虚拟机,以及灵活和统一规模集

  • 如果你的 VM 或规模集上应用了网络安全组 (NSG) 规则,可能无法从 Internet 存储库下载包。 对于存储帐户,将包下载到锁定的 VM 需要设置专用链接。

  • 支持块 Blob:此功能可通过将大文件分成更小的可管理块来有效地处理大文件。 非常适合上传大量数据、流式处理和后台上传。

什么是 VM 应用包?

VM 应用程序包使用多种资源类型:

资源 说明
Azure Compute Gallery 库是用于管理和共享应用程序包的存储库。 用户可以共享库资源,所有子资源将自动共享。 每个订阅的库名称必须是唯一的。 例如,你可能有一个库用来存储所有操作系统映像,另一个库用来存储所有 VM 应用程序。
VM 应用程序 VM 应用程序的定义。 这是一个逻辑资源,用于存储其中所有版本的公共元数据。 例如,你可能有一个 Apache Tomcat 的应用程序定义,其中有多个版本。
VM 应用程序版本 可部署的资源。 可以将 VM 应用程序版本全局复制到离 VM 基础设施更近的目标区域。 必须先将 VM 应用程序版本复制到区域,然后才能将其部署到该区域中的 VM 上。

限制

  • 每个区域不超过 3 个副本:创建 VM 应用程序版本时,每个区域的最大副本数量是三个。

  • 具有公共访问权限的存储或具有读取权限的 SAS URI:存储帐户需要具有公共级别访问权限或使用具有读取权限的 SAS URI,因为其他限制级别会导致部署失败。

  • 重试失败的安装:目前,重试失败的安装的唯一方法是从配置文件中删除该应用程序,然后将其重新添加。

  • 每台 VM 仅限 25 个应用程序:任何时候均不得将超过 25 个应用程序部署到一台 VM。

  • 2GB 应用程序大小:应用程序版本的最大文件大小为 2GB。

  • 不能保证实现脚本中的重新启动功能:如果脚本需要重新启动,则建议在部署过程中将该应用程序置于最后。 尽管代码会尝试处理重启,但可能会失败。

  • 需要 VM 代理:VM 代理必须存在于 VM 中,并且必须能够收到目标状态。

  • 同一 VM 上的同一应用程序的多个版本:不能在一个 VM 上安装同一应用程序的多个版本。

  • 当前不支持移动操作:目前不支持使用 VM 应用将 VM 移动到其他资源组。

注意

对于 Azure Compute Gallery 和 VM 应用程序,可以在复制后删除存储 SAS。 但是,任何后续更新操作都需要有效的 SAS。

成本

使用 VM 应用程序包不会产生额外的费用,但以下资源需要付费:

  • 存储每个包和任何副本的存储成本。
  • 将第一个映像版本从源区域复制到目标区域的网络传出费用。 后续副本将在区域内进行处理,因此不会产生额外费用。

有关网络流出量的详细信息,请参阅带宽定价

VM 应用程序

VM 应用程序资源定义有关 VM 应用程序的以下内容:

  • 存储 VM 应用程序的 Azure Compute Gallery
  • 应用程序的名称
  • 支持的操作系统类型,如 Linux 或 Windows
  • VM 应用程序的说明

VM 应用程序版本

VM 应用程序版本是可部署的资源。 版本是用以下属性定义的:

  • 版本号
  • 链接到存储帐户中的应用程序包文件
  • 安装用于安装应用程序的字符串
  • 删除字符串以显示如何正确地删除应用
  • 将包文件下载到 VM 时要使用的包文件名
  • 要用于在 VM 上配置应用的配置文件名
  • 指向 VM 应用程序的配置文件(其中可加入许可证文件)的链接
  • 更新字符串以了解如何将 VM 应用程序更新到更高版本
  • 生命周期结束日期。 生命周期结束日期仅供参考;你仍可以在生命周期日期后部署 VM 应用程序版本。
  • 最新版本中不包含它。 可将某个版本设为不用作最新版本的应用程序。
  • 用于复制的目标区域
  • 每个区域的副本计数

下载目录

应用程序包和配置文件的下载位置如下:

  • Linux:/var/lib/waagent/Microsoft.CPlat.Core.VMApplicationManagerLinux/<appname>/<app version>
  • Windows: C:\Packages\Plugins\Microsoft.CPlat.Core.VMApplicationManagerWindows\1.0.9\Downloads\<appname>\<app version>

假设应用程序包和配置文件位于当前目录中,则应写入安装/更新/删除命令。

文件命名

将应用程序文件下载到 VM 后,它将重命名为“MyVmApp”(没有扩展名)。 这是因为 VM 不知道包的原始名称或扩展名。 它利用它唯一的名称,即应用程序名称本身 - “MyVmApp”。

下面是一些用于导航此问题的替代方法:

可以修改脚本以包含用于在执行前重命名文件的命令:

move .\\MyVmApp .\\MyApp.exe & MyApp.exe /S

还可以使用 packageFileName(和相应的 configFileName)属性来指示我们重命名文件的内容。 例如,将其设置为“MyApp.exe”将使安装脚本只需为:

MyAppe.exe /S

提示

如果 Blob 最初名为“myApp.exe”而不是“myapp”,则上述脚本无需设置 packageFileName 属性即可正常运行。

命令解释器

默认的命令解释器是:

  • Linux:/bin/bash
  • Windows: cmd.exe

只要它安装在计算机上,通过调用可执行文件并将命令传递给它,就可以使用不同的解释器,如 Chocolatey 或 PowerShell。 例如,若要让命令在 Windows 上的 PowerShell 中运行,而不是在 cmd 中运行,可以传递 powershell.exe -Command '<powershell commmand>'

如何处理更新

当更新在 VM 或虚拟机规模集上的应用程序版本时,将使用在部署期间提供的更新命令。 如果更新后的版本没有更新命令,则删除当前版本并安装新版本。

写入更新命令时,应假定能够从任何旧版本的 VM 应用程序进行更新。

关于在 Linux 上创建 VM 应用程序的技巧

适用于 Linux 的第三方应用程序可以通过几种方式打包。 让我们探讨如何针对一些最常见情况创建安装命令。

.tar 和 .gz 文件

这些文件是压缩存档,可提取到所需位置。 如需将原始程序包提取到特定位置,请查看原始包的安装说明。 如果 .tar.gz 文件包含源代码,请参阅包的说明以了解如何从源位置安装。

在 Linux 计算机上安装 golang 的安装命令示例:

sudo tar -C /usr/local -xzf go_linux

删除命令示例:

sudo rm -rf /usr/local/go

使用 .deb.rpm 和其他供 Internet 访问受限的 VM 使用的特定于平台的包创建应用程序包

可以为特定于平台的包管理器下载单独的包,但这些包通常不一定包含所有依赖项。 对于这些文件,还必须在应用程序包中包括所有依赖项,或者让系统包管理器通过 VM 可用的存储库来下载依赖项。 如果使用的 VM 在 Internet 访问方面受到限制,则必须自己打包所有依赖项。

找出依赖项可能有点棘手。 有第三方工具可以显示整个依赖项树。

在 Ubuntu 中,你可以运行 sudo apt show <package_name> | grep Depends 显示执行 sudo apt-get install <packge_name> 命令时安装的所有包。 然后,可以使用该输出下载所有 .deb 文件,以创建可用作应用程序包的存档。

  1. 例如,若要创建 VM 应用程序包来安装适用于 Ubuntu 的 PowerShell,请先运行以下命令启用可以从中下载 PowerShell 的存储库,并标识新 Ubuntu VM 上的包依赖项。
# Download the Microsoft repository GPG keys
wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb"
# Register the Microsoft repository GPG keys
sudo dpkg -i packages-microsoft-prod.deb
sudo rm -rf packages-microsoft-prod.deb
sudo apt update
sudo apt show powershell | grep Depends
  1. 请检查列出以下包的行“依赖”的输出:
Depends: libc6, lib32gcc-s1, libgssapi-krb5-2, libstdc++6, zlib1g, libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52, libssl3|libssl1.1|libssl1.0.2|libssl1.
  1. 使用 sudo apt-get download <package_name> 下载其中的每个文件,然后创建包含所有文件的 tar 压缩存档。
  • Ubuntu 18.04:
mkdir /tmp/powershell
cd /tmp/powershell
sudo apt-get download libc6
sudo apt-get download lib32gcc-s1
sudo apt-get download libgssapi-krb5-2
sudo apt-get download libstdc++6
sudo apt-get download zlib1g
sudo apt-get download libssl1.1
sudo apt-get download libicu60
sudo apt-get download powershell
sudo tar -cvzf powershell.tar.gz *.deb
  • Ubuntu 20.04:
mkdir /tmp/powershell
cd /tmp/powershell
sudo apt-get download libc6
sudo apt-get download lib32gcc-s1
sudo apt-get download libgssapi-krb5-2
sudo apt-get download libstdc++6
sudo apt-get download zlib1g
sudo apt-get download libssl1.1
sudo apt-get download libicu66
sudo apt-get download powershell
sudo tar -cvzf powershell.tar.gz *.deb
  • Ubuntu 22.04:
mkdir /tmp/powershell
cd /tmp/powershell
sudo apt-get download libc6
sudo apt-get download lib32gcc-s1
sudo apt-get download libgssapi-krb5-2
sudo apt-get download libstdc++6
sudo apt-get download zlib1g
sudo apt-get download libssl3
sudo apt-get download libicu70
sudo apt-get download powershell
sudo tar -cvzf powershell.tar.gz *.deb
  1. 此 tar 存档将是应用程序包文件。
  • 在这种情况下,安装命令为:
sudo tar -xvzf powershell.tar.gz && sudo dpkg -i *.deb
  • 删除命令为:
sudo apt remove powershell

使用 sudo apt autoremove,而不是明确尝试删除所有依赖项。 你可能已经安装了包含重叠依赖项的其他应用程序,在这种情况下,显式删除命令将失败。

如果你不想自行解决依赖项并且 apt 能够连接到存储库,则可以使用一个 .deb 文件来安装应用程序,并让 apt 处理依赖项。

安装命令示例:

dpkg -i <package_name> || apt --fix-broken install -y

关于在 Windows 上创建 VM 应用程序的技巧

Windows 中的大多数第三方应用程序作为 .exe 或 .msi 安装程序提供。 部分应用程序还可用作提取和运行 zip 文件。 让我们看看每种格式的最佳实践。

.exe 安装程序

安装程序可执行文件通常启动用户界面 (UI),并要求用户选择 UI。 如果安装程序支持静默模式参数,则应将此参数包含在安装字符串中。

cmd.exe 还要求可执行文件具有扩展名 .exe,因此你需要重命名该文件,加上 .exe 扩展名。

如果我想为作为可执行文件提供的 myApp.exe 创建一个 VM 应用程序包,我的 VM 应用程序称为“myApp”,所以我编写命令时假设应用程序包在当前目录中:

"move .\\myApp .\\myApp.exe & myApp.exe /S -config myApp_config"

如果安装程序可执行文件不支持卸载参数,有些情况下你可以在测试计算机上查找注册表,以了解卸载程序所在的位置。

在注册表中,卸载字符串存储在 Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\<installed application name>\UninstallString 中,因此我将使用内容作为删除命令:

'\"C:\\Program Files\\myApp\\uninstall\\helper.exe\" /S'

.msi 安装程序

要通过命令行来执行 .msi 安装程序,安装或删除应用程序的命令应使用 msiexec。 通常,msiexec 作为单独的进程运行,cmd 不会等待它完成,这可能会导致在安装多个 VM 应用程序时出现问题。 start 命令可以与 msiexec 结合使用,以确保在命令返回之前安装完成。 例如:

start /wait %windir%\\system32\\msiexec.exe /i myapp /quiet /forcerestart /log myapp_install.log

删除命令示例:

start /wait %windir%\\system32\\msiexec.exe /x $appname /quiet /forcerestart /log ${appname}_uninstall.log

通常,start 命令将在批处理脚本中调用。 如果与 /wait 参数一起使用,调用脚本将暂停,直到被调用的进程终止。 完成后,批处理脚本将检查 start 命令设置的 errorlevel 变量,然后退出,如下所示:

start /wait %windir%\\system32\\msiexec.exe /i myapp /quiet /forcerestart /log myapp_install.log
if %errorlevel% neq 0 exit /b %errorlevel%
...

压缩文件

对于.zip 或压缩文件,请将应用程序包的内容重命名并解压到所需的目标。

安装命令示例:

rename myapp myapp.zip && mkdir C:\myapp && powershell.exe -Command "Expand-Archive -path myapp.zip -destinationpath C:\myapp"

删除命令示例:

rmdir /S /Q C:\\myapp

将失败视为部署失败

无论在安装/更新/删除时是否有任何 VM 应用程序失败,VM 应用程序扩展始终会返回成功。 仅当扩展或底层基础架构出现问题时,VM 应用程序扩展才将扩展状态报告为失败。 此行为是由“将失败视为部署失败”标志触发的,该标志默认设置为 $false,并且可以更改为 $true。 失败标志可以在 PowerShellCLI 中配置。

排查 VM 应用程序问题

若要了解是否已成功将特定 VM 应用程序添加到 VM 实例,请查看 VM 应用程序扩展的消息。

若要详细了解如何获取 VM 扩展的状态,请参阅 Linux 的虚拟机扩展和功能Windows 的虚拟机扩展和功能

若要获取 VM 扩展的状态,请使用 Get-AzVM

Get-AzVM -name <VM name> -ResourceGroupName <resource group name> -Status | convertto-json -Depth 10

若要获取规模集扩展的状态,请使用 Get-AzVMSS

$result = Get-AzVmssVM -ResourceGroupName $rgName -VMScaleSetName $vmssName -InstanceView
$resultSummary  = New-Object System.Collections.ArrayList
$result | ForEach-Object {
    $res = @{ instanceId = $_.InstanceId; vmappStatus = $_.InstanceView.Extensions | Where-Object {$_.Name -eq "VMAppExtension"}}
    $resultSummary.Add($res) | Out-Null
}
$resultSummary | convertto-json -depth 5

Error messages

Message 说明
当前 VM 应用程序版本 {name} 已于 {date} 弃用。 你尝试部署的 VM 应用程序版本已被弃用。 尝试使用 latest,而不是指定特定的版本。
当前 VM 应用程序版本 {name} 支持操作系统 {OS},而当前 OSDisk 的操作系统为 {OS}。 你尝试将 Linux 应用程序部署到 Windows 实例,或者反之。
已超过了 VM 应用程序的最大数量(最大值=5,当前值={count})。 使用较少的应用程序并重试请求。 目前每个 VM 或规模集仅支持 5 个 VM 应用程序。
指定了多个具有相同 packageReferenceId 的 VMApplication。 多次指定了相同的应用程序。
订阅无权访问此映像。 订阅无权访问此应用程序版本。
参数中的存储帐户不存在。 没有此订阅的通知。
平台映像 {image} 不可用。 确认存储配置文件中的所有字段均正确。 有关存储配置文件的更多详细信息,请参阅https://aka.ms/storageprofile 应用程序不存在。
库映像 {image} 在 {region} 区域中不可用。 请联系映像所有者以将其复制到此区域,或者更改你请求的区域。 库应用程序版本存在,但未复制到此区域。
SAS 对于源 uri {uri} 无效。 尝试检索有关 url(mediaLink 或 defaultConfigurationLink)的信息时从存储收到 Forbidden 错误。
源 uri {uri} 引用的 Blob 不存在。 为 mediaLink 或 defaultConfigurationLink 属性提供的 Blob 不存在。
由于以下错误,无法访问库库应用程序版本 url {url}:找不到远程名称。 确保 blob 存在并且可公开访问,或者是具有读取权限的 SAS url。 最可能的情况是未提供具有读取权限的 SAS uri。
由于以下错误,无法访问库库应用程序版本 url {url}:{error description}。 确保 blob 存在并且可公开访问,或者是具有读取权限的 SAS url。 提供的存储 blob 存在问题。 错误描述提供更多信息。
{Application} 上不允许使用操作 {operationName},因为该操作已被标记为删除。 只能重试 Delete 操作(或等待当前操作完成)。 尝试更新当前正在删除的应用程序。
参数“galleryApplicationVersion.properties.publishingProfile.replicaCount”的值 {value} 超出范围。 此值必须介于 1 到 3 之间(均含)。 VM Application 版本只允许 1 到 3 个副本。
不允许更改属性“galleryApplicationVersion.properties.publishingProfile.manageActions.install”。 (或更新、删除) 无法更改现有 VmApplication 上的任何管理操作。 必须创建新的 VmApplication 版本。
不允许更改属性“galleryApplicationVersion.properties.publishingProfile.settings.packageFileName”。 (或 configFileName) 无法更改任何设置,例如包文件名或配置文件名。 必须创建新的 VmApplication 版本。
源 uri {uri} 引用的 blob 太大:大小 = {size}。 允许的最大 blob 大小为“1 GB”。 mediaLink 或 defaultConfigurationLink 引用的 blob 的最大大小当前为 1 GB。
源 uri {uri} 引用的 blob 为空。 引用了一个空的 blob。
{operation} 操作不支持 {type} blob 类型。 仅支持页 blob 和块 blob。 VmApplications 仅支持页 blob 和块 blob。
SAS 对于源 uri {uri} 无效。 为 mediaLink 或 defaultConfigurationLink 提供的 SAS uri 不是有效的 SAS uri。
无法在目标区域指定 {region},因为订阅缺少必需的功能 {featureName}。 使用所需的功能注册订阅,或者从目标区域列表中删除区域。 若要在某些受限区域使用 VmApplication,必须为该订阅注册功能标志。
库映像版本发布配置文件区域 {regions} 必须包含映像版本的位置 {location}。 要复制的区域列表必须包含应用程序版本所在的位置。
目标发布区域中不允许出现重复区域。 发布区域不能有重复项。
库应用程序版本资源当前不支持加密。 VM 应用程序不支持目标区域的加密属性
实体名称与请求 URL 中的名称不匹配。 请求 URL 中指定的库应用程序版本与请求正文中指定的版本不匹配。
库应用程序版本名称无效。 应用程序版本名称应遵循 Major(int32)。 Minor(int32)。 Patch(int32) 格式,其中 int 介于 0 到 2,147,483,647 之间(均含)。 例如 1.0.0、2018.12.1 等。 画廊应用程序版本必须遵循指定的格式。

后续步骤