为 Azure 应用服务配置自定义容器

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

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

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

注意

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

支持的父映像

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

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

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

更改自定义容器的 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 容器注册表拉取。 这些步骤使用系统分配的托管标识,但也可以使用用户分配的托管标识。

  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 基于角色的访问控制?

  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 容器注册表中进行拉取。

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

若要从虚拟网络或本地的注册表进行连接和拉取,应用必须与虚拟网络集成。 还需要为 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 请求。 在拉取和启动新容器时,应用服务将继续为来自旧容器的请求提供服务。 应用服务仅在启动后将请求发送到新容器,并已准备好接收请求。

了解如何存储容器映像

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

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

配置端口号

默认情况下,应用程序服务会假定您的自定义容器监听端口 80。 如果容器侦听其他端口,请在应用服务应用中设置 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"}

应用服务目前允许容器只为 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 映像通过 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 目录时,自定义容器可以访问永久性存储。

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

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

默认情况下,在 Windows 自定义容器上启用持久存储。 若要禁用它,请使用 WEBSITES_ENABLE_APP_SERVICE_STORAGEfalse 应用设置的值设为 。 在 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 中保存的数据被计入应用服务计划中包含的 存储空间配额

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

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

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

默认情况下,持久存储在 Linux 自定义容器上处于已禁用状态。 若要启用它,请使用以下命令,使用 Azure Cli 在 Bash 中将应用设置值设置为WEBSITES_ENABLE_APP_SERVICE_STORAGEtrue

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。 这意味着 TLS 请求永远不会到达你的应用。 无需(不应)在应用中实现对 TLS 的任何支持。

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

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

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

如果应用程序依赖于这些密钥,每次重启时的新密钥可能会重置 ASP.NET 窗体身份验证和视图状态。 要阻止自动重新生成密钥,请手动将其设置为应用服务应用设置

连接到容器

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

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

访问诊断日志

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

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

Azure 门户

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

Kudu

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

默认情况下,无法访问 C:\home\LogFiles SSH 终端中的文件夹,因为未启用永久性共享存储。 要在控制台终端中启用此行为,请启用持久共享存储

如果尝试使用 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)定义,必须小于等于主机的总物理内存。 例如,在 RAM 为 8 GB 的应用服务计划中,所有应用的累积总数 WEBSITE_MEMORY_LIMIT_MB 不能超过 8 GB。 有关可用内存量的详细信息,请参阅 应用服务定价中的高级 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 门户或 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.

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

自定义运行状况 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"}

下表列出了可能的值:

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

支持组托管服务帐户

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

启用 SSH

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

  1. 使用以下示例内容创建标准 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-cbcaes256-cbc
    • 这些 MACs 值必须在此列表中至少包含一项: hmac-sha1hmac-sha1-96
  2. 创建一个名为 entrypoint.sh 的入口点脚本,或者更改任何现有的入口点文件。 添加命令以启动 SSH 服务,以及应用程序启动命令。 以下示例演示如何启动 Python 应用程序。 根据项目语言或堆栈替换最后一个命令:

    #!/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! 是因为应用服务使用它来授予你对容器的 SSH 会话的访问权限。 此配置不允许从外部建立到容器的连接。 容器的端口 2222 只能在专用虚拟网络的网桥网络中访问。 Internet 上的攻击者无法访问它。

  4. 重新生成 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 秒内再次检查。

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

配置多容器应用

在 Docker Compose 中使用持久性存储

多容器应用(如 WordPress)需要持久存储才能正常工作。 若要启用持久存储,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 是应用服务中映射到应用的持久存储的环境变量。 例如:

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 配置选项。

支持的选项

不支持的选项

  • 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 路径。 应用服务使用它来检查容器是否能够处理请求。 “404”错误响应指示路径不存在,它向应用服务发出信号,指出容器正常且已准备好响应请求。