Compartilhar via

为Azure App Service配置自定义容器

本文介绍如何将自定义容器配置为在Azure App Service上运行。

了解关键概念并获取有关App Service中 Windows 应用的容器化的说明。 新用户应首先遵循 自定义容器快速入门教程

了解关键概念,并获取有关 App Service 中 Linux 应用的容器化的说明。 新用户应首先遵循 自定义容器快速入门教程

注意

不再支持将服务主体用于 Windows 容器映像拉取身份验证。 建议对 Windows 和 Linux 容器使用托管标识。

支持的父映像

为自定义 Windows 映像选择适合您所需框架的正确父映像(基础映像):

  • 若要部署 .NET Framework 应用,请使用基于 Windows Server 2019 Core 长期服务渠道版本的基础镜像。
  • 若要部署 .NET Core 应用,请使用基于 Windows Server 2019 Nano Annual Channel 版本的父映像。

在应用启动期间,下载父映像需要一些时间。 可以使用已在Azure App Service中缓存的以下父映像之一来缩短启动时间:

更改自定义容器的 Docker 映像

使用以下命令将当前 Docker 映像更改为现有自定义容器中的新映像:

az webapp config container set --name <app-name> --resource-group <group-name> --docker-custom-image-name <docker-hub-repo>/<image>

使用专用注册表中的映像

若要从专用注册表(如Azure Container Registry)使用映像,请运行以下命令:

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 Container Registry拉取映像

使用以下步骤将 Web 应用配置为通过托管标识从 Azure Container Registry 拉取。 这些步骤使用系统分配的托管标识,但也可以使用用户分配的托管标识。

  1. 使用 命令为 Web 应用启用az webapp identity assign

    az webapp identity assign --resource-group <group-name> --name <app-name> --query principalId --output tsv
    

    应用名称<替换为>在上一步中使用的名称。 命令的输出(由 --query--output 参数筛选)是分配的标识的服务主体 ID。

  2. 获取容器注册表的资源 ID:

    az acr show --resource-group <group-name> --name <registry-name> --query id --output tsv
    

    将 <registry-name> 替换为注册表的名称。 命令的输出,由 --query--output 参数进行筛选,是容器注册表的资源 ID。

  3. 将托管标识的权限授予访问容器注册表的权限:

    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基于角色的access control?

  4. 将应用程序配置为使用托管标识以从 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'

  5. (可选)如果应用使用用户分配的托管标识,请确保在 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 Container Registry 拉取。

使用来自受网络保护的注册表库的镜像

若要从虚拟网络或本地内的注册表进行连接和拉取,应用必须与虚拟网络集成。 还需要虚拟网络集成来与带有专用终结点的Azure容器注册表进行连接。 配置网络和 DNS 解析后,启用通过虚拟网络的镜像拉取路由。 请配置vnetImagePullEnabled站点配置:

az resource update --resource-group <group-name> --name <app-name> --resource-type "Microsoft.Web/sites" --set properties.vnetImagePullEnabled [true|false]

如果看不到更新的容器,请进行故障排除以确定应该采取的措施。

如果将 Docker 容器的设置更改为指向新的容器,可能需要几分钟,应用才能从新容器处理 HTTP 请求。 在拉取和启动新容器时,App Service继续为来自旧容器的请求提供服务。 App Service仅在新容器启动后向新容器发送请求,并且已准备好接收请求。

了解如何存储容器映像

首次在 App Service 中运行自定义 Docker 映像时,App Service执行 docker pull 命令并提取所有映像层。 层存储在磁盘上,与在本地使用 Docker 时相同。 每次应用重启时,App Service执行 docker pull 命令。 它只会拉取已更改的层。 如果没有更改,App Service在本地磁盘上使用现有层。

如果应用出于任何原因更改计算实例(如更改定价层),App Service必须再次拉取所有层。 如果横向扩展以添加更多实例,那么情况也是如此。 此外,在极少数情况下,应用实例可能会在没有缩放操作的情况下发生变化。

