为 Azure 应用服务配置自定义容器
本文说明如何将自定义容器配置为在 Azure App Service 上运行。
本指南提供有关应用服务中的 Linux 应用的容器化的重要概念和说明。 若从未使用过 Azure 应用服务,则请先按照自定义容器快速入门和教程进行操作。 有关挎斗容器(预览版),请参阅教程:在 Azure 应用服务中为自定义容器配置挎斗容器(预览版)。
注意
Windows 容器映像拉取身份验证不再支持服务主体。 建议的方法是将托管标识用于 Windows 和 Linux 容器
支持的父映像
对于自定义 Windows 映像,必须为所需框架选择适当的父映像(基础映像):
- 若要部署 .NET Framework 应用,请使用基于 Windows Server 2019 Core 长期服务渠道 (LTSC) 发行版的父映像。
- 若要部署 .NET Core 应用,请使用基于 Windows Server 2019 Nano 半年服务渠道 (SAC) 发行版的父映像。
在应用启动期间,下载父映像需要一些时间。 不过,可以使用已缓存在 Azure 应用服务中的下述父映像之一,缩短启动时间:
- mcr.microsoft.com/windows/servercore:ltsc2022
- mcr.microsoft.com/windows/servercore:ltsc2019
- mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2022
- mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019
- mcr.microsoft.com/dotnet/runtime:6.0-nanoserver-ltsc2022
- mcr.microsoft.com/dotnet/runtime:6.0-nanoserver-1809
- mcr.microsoft.com/dotnet/aspnet:6.0-nanoserver-ltsc2022
- mcr.microsoft.com/dotnet/aspnet:6.0-nanoserver-1809
更改自定义容器的 Docker 映像
若要将现有的自定义容器从当前 Docker 映像更改为新映像,请使用以下命令:
az webapp config container set --name <app-name> --resource-group <group-name> --docker-custom-image-name <docker-hub-repo>/<image>
使用专用注册表中的映像
使用专用注册表(如 Azure 容器注册表)中的映像,请运行以下命令:
az webapp config container set --name <app-name> --resource-group <group-name> --docker-custom-image-name <image-name> --docker-registry-server-url <private-repo-url> --docker-registry-server-user <username> --docker-registry-server-password <password>
对于 <username> 和 <password>,请提供专用注册表帐户的登录凭据。
使用托管标识从 Azure 容器注册表拉取映像
使用以下步骤配置 Web 应用,以使用托管标识从 Azure 容器注册表 (ACR) 进行拉取。 这些步骤使用系统分配的托管标识,但你也可以使用用户分配的托管标识。
使用
az webapp identity assign
命令为 Web 应用启用系统分配的托管标识:az webapp identity assign --resource-group <group-name> --name <app-name> --query principalId --output tsv
将
<app-name>
替换为上一步使用的名称。 命令的输出(由--query
和--output
参数筛选)是分配的标识的服务主体 ID。获取 Azure 容器注册表的资源 ID:
az acr show --resource-group <group-name> --name <registry-name> --query id --output tsv
将
<registry-name>
替换为注册表的名称。 命令的输出(由--query
和--output
参数筛选)是 Azure 容器注册表的资源 ID。授予托管标识访问容器注册表的权限:
az role assignment create --assignee <principal-id> --scope <registry-resource-id> --role "AcrPull"
请替换以下值:
- 将
<principal-id>
替换为az webapp identity assign
命令中的服务主体 ID - 将
<registry-resource-id>
替换为az acr show
命令中的容器注册表 ID
有关这些权限的详细信息,请参阅什么是 Azure 基于角色的访问控制。
- 将
配置应用,以使用托管标识从 Azure 容器注册表进行拉取。
az webapp config set --resource-group <group-name> --name <app-name> --generic-configurations '{"acrUseManagedIdentityCreds": true}'
请替换以下值:
- 将
<app-name>
替换为 Web 应用的名称。
提示
如果使用 PowerShell 控制台运行命令,则需在本步骤和下一步中将
--generic-configurations
参数中的字符串进行转义。 例如:--generic-configurations '{\"acrUseManagedIdentityCreds\": true'
- 将
(可选)如果应用使用用户分配的托管标识,请确保在 Web 应用中已进行了标识配置,然后设置
acrUserManagedIdentityID
属性来指定其客户端 ID:az identity show --resource-group <group-name> --name <identity-name> --query clientId --output tsv
替换用户分配的托管标识的
<identity-name>
,并使用输出<client-id>
来配置用户分配的托管标识 ID。az webapp config set --resource-group <group-name> --name <app-name> --generic-configurations '{"acrUserManagedIdentityID": "<client-id>"}'
全部设置完毕后,Web 应用现在使用托管标识从 Azure 容器注册表中进行拉取。
使用受网络保护的注册表中的映像
若要连接虚拟网络内的或本地的注册表并从中拉取数据,应用必须与虚拟网络 (VNET) 集成。 对于具有专用终结点的 Azure 容器注册表,也需要 VNET 集成。 配置好网络和 DNS 解析后,可通过配置 vnetImagePullEnabled
站点设置启用通过虚拟网络拉取映像的路由:
az resource update --resource-group <group-name> --name <app-name> --resource-type "Microsoft.Web/sites" --set properties.vnetImagePullEnabled [true|false]
我看不到更新的容器
如果将 Docker 容器的设置更改为指向新的容器,可能需要几分钟,应用才能从新容器处理 HTTP 请求。 在拉取和启动新容器时,应用服务会继续处理来自旧容器的请求。 只有新容器已启动并准备好接收请求后,应用服务才会开始向新容器发送请求。
容器映像的存储方式
首次在应用服务中运行自定义 Docker 映像时,应用服务会执行 docker pull
并拉取所有映像层。 这些层存储在磁盘上,就像使用 Docker 本地一样。 应用服务每次重新启动时,都将执行 docker pull
,但只拉取已更改的层。 如果没有更改,应用服务将使用本地磁盘上的现有层。
如果应用由于某种原因(例如向上和向下扩展定价层)更改了计算实例,应用服务必须再次拉取所有层。 如果横向扩展以添加更多实例,则也是这种情况。 在极少数情况下,应用实例可能会在无扩展操作的情况下发生变化。
配置端口号
默认情况下,应用服务假定自定义容器在端口 80 上进行侦听。 如果容器侦听其他端口,请在应用服务应用中设置 WEBSITES_PORT
应用设置。 可以通过 Azure CLI 进行设置。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITES_PORT=8000
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"WEBSITES_PORT"="8000"}
应用服务目前允许容器只为 HTTP 请求提供一个端口。
配置环境变量
自定义容器可能会使用需要在外部提供的环境变量。 可以通过 Azure CLI 传入它们。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings DB_HOST="myownserver.mysql.database.chinacloudapi.cn"
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"DB_HOST"="myownserver.mysql.database.chinacloudapi.cn"}
当应用运行时,应用服务应用设置会自动作为环境变量注入到进程中。 可以通过 URL https://<app-name>.scm.chinacloudsites.cn/Env
来验证容器环境变量。
如果应用使用专用注册表或 Docker Hub 中的映像,则用于访问存储库的凭据保存在环境变量 DOCKER_REGISTRY_SERVER_URL
、DOCKER_REGISTRY_SERVER_USERNAME
、DOCKER_REGISTRY_SERVER_PASSWORD
中。 由于存在安全风险,这些保留变量名都不会向应用程序公开。
对于基于 IIS 或 .NET Framework(4.0 或更高版本)的容器,应用服务会将它们作为 .NET 应用设置和连接字符串自动注入到 System.ConfigurationManager
中。 对于所有其他语言或框架,它们作为该进程的环境变量提供,其中包含以下相应的前缀之一:
APPSETTING_
SQLCONTR_
MYSQLCONTR_
SQLAZURECOSTR_
POSTGRESQLCONTR_
CUSTOMCONNSTR_
此方法适用于单容器应用或多容器应用,其中环境变量是在 docker-compose.yml 文件中指定的。
添加持久共享存储
你可以在你的自定义容器文件系统中使用 C:\home 目录,以便在重新启动时持续保存文件,并在不同的实例中共享它们。 提供 C:\home
目录是为了使自定义容器能够访问持久存储。
禁用持久存储后,写入 C:\home
目录的所有内容不会在应用重动或多个实例之间持久保存。 启用持久存储时,将保留写入到 C:\home
目录的所有内容,可由横向扩展的应用的所有实例访问。 此外,当容器启动时,容器的 C:\home
目录内的任何内容都将被持久存储上已存在的任何现有文件覆盖。
唯一的例外是 C:\home\LogFiles
目录,它用于存储容器和应用程序日志。 如果使用“文件系统”选项启用应用程序日志记录,则此文件夹始终在应用重启时保留,与启用或禁用持久存储无关。 换句话说,启用或禁用持久存储不影响应用程序的日志记录行为。
默认情况下,在 Windows 自定义容器上启用持久存储。 若要禁用,请通过 Cloud Shell 将 WEBSITES_ENABLE_APP_SERVICE_STORAGE
应用设置值设为 false
。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITES_ENABLE_APP_SERVICE_STORAGE=false
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"WEBSITES_ENABLE_APP_SERVICE_STORAGE"=false}
你可以在你的自定义容器文件系统中使用 /home 目录,以便在重新启动时持续保存文件,并在不同的实例中共享它们。 提供 /home
目录是为了使自定义容器能够访问持久存储。 在 /home
中保存数据计入应用服务计划中包含的存储空间配额。
禁用持久存储后,写入 /home
目录的所有内容不会在应用重动或多个实例之间持久保存。 启用持久存储时,将保留写入到 /home
目录的所有内容,可由横向扩展的应用的所有实例访问。 此外,当容器启动时,容器的 /home
目录内的任何内容都将被持久存储上已存在的任何现有文件覆盖。
唯一的例外是 /home/LogFiles
目录,它用于存储容器和应用程序日志。 如果使用“文件系统”选项启用应用程序日志记录,则此文件夹始终在应用重启时保留,与启用或禁用持久存储无关。 换句话说,启用或禁用持久存储不影响应用程序的日志记录行为。
建议将数据写入 /home
或装载的 Azure 存储路径。 在重启期间,在这些路径外部写入的数据不是持久的,会保存到独立于应用服务计划文件存储配额的平台托管主机磁盘空间。
默认情况下,持久存储在 Linux 自定义容器上处于已禁用状态。 若要启用,请通过 Azure CLI 或 Azure PowerShell 将 WEBSITES_ENABLE_APP_SERVICE_STORAGE
应用设置值设置为 true
。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITES_ENABLE_APP_SERVICE_STORAGE=true
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"WEBSITES_ENABLE_APP_SERVICE_STORAGE"=true}
注意
你还可以配置自己的持久存储。
检测 HTTPS 会话
应用服务在前端终止 TLS/SSL。 也就是说,TLS/SSL 请求永远不会进入你的应用程序。 不需要,也不应在应用程序中实现对 TLS/SSL 的任何支持。
前端位于 Azure 数据中心内。 如果对应用程序使用 TLS/SSL,则始终会安全加密 Internet 上的流量。
自定义 ASP.NET 计算机密钥注入
在容器启动过程中,会将自动生成的密钥作为 ASP.NET 加密例程的计算机密钥注入到容器中。 可以通过以下环境变量在容器中找到这些密钥:MACHINEKEY_Decryption
、MACHINEKEY_DecryptionKey
、MACHINEKEY_ValidationKey
、MACHINEKEY_Validation
。
如果应用程序依赖于这些密钥,每次重启时的新密钥可能会重置 ASP.NET 窗体身份验证和视图状态。 要阻止自动重新生成密钥,请手动将其设置为应用服务应用设置。
连接到容器
通过导航到https://<app-name>.scm.chinacloudsites.cn/
并选择 SSH 选项,可以直接连接到 Windows 容器以执行诊断任务。 与容器建立直接 SSH 会话,可以在容器中运行命令。
- 它独立于其上方的图形浏览器运行,只显示共享存储中的文件。
- 在向外扩展的应用程序中,SSH 会话连接到一个容器实例。 可以从顶部 Kudu 菜单的“实例”下拉列表中选择其他实例。
- 重启应用后,SSH 会话内对容器所做的任何更改都不会保留(共享存储中的更改除外),因为它不是 Docker 映像的一部分。 要保存更改,如注册表设置和软件安装,请将其设为 Dockerfile 的一部分。
访问诊断日志
应用服务通过 Docker 主机以及容器中的活动记录操作。 默认情况下,会附带 Docker 主机中的日志(平台日志),但容器中的应用程序日志或 web 服务器日志则需要手动启用。 有关详细信息,请参阅启用应用程序日志记录和启用 Web 服务器日志记录。
有多种方法可访问 Docker 日志:
在 Azure 门户中配置
Docker 日志显示在门户中应用的“容器设置”页面中。 日志被截断,但可以选择“下载”来下载所有日志。
来自 Kudu
导航到 https://<app-name>.scm.chinacloudsites.cn/DebugConsole
并选择 LogFiles 文件夹以查看各个日志文件。 要下载整个 LogFiles 目录,请选择目录名称左侧的“下载”图标。 还可以使用 FTP 客户端访问此文件夹。
在 SSH 终端中,默认情况下无法访问 C:\home\LogFiles
文件夹,因为未启用持久共享存储。 要在控制台终端中启用此行为,请启用持久共享存储。
如果尝试使用 FTP 客户端下载当前正在使用的 Docker 日志,可能会由于文件锁定而出现错误。
使用 Kudu API
直接导航到 https://<app-name>.scm.chinacloudsites.cn/api/logs/docker
以查看 Docker 日志的元数据。 可能会看到列出了多个日志文件,而href
属性允许直接下载日志文件。
要将所有日志一起下载到一个 ZIP 文件中,请访问 https://<app-name>.scm.chinacloudsites.cn/api/logs/docker/zip
。
自定义容器内存
默认情况下,部署在 Azure 应用服务中的所有 Windows 容器均配置了内存限额。 下表列出了每个应用服务计划 SKU 的默认设置。
应用服务计划 SKU | 每个应用的默认内存限额(以 MB 为单位) |
---|---|
P1v3 | 1024 |
P1Mv3 | 1024 |
P2v3 | 1536 |
P2Mv3 | 1536 |
可以通过 Azure CLI 或 Azure PowerShell 提供 WEBSITE_MEMORY_LIMIT_MB
应用设置来更改此值。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITE_MEMORY_LIMIT_MB=2000
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"WEBSITE_MEMORY_LIMIT_MB"=2000}
该值以 MB 为单位定义,并且必须小于或等于主机的总物理内存。 例如,在具有 8 GB RAM 的应用服务计划中,所有应用的累积总数 WEBSITE_MEMORY_LIMIT_MB
不得超过 8 GB。 有关每个定价层的可用内存量的信息,请参阅应用程序服务定价。
自定义计算核心数
默认情况下,Windows 容器将运行,其中包含所选定价层的所有可用内核。 例如,可能想要减少过渡槽使用的内核数。 要减少容器使用的内核数,请将 WEBSITE_CPU_CORES_LIMIT
应用设置设置为首选的内核数。 可以通过 Azure CLI 进行设置。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --slot staging --settings WEBSITE_CPU_CORES_LIMIT=1
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"WEBSITE_CPU_CORES_LIMIT"=1}
注意
更新应用设置会触发自动重新启动,从而使停机时间最短。 对于生产应用,请考虑将其交换到过渡槽,在过渡槽中更改应用设置,然后将其交换回生产。
通过门户或 Kudu 门户 (https://<app-name>.scm.chinacloudsites.cn/webssh/host
) 打开 SSH 会话,并使用 PowerShell 键入以下命令,验证调整后的数字。 每个命令输出一个数字。
Get-ComputerInfo | ft CsNumberOfLogicalProcessors # Total number of enabled logical processors. Disabled processors are excluded.
Get-ComputerInfo | ft CsNumberOfProcessors # Number of physical processors.
处理器可能是多核处理器或超线程处理器。 有关每个定价层可用核心数量的信息,请参阅应用程序服务定价。
自定义运行状况 ping 行为
应用服务认为容器在容器启动时成功启动并响应 HTTP ping。 运行状况 ping 请求包含标头 User-Agent= "App Service Hyper-V Container Availability Check"
。 如果容器在一段时间后启动但不响应 ping,应用服务会在 Docker 日志中记录一个事件,指出容器未启动。
如果你的应用程序占用大量资源,则容器可能无法及时响应 HTTP ping。 要控制 HTTP ping 失败时的操作,请设置 CONTAINER_AVAILABILITY_CHECK_MODE
应用设置。 可以通过 Azure CLI 进行设置。 在 Bash 中:
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings CONTAINER_AVAILABILITY_CHECK_MODE="ReportOnly"
在 PowerShell 中运行:
Set-AzWebApp -ResourceGroupName <group-name> -Name <app-name> -AppSettings @{"CONTAINER_AVAILABILITY_CHECK_MODE"="ReportOnly"}
下表列出了可能的值:
“值” | 说明 |
---|---|
Repair | 三次连续可用性检查后重启容器 |
ReportOnly | 默认值。 请不要重启容器,但在三次连续的可用性检查后,会在容器的 Docker 日志中报告。 |
关闭 | 不检查可用性。 |
支持组托管服务帐户
应用服务中的 Windows 容器当前不支持组托管服务帐户 (gMSA)。
启用 SSH
安全外壳 (SSH) 通常用于通过命令行终端以远程方式执行管理命令。 若要使用自定义容器启用 Azure 门户 SSH 控制台功能,需要执行以下步骤:
使用以下示例内容创建标准
sshd_config
文件,并将其放置在应用程序项目根目录上:Port 2222 ListenAddress 0.0.0.0 LoginGraceTime 180 X11Forwarding yes Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr MACs hmac-sha1,hmac-sha1-96 StrictModes yes SyslogFacility DAEMON PasswordAuthentication yes PermitEmptyPasswords no PermitRootLogin yes Subsystem sftp internal-sftp
注意
此文件配置 OpenSSH,并且必须包含以下项,以符合 Azure 门户 SSH 功能:
Port
必须设置为 2222。Ciphers
必须至少包含此列表中的一项:aes128-cbc,3des-cbc,aes256-cbc
。MACs
必须至少包含此列表中的一项:hmac-sha1,hmac-sha1-96
。
创建一个名称为
entrypoint.sh
的入口点脚本(或更改任何现有的入口点文件),并添加用于启动 SSH 服务的命令以及应用程序启动命令。 以下示例演示如何启动 Python 应用程序。 请根据项目语言/堆栈替换最后一个命令:根据基础映像分发方式,将以下说明添加到 Dockerfile。 这些指示会分别复制新文件、安装 OpenSSH 服务器、设置适当的权限和配置自定义入口点,并公开应用程序和 SSH 服务器所需的端口:
COPY entrypoint.sh ./ # Start and enable SSH RUN apt-get update \ && apt-get install -y --no-install-recommends dialog \ && apt-get install -y --no-install-recommends openssh-server \ && echo "root:Docker!" | chpasswd \ && chmod u+x ./entrypoint.sh COPY sshd_config /etc/ssh/ EXPOSE 8000 2222 ENTRYPOINT [ "./entrypoint.sh" ]
注意
根密码必须恰好是
Docker!
,因为应用服务使用它以使你能够使用容器访问 SSH 会话。 此配置不允许从外部建立到容器的连接。 容器的端口 2222 只能在专用虚拟网络的桥网络中访问,Internet 上的攻击者无法访问该端口。重新生成 Docker 映像并将其推送到注册表,然后在 Azure 门户上测试 Web 应用 SSH 功能。
有关进一步的故障排除信息,请参阅 Azure 应用服务博客:在用于容器的 Linux Web 应用上启用 SSH
访问诊断日志
可以访问在容器中生成的控制台日志。
首先,请运行以下命令,以便启用容器日志记录功能:
az webapp log config --name <app-name> --resource-group <resource-group-name> --docker-container-logging filesystem
将 <app-name>
和 <resource-group-name>
替换为适合 Web 应用的名称。
启用容器日志记录功能以后,请运行以下命令来查看日志流:
az webapp log tail --name <app-name> --resource-group <resource-group-name>
如果没有立即看到控制台日志,请在 30 秒后重新查看。
若要随时停止日志流式处理,可键入 CtrlC。
也可通过浏览器在 https://<app-name>.scm.chinacloudsites.cn/api/logs/docker
中检查日志文件。
配置多容器应用
在 Docker Compose 中使用持久性存储
多容器应用(如 WordPress)需要持久存储才能正常工作。 要启用持久存储,你的 Docker Compose 配置必须指向容器外部的存储位置。 在应用重新启动后,容器中的存储位置不会保存更改。
通过在 Azure CLI 中使用 az webapp config appsettings set 命令来设置 WEBSITES_ENABLE_APP_SERVICE_STORAGE
应用设置,以此启用持久存储。
az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITES_ENABLE_APP_SERVICE_STORAGE=TRUE
在 docker-compose.yml 文件中,将 volumes
选项映射到 ${WEBAPP_STORAGE_HOME}
。
WEBAPP_STORAGE_HOME
是应用服务中已映射到应用持续性存储的环境变量。 例如:
wordpress:
image: <image name:tag>
volumes:
- "${WEBAPP_STORAGE_HOME}/site/wwwroot:/var/www/html"
- "${WEBAPP_STORAGE_HOME}/phpmyadmin:/var/www/phpmyadmin"
- "${WEBAPP_STORAGE_HOME}/LogFiles:/var/log"
预览版限制
多容器目前以预览版提供。 不支持以下应用服务平台功能:
- 身份验证/授权
- 托管标识
- CORS
- Docker Compose 方案不支持虚拟网络集成
- 目前,Azure 应用服务上的 Docker Compose 的限制为 4,000 个字符。
Docker Compose 选项
以下列表显示了支持和不支持的 Docker Compose 配置选项:
支持的选项
- 命令
- entrypoint
- 环境
- image
- ports
- restart
- services
- 卷(不支持映射到 Azure 存储)
不支持的选项
- build(不允许)
- depends_on(已忽略)
- networks(忽略)
- secrets(忽略)
- 除了 80 和 8080 之外的端口(忽略)
- 默认环境变量(如
$variable and ${variable}
)与 docker 中的不同
语法限制
- “version x.x”始终需要是文件中的第一个 YAML 语句
- 端口部分必须使用带引号的数字
- 图像和卷部分必须带引号,并且不能有权限定义
- 卷部分在卷名后不得有空的大括号
注意
未显式指明的任何其他选项在公共预览版中将被忽略。
日志中的 robots933456
你可能会在容器日志中看到以下消息:
2019-04-08T14:07:56.641002476Z "-" - - [08/Apr/2019:14:07:56 +0000] "GET /robots933456.txt HTTP/1.1" 404 415 "-" "-"
可以放心忽略此消息。 /robots933456.txt
是一个虚拟 URL 路径,应用服务使用它来检查容器能否为请求提供服务。 404 响应只是指示该路径不存在,但它让应用服务知道容器处于正常状态并已准备就绪,可以响应请求。
后续步骤
或查看更多资源: