使用自定义容器将自定义软件迁移到 Azure 应用服务
Azure 应用服务在 Windows 上提供预定义的应用程序堆栈,例如 ASP.NET 或 Node.js。 这些应用程序堆栈在 IIS 上运行。 预配置的 Windows 环境锁定了操作系统,不允许对其进行以下操作:
- 管理访问。
- 软件安装。
- 全局程序集缓存更改。
有关详细信息,请参阅 Azure 应用服务上的操作系统功能。
可以从 Visual Studio 部署自定义配置的 Windows 映像,以进行应用所需的 OS 更改。 这使得可以轻松迁移需要自定义 OS 和软件配置的本地应用。 本教程演示如何将使用 Windows 字体库中安装的自定义字体的 ASP.NET 应用迁移到应用服务。 你将自定义配置的 Windows 映像从 Visual Studio 部署到 Azure 容器注册表,然后在应用服务中运行它。
先决条件
为完成此教程:
- 注册 Docker 中心帐户。
- 安装用于 Windows 的 Docker。
- 配置 Docker 来运行 Windows 容器。
- 安装 Visual Studio 2022,其中包含 ASP.NET 和 Web 开发以及 Azure 开发工作负载 。 如果已安装 Visual Studio 2022:
- 通过选择“帮助”>“检查更新”,在 Visual Studio 中安装最新更新。
- 在 Visual Studio 中,通过选择“工具”>“获取工具和功能”,添加工作负载。
在本地设置应用
下载示例
在此步骤中,将设置本地 .NET 项目。
- 下载示例项目 。
- 提取(解压缩)custom-font-win-container-master.zip 文件。
示例项目包括一个简单的 ASP.NET 应用程序,该应用程序使用安装在 Windows 字体库中的自定义字体。 不需要安装字体。 但是,此示例是一个与基础 OS 集成的应用示例。 要将此类应用迁移到应用服务,需要重新构建代码以移除集成,或通过自定义 Windows 容器将其按原样迁移。
安装字体
在 Windows 资源管理器中,导航到“custom-font-win-container-master/CustomFontSample”,右键单击“FrederickatheGreat-Regular.ttf”,然后选择“安装” 。
运行应用
在 Visual Studio 中打开 custom-font-win-container-master/CustomFontSample.sln 文件。
选择 Ctrl+F5 在不调试的情况下运行应用。 该应用将显示在默认浏览器中。
此应用使用已安装的字体,因此无法在应用服务沙盒中运行。 但是,可以改为使用 Windows 容器对其进行部署,因为可以在 Windows 容器中安装该字体。
配置 Windows 容器
在解决方案资源管理器中,右键单击“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”项目,选择“发布” 。
创建并发布注册表。
在发布向导中,选择“容器注册表”>“新建 Azure 容器注册表”>“发布” 。
使用 Azure 帐户登录
在“新建 Azure 容器注册表”对话框中,选择“添加帐户”,然后登录到你的 Azure 订阅。 如果已登录,请从下拉列表中选择包含所需订阅的帐户。
配置注册表
使用下表中的建议值作为指南配置新的容器注册表。 完成后,选择“创建”。
设置 | 建议值 |
---|---|
DNS 前缀 | 保留生成的注册表名称,或将其更改为另一个唯一的名称。 |
资源组 | 选择“新建”,键入 myResourceGroup,然后选择“确定”。 |
SKU | 基本。 有关详细信息,请参阅定价层。 |
注册表位置 | 中国北部 2 |
终端窗口随即打开并显示映像部署进度。 等待部署完成。
登录 Azure
登录到 Azure 门户。
创建 Web 应用
在左侧菜单中,选择“创建资源”>“Web”>“用于容器的 Web 应用” 。
配置应用基本信息
在“基本信息”选项卡中,根据下表配置设置。 然后选择“下一步: Docker”。
设置 | 建议的值 |
---|---|
订阅 | 确保选择正确的订阅。 |
资源组 | 选择“新建”,键入 myResourceGroup,然后选择“确定”。 |
名称 | 键入唯一名称。 Web 应用的 URL 为 https://<app-name>.chinacloudsites.cn ,其中 <app-name> 是应用名称。 |
发布 | Docker 容器 |
操作系统 | Windows |
区域 | 中国北部 2 |
Windows 计划 | 选择“新建”,键入 myAppServicePlan,然后选择“确定”。 |
“基本信息”选项卡应如下所示:
配置 Windows 容器
在“Docker”选项卡中,按下表所示配置自定义 Windows 容器,然后选择“查看 + 创建”。
设置 | 建议的值 |
---|---|
映像源 | Azure 容器注册表 |
注册表 | 选择前面创建的注册表。 |
图像 | customfontsample |
标记 | 最新 |
完成应用创建
选择“创建”,等待 Azure 创建所需的资源。
浏览到 Web 应用
部署完成后,将显示一个通知框。
选择“转到资源”。
在应用页中,选择“URL”下的链接。
如果会打开一个如以下页面所示的新浏览器页面:
等待几分钟,然后重试,直到主页显示你所需的字体:
祝贺你! 你已通过 Windows 容器将 ASP.NET 应用程序迁移到 Azure 应用服务。
查看容器启动日志
加载 Windows 容器可能需要一些时间。 若要查看进度,请转到以下 URL。 (请将 app-name 替换为你的应用名称<>。)
https://<app-name>.scm.chinacloudsites.cn/api/logstream
流式传输的日志如下所示:
14/09/2018 23:16:19.889 INFO - Site: fonts-win-container - Creating container for image: customfontsample20180914115836.azurecr.cn/customfontsample:latest.
14/09/2018 23:16:19.928 INFO - Site: fonts-win-container - Create container for image: customfontsample20180914115836.azurecr.cn/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-64 体系结构。 不支持 ARM64。
本教程介绍如何执行下列操作:
- 将自定义 Docker 映像推送到 Azure 容器注册表。
- 将自定义映像部署到应用服务。
- 配置环境变量。
- 使用托管标识将映像拉取到应用服务中。
- 访问诊断日志。
- 启用从 Azure 容器注册表到应用服务的 CI/CD。
- 使用 SSH 连接到容器。
完成本教程会导致 Azure 帐户中产生一点容器注册表费用,如果容器托管时间超过一个月,还会产生其他费用。
设置初始环境
本教程需要 2.0.80 或更高版本 Azure CLI。 如果你使用的是 Azure 本地 Shell,则最新版本已安装。
- 具有活动订阅的 Azure 帐户。 创建帐户。
可以使用本地 Azure CLI。
如果需要,请安装 Azure CLI 来运行 CLI 参考命令。
本地 Azure CLI,请了解如何安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI。
通过使用 az login 命令登录到 Azure CLI。 若要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅使用 Azure CLI 登录。
出现提示时,请在首次使用时安装 Azure CLI 扩展。 有关扩展详细信息,请参阅使用 Azure CLI 的扩展。
运行 az version 以查找安装的版本和依赖库。 若要升级到最新版本,请运行 az upgrade。
- 安装 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
(如果尚未登录)。
运行以下命令生成映像:
docker build --tag appsvc-tutorial-custom-image .
本地运行 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 文件包含 CRLF 行尾而不是预期的 LF 行尾。 如果使用 Git 来克隆示例存储库,但省略了
--config core.autocrlf=input
参数,就会发生此错误。 在这种情况下,请使用--config
参数再次克隆存储库。 如果已编辑 init.sh 并以 CRLF 结尾进行保存,也可能会发生此错误。 在这种情况下,请仅以 LF 结尾再次保存文件。浏览到
http://localhost:8000
,验证 Web 应用和容器是否正常运行。
I. 创建用户分配的托管标识
应用服务可以使用默认托管标识或用户分配的托管标识向容器注册表进行身份验证。 本教程使用用户分配的托管标识。
运行 az group create 命令创建资源组:
az group create --name msdocs-custom-container-tutorial --location chinanorth2
可以更改
--location
值以指定附近的区域。在资源组中创建托管标识:
az identity create --name myID --resource-group msdocs-custom-container-tutorial
II. 创建容器注册表
使用以下
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
用于使用管理凭据将映像推送到注册表。通过运行
az credential acr show
命令检索管理凭据:az acr credential show --resource-group msdocs-custom-container-tutorial --name <registry-name>
此命令的 JSON 输出提供两个密码以及注册表的用户名。
III. 将示例映像推送到 Azure 容器注册表
在本部分,你会将映像推送到 Azure 容器注册表,供应用服务稍后使用。
在生成示例映像的本地终端中,使用
docker login
命令登录到容器注册表:docker login <registry-name>.azurecr.cn --username <registry-username>
将
<registry-name>
和<registry-username>
替换为前面步骤中的值。 出现提示时,键入在上一部分中获取的某个密码。在本部分余下的所有步骤中都使用相同的注册表名称。
成功登录后,将本地 Docker 映像标记到注册表:
docker tag appsvc-tutorial-custom-image <registry-name>.azurecr.cn/appsvc-tutorial-custom-image:latest
使用
docker push
命令将映像推送到注册表:docker push <registry-name>.azurecr.cn/appsvc-tutorial-custom-image:latest
第一次上传映像可能需要几分钟时间,因为它包含基本映像。 后续上传速度通常较快。
在等待期间,可以完成下一部分中的步骤,将应用服务配置为从注册表部署。
IV. 为注册表的托管标识授权
创建的托管标识尚未获得从容器注册表拉取映像的授权。 在此步骤中,你将启用授权。
检索托管标识的主体 ID:
principalId=$(az identity show --resource-group msdocs-custom-container-tutorial --name myID --query principalId --output tsv)
检索容器注册表的资源 ID:
registryId=$(az acr show --resource-group msdocs-custom-container-tutorial --name <registry-name> --query id --output tsv)
授予托管标识访问容器注册表的权限:
az role assignment create --assignee $principalId --scope $registryId --role "AcrPull"
有关这些权限的详细信息,请参阅什么是 Azure 基于角色的访问控制?
V. 创建 Web 应用
使用
az appservice plan create
命令创建应用服务计划:az appservice plan create --name myAppServicePlan --resource-group msdocs-custom-container-tutorial --is-linux
应用服务计划对应托管 Web 应用的虚拟机。 默认情况下,前面的命令使用平价的 B1 定价层,该定价层第一个月免费提供。 可以使用
--sku
参数指定层级。使用
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.cn/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。 示例容器在端口 8000 上侦听 Web 请求。
- 告知应用使用托管标识从容器注册表拉取映像。
- 配置从容器注册表进行持续部署(每次将映像推送到注册表都会触发应用拉取新映像的操作)。 Web 应用无需此配置即可从容器注册表拉取映像,但此配置可以让 Web 应用知道何时将新映像推送到了注册表。 如果不完成此配置,则必须通过重启 Web 应用来手动触发映像拉取。
使用
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>
替换为上一步使用的名称。使用
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>
替换为上一步使用的名称。使用托管标识将应用配置为从 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>
替换为上一步使用的名称。设置由 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
在应用服务中启用 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。使用在上一步中获取的 CI_CD_URL 在容器注册表中创建 Webhook。
az acr webhook create --name appserviceCD --registry <registry-name> --uri $cicdUrl --actions push --scope appsvc-tutorial-custom-image:latest
若要测试是否已正确配置 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 应用
首次尝试访问应用时,应用可能需要一些时间来响应,因为应用服务必须从注册表中拉取整个映像。 如果浏览器超时,刷新页面即可。 拉取初始映像后,后续测试的运行速度将快得多。
VIII. 访问诊断日志
等待应用服务拉取映像时,通过将容器日志流式传输到终端来确切了解应用服务执行的操作是非常有用的。
启用容器日志记录:
az webapp log config --name <app-name> --resource-group msdocs-custom-container-tutorial --docker-container-logging filesystem
启用日志流:
az webapp log tail --name <app-name> --resource-group msdocs-custom-container-tutorial
如果没有立即看到控制台日志,请在 30 秒后重新查看。
也可通过浏览器在
https://<app-name>.scm.chinacloudsites.cn/api/logs/docker
中检查日志文件。不论任何时候,想要停止日志流式处理,请选择 Ctrl+C。
IX. 修改应用程序代码并重新部署
在本部分中,你将对 Web 应用代码进行更改,重新生成映像,然后将其推送到容器注册表。 然后,应用服务会自动从注册表中拉取更新后的映像,以更新运行的 Web 应用。
在本地 docker-django-webapp-linux 文件夹中,打开文件 app/templates/app/index.html 。
更改第一个 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>
保存所做更改。
更改为 docker-django-webapp-linux 文件夹,然后重新生成映像:
docker build --tag appsvc-tutorial-custom-image .
将映像的标记更新为
latest
:docker tag appsvc-tutorial-custom-image <registry-name>.azurecr.cn/appsvc-tutorial-custom-image:latest
将
<registry-name>
替换为注册表的名称。将映像推送到注册表:
docker push <registry-name>.azurecr.cn/appsvc-tutorial-custom-image:latest
当映像推送完成时,Webhook 会通知应用服务有关推送的信息,应用服务会尝试在更新的映像中进行拉取。 等待几分钟,然后浏览到
https://<app-name>.chinacloudsites.cn
来验证是否已部署更新。
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 帐户进行身份验证。
使用 SSH 时,不应更改 root:Docker!
。 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 连接。
浏览到
https://<app-name>.scm.chinacloudsites.cn/webssh/host
并使用 Azure 帐户登录。 将<app-name>
替换为 Web 应用的名称。登录后,你会被重定向到 Web 应用的信息页。 选择页面顶部的“SSH”,打开 shell 并使用命令。
例如,可以使用
top
命令检查在应用中运行的进程。
XI. 清理资源
后续步骤
你已了解:
- 将自定义映像部署到专用容器注册表。
- 在应用服务中部署自定义映像。
- 更新并重新部署映像。
- 访问诊断日志。
- 使用 SSH 连接到容器。
- 将自定义 Docker 映像推送到 Azure 容器注册表。
- 将自定义映像部署到应用服务。
- 配置环境变量。
- 使用托管标识将映像拉取到应用服务中。
- 访问诊断日志。
- 启用从 Azure 容器注册表到应用服务的 CI/CD。
- 使用 SSH 连接到容器。
在下一教程中,你将了解如何使用自定义域和证书提供安全保障。
或者,查看其他资源: