你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用自定义容器将自定义软件迁移到 Azure 应用服务

Azure 应用服务在 Windows 上提供预定义的应用程序堆栈,例如在 IIS 上运行的 ASP.NET 或 Node.js。 预配置的 Windows 环境锁定了操作系统,不允许对其进行以下操作:

  • 管理访问。
  • 软件安装。
  • 全局程序集缓存更改。

有关详细信息,请参阅 Azure 应用服务上的操作系统功能

可以从 Visual Studio 部署自定义配置的 Windows 映像,以进行应用所需的 OS 更改。 因此,可以轻松迁移需要自定义 OS 和软件配置的本地应用。 本教程演示如何将使用 Windows 字体库中安装的自定义字体的 ASP.NET 应用迁移到应用服务。 你将自定义配置的 Windows 映像从 Visual Studio 部署到 Azure 容器注册表,然后在应用服务中运行它。

显示在 Windows 容器中运行的 Web 应用。

先决条件

为完成此教程:

在本地设置应用

下载示例

在此步骤中,将设置本地 .NET 项目。

示例项目包括一个简单的 ASP.NET 应用程序,该应用程序使用安装在 Windows 字体库中的自定义字体。 不需要安装字体。 但是,此示例是一个与基础 OS 集成的应用示例。 要将此类应用迁移到应用服务,需要重新构建代码以移除集成,或通过自定义 Windows 容器将其按原样迁移。

安装字体

在 Windows 资源管理器中,导航到“custom-font-win-container-master/CustomFontSample”,右键单击“FrederickatheGreat-Regular.ttf”,然后选择“安装” 。

该字体在 Google Fonts 中公开发布。

运行应用

在 Visual Studio 中打开 custom-font-win-container-master/CustomFontSample.sln 文件。

键入 Ctrl+F5 在不调试的情况下运行应用。 该应用将显示在默认浏览器中。

显示在默认浏览器中显示的应用的屏幕截图。

此应用使用已安装的字体,因此无法在应用服务沙盒中运行。 但是,可以改为使用 Windows 容器对其进行部署,因为可以在 Windows 容器中安装该字体。

配置 Windows 容器

在解决方案资源管理器中,右键单击“CustomFontSample”项目,选择“添加”>“容器业务流程支持” 。

解决方案资源管理器窗口的屏幕截图,其中显示已选择 CustomFontSample 项目、“添加”和“容器业务流程协调程序支持”菜单项。

选择“Docker Compose”>“确定” 。

现在,项目设置为在 Windows 容器中运行。 Dockerfile 添加到 CustomFontSample 项目,docker-compose 项目添加到解决方案。

在解决方案资源管理器中,打开 Dockerfile。

需要使用受支持的父映像。 通过将 FROM 行替换为以下代码,更改父映像:

FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2-windowsservercore-ltsc2019

在该文件的末尾,添加以下行并保存文件:

RUN ${source:-obj/Docker/publish/InstallFont.ps1}

可以在 CustomFontSample 项目中找到 InstallFont.ps1。 它是一个安装该字体的简单脚本。 可在 PowerShell 库中找到更复杂的脚本版本。

注意

若要在本地测试 Windows 容器,请确保在本地计算机上启动 Docker。

发布到 Azure 容器注册表

Azure 容器注册表可以存储用于容器部署的映像。 可以将应用服务配置为使用 Azure 容器注册表中托管的映像。

打开发布向导

在解决方案资源管理器中,右键单击“CustomFontSample”项目,选择“发布” 。

解决方案资源管理器的屏幕截图,其中已选择 CustomFontSample 项目和“发布”。

创建注册表并发布

在发布向导中,选择“容器注册表”>“新建 Azure 容器注册表”>“发布” 。

发布向导的屏幕截图,其中显示已选择“容器注册表”、“新建 Azure 容器注册表”和“发布”按钮。

使用 Azure 帐户登录

在“新建 Azure 容器注册表”对话框中,选择“添加帐户”,然后登录到你的 Azure 订阅。 如果已登录,请从下拉列表中选择包含所需订阅的帐户。

登录到 Azure。

配置注册表

根据下表中建议的值配置新的容器注册表。 完成后,选择“创建”。