配置端口号

默认情况下,App Service 默认认为自定义容器监听端口80。 如果容器侦听其他端口,请在App Service应用中设置 WEBSITES_PORT 应用设置。 在 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"}

App Service当前允许容器仅公开 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"}

当应用运行时,App Service应用设置会自动作为环境变量注入进程。 可以通过 URL https://<app-name>.scm.chinacloudsites.cn/Env 来验证容器环境变量。

使用自定义 Docker 映像通过 SSH 连接到容器时,如果尝试使用类似 env 或这样的 printenv命令,则只能看到几个环境变量。 若要查看容器中的所有环境变量,就像传入应用程序以供运行时使用一样,请将此行添加到入口点脚本:

eval $(printenv | sed -n "s/^\([^=]\+\)=\(.*\)$/export \1=\2/p" | sed 's/"/\\\"/g' | sed '/=/s//="/' | sed 's/$/"/' >> /etc/profile)

请参阅 完整示例

如果应用使用专用注册表中的映像或来自Docker Hub的映像,则用于访问存储库的凭据将保存在环境变量中:DOCKER_REGISTRY_SERVER_URLDOCKER_REGISTRY_SERVER_USERNAMEDOCKER_REGISTRY_SERVER_PASSWORD。 由于存在安全风险,这些保留变量名都不会向应用程序公开。

对于 Internet Information Services(IIS)或 .NET Framework(4.0 或更高版本)容器,凭据通过 App Service 自动注入到 System.ConfigurationManager ,作为 .NET 应用程序设置和连接字符串的一部分。 对于所有其他语言或框架,它们作为进程的环境变量提供,其中包含以下前缀之一:

  • APPSETTING_
  • SQLCONTR_
  • MYSQLCONTR_
  • SQLAZURECOSTR_
  • POSTGRESQLCONTR_
  • CUSTOMCONNSTR_

可以将此方法用于单一容器或多重容器应用,其中环境变量在 docker-compose.yml 文件中指定。

使用持久性共享存储

可以使用 C:\home 自定义容器文件系统中的目录跨重启保留文件,并在实例之间共享这些文件。 使用 C:\home 目录时,自定义容器可以访问永久性存储。

禁用永久性storage时,不会在应用重启或多个实例之间持久写入 C:\home 目录。 启用持久性storage后,对 C:\home 目录的所有写入都会保留。 横向扩展应用的所有实例都可以访问它们。 容器启动时,如果永久性storage上存在任何文件,则会覆盖容器的 C:\home 目录中的任何内容。

唯一的例外是 C:\home\LogFiles 目录。 此目录存储容器和应用程序日志。 如果启用了带有文件系统选项的应用日志记录,则无论是否启用持久性存储,文件夹在应用重启时始终保留。 换句话说,启用或禁用永久性storage时,它不会影响应用程序日志记录行为。

默认情况下,Windows 自定义容器上已启用持久存储。 若要禁用它,请使用 Cloud Shell 应用设置值设置为 >。 在 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 自定义容器文件系统中的目录跨重启保留文件,并在实例之间共享这些文件。 使用 C:\home 目录时,自定义容器可以访问持久化存储。 请记住,您在 /home 中保存的数据会计入您 App Service 计划中包含的存储空间配额。

禁用永久性storage时,不会在应用重启或多个实例之间持久写入 C:\home 目录。 启用持久性storage后,对 C:\home 目录的所有写入都会保留。 扩展应用程序的所有实例都可以访问它们。 容器启动时,如果永久性storage上存在任何文件,则会覆盖容器的 C:\home 目录中的任何内容。

唯一的例外是 C:\home\LogFiles 目录。 此目录存储容器和应用程序日志。 如果启用应用日志记录并使用File System选项,则文件夹在应用重启时始终保留,无论是否启用持久性存储。 换句话说,启用或禁用永久性storage时,它不会影响应用程序日志记录行为。

