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

教程:使用 GitHub 和 Azure 部署环境在 CI/CD 中部署环境

本教程介绍如何将 Azure 部署环境集成到 CI/CD 管道中。 可以使用支持 CI/CD 的任何 GitOps 提供程序,例如 GitHub Actions、Azure Arc、GitLab 或 Jenkins。

持续集成和持续交付 (CI/CD) 是一种软件开发方法,可帮助团队自动执行编译、测试和部署软件更改的过程。 CI/CD 使你能够更频繁、更自信地发布软件更改。

将使用具有以下三个分支的工作流:main、dev 和 test。

  • main 分支始终被视为生产分支。
  • 从 main 分支创建 feature 分支。
  • 创建拉取请求以将 feature 分支合并到 main。

在本教程中,此工作流是一个简单的例子。 实际工作流可能更为复杂。

在开始本教程之前,可以通过查看 Azure 部署环境的关键概念来熟悉部署环境资源和概念。

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

  • 创建和配置开发人员中心
  • 创建 key vault
  • 创建和配置 GitHub 存储库
  • 将目录添连接到开发人员中心
  • 配置部署标识
  • 配置 GitHub 环境
  • 测试 CI/CD 管道

先决条件

  • 具有活动订阅的 Azure 帐户。
  • Azure 订阅的所有者权限。
  • 一个 GitHub 帐户。
    • 如果没有该帐户,请注册免费版
  • 安装 Git
  • 安装 Azure CLI

1. 创建和配置开发人员中心

在本部分中,你将创建一个具有三种环境类型的 Azure 部署环境开发人员中心和项目:开发测试和 Prod

  • Prod 环境类型包含单个生产环境。
  • 为每个功能分支在 Dev 中创建一个新环境。
  • 在每个拉取请求的测试中创建一个新环境。

1.1 设置 Azure CLI

首先,登录到 Azure。 运行以下命令,然后按照提示完成身份验证过程。

az login

接下来,安装 Azure CLI 的 Azure 开发中心扩展。

az extension add --name devcenter --upgrade

安装当前扩展后,注册 Microsoft.DevCenter 命名空间。

az provider register --namespace Microsoft.DevCenter

提示

在本教程中,你需要将多个值保存为环境变量,供稍后使用。 你可能还希望在其他位置记录这些值,以确保它们在需要时可用。

获取用户的 ID 并将其设置为环境变量供稍后使用:

MY_AZURE_ID=$(az ad signed-in-user show --query id -o tsv)

检索当前订阅的订阅 ID。

AZURE_SUBSCRIPTION_ID=$(az account show --query id --output tsv)

检索当前租户的租户 ID。

AZURE_TENANT_ID=$(az account show --query tenantId --output tsv)

设置以下环境变量:

LOCATION="eastus"
AZURE_RESOURCE_GROUP=<resourceGroupName>
AZURE_DEVCENTER=<devcenterName>
AZURE_PROJECT=<projectName>
AZURE_KEYVAULT=<keyVaultName>

注意

必须使用全局唯一的密钥保管库名称。 否则,可能会收到以下错误: Code: VaultAlreadyExists Message: The vault name 'mykeyvaultname' is already in use. Vault names are globally unique so it is possible that the name is already taken.

1.2 创建开发人员中心

开发人员中心汇集了具有类似设置的项目和环境。 开发人员中心提供对可用于创建环境的模板和项目目录的访问权限。 开发人员中心还提供管理对环境和项目的访问权限的方法。

创建资源组。

az group create \
  --name $AZURE_RESOURCE_GROUP \
  --location $LOCATION

创建新的开发人员中心。

az devcenter admin devcenter create \
  --name $AZURE_DEVCENTER \
  --identity-type SystemAssigned \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION

上一个命令输出 JSON。 将 ididentity.principalId 的值保存为环境变量,供稍后使用。

AZURE_DEVCENTER_ID=<id>
AZURE_DEVCENTER_PRINCIPAL_ID=<identity.principalId>

1.3 在订阅上分配开发人员中心标识所有者角色

开发人员中心需要权限才能在与环境类型关联的订阅上分配角色。