设置 建议的值 更多信息
DNS 前缀 保留生成的注册表名称,或将其更改为另一个唯一的名称。
资源组 选择“新建”,键入 myResourceGroup,然后选择“确定”。
SKU 基本 定价层
注册表位置 西欧

配置 Azure 容器注册表。

终端窗口随即打开并显示映像部署进度。 等待部署完成。

登录 Azure

登录到 Azure 门户

创建 Web 应用

在左侧菜单中,选择“创建资源”>“Web”>“用于容器的 Web 应用” 。

配置应用基本信息

在“基本信息”选项卡中,根据下表来配置设置,然后选择“下一步: Docker”。

设置 建议的值 更多信息
订阅 确保选择正确的订阅。
资源组 选择“新建”,键入 myResourceGroup,然后选择“确定”
名称 键入唯一名称。 Web 应用的 URL 为 https://<app-name>.azurewebsites.net,其中 <app-name> 是应用名称。
发布 Docker 容器
操作系统 Windows
区域 “西欧”
Windows 计划 选择“新建”,键入 myAppServicePlan,然后选择“确定”。

“基本信息”选项卡应如下所示:

显示用于配置 Web 应用的“基本信息”选项卡。

配置 Windows 容器

在“Docker”选项卡中,按下表所示配置自定义 Windows 容器,并选择“查看 + 创建”。

设置 建议的值
映像源 Azure 容器注册表
注册表 选择前面创建的注册表
图像 customfontsample
标记 最新

完成应用创建

选择“创建”,等待 Azure 创建所需的资源。

浏览到 Web 应用

Azure 操作完成后,会显示通知框。

显示 Azure 操作已完成。

  1. 选择“转到资源”。

  2. 在应用页中,选择“URL”下的链接。

如果会打开一个如以下页面所示的新浏览器页面:

显示 Web 应用的新浏览器页面。

等待几分钟,然后重试,直到主页显示你所需的美观字体:

使用配置的字体显示主页。

恭喜! 你已通过 Windows 容器将 ASP.NET 应用程序迁移到 Azure 应用服务。

查看容器启动日志

加载 Windows 容器可能需要一些时间。 若要查看进度,请通过将 <app-name> 替换为你的应用的名称,转到以下 URL。

https://<app-name>.scm.azurewebsites.net/api/logstream

流式传输的日志如下所示:

14/09/2018 23:16:19.889 INFO - Site: fonts-win-container - Creating container for image: customfontsample20180914115836.azurecr.io/customfontsample:latest.
14/09/2018 23:16:19.928 INFO - Site: fonts-win-container - Create container for image: customfontsample20180914115836.azurecr.io/customfontsample:latest succeeded. Container Id 329ecfedbe370f1d99857da7352a7633366b878607994ff1334461e44e6f5418
14/09/2018 23:17:23.405 INFO - Site: fonts-win-container - Start container succeeded. Container: 329ecfedbe370f1d99857da7352a7633366b878607994ff1334461e44e6f5418
14/09/2018 23:17:28.637 INFO - Site: fonts-win-container - Container ready
14/09/2018 23:17:28.637 INFO - Site: fonts-win-container - Configuring container
14/09/2018 23:18:03.823 INFO - Site: fonts-win-container - Container ready
14/09/2018 23:18:03.823 INFO - Site: fonts-win-container - Container start-up and configuration completed successfully

Azure 应用服务使用 Docker 容器技术同时托管内置映像和自定义映像。 若要查看内置映像的列表,请运行 Azure CLI 命令 'az webapp list-runtimes --os linux'。 如果这些映像无法满足需要,可以生成并部署自定义映像。

注意

容器应面向 x86-x64 体系结构,不支持 ARM64。

本教程介绍如何执行下列操作:

  • 向 Azure 容器注册表推送自定义 Docker 映像
  • 将自定义映像部署到应用服务
  • 配置环境变量
  • 使用托管标识将映像拉取到应用服务中
  • 访问诊断日志
  • 启用从 Azure 容器注册表到应用服务的 CI/CD
  • 使用 SSH 连接到容器

完成本教程会导致 Azure 帐户中产生一点容器注册表费用,并且可能会因为容器托管时间超过一个月而产生其他费用。