建议将数据写入 /home装载的 Azure 存储路径。 在重启期间,在这些路径之外写入的数据不会持久。 数据将保存到平台托管的主机磁盘空间,该空间独立于 App Service 计划文件存储配额。

默认情况下,Linux 自定义容器上的持久性存储为禁用。 若要启用它,请使用以下命令,使用 bash 中的Azure Cli将 WEBSITES_ENABLE_APP_SERVICE_STORAGE 应用设置值设置为 true

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 会话

App Service在前端终止 TLS。 这意味着 TLS 请求永远不会到达你的应用。 无需(不应)在应用中实现对 TLS 的任何支持。

前端位于Azure数据中心内。 如果将 TLS 与应用配合使用,则通过 Internet 的流量始终安全加密。

自定义 ASP.NET 计算机密钥注入

在容器启动期间,会自动生成密钥并将其注入到容器中,作为 ASP.NET 加密例程的计算机密钥。 可以通过查找以下环境变量,在容器中找到这些密钥MACHINEKEY_DecryptionMACHINEKEY_DecryptionKeyMACHINEKEY_ValidationKeyMACHINEKEY_Validation

每次重启时的新密钥都可能会重置 ASP.NET表单身份验证和查看状态(如果应用依赖于它们)。 若要防止自动重新生成密钥,手动将其设置为App Service应用设置

连接到容器

若要直接连接到 Windows 容器以执行诊断任务,请转到 https://<app-name>.scm.chinacloudsites.cn/ 并选择 SSH 选项。 此选项建立一个直接 SSH 会话,可在其中运行容器内的命令。

  • 它与上面的图形浏览器分开运行,后者仅显示您共享存储中的文件。
  • 在横向扩展的应用程序中,SSH 会话连接到其中一个容器实例。 可以从顶部 Kudu 菜单中的 “实例 ”下拉列表中选择不同的实例。
  • 共享存储的更改除外,在应用重启时,从 SSH 会话中对容器所做的任何更改不会保留。 这些更改不是 Docker 映像的一部分。 若要保留注册表设置和软件安装等更改,请将它们纳入 Dockerfile。

访问诊断日志

应用服务记录 Docker 主机的操作和容器内的活动。 默认情况下会启用 Docker 主机(平台日志)中的日志。 需要从容器中手动启用应用程序日志或 Web 服务器日志。 有关详细信息,请参阅启用应用程序日志记录启用 Web 服务器日志记录

可以通过多种方式访问 Docker 日志:

Azure portal

Docker 日志在 Azure 门户的应用Container Settings 窗格中显示。 日志将被截断。 若要下载所有日志,请选择“ 下载”。

Kudu

若要查看单个日志文件,请转到 https://<app-name>.scm.chinacloudsites.cn/DebugConsole 并选择 LogFiles 该文件夹。 若要下载整个 LogFiles 目录,请选择目录名称左侧的 “下载 ”图标。 还可以使用 FTP 客户端access此文件夹。

默认情况下,您无法访问 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 App Service中部署的所有 Windows 容器都配置了内存限制。 下表列出了每个App Service计划 SKU 的默认设置。

App Service计划 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)定义,必须小于等于主机的总物理内存。 例如,在 RAM 为 8 GB 的 App Service 计划中,所有应用的 WEBSITE_MEMORY_LIMIT_MB 累积总和不能超过 8 GB。 有关可用内存量的详细信息,请参阅 App Service 定价中的 Premium v3 服务计划

自定义计算核心数

默认情况下,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}

提示

更新应用设置会触发自动重启,这会导致最短的停机时间。 对于生产应用,请考虑将其切换到预备槽。 在暂存槽中更改应用设置,然后将其交换回生产环境。

若要验证调整后的号码,请使用 Azure portal 或 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.

处理器可能是多核处理器或超线程处理器。 若要了解可用的核心数,请参阅 App Service 定价中的 Premium v3 服务计划

自定义运行状况 ping 行为