为了降低不必要的复杂性,在本教程中,开发人员中心和所有环境类型使用单个订阅。 实际上,开发人员中心和目标部署订阅可能是应用了不同策略的单独订阅。

az role assignment create \
  --scope /subscriptions/$AZURE_SUBSCRIPTION_ID \
  --role Owner \
  --assignee-object-id $AZURE_DEVCENTER_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal

1.4 创建环境类型

在开发人员中心级别,环境类型定义开发团队可以创建的环境,例如开发、测试、沙盒、预生产或生产环境。

创建三个新环境类型:开发测试和 Prod

az devcenter admin environment-type create \
  --name Dev \
  --resource-group $AZURE_RESOURCE_GROUP \
  --dev-center $AZURE_DEVCENTER
az devcenter admin environment-type create \
  --name Test \
  --resource-group $AZURE_RESOURCE_GROUP \
  --dev-center $AZURE_DEVCENTER
az devcenter admin environment-type create \
  --name Prod \
  --resource-group $AZURE_RESOURCE_GROUP \
  --dev-center $AZURE_DEVCENTER

1.5 创建项目

项目是开发团队的访问点。 每个项目都与一个开发中心相关联。

创建新项目。

az devcenter admin project create \
  --name $AZURE_PROJECT \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION \
  --dev-center-id $AZURE_DEVCENTER_ID

上一个命令输出 JSON。 将 id 值保存为环境变量,供稍后使用。

AZURE_PROJECT_ID=<id>

向自己分配 DevCenter 项目管理员角色。

az role assignment create \
  --scope "$AZURE_PROJECT_ID" \
  --role "DevCenter Project Admin" \
  --assignee-object-id $MY_AZURE_ID \
  --assignee-principal-type User

1.6 创建项目环境类型

在项目级别,平台工程师指定适合开发团队的环境类型。

为开发人员中心上创建的每个环境类型创建新的项目环境类型。

az devcenter admin project-environment-type create \
  --name Dev \
  --roles "{\"b24988ac-6180-42a0-ab88-20f7382dd24c\":{}}" \
  --deployment-target-id /subscriptions/$AZURE_SUBSCRIPTION_ID \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION \
  --project $AZURE_PROJECT \
  --identity-type SystemAssigned \
  --status Enabled
az devcenter admin project-environment-type create \
  --name Test \
  --roles "{\"b24988ac-6180-42a0-ab88-20f7382dd24c\":{}}" \
  --deployment-target-id /subscriptions/$AZURE_SUBSCRIPTION_ID \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION \
  --project $AZURE_PROJECT \
  --identity-type SystemAssigned \
  --status Enabled
az devcenter admin project-environment-type create \
  --name Prod \
  --roles "{\"b24988ac-6180-42a0-ab88-20f7382dd24c\":{}}" \
  --deployment-target-id /subscriptions/$AZURE_SUBSCRIPTION_ID \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION \
  --project $AZURE_PROJECT \
  --identity-type SystemAssigned \
  --status Enabled

2. 创建密钥保管库

在本部分,你将创建新的密钥保管库。 本教程稍后将使用此密钥保管库从 GitHub 保存个人访问令牌

az keyvault create \
  --name $AZURE_KEYVAULT \
  --resource-group $AZURE_RESOURCE_GROUP \
  --location $LOCATION \
  --enable-rbac-authorization true

同样,将上一命令的 JSON 输出中的 id 保存为环境变量。

AZURE_KEYVAULT_ID=<id>

给自己新的密钥保管库密钥库 管理员角色。

az role assignment create \
  --scope $AZURE_KEYVAULT_ID \
  --role "Key Vault Administrator" \
  --assignee-object-id $MY_AZURE_ID \
  --assignee-principal-type User

将开发人员中心的标识分配给密钥库机密用户的角色。

az role assignment create \
  --scope $AZURE_KEYVAULT_ID \
  --role "Key Vault Secrets User" \
  --assignee-object-id $AZURE_DEVCENTER_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal

3. 创建和配置 GitHub 存储库

在本部分,你将创建新的 GitHub 存储库来存储目录。 Azure 部署环境同时支持 GitHub 和 Azure DevOps 存储库。 在本教程中,你将使用 GitHub。

3.1 创建新的 GitHub 存储库

在此步骤,你将在 GitHub 帐户中创建一个具有预定义目录结构、分支和文件的新存储库。 这些项是从示例模板存储库生成的。

  1. 使用此链接可通过示例模板生成新的 GitHub 存储库。

    Screenshot showing the GitHub create repository from template page.

  2. 如果没有付费 GitHub 帐户,请将存储库设置为“公共”。

  3. 选择“从模板创建存储库”。

  4. 在“操作”选项卡上,发现“创建环境”操作失败。 这是预期的行为,你可以继续执行下一步。

3.2 保护存储库的 main 分支

可以通过设置分支保护规则来保护重要分支。 保护规则定义协作者是否可以删除推送或将推送强制发送到分支。 这些规则还针对发送到分支的所有推送设置了要求,例如传递状态检查或线性提交历史记录。

注意

受保护的分支可以在 GitHub Free 和组织的 GitHub Free 公共存储库中使用,也可以在 GitHub Pro、GitHub Team、GitHub Enterprise Cloud 和 GitHub Enterprise Server 的公共和私有存储库中使用。 有关详细信息,请参阅 GitHub 的产品

  1. 如果尚未开放,请导航到存储库的主页。

  2. 在存储库名称下,选择“设置”。 如果看不到“设置”选项卡,请选择...下拉菜单,然后选择设置

    Screenshot showing the GitHub repository page with settings highlighted.

  3. 在边栏的“代码和自动化”部分中,选择“分支”。

    Screenshot showing the settings page, with branches highlighted.

  4. 在“分支保护规则”下,选择“添加分支保护规则”。

    Screenshot showing the branch protection rule page, with Add branch protection rule highlighted.

  5. 在分支名称模式,输入 main

    Screenshot showing the branch name pattern text box, with main highlighted.

  6. 在“保护匹配分支”下,选择“合并前需要拉取请求”。

    Screenshot showing protect matching branches with Require a pull request before merging selected and highlighted.

  7. (可选)可以启用更多保护规则

  8. 选择“创建” 。

3.3 配置存储库变量

注意

GitHub Actions 的配置变量处于测试阶段,可能会发生变化。

  1. 在边栏的“安全性”部分中,选择“机密和变量”,然后选择“操作”。

    Screenshot showing the Security section of the sidebar with Actions highlighted.

  2. 选择“变量”选项卡。

  3. 对于表中的每一项:

    1. 选择“新建存储库变量”。
    2. 在“名称”字段中,输入变量名称。
    3. 在“值”字段中,输入表中描述的值。
    4. 选择“添加变量”。
    变量名称 变量值
    AZURE_DEVCENTER 开发人员中心名称
    AZURE_PROJECT 项目名称
    AZURE_CATALOG 设置为“环境”
    AZURE_CATALOG_ITEM 设置为“FunctionApp”
    AZURE_SUBSCRIPTION_ID Azure 订阅 ID
    AZURE_TENANT_ID Azure 租户 ID

    Screenshot showing the variables page with the variables table.

3.4 创建 GitHub 个人访问令牌

接下来,创建细粒度个人访问令牌,使 Azure 部署环境开发人员中心能够连接到存储库并使用环境目录。

注意

细粒度个人访问令牌目前处于测试阶段,可能会发生更改。 若要留下反馈,请参阅反馈讨论

  1. 在 GitHub.com 上任意页面的右上角,选择个人资料照片,然后选择“设置”。

  2. 在左侧边栏中,选择“开发人员设置”。

  3. 在左侧边栏中的“个人访问令牌”下,选择“细粒度令牌”,然后选择“生成新令牌”。

    Screenshot showing the GitHub personal access token options, with Fine-grained tokens and Generate new token highlighted.

  4. “新建细化的个人访问令牌”页上,在“令牌名称”下输入令牌的名称。

  5. 在“过期时间”下,选择令牌的过期时间。

  6. 在“资源所有者”下选择 GitHub 用户。

  7. 在“存储库访问权限”下,选择“仅选择存储库”,然后在“所选存储库”下拉列表中搜索并选择所创建的存储库。

    Screenshot showing GitHub repository access options, with Only select repositories highlighted.

  8. 在“权限”下,选择“存储库权限”,并将“内容”更改为“只读”。

    Screenshot showing GitHub repository permissions with Contents highlighted.

  9. 选择“生成令牌”。

  10. 立即复制并保存个人访问令牌。 无法再次查看它。

