这篇文章是帮助您将2023 年 3 月微服务中的概念付诸实践的四个教程之一: 开始交付微服务:
自动化部署对于大多数项目的成功至关重要。 然而,仅仅部署代码是不够的。 您还需要确保停机时间有限(或消除),并且需要能够在发生故障时快速回滚。 结合金丝雀部署和蓝绿部署是确保新代码可行的常用方法。 该策略包括两个步骤:
如果您不熟悉在应用程序或网站的不同版本之间分配流量(流量分割)的不同用例,请阅读我们博客上的如何使用高级流量管理提高 Kubernetes 的弹性,以获得对蓝绿部署、金丝雀发布、A/B 测试、速率限制、熔断等的概念性理解。 虽然该博客专门讨论 Kubernetes,但其概念广泛应用于微服务应用程序。
在本教程中,我们展示如何使用GitHub Actions自动执行金丝雀蓝绿部署的第一步。 在本教程的四个挑战中,您将使用 Microsoft Azure 容器应用部署应用的新版本,然后使用Azure 流量管理器将流量从旧环境转移到新环境:
笔记: 虽然本教程使用 Azure 容器应用程序,但其概念和技术可应用于任何基于云的主机。
如果您想在自己的环境中完成本教程,您需要:
创建并配置必要的基础资源。 分叉并克隆本教程的存储库,登录 Azure CLI,并安装 Azure 容器应用的扩展。
在您的主目录中,创建microservices-march目录。 (您也可以使用不同的目录名称并相应地调整说明。)
笔记: 在整个教程中,省略了 Linux 命令行上的提示,以便更容易地将命令复制并粘贴到终端中。
mkdir ~/microservices-marchcd ~/microservices-march
使用 GitHub CLI 或 GUI 将Microservices March 平台存储库分叉并克隆到您的个人 GitHub 帐户。
登录 Azure CLI。按照提示使用浏览器登录:
az login [ { “云名称”: “AzureCloud”,“homeTenantId”:“cfd11e0f-1435-450s-bdr1-ffab73b4er8e”,“id”: “60efapl2-38ad-41w8-g49a-0ecc6723l97c”, “isDefault”: true, “managedByTenants”: [], “name”: “Azure 订阅 1”、“状态”: “已启用”,“租户 ID”:“cfda3e0f-14g5-4e05-bfb1-ffab73b4fsde”,“用户”:{“名称”:“user@example.com”,“类型”:“用户”}}]
安装containerapp
扩展:
az extension add --name containerapp -upgrade已安装的扩展“containerapp”处于预览状态。
在此初始挑战中,您将创建一个 NGINX Azure 容器应用程序作为应用的初始版本,用作金丝雀蓝绿部署的基线。 Azure 容器应用是一项 Microsoft Azure 服务,您可以用它在生产就绪的容器环境中轻松执行打包在容器中的应用代码。
为容器应用创建Azure 资源组:
az group create --name my-container-app-rg --location westus{
"id": "/subscriptions/0efafl2-38ad-41w8-g49a-0ecc6723l97c/resourceGroups/my-container-app-rg",
"location: "westus",
"managedBy": null,
"name": "my-container-app-rg",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}
将容器部署到 Azure 容器应用(此步骤可能需要一段时间):
az containerapp up \ --resource-group my-container-app-rg \
--name my-container-app \
--source ./ingress \
--ingress external \
--target-port 80 \
--location westus
...
- image:
registry: cac085021b77acr.azurecr.io
repository: my-container-app
tag: "20230315212413756768"
digest: sha256:90a9fc67c409e244195ec0ea190ce3b84195ae725392e8451...
runtime-dependency:
registry: registry.hub.docker.com
repository: library/nginx
tag: "1.23"
digest: sha256:aa0afebbb3cfa473099a62c4b32e9b3fb73ed23f2a75a65ce...
git: {}
运行ID cf1 已成功完成,耗时27秒
我们正在资源组 my-container-app-rg 中创建容器应用 my-container-app
我们以名为 "ca2ffbce7810acrazurecrio-cac085021b77acr" 的机密添加了注册表密码
容器应用已创建。 您可以通过链接 https://my-container-app.delightfulmoss-eb6d59d5.westus.azurecontainerapps.io/ 访问您的应用
...
在步骤 2 的输出中,找到在Azure 容器注册表(ACR) 中创建的容器应用的名称和 URL。 它们在示例输出中以橙色突出显示。 您将使用输出中的值(与步骤 2 中的示例输出不同)替换整个教程中命令中指示的变量:
容器应用的名称– 在image.registry
项中, .azurecr.io
之前的字符串。 在步骤2中的示例输出中,它是cac085021b77acr
。
将此字符串替换为 <ACR_名称>
在后续命令中。
容器应用的 URL – 以Container
app
created
开头的行上的 URL。 在步骤 2 中的示例输出中,它是https://my-container-app.delightfulmoss-eb6d59d5.westus.azurecontainerapps.io/
。
将此 URL 替换为 <ACR_URL>
在后续命令中。
根据蓝绿部署的要求启用容器应用的修订:
az containerapp revision set-mode \ --name my-container-app \
--resource-group my-container-app-rg \
--mode multiple
“多实例模式”
(可选)通过查询容器中的/health端点来测试部署是否正常工作:
卷曲 <ACR_URL>/健康好的
在本次挑战中,您将获得 JSON 令牌,使您能够自动化 Azure 容器应用程序部署。
首先获取 Azure 容器注册表 (ACR) 的 ID,然后获取 Azure托管标识的主体 ID。 然后,将 ACR 的内置 Azure 角色分配给托管标识,并配置容器应用以使用托管标识。 最后,您将获得托管身份的 JSON 凭据,GitHub Actions 将使用该凭据向 Azure 进行身份验证。
虽然这组步骤看起来很繁琐,但您只需在创建新应用时执行一次,即可完全编写该过程的脚本。 本教程将要求您手动执行这些步骤以熟悉它们。
笔记: 此创建部署凭据的过程特定于 Azure。
查找托管身份的主体 ID。 它出现在输出的PrincipalID
列中(为了易读,分为两行)。 您将用该值代替 <managed_identity_principal_ID>
在步骤 3:
az containerapp identity assign \ --name my-container-app \
--resource-group my-container-app-rg \
--system-assigned \
--output table
PrincipalId ...
------------------------------------ ...
39f8434b-12d6-4735-81d8-ba0apo14579f ...
... TenantId
... ------------------------------------
... cfda3e0f-14g5-4e05-bfb1-ffab73b4fsde
在 ACR 中查找容器应用的资源 ID,替换 <ACR_名称>
使用您在第 3 步中记录的姓名 挑战 1。 您将用该值代替 <ACR_资源_ID>
下一步:
az acr show --name <ACR_name> --query id --output tsv/subscriptions/60efafl2-38ad-41w8-g49a-0ecc6723l97c/resourceGroups/my-container-app-rg/providers/Microsoft.ContainerRegistry/registries/cac085021b77acr
将 ACR 的内置 Azure 角色分配给容器应用的托管标识,替换 <管理身份主体 ID>
使用在步骤 1 中获得的托管身份,以及 <ACR_资源_ID>
使用步骤 2 中获得的资源 ID:
az role assignment create \ --assignee <managed_identity_principal_ID> \
--role AcrPull \
--scope <ACR_resource_ID>
{
"condition": null,
"conditionVersion": null,
"createdBy": null,
"createdOn": "2023-03-15T20:28:40.831224+00:00",
"delegatedManagedIdentityResourceId": null,
"description": null,
"id": "/subscriptions/0efafl2-38ad-41w8-g49a-0ecc6723l97c/resourceGroups/my-container-app-rg/providers/Microsoft.ContainerRegistry/registries/cac085021b77acr/providers/Microsoft.Authorization/roleAssignments/f0773943-8769-44c6-a820-ed16007ff249",
"name": "f0773943-8769-44c6-a820-ed16007ff249",
"principalId": "39f8ee4b-6fd6-47b5-89d8-ba0a4314579f",
"principalType": "ServicePrincipal",
"resourceGroup": "my-container-app-rg",
"roleDefinitionId": "/subscriptions/60e32142-384b-43r8-9329-0ecc67dca94c/providers/Microsoft.Authorization/roleDefinitions/7fd21dda-4fd3-4610-a1ca-43po272d538d",
"scope": "/subscriptions/ 0efafl2-38ad-41w8-g49a-0ecc6723l97c/resourceGroups/my-container-app-rg/providers/Microsoft.ContainerRegistry/registries/cac085021b77acr",
"type": "Microsoft.Authorization/roleAssignments",
"updatedBy": "d4e122d6-5e64-4bg1-9cld-2aceeb0oi24d",
"updatedOn": "2023-03-15T20:28:41.127243+00:00"
}
将容器应用配置为在从 ACR 拉取映像时使用托管标识,替换 <ACR_名称>
使用您在步骤 3 中记录的容器应用名称 挑战 1 (也用于上述步骤 2):
az containerapp registry set \ --name my-container-app \
--resource-group my-container-app-rg \
--server <ACR_name>.azurecr.io \
--identity system
[
{
"identity": "system",
"passwordSecretRef": "",
"server": "cac085021b77acr.azurecr.io",
"username": ""
}
]
查找您的Azure 订阅 ID 。
az 帐户显示--查询 ID--输出 tsv 0efafl2-38ad-41w8-g49a-0ecc6723l97c
创建一个 JSON 令牌,其中包含 GitHub Action 要使用的凭据,替换 <订阅 ID>
使用您的 Azure 订阅 ID。保存输出以粘贴为名为的机密的值 AZURE_CREDENTIALS
在 将机密添加到您的 GitHub 存储库。 您可以放心地忽略有关--sdk-auth
已被弃用的警告;这是一个已知问题:
az ad sp create-for-rbac \ --name my-container-app-rbac \
--role contributor \
--scopes /subscriptions/<subscription_ID>/resourceGroups/my-container-app-rg \
--sdk-auth \
--output json
选项 “--sdk-auth” 已弃用,未来版本将移除。
... {
"clientId":"0732444d-23e6-47fb-8c2c-74bddfc7d2er",
"clientSecret": "qg88Q~KJaND4JTWRPOLWgCY1ZmZwN5MK3N.wwcOe",
"subscriptionId": "0efafl2-38ad-41w8-g49a-0ecc6723l97c",
"tenantId": "cfda3e0f-14g5-4e05-bfb1-ffab73b4fsde",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
在这个挑战中,您将机密添加到您的 GitHub 存储库(用于管理 GitHub Action 工作流中的敏感数据),创建一个 Action 工作流文件,并执行 Action 工作流。
有关机密管理的详细介绍,请参阅我们博客上 3 月 23 日针对微服务的第二篇教程《如何安全地管理容器中的机密》 。
要部署应用的新版本,您需要在“设置”中分叉的 GitHub 存储库中创建一系列机密。 这些机密是在挑战 2中创建的托管身份的 JSON 凭据,以及将新版本的 NGINX 映像部署到 Azure 所需的一些敏感的部署特定参数。 在下一部分中,您将在 GitHub Action 中使用这些机密来自动化金丝雀蓝绿部署。
如果使用 GitHub GUI:
在指定的字段中输入以下值:
AZURE_CREDENTIALS
重复步骤 3-5 三次以创建表中列出的机密。 将Secret Name和Secret Value列中的值分别输入到 GUI 的名称和Secret字段中。 对于第三个秘密,替换 <ACR_名称>
使用您在第 3 步中记录的分配给容器应用的名称 挑战 1。
秘密名称 | 秘密值 |
---|---|
容器应用名称 |
我的容器应用程序 |
资源组 |
我的容器应用程序-rg |
ACR_NAME |
<ACR_名称> |
如果使用 GitHub CLI:
在你的 repo 的根目录下,创建一个临时文件。
触摸〜/creds.json
创建秘密:
gh secret 设置 AZURE_CREDENTIALS --repo <你的 GitHub 帐户> /platform < ~/creds.json
删除creds.json :
rm ~/creds.json
重复此命令以创建另外三个秘密:
gh 秘密套装 <秘密名称> --repo <你的 GitHub 帐户>/平台
每次重复,更换 <秘密名称>
其中一个值 秘密名称 表中的列。 在提示符下,从Secret Value列中粘贴关联的值。 对于第三个秘密,替换 <ACR_名称>
使用您在第 3 步中记录的分配给容器应用的名称 挑战 1。
秘密名称 | 秘密值 |
---|---|
容器应用名称 |
我的容器应用程序 |
资源组 |
我的容器应用程序-rg |
ACR_NAME |
<ACR_名称> |
有了托管身份和机密后,您可以为 GitHub Action 创建工作流文件,以自动执行金丝雀蓝绿部署。
笔记: 工作流文件以 YAML 格式定义,其中空格很重要。 确保保留以下步骤中显示的缩进。
为 Action 工作流创建一个文件。
如果使用 GitHub GUI:
如果使用 GitHub CLI,请创建.github/workflows目录并创建一个名为main.yml的新文件:
mkdir .github/workflowstouch .github/workflows/main.yml
使用您喜欢的文本编辑器,将工作流的文本添加到main.yml 。 最简单的方法是复制“完整工作流文件中”出现的文本。 或者,您可以通过添加此步骤中注释的片段集来手动构建文件。
笔记: 工作流文件以 YAML 格式定义,其中空格很重要。 如果您复制片段,请务必保留缩进(并且为了更加确定,请将您的文件与完整工作流文件进行比较。
定义工作流的名称:
姓名: 部署到 AzureDeploy to Azure
配置在向主分支发出推送或拉取请求时运行的工作流:
开启:
推送:
分支:
-主要
拉取请求:
分支:
-主要
在作业
部分中,定义构建部署
作业,该作业签出代码、登录 Azure 并将应用部署到 Azure 容器应用:
作业:构建-部署:运行于:ubuntu-22.04 步骤:- 名称: 检查代码库用途:actions/checkout@v3 - 名称: 登录到 Azure 使用:azure/login@v1 和:creds:${{ secrets.AZURE_CREDENTIALS } } - 姓名: 构建并部署容器应用运行:| # 手动添加 containerapp 扩展 az extension add --name containerapp --upgrade # 使用 Azure CLI 部署更新 az containerapp up -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} \ - 来源${{ github.workspace }}/ingress \ --registry-server${{ secrets.ACR_NAME }复制代码
定义测试部署
作业,该作业获取新部署修订版的暂存 URL,并使用 GitHub Action ping API 端点/health以确保新修订版正在响应。 如果健康检查成功,容器应用上的 Azure 流量管理器将更新,以将所有流量指向新部署的容器。
笔记: 确保将test-deployment
键缩进与您在上一个项目中定义的build-deploy
键相同的级别:
测试部署:需求:构建部署运行于:ubuntu-22.04 步骤:- 名称: 登录到 Azure 使用:azure/login@v1 和:creds:${{ secrets.AZURE_CREDENTIALS } } - 姓名: 获取新容器名称运行:| # 手动添加 containerapp 扩展 az extension add --name containerapp --upgrade # 获取最后部署的修订名称 REVISION_NAME=`az containerapp revision list -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --query "[].name" -o tsv | tail -1` # 获取最后部署的修订的 fqdn REVISION_FQDN=`az containerapp revision show -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --revision "$REVISION_NAME" --query properties.fqdn -o tsv` # 将值存储在环境变量中 echo "REVISION_NAME=$REVISION_NAME" >> $GITHUB_ENV echo "REVISION_FQDN=$REVISION_FQDN" >> $GITHUB_ENV - name: 测试部署 ID:test-deployment 使用:jtalk/url-health-check-action@v3 # 市场操作使用以下方式接触端点:url:“https://${{ env.REVISION_FQDN } }/health” # 暂存端点 - 名称: 部署成功运行:| echo "部署成功! 启用新修订版本” az containerapp ingress Traffic set -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --修订权重”${{ env.REVISION_NAME } }=100”
这是 Action 工作流文件的完整文本。
姓名: 部署到 Azure:推送:分支:-主要拉取请求:分支:-主要作业:构建部署:运行于:ubuntu-22.04 步骤:-名称: 检查代码库用途:actions/checkout@v3 - 名称: 登录到 Azure 使用:azure/login@v1 和:creds:${{ secrets.AZURE_CREDENTIALS } } - 姓名: 构建并部署容器运行:| # 手动添加 containerapp 扩展 az extension add --name containerapp -upgrade # 使用 Azure CLI 部署更新 az containerapp up -n${{ secrets.CONTAINER_APP_NAME } } \ -g${{ secrets.RESOURCE_GROUP } } \ - 来源${{ github.workspace }}/ingress \ --registry-server${{ secrets.ACR_NAME } }.azurecr.io 测试部署:需求:构建部署运行于:ubuntu-22.04 步骤:- 名称: 登录到 Azure 使用:azure/login@v1 和:creds:${{ secrets.AZURE_CREDENTIALS } } - 姓名: 获取新容器名称运行:| # 为 Azure CLI 安装 containerapp 扩展 az extension add --name containerapp --upgrade # 获取最后部署的修订名称 REVISION_NAME=`az containerapp revision list -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --query "[].name" -o tsv | tail -1` # 获取最后部署的修订的 fqdn REVISION_FQDN=`az containerapp revision show -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --revision "$REVISION_NAME" --query properties.fqdn -o tsv` # 将值存储在环境变量中 echo "REVISION_NAME=$REVISION_NAME" >> $GITHUB_ENV echo "REVISION_FQDN=$REVISION_FQDN" >> $GITHUB_ENV - name: 测试部署 ID:test-deployment 使用:jtalk/url-health-check-action@v3 # 市场操作使用以下方式接触端点:url:“https://${{ env.REVISION_FQDN } }/health” # 暂存端点 - 名称: 部署成功运行:| echo "部署成功! 启用新修订版本” az containerapp ingress Traffic set -n${{ secrets.CONTAINER_APP_NAME } -g 复制代码${{ secrets.RESOURCE_GROUP }} --修订权重”${{ env.REVISION_NAME } }=100”
如果使用 GitHub GUI:
如果使用 GitHub CLI:
将main.yml添加到 Git 暂存区:
git 添加 .github/workflows/main.yml
提交文件:
git commit -m “feat:创建 GitHub Actions 工作流程”
将你的更改推送到 GitHub:
git push
监控工作流程的进度:
gh 工作流视图 main.yml --repo <你的 GitHub 帐户>/平台
在这个挑战中,您将测试工作流程。 首先模拟对 Ingress 负载均衡器的成功更新,并确认应用已更新。 然后,您模拟一次不成功的更新(导致内部服务器错误)并确认已发布的应用保持不变。
创建成功的更新并观察工作流程是否成功。
如果使用 GitHub GUI:
在文件末尾附近的location
/health
块中,按指示更改return
指令:
location /health {
access_log off;
return 200 "更新成功!\n";
}
成功
!”
消息。您可以通过启动终端会话并向应用程序发送健康检查请求来确认该消息,再次替换 <ACR_URL>
使用您在步骤 3 中记录的值 挑战 1:
卷曲 <ACR_URL>/健康更新成功!
如果使用 GitHub CLI:
创建一个名为patch-1的新分支:
git checkout -b patch-1
在您喜欢的文本编辑器中打开ingress/default.conf.template并在文件末尾附近的location
/health
块中,按指示更改return
指令:
location /health {
access_log off;
return 200 "更新成功!\n";
}
将default.conf.template添加到 Git 暂存区:
git 添加 ingress/default.conf.template
提交文件:
git commit -m “feat:更新 NGINX 入口”
将你的更改推送到 GitHub:
git push --set-upstream 原点补丁-1
创建拉取请求(PR):
gh pr create --head patch-1 --fill --repo <你的 GitHub 帐户> /platform
监控工作流程的进度:
gh 工作流视图 main.yml --repo <你的 GitHub 帐户>/平台
工作流程完成后,向应用程序发送健康检查请求,替换 <ACR_URL>
使用您在步骤 3 中记录的值 挑战 1:
卷曲 <ACR_URL>/健康
更新成功!
现在创建一个不成功的更新并观察工作流程失败。 这基本上涉及重复“进行成功更新”中的步骤,但使用不同的返回
指令值。
如果使用 GitHub GUI:
按照指示更改返回
指令:
location /health {
access_log off;
return 500 "更新失败!\n";
}
工作流程完成后,导航到您的容器应用 <ACR_URL>/健康 终点,其中 <ACR_URL> 是您在第 3 步中记录的网址 挑战 1。
注意消息是更新成功
!
(与上次成功更新后相同)。 虽然这看起来有些矛盾,但它实际上证实了这次更新失败了——更新尝试导致状态500
(意思是内部
服务器
错误
)并且没有被应用。
您可以通过启动终端会话并向应用程序发送健康检查请求来确认该消息,再次替换 <ACR_URL>
使用您在步骤 3 中记录的值 挑战 1:
卷曲 <ACR_URL>/健康更新成功!
如果使用 GitHub CLI:
查看您在上一节中创建的patch-1分支:
git checkout 补丁-1
在您喜欢的文本编辑器中打开ingress/default.conf.template并再次更改return
指令,如下所示:
location /health {
access_log off;
return 500 "更新失败!\n";
}
将default.conf.template添加到 Git 暂存区:
git 添加 ingress/default.conf.template
提交文件:
git commit -m “feat: 再次更新 NGINX ingress”
将你的更改推送到 GitHub:
git push
监控工作流程的进度:
gh 工作流视图 main.yml --repo <你的 GitHub 帐户>/平台
工作流程完成后,向应用程序发送健康检查请求,替换 <ACR_URL>
使用您在步骤 3 中记录的值 挑战 1:
卷曲 <ACR_URL>/健康更新成功!
这条消息“更新成功
!”
看起来似乎有些矛盾(与上次更新成功后的消息相同)。 虽然这看起来有些矛盾,但实际上它证实了这次更新失败了——更新尝试导致状态500
(意思是内部
服务器
错误
)并且没有被应用。
您可能希望删除在教程中部署的 Azure 资源,以避免后续产生任何潜在费用:
az 组删除-n my-container-app-rg-y
如果愿意,您还可以删除您创建的分支。
如果使用 GitHub GUI:
如果使用 GitHub CLI:
gh repo delete <你的 GitHub 帐户> /platform -yes
恭喜! 您已经了解了如何使用 GitHub Actions 对微服务应用进行金丝雀蓝绿部署。查看 GitHub 文档中的这些文章,继续探索和增长您对 DevOps 的了解:
如果您已准备好尝试金丝雀部署的第二步(在生产中测试),请查看我们博客上 2022 年 3 月微服务教程《使用金丝雀部署提高正常运行时间和弹性》 。 它使用 NGINX Service Mesh 逐步过渡到新的应用程序版本。 即使您的部署还不够复杂,不需要服务网格,或者您没有使用 Kubernetes,这些原则仍然适用于仅使用 Ingress 控制器或负载均衡器的更简单的部署。
要继续您的微服务教育,请查看 2023 年 3 月的微服务。 在第 3 单元“通过自动化加速微服务部署”中,您将了解有关自动化部署的更多信息。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”