使用 Visual Studio 创建的 GitHub Actions 工作流将应用程序部署到 Azure
从 Visual Studio 2019 版本 16.11 开始,可以为托管在 GitHub.com 上的 .NET 项目创建新的 GitHub Actions 工作流。
先决条件
- 必须在 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 机密。 如果失败,它将告知你,并为你提供重试的机会。
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 容器应用环境。 如果以前不知道该实例是什么或尚未创建,请为此实例创建一个新实例。
创建后,会显示新的 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
若要测试更改,请提交更改并将其推送到触发器代码中指定的存储库的分支。 无需创建 Pull Request(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 访问设置正确的用户名和密码机密。 在创建 Azure 资产或从 Microsoft Visual Studio IDE 中的 GitHub Actions 屏幕创建 Azure 资产时,Visual Studio 会尝试自动执行此操作。 可以在 GitHub 中检查机密,确保它们存在,或者在必要时重新生成并通过存储库的“设置”部分再次添加到 GitHub。 根据工作流的每个部分中引用的内容检查机密 ID。 如有必要,可以转到 Azure 门户中的容器注册表,获取容器注册表的用户名和密码,并使用这些值更新 GitHub 中的机密。
如果运行 az ad sp create-for-rbac
命令来设置服务主体并获取客户端 ID、客户端密码和租户 ID,请在 GitHub 存储库的 GitHub Actions 机密 部分中将客户端 ID 和客户端密码添加为机密。 可以采用用户名(应用客户端 ID)和密码(客户端密码)的形式提供 Azure 登录凭据,以便进行 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 服务?
- Azure Web 应用
- Azure Functions
- Azure API 管理