3.5 将个人访问令牌保存到密钥保管库

接下来,将个人访问令牌保存为名为 pat 的密钥保管库机密。

az keyvault secret set \
    --name pat \
    --vault-name $AZURE_KEYVAULT \
    --value <personalAccessToken>

4. 将目录连接到开发人员中心

在 Azure 部署环境中,目录是包含一组环境定义的存储库。 目录项由基础结构即代码 (IaC) 模板和充当清单的环境文件组成。 模板定义环境,环境文件提供有关模板的元数据。 开发团队使用目录中的环境定义来创建环境。

用于创建 GitHub 存储库的模板包含 Environments 文件夹中的目录。

将目录添加到开发人员中心

在以下命令中,将 < Organization/Repository > 替换为 GitHub 组织和存储库名称。

az devcenter admin catalog create \
    --name Environments \
    --resource-group $AZURE_RESOURCE_GROUP \
    --dev-center $AZURE_DEVCENTER \
    --git-hub path="/Environments" branch="main" secret-identifier="https://$AZURE_KEYVAULT.vault.azure.net/secrets/pat" uri="https://github.com/< Organization/Repository >.git"

5. 配置部署标识

使用 GitHub Actions 进行 OpenID Connect 是一种身份验证方法,它使用生存期较短的令牌来增强安全性。 建议使用这种方法向 Azure 验证 GitHub Actions。

还可以直接使用机密对服务主体进行身份验证,但本教程的范围不足。

5.1 配置部署标识

  1. 为每个三种环境类型注册 Microsoft Entra 应用程序和服务主体

    创建用于 DevMicrosoft Entra 应用程序。

    az ad app create --display-name "$AZURE_PROJECT-Dev"
    

    此命令输出 JSON,其中包含在创建具有 Graph API 的联合凭据时使用的 id 以及 appId(也称为客户端 ID)。

    设置以下环境变量:

    DEV_AZURE_CLIENT_ID=<appId>
    DEV_APPLICATION_ID=<id>
    

    重复测试

    az ad app create --display-name "$AZURE_PROJECT-Test"
    
    TEST_AZURE_CLIENT_ID=<appId>
    TEST_APPLICATION_ID=<id>
    

    对于 Prod

    az ad app create --display-name "$AZURE_PROJECT-Prod"
    
    PROD_AZURE_CLIENT_ID=<appId>
    PROD_APPLICATION_ID=<id>
    
  2. 为每个应用程序创建服务主体。

    运行以下命令为 Dev 创建新服务主体。

     az ad sp create --id $DEV_AZURE_CLIENT_ID
    

    此命令使用不同的 id 生成 JSON 输出,将在下一步中使用。

    设置以下环境变量:

    DEV_SERVICE_PRINCIPAL_ID=<id>
    

    重复测试

     az ad sp create --id $TEST_AZURE_CLIENT_ID
    
    TEST_SERVICE_PRINCIPAL_ID=<id>
    

    对于 Prod

     az ad sp create --id $PROD_AZURE_CLIENT_ID
    
    PROD_SERVICE_PRINCIPAL_ID=<id>
    
  3. 运行以下命令,为每个 Active Directory 应用程序创建新的联合标识凭据

    在以下三个命令中,将 < Organization/Repository > 替换为 GitHub 组织和存储库名称。

    Dev 创建联合标识凭据。

    az rest --method POST \
        --uri "https://graph.microsoft.com/beta/applications/$DEV_APPLICATION_ID/federatedIdentityCredentials" \
        --body '{"name":"ADEDev","issuer":"https://token.actions.githubusercontent.com","subject":"repo:< Organization/Repository >:environment:Dev","description":"Dev","audiences":["api://AzureADTokenExchange"]}'
    

    用于 测试

    az rest --method POST \
        --uri "https://graph.microsoft.com/beta/applications/$TEST_APPLICATION_ID/federatedIdentityCredentials" \
        --body '{"name":"ADETest","issuer":"https://token.actions.githubusercontent.com","subject":"repo:< Organization/Repository >:environment:Test","description":"Test","audiences":["api://AzureADTokenExchange"]}'
    

    对于 Prod

    az rest --method POST \
        --uri "https://graph.microsoft.com/beta/applications/$PROD_APPLICATION_ID/federatedIdentityCredentials" \
        --body '{"name":"ADEProd","issuer":"https://token.actions.githubusercontent.com","subject":"repo:< Organization/Repository >:environment:Prod","description":"Prod","audiences":["api://AzureADTokenExchange"]}'
    

5.2 将角色分配给部署标识

  1. 为每个部署标识分配项目的“读取者”角色。

    az role assignment create \
        --scope "$AZURE_PROJECT_ID" \
        --role Reader \
        --assignee-object-id $DEV_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    
    az role assignment create \
        --scope "$AZURE_PROJECT_ID" \
        --role Reader \
        --assignee-object-id $TEST_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    
    az role assignment create \
        --scope "$AZURE_PROJECT_ID" \
        --role Reader \
        --assignee-object-id $PROD_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    
  2. 将部署环境用户角色的每个部署标识分配给其相应的环境类型。

    az role assignment create \
        --scope "$AZURE_PROJECT_ID/environmentTypes/Dev" \
        --role "Deployment Environments User" \
        --assignee-object-id $DEV_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    
    az role assignment create \
        --scope "$AZURE_PROJECT_ID/environmentTypes/Test" \
        --role "Deployment Environments User" \
        --assignee-object-id $TEST_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    
    az role assignment create \
        --scope "$AZURE_PROJECT_ID/environmentTypes/Prod" \
        --role "Deployment Environments User" \
        --assignee-object-id $PROD_SERVICE_PRINCIPAL_ID \
        --assignee-principal-type ServicePrincipal
    

6. 配置 GitHub 环境

在 GitHub 环境中,可以使用保护规则和机密配置环境。 引用环境的工作流程作业在运行或访问环境的机密之前,必须遵循环境的任何保护规则。

创建映射到 Azure 部署环境项目中的环境类型的开发测试和 Prod 环境。

注意

所有产品的公共存储库提供环境、环境机密和环境保护规则。 若要访问专用存储库或内部存储库中的环境、环境机密和部署分支,必须使用 GitHub Pro、GitHub Team 或 GitHub Enterprise。 若要访问专用存储库或内部存储库中的其他环境保护规则,必须使用 GitHub Enterprise。 有关详细信息,请参阅 GitHub 的产品

6.1 创建 Dev 环境

  1. 在 GitHub 中,导航到存储库的主页。

  2. 在存储库名称下,选择“设置”。 如果看不到“设置”选项卡,请选择...下拉菜单,然后选择设置

  3. 在左侧边栏中,选择“环境”。

  4. 选择“新建环境”,输入“Dev”作为环境名称,然后选择“配置环境”。

    Screenshot showing the Environments Add pane, with the environment name Dev, and Configure Environment highlighted.

  5. 在“环境机密”下,选择“添加机密”,并在“名称”中输入 AZURE_CLIENT_ID。

    Screenshot showing the Environment Configure Dev pane, with Add secret highlighted.

  6. 对于 “值”,请输入前面创建的 *Dev**Microsoft Entra 应用的客户端 IDappId(保存为 $DEV_AZURE_CLIENT_ID 环境变量)。

    Screenshot of the Add secret box with the name AZURE CLIENT ID, the value set to an ID number, and add secret highlighted.

  7. 选择“添加机密”。

6.2 创建 Test 环境