App Service认为容器在启动并响应 HTTP ping 时成功启动容器。 运行状况 ping 请求包含标头 User-Agent= "App Service Hyper-V Container Availability Check"。 如果容器在某个时间后启动但不响应 ping,App Service在 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"}

下表列出了可能的值:

Description
Repair 连续进行三次可用性检查后重启容器。
ReportOnly 默认值。 在连续进行三次可用性检查后报告 Docker 日志中的容器,但不要重启它。
Off 不检查可用性。

支持组托管服务帐户

App Service中的 Windows 容器不支持组托管服务帐户。

启用 SSH

可以使用安全外壳(SSH)从命令行终端远程运行管理命令。 若要使用自定义容器启用 Azure portal SSH 控制台功能,请执行以下步骤:

  1. 使用以下示例内容创建标准 sshd_config 文件,并将其放置在应用程序project根目录上:

    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 portal SSH 功能:

    • 该值 Port 必须设置为 2222
    • 这些Ciphers值必须包含此列表中的至少一项:aes128-cbc、或3des-cbcaes256-cbc
    • 这些 MACs 值必须在此列表中至少包含一项: hmac-sha1hmac-sha1-96
  2. 创建一个名为 entrypoint.sh 的入口点脚本,或者更改任何现有的入口点文件。 添加命令以启动 SSH 服务,以及应用程序启动命令。 以下示例演示如何启动 Python 应用程序。 根据project语言或堆栈替换最后一个命令:

    #!/bin/sh
    set -e
    service ssh start
    exec gunicorn -w 4 -b 0.0.0.0:8000 app:app
    
  3. 请根据基础镜像的发行版将以下说明添加到 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!,因为 App Service 使用它来授予你对容器 SSH 会话的访问权限。 此配置不允许从外部建立到容器的连接。 容器的端口2222只能在专用虚拟网络的网桥网络中访问。 互联网中的攻击者无法访问它。

  4. 重新生成 Docker 映像并将其推送到注册表,然后在Azure portal中测试 Web App SSH 功能。

有关故障排除的详细信息,请参阅Azure App Service博客:适用于容器的 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 秒内再次检查。

若要随时停止日志流式处理,请使用键盘快捷方式 Ctrl+C。

配置多容器应用

在 Docker Compose 中使用持久性存储

WordPress 等多容器应用需要持久storage才能正常运行。 若要启用持久存储,Docker Compose 配置必须指向容器外部存储位置。 应用程序容器中的存储位置在应用程序重启后不会保留更改。

若要启用持久性存储,请设置 WEBSITES_ENABLE_APP_SERVICE_STORAGE 应用设置。 在 Azure CLI 中使用 az webapp config appsettings set 命令。

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 是 App Service 中用于映射到应用持久性存储的环境变量。 例如:

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"

预览限制

多容器功能目前处于预览状态。 不支持以下App Service平台功能:

  • 身份验证或授权。
  • 托管标识。
  • 跨域资源共享 (CORS)。
  • 虚拟网络与 Docker Compose 场景的集成。

Azure App Service上的 Docker Compose 当前限制为 4,000 个字符。

Docker Compose 选项

以下部分显示了受支持的和不支持的 Docker Compose 配置选项。

支持的选项

不支持的选项

  • build (不允许)
  • depends_on (已忽略)
  • networks (已忽略)
  • secrets (已忽略)
  • 808080 以外的端口(8080 已忽略)
  • 默认环境变量,如 $variable${variable}(与 Docker 中不同)

语法限制

  • 文件中的第一个 YAML 语句始终需要 version x.x
  • 端口部分必须使用带引号的数字。
  • image > volume 节必须带引号,并且不能具有权限定义。
  • 卷部分不能在卷名称后面包含空大括号。

注意

预览版中将忽略未显式提及的任何其他选项。

忽略日志中的 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 路径。 App Service使用它来检查容器是否能够处理请求。 “404”错误响应指示路径不存在,并指示App Service容器正常且已准备好响应请求。