设置初始环境

本教程需要 2.0.80 或更高版本 Azure CLI。 如果你使用的是 Azure Cloud Shell,则表示已安装最新版本。

  • 安装 Docker,用于构建 Docker 映像。 安装 Docker 可能需要重启计算机。

安装 Docker 后,请打开终端窗口,验证是否已安装 Docker:

docker --version

克隆或下载示例应用

可以通过 git 克隆或下载操作获取此教程的示例。

使用 git 进行克隆

克隆示例存储库:

git clone https://github.com/Azure-Samples/docker-django-webapp-linux.git --config core.autocrlf=input

请确保包括 --config core.autocrlf=input 参数,以确保 Linux 容器中使用的文件中的行尾正确:

然后,导航到以下文件夹:

cd docker-django-webapp-linux

从 GitHub 下载

可以访问 https://github.com/Azure-Samples/docker-django-webapp-linux,依次选择“克隆”和“下载 ZIP”,而不使用 git 克隆。

将 ZIP 文件解压缩到名为 docker-django-webapp-linux 的文件夹中。

然后,在 docker-django-webapp-linux 文件夹中打开一个终端窗口。

(可选)检查 Docker 文件

示例中名为 Dockerfile 的文件,描述了 Docker 映像并包含配置说明:

FROM tiangolo/uwsgi-nginx-flask:python3.6

RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt --no-cache-dir
ADD . /code/

# ssh
ENV SSH_PASSWD "root:Docker!"
RUN apt-get update \
        && apt-get install -y --no-install-recommends dialog \
        && apt-get update \
 && apt-get install -y --no-install-recommends openssh-server \
 && echo "$SSH_PASSWD" | chpasswd 

COPY sshd_config /etc/ssh/
COPY init.sh /usr/local/bin/

RUN chmod u+x /usr/local/bin/init.sh
EXPOSE 8000 2222

#CMD ["python", "/code/manage.py", "runserver", "0.0.0.0:8000"]
ENTRYPOINT ["init.sh"]
  • 第一组命令在环境中安装应用的要求。
  • 第二组命令创建 SSH 服务器来实现容器和主机之间的安全通信。
  • 最后一行 ENTRYPOINT ["init.sh"] 调用 init.sh 来启动 SSH 服务和 Python 服务器。

在本地生成和测试映像

注意

