使用 Visual Studio 创建的 GitHub Actions 工作流将应用程序部署到 Azure
从 Visual Studio 2019 版本 16.11 开始,你可为 GitHub.com 上托管的 .NET 项目创建新的 GitHub 操作工作流。
先决条件
- 你必须在 Visual Studio 中登录到自己的 GitHub 帐户。
- 一个 Azure 帐户。 如果没有 Azure 帐户,请激活你的 Visual Studio 订阅者 Azure 权益或注册免费试用版。
使用 GitHub Actions 将单个项目部署到 Azure
在解决方案资源管理器中,右键单击 GitHub.com 托管项目,然后选择发布。
在下一屏幕上,选择“Azure”,然后选择“下一步” 。
根据项目类型,获取可供选择的不同的 Azure 服务列表。 选择一项满足需求的受支持的 Azure 服务。
在向导的最后一步,选择“使用 GitHub Actions 工作流的 CI/CD (生成 yml 文件)”,然后选择“完成” 。
Visual Studio 会生成新的 GitHub Actions 工作流,并要求你提交它且将其推送到 GitHub.com。
如果使用内置 Git 工具完成此步骤,Visual Studio 将检测工作流的执行。
设置 GitHub 机密
若要使生成的工作流成功部署到 Azure,则可能需访问发布配置文件。
要成功部署,则可能还需访问服务主体。
在任何情况下,Visual Studio 都会尝试为你使用正确的值设置 Github 机密。 如果设置失败,它将通知你,并让你有机会重试。
如果无法重新设置机密,Visual Studio 会提供手动获取机密访问权限的机会,让你能够通过 GitHub.com 上的存储库页面完成该过程。
使用 GitHub Actions 将多个项目部署到 Azure 容器应用
如果有多个使用 Docker 容器的项目,并且你希望将其部署为多项目应用,请按照以下步骤操作。 可以部署多项目应用,例如将微服务实现到 Azure 容器应用或 Azure Kubernetes 服务 (AKS) 的应用。 本文介绍 Azure 容器应用。
右键单击解决方案资源管理器中的“GitHub Actions”节点,然后选择“新建工作流”。 此时会显示 GitHub Actions 工作流向导。
在“GitHub Actions 工作流”目标屏幕上,选择“Azure”。
对于特定目标,请选择“Azure 容器应用”。 向导将转到“容器应用”屏幕。
选择现有的 Azure 容器应用,或选择“新建”。
创建新应用时,会看到以下屏幕。 测试或学习时,最好创建新的资源组,以便日后更方便地删除所有内容。 容器应用环境是围绕着容器应用组的一个安全边界,这些容器应用共享同一个虚拟网络并将日志写入到同一个日志目的地。 请参阅 Azure 容器应用环境。 如果不知道它是什么或者之前未创建过该环境,请为此实例创建一个新环境。
创建后,会显示新的 Azure 容器应用实例。
选择“下一步”转到“注册表”屏幕。 选择现有 Azure 容器注册表,或创建新注册表。
如果选择创建新注册表,则会看到以下屏幕。 提供资源组、SKU,并尽可能选择与以前相同的区域。 有关 Azure 容器注册表 SKU 的信息,请参阅 Azure 容器注册表服务层级。
创建后,新注册表将显示在屏幕上。
将显示解决方案中的可部署项目;选择要在同一 Azure 容器应用实例中一起部署的项目。
选择完成。 可以看到发出了命令,用于在 Azure 中创建资产并设置身份验证。 如果出现任何问题,请记下使用的命令行,因为你可以从 CLI 重试。 如果在此阶段遇到授权失败,请不要过于担心。 你也可以在 Visual Studio 中稍后设置身份验证。
完成后,将显示摘要屏幕。 摘要屏幕会显示凭据,这些凭据与 Visual Studio 在 GitHub 存储库的 GitHub Actions 机密中创建的条目匹配。 检查是否有任何黄色警告标志。 如果在创建过程中有任何身份验证步骤出现问题,则可以通过单击警告标志旁的链接并执行几个步骤来更正该问题。
打开工作流文件,检查 Visual Studio 生成的内容。 虽然 Visual Studio 会尽可能根据你的情况生成工作流,但每个应用和存储库都是独一无二的,因此,通常需要你手动编辑 Visual Studio 生成的工作流 YML 文件,才能正确运行它。 若要打开该文件,请在解决方案资源管理器中展开 GitHub Actions 节点,右键单击刚刚创建的工作流,然后选择“编辑”。
下面显示了 Visual Studio 为具有两个可部署项目(WebAPI 和 WebFrontEnd)的解决方案创建的工作流文件示例。
on:
push:
branches:
- main
env:
CONTAINER_REGISTRY_LOGIN_SERVER: registry20230810121555.azurecr.io
CONTAINER_APP_NAME: containerapp20230810121017
CONTAINER_APP_RESOURCE_GROUP_NAME: webfrontend-container-app-1234
CONTAINER_APP_CONTAINER_NAME: containerapp
jobs:
WebApi_buildImageAndDeploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker registry
uses: docker/login-action@v2
with:
registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.registry20230810121555_USERNAME_6891 }}
password: ${{ secrets.registry20230810121555_PASSWORD_6891 }}
- name: Build and push Docker image to Azure container registry
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webapi:${{ github.sha }}
file: WebApi\Dockerfile
- name: Azure login
uses: azure/login@v1
with:
creds: ${{ secrets.containerapp20230810121017_SPN }}
- name: Deploy to Azure container app
uses: azure/CLI@v1
with:
inlineScript: >-
az config set extension.use_dynamic_install=yes_without_prompt
az containerapp registry set --name ${{ env.CONTAINER_APP_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --server ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} --username ${{ secrets.registry20230810121555_USERNAME_2047 }} --password ${{ secrets.registry20230810121555_PASSWORD_2047 }}
az containerapp update --name ${{ env.CONTAINER_APP_NAME }} --container-name ${{ env.CONTAINER_APP_CONTAINER_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --image ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webapi:${{ github.sha }}
- name: Azure logout
run: az logout
WebFrontEnd_buildImageAndDeploy:
runs-on: ubuntu-latest
needs: WebApi_buildImageAndDeploy
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker registry
uses: docker/login-action@v2
with:
registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.registry20230810121555_USERNAME_2047 }}
password: ${{ secrets.registry20230810121555_PASSWORD_2047 }}
- name: Build and push Docker image to Azure container registry
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
file: WebFrontEnd\Dockerfile
- name: Azure login
uses: azure/login@v1
with:
creds: ${{ secrets.containerapp20230810121017_SPN }}
- name: Deploy to Azure container app
uses: azure/CLI@v1
with:
inlineScript: >-
az config set extension.use_dynamic_install=yes_without_prompt
az containerapp registry set --name ${{ env.CONTAINER_APP_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --server ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} --username ${{ secrets.registry20230810121555_USERNAME_2047 }} --password ${{ secrets.registry20230810121555_PASSWORD_2047 }}
az containerapp update --name ${{ env.CONTAINER_APP_NAME }} --container-name ${{ env.CONTAINER_APP_CONTAINER_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --image ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
- name: Azure logout
run: az logout
该工作流的主要功能是使用正确的身份验证登录到 Azure 服务,并运行命令来生成和部署应用。
编辑和测试工作流
上述过程生成了工作流 YML 文件,但通常需要对其进行评审和自定义,然后才能用于部署。 你可能需要参考 GitHub 关于编写工作流操作的指南;请参阅关于自定义操作。 工作流文件包含许多可配置元素,例如环境变量的设置和机密的名称。 可以看到其中引用了 Dockerfiles 的位置、Azure 容器应用的名称、用于触发工作流运行的存储库中的分支,以及 GitHub 中的机密。 机密使用语法 ${{ secrets.SECRET_NAME }}
进行引用。 请参阅 GitHub Actions 机密。
如果项目不在存储库的根目录中,则需要更改工作流以指定用于查找 Dockerfiles 的路径。 为这两个项目中 Dockerfile 的相对路径添加环境变量。
DOCKER_FILEPATH_WEBAPI: docker/ComposeSample/WebApi/Dockerfile
DOCKER_FILEPATH_WEBFRONTEND: docker/ComposeSample/WebFrontend/Dockerfile
将这些环境变量的值用于 file
参数,如下所示:
- name: Build and push Docker image to Azure container registry
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
file: ${{ env.DOCKER_FILEPATH_WEBFRONTEND }}
如需对 Dockerfile 进行更改,请更改、保存更改、提交更改,并将更改推送到远程存储库。 Visual Studio 生成的工作流包含一个触发器,会在指定分支上出现更新时促使工作流运行。 如果要推送到 working
分支,将显示类似以下的代码:
on:
push:
branches:
- working
若要测试更改,请提交更改并将其推送到触发器代码中指定的存储库分支。 无需创建拉取请求 (PR)。 只要 push
触发器设置为正确的分支,工作流就会运行。
在存储库(位于 GitHub.com)的“操作”选项卡中,查找工作流运行。 可以使用 Visual Studio 中 GitHub Actions 摘要选项卡上的链接直接前往那里。 在 GitHub 中,可以打开工作流运行以查看日志。
疑难解答
如果工作流未成功运行,以下故障排除提示可能会提供帮助。
问题:生成阶段不执行生成
Dockerfile 中可能会遇到的一个问题是,生成阶段的工作方式与 Visual Studio 中的不同。 Visual Studio 为项目生成的默认 Dockerfile 可展示此问题。 如果 Dockerfile 出现这样的问题,请考虑对生成阶段进行以下修改。 下面是一个示例,其中项目位于存储库中的 docker/ComposeSample/WebApi
。 这里提供了完整路径,原因是工作流生成容器中的 Dockerfile 上下文设置为存储库的根目录,但在 Visual Studio 中,它设置为项目文件夹的上级文件夹。 此处追加了后缀 _build
以创建生成文件夹,因此复制的是整个文件夹,而不只是项目文件。 与 Visual Studio 生成的默认 Dockerfile 相比,删除了 COPY 命令的第一个参数中路径的文件部分,以便复制整个文件夹,而不仅仅是项目文件。 如果没有这些更改,此阶段将生成 MSBuild 错误。
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["docker/ComposeSample/WebApi/", "WebApi_build/"]
RUN dotnet restore "WebApi_build/WebApi.csproj"
COPY . .
WORKDIR "/src/WebApi_build"
RUN dotnet build "WebApi.csproj" -c Release -o /app/build
问题:身份验证凭据
工作流要求为 Azure 访问设置正确的用户名和密码机密。 Visual Studio 会在创建 Azure 资产时或从 Microsoft Visual Studio IDE 中的 GitHub Actions 屏幕自动执行此操作。 你可以检查 GitHub 中的机密,并确保机密位于其中,或者根据需要使用存储库中的“设置”部分重新生成机密并再次将它们添加到 GitHub。 根据工作流的每个部分中引用的内容检查机密 ID。 如有必要,可以转到 Azure 门户中的容器注册表,获取容器注册表的用户名和密码,并使用这些值更新 GitHub 中的机密。
如果运行 az ad sp create-for-rbac
命令来设置服务主体并获取客户端 ID、客户端密码和租户 ID,请在 GitHub 存储库的 GitHub Actions 机密部分中将客户端 ID 和客户端密码添加为机密。 你可以为 Azure 容器应用身份验证提供用户名(应用的客户端 ID)和密码(客户端密码)形式的 Azure 登录凭据。 为此,请将 Azure login
步骤替换为以下代码。 使用为客户端 ID 和客户端密码创建的自己的 GitHub 机密名称,并使用同一命令输出中的租户 ID。
- name: Azure login
uses: azure/CLI@v1
with:
inlineScript: |
az login --service-principal -u ${{ secrets.GITHUB_SECRETID_FOR_USERNAME }} -p ${{ secrets.GITHUB_SECRETID_FOR_PASSWORD }} --tenant {your tenant ID}
az account list
如果 Dockerfile 正常工作且身份验证正确,但工作流仍存在问题,请考虑参考以下资源:
支持哪些项目类型?
- ASP.NET Core
- ASP.NET 5 及更高版本
- Azure Functions
支持哪些 Azure 服务?
- Azure Web 应用
- Azure Functions
- Azure API 管理