在左侧边栏中选择“环境”,返回到环境主页。

  1. 选择“新建环境”,输入“Test”作为环境名称,然后选择“配置环境”。

  2. 在“环境机密”下,选择“添加机密”,并在“名称”中输入 AZURE_CLIENT_ID。

  3. 在“”中,输入前面创建的 Test Microsoft Entra 应用的客户端 ID (appId),(另存为 $TEST_AZURE_CLIENT_ID 环境变量)。

  4. 选择“添加机密”。

6.3 创建 Prod 环境

再次在左侧边栏中选择“环境”,返回到环境主页

  1. 选择“新建环境”,输入“Prod”作为环境名称,然后选择“配置环境”。

  2. 在“环境机密”下,选择“添加机密”,并在“名称”中输入 AZURE_CLIENT_ID。

  3. 在“”中,输入前面创建的 Prod Microsoft Entra 应用的客户端 ID (appId),(另存为 $PROD_AZURE_CLIENT_ID 环境变量)。

  4. 选择“添加机密”。

接下来,将自己设置为此环境的必需审阅者。 尝试部署到 Prod 时,GitHub Actions 等待获得批准后再开始。 当作业正在等待审批时,它的状态为 “正在等待”。 如果作业在 30 天内未获得批准,会自动失败。

有关环境和所需审批的详细信息,请参阅 使用环境进行部署

  1. 选择“必需审阅者”。

  2. 搜索并选择 GitHub 用户。 最多可输入 6 个人员或团队。 只有一个必需的审查者需要批准该作业才能继续。

  3. 选择“保存保护规则”。

最后配置为 main 部署分支:

  1. 在“部署分支”下拉列表中,选择“所选分支”。

  2. 选择“ 添加部署分支规则 ”,然后输入 main 分支 名称模式

  3. 选择“添加规则”。

7. 测试 CI/CD 管道

在本部分,你将对存储库进行一些更改并测试 CI/CD 管道。

7.1 克隆存储库

  1. 在终端中,将 CD 放入要在本地克隆存储库的文件夹。

  2. 克隆存储库。 在以下命令中,确保将 < Organization/Repository > 替换为 GitHub 组织和存储库名称。

    git clone https://github.com/< Organization/Repository >.git
    
  3. 导航到克隆目录。

    cd <repository>
    
  4. 接下来,创建一个新分支并将其远程发布。

    git checkout -b feature1
    
    git push -u origin feature1
    

    特定于此分支的 Azure 中创建了一个新环境。

  5. 在 GitHub 上,导航到新创建的存储库的主页。

  6. 在存储库名称下,选择“Actions”。

    你将会看到新的“创建环境”工作流正在运行。

7.2 更改代码

  1. 在 VS Code 中打开本地克隆的存储库。

  2. ADE 中。教程 文件夹,对文件进行更改。

  3. 保存所做更改。

7.3 推送更改以更新环境

  1. 暂存更改并推送到 feature1 分支。

    git add .
    git commit -m '<commit message>'
    git push
    
  2. 在存储库的“操作”页上,可以看到一个新的“更新环境”工作流正在运行。

7.4 创建拉取请求

  1. 创建 GitHub 拉取请求main <- feature1

  2. 在存储库的“操作”页上,会看到一个新工作流已开始使用测试环境类型创建特定于拉取请求的环境。

7.5 合并拉取请求

  1. 在 GitHub 上,导航到创建的拉取请求。

  2. 合并拉取请求。

    更改将发布到生产环境中,并删除分支和拉取请求环境。

清理资源

如果你不打算使用已创建的任何资源,请删除它们,以免继续产生费用。 如果已将示例应用程序部署在其他资源组中,可能需要重复以下步骤。

若要使用 Azure 门户删除资源,请执行以下操作:

  1. 选择左上角的菜单按钮,然后选择“资源组”。

  2. 从列表中选择你创建的资源组。

  3. 选择“删除资源组”

  4. 输入资源组名称。 然后选择“删除”。

若要使用 Azure CLI 删除资源,请输入以下命令:

az group delete --name <my-dev-center-rg>

请记住,删除资源组会删除其中的所有资源。