Docker Hub 对每个 IP 的匿名请求数和每个免费用户的经过身份验证的请求数都有配额(请参阅“数据传输”)。 如果发现来自 Docker Hub 的请求受到限制,请尝试 docker login(如果尚未登录)。

  1. 运行以下命令生成映像:

    docker build --tag appsvc-tutorial-custom-image .
    
  2. 本地运行 Docker 容器来测试生成是否有效:

    docker run -it -p 8000:8000 appsvc-tutorial-custom-image
    

    docker run 命令通过 -p 参数后跟映像名称来指定端口。 -it 允许通过 Ctrl+C 来停止。

    提示

    如果在 Windows 上运行时显示错误“standard_init_linux.go:211: exec 用户进程导致‘无此类文件或目录’”,则表示 init.sh 文件包含 CR-LF 行尾而不是预期的 LF 行尾。 如果使用 git 克隆示例存储库,但省略了 --config core.autocrlf=input 参数,就会发生此错误。 在这种情况下,请使用 `--config`` 参数再次克隆存储库。 如果已编辑 init.sh 并以 CRLF 结尾进行保存,也可能会发生此错误。 在这种情况下,请仅以 LF 结尾再次保存文件。

  3. 浏览到 http://localhost:8000,验证 Web 应用和容器是否正常运行。

    在本地测试 Web 应用。

I. 创建用户分配的托管标识

应用服务可以使用默认托管标识或用户分配的托管标识向容器注册表进行身份验证。 本教程使用用户分配的托管标识。

  1. 运行 az group create 命令创建资源组:

    az group create --name msdocs-custom-container-tutorial --location westeurope
    

    可以更改 --location 值以指定附近的区域。

  2. 在资源组中创建托管标识。

    az identity create --name myID --resource-group msdocs-custom-container-tutorial
    

II. 创建容器注册表

  1. 使用 az acr create 命令创建容器注册表,并将 <registry-name> 替换为你的注册表的唯一名称。 该名称只能包含字母和数字,并且必须在整个 Azure 中都是唯一的。

    az acr create --name <registry-name> --resource-group msdocs-custom-container-tutorial --sku Basic --admin-enabled true
    

    参数 --admin-enabled 用于使用一组管理凭据将映像推送到注册表。

  2. 通过运行 az acr show 命令检索管理凭据:

    az acr credential show --resource-group msdocs-custom-container-tutorial --name <registry-name>
    

    此命令的 JSON 输出提供两个密码以及注册表的用户名。

III. 将示例映像推送到 Azure 容器注册表

在本部分,你会将映像推送到 Azure 容器注册表,供应用服务稍后使用。

  1. 在生成示例映像的本地终端中,使用 docker login 命令登录到容器注册表:

    docker login <registry-name>.azurecr.io --username <registry-username>
    

    <registry-name><registry-username> 替换为前面步骤中的值。 出现提示时,键入在上一步骤中获取的某个密码。

    在本部分余下的所有步骤中都使用相同的注册表名称。

  2. 成功登录后,将本地 Docker 映像标记到注册表:

    docker tag appsvc-tutorial-custom-image <registry-name>.azurecr.io/appsvc-tutorial-custom-image:latest
    
  3. 使用 docker push 命令将映像推送到注册表:

    docker push <registry-name>.azurecr.io/appsvc-tutorial-custom-image:latest
    

    第一次上传映像可能需要几分钟时间,因为它包含基本映像。 后续上传速度通常较快。

    在等待期间,可以完成下一部分中的步骤,将应用服务配置为从注册表部署。

IV. 为注册表的托管标识授权

创建的托管标识尚未获得从容器注册表拉取映像的授权。 在此步骤中,你将启用授权。

  1. 检索托管标识的主体 ID:

    principalId=$(az identity show --resource-group msdocs-custom-container-tutorial --name myID --query principalId --output tsv)
    
  2. 检索容器注册表的资源 ID:

    registryId=$(az acr show --resource-group msdocs-custom-container-tutorial --name <registry-name> --query id --output tsv)
    
  3. 授予托管标识访问容器注册表的权限:

    az role assignment create --assignee $principalId --scope $registryId --role "AcrPull"
    

    有关这些权限的详细信息,请参阅什么是 Azure 基于角色的访问控制

V. 创建 Web 应用

  1. 使用 az appservice plan create 命令创建应用服务计划:

    az appservice plan create --name myAppServicePlan --resource-group msdocs-custom-container-tutorial --is-linux
    

    应用服务计划对应托管 Web 应用的虚拟机。 默认情况下,前面的命令使用平价的 B1 定价层,该定价层第一个月免费提供。 可以使用 --sku 参数控制层。

  2. 使用 az webapp create 命令创建 Web 应用:

    az webapp create --resource-group msdocs-custom-container-tutorial --plan myAppServicePlan --name <app-name> --deployment-container-image-name <registry-name>.azurecr.io/appsvc-tutorial-custom-image:latest
    

    <app-name> 替换为 Web 应用的名称,该名称在整个 Azure 中必须是唯一的。 同时将 <registry-name> 替换为上一部分中注册表的名称。

    提示

    可以随时使用命令 az webapp config container show --name <app-name> --resource-group msdocs-custom-container-tutorial 检索 Web 应用的容器设置。 该映像在 DOCKER_CUSTOM_IMAGE_NAME 属性中指定。 当通过 Azure DevOps 或 Azure 资源管理器模板部署 Web 应用时,映像还可能出现在名为 LinuxFxVersion 的属性中。 这两个属性的作用相同。 如果 Web 应用的配置中同时存在这两个属性,则优先使用 LinuxFxVersion

VI. 配置 Web 应用

在此步骤中,按如下方式配置 Web 应用:

  • 示例容器在端口 8000 上侦听 Web 请求;将应用配置为向端口 8000 发送请求。
  • 告知应用使用托管标识从容器注册表拉取映像。
  • 配置从容器注册表进行持续部署(或者,每次将映像推送到注册表都会触发应用拉取新映像的操作)。 Web 应用无需此配置即可从容器注册表拉取映像,但此配置可以让 Web 应用知道何时将新映像推送到了注册表。 如果不完成此配置,则必须通过重启 Web 应用来手动触发映像拉取。
  1. 使用 az webapp config appsettings set 按应用代码的需要设置 WEBSITES_PORT 环境变量:

    az webapp config appsettings set --resource-group msdocs-custom-container-tutorial --name <app-name> --settings WEBSITES_PORT=8000
    

    <app-name> 替换为上一步使用的名称。

    有关此环境变量的详细信息,请参阅示例 GitHub 存储库中的自述文件

  2. 使用 az webapp identity assign 命令在 Web 应用中启用用户分配的托管标识:

    id=$(az identity show --resource-group msdocs-custom-container-tutorial --name myID --query id --output tsv)
    az webapp identity assign --resource-group msdocs-custom-container-tutorial --name <app-name> --identities $id
    

    <app-name> 替换为上一步使用的名称。

  3. 使用托管标识将应用配置为从 Azure 容器注册表拉取映像。

    appConfig=$(az webapp config show --resource-group msdocs-custom-container-tutorial --name <app-name> --query id --output tsv)
    az resource update --ids $appConfig --set properties.acrUseManagedIdentityCreds=True
    

    <app-name> 替换为上一步使用的名称。

  4. 设置由 Web 应用用来从 Azure 容器注册表拉取映像的客户端 ID。 如果使用系统分配的托管标识,则不需要执行此步骤。

    clientId=$(az identity show --resource-group msdocs-custom-container-tutorial --name myID --query clientId --output tsv)
    az resource update --ids $appConfig --set properties.AcrUserManagedIdentityID=$clientId
    
  5. 在应用服务中启用 CI/CD。

    cicdUrl=$(az webapp deployment container config --enable-cd true --name <app-name> --resource-group msdocs-custom-container-tutorial --query CI_CD_URL --output tsv)
    

    CI_CD_URL 是应用服务为你生成的 URL。 注册表应使用此 URL 来通知应用服务发生了映像拉取。 实际上,它并不会为你创建 Webhook。

  6. 使用在上一步中获取的 CI_CD_URL 在容器注册表中创建 Webhook。

    az acr webhook create --name appserviceCD --registry <registry-name> --uri $cicdUrl --actions push --scope appsvc-tutorial-custom-image:latest
    
  7. 若要测试是否已正确配置 Webhook,请对 Webhook 执行 ping 操作,并查看是否收到 200 OK 响应。

    eventId=$(az acr webhook ping --name appserviceCD --registry <registry-name> --query id --output tsv)
    az acr webhook list-events --name appserviceCD --registry <registry-name> --query "[?id=='$eventId'].eventResponseMessage"
    

    提示

    若要查看有关所有 Webhook 事件的所有信息,请删除 --query 参数。

    如果你是流式处理容器日志,应在 Webhook ping 后看到 Starting container for site 消息,因为 Webhook 会触发应用重启。

VII. 浏览到 Web 应用

若要测试应用,请浏览到 https://<app-name>.azurewebsites.net,将 <app-name> 替换为 Web 应用的名称。

首次访问时,应用可能需要一些时间来响应,因为应用服务必须从注册表中拉取整个映像。 如果浏览器超时,刷新页面即可。 拉取初始映像后,后续测试的运行速度将快得多。

浏览器的屏幕截图,其中显示了 Web 应用在 Azure 中成功运行。

VIII. 访问诊断日志

等待应用服务拉取映像时,通过将容器日志流式传输到终端来确切了解应用服务执行的操作是非常有用的。

  1. 启用容器日志记录:

    az webapp log config --name <app-name> --resource-group msdocs-custom-container-tutorial --docker-container-logging filesystem
    
  2. 启用日志流:

    az webapp log tail --name <app-name> --resource-group msdocs-custom-container-tutorial
    

    如果没有立即看到控制台日志,请在 30 秒后重新查看。

    也可通过浏览器在 https://<app-name>.scm.azurewebsites.net/api/logs/docker 中检查日志文件。

  3. 若要随时停止日志流式处理,请键入 Ctrl+C

IX. 修改应用程序代码并重新部署

在本部分中,你将对 Web 应用代码进行更改,重新生成映像,然后将其推送到容器注册表。 然后,应用服务会自动从注册表中拉取更新后的映像,以更新运行的 Web 应用。

  1. 在本地 docker-django-webapp-linux 文件夹中,打开文件 app/templates/app/index.html 。

  2. 更改第一个 HTML 元素,使其与以下代码相匹配。

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="#">Azure App Service - Updated Here!</a>
        </div>
      </div>
    </nav>
    
  3. 保存所做更改。

  4. 更改为 docker-django-webapp-linux 文件夹,然后重新生成映像:

    docker build --tag appsvc-tutorial-custom-image .
    
  5. 将映像的标记更新为最新:

    docker tag appsvc-tutorial-custom-image <registry-name>.azurecr.io/appsvc-tutorial-custom-image:latest
    

    <registry-name> 替换为注册表的名称。

  6. 将映像推送到注册表:

    docker push <registry-name>.azurecr.io/appsvc-tutorial-custom-image:latest
    
  7. 映像推送完成后,Webhook 会通知应用服务有关推送的信息,应用服务会尝试在更新的映像中进行拉取。 等待几分钟,然后浏览到 https://<app-name>.azurewebsites.net 来验证是否已部署更新。

X. 使用 SSH 连接到容器

SSH 实现容器和客户端之间的安全通信。 若要启用到容器的 SSH 连接,必须针对该连接配置自定义映像。 容器运行后,你可以打开 SSH 连接。

为 SSH 配置容器

本教程中使用的示例应用在 Dockerfile 中已有必要的配置,该配置将安装 SSH 服务器并设置登录凭据。 本部分仅供参考。 若要连接到容器,请跳到下一部分。

ENV SSH_PASSWD "root:Docker!"
RUN apt-get update \
        && apt-get install -y --no-install-recommends dialog \
        && apt-get update \
  && apt-get install -y --no-install-recommends openssh-server \
  && echo "$SSH_PASSWD" | chpasswd 

注意

此配置不允许从外部建立到容器的连接。 只能通过 Kudu/SCM 站点使用 SSH。 Kudu/SCM 站点使用 Azure 帐户进行身份验证。 root:Docker! 不应更改 SSH。 SCM/KUDU 将使用 Azure 门户凭据。 使用 SSH 时,更改此值将导致错误。

Dockerfile 还将 sshd_config 文件复制到 /etc/ssh/ 文件夹,并在容器上公开端口 2222 :

COPY sshd_config /etc/ssh/

# ...

EXPOSE 8000 2222

端口 2222 是一个仅供内部使用的端口,仅可供专用虚拟网络的桥网络中的容器访问。

最后,入口脚本 init.sh 启动 SSH 服务器。

#!/bin/bash
service ssh start

打开到容器的 SSH 连接

  1. 浏览到 https://<app-name>.scm.azurewebsites.net/webssh/host 并使用 Azure 帐户登录。 将 <app-name> 替换为 Web 应用的名称。

  2. 登录后,你会被重定向到 Web 应用的信息页。 选择页面顶部的“SSH”,打开 shell 并使用命令。

    例如,可以使用 top 命令检查在其中运行的进程。

XI. 清理资源

本文中创建的资源可能会持续产生费用。 若要清理资源,只需删除包含这些资源的资源组即可:

az group delete --name msdocs-custom-container-tutorial

后续步骤

你已了解:

  • 将自定义映像部署到专用容器注册表
  • 在应用服务中部署和自定义映像
  • 更新并重新部署映像
  • 访问诊断日志
  • 使用 SSH 连接到容器
  • 向 Azure 容器注册表推送自定义 Docker 映像
  • 将自定义映像部署到应用服务
  • 配置环境变量
  • 使用托管标识将映像拉取到应用服务中
  • 访问诊断日志
  • 启用从 Azure 容器注册表到应用服务的 CI/CD
  • 使用 SSH 连接到容器

下一教程介绍如何使用自定义域和证书保护应用。

或者,查看其他资源: