Azure 容器应用中的蓝绿部署
蓝绿部署是一种软件发布策略,旨在最大限度地减少停机并降低与部署新版本应用程序相关的风险。 在蓝绿部署中,设置了两个相同的环境,分别称为“蓝色”和“绿色”。 一个环境(蓝色)运行当前应用程序版本,一个环境(绿色)运行新的应用程序版本。
测试绿色环境后,实时流量将定向到该环境,蓝色环境用于在下一个部署周期内部署新的应用程序版本。
可以通过组合容器应用修订、 流量权重以及修订标签,在 Azure 容器应用中启用蓝绿部署。
使用修订创建应用程序的蓝色和绿色版本的实例。
修订 | 说明 |
---|---|
蓝色修订版 | 标记为蓝色的修订版是应用程序的当前运行稳定版本。 此修订是用户与之交互的修订,也是生产流量的目标。 |
绿色 修订版 | 标记为绿色的修订版是蓝色修订版的副本,但它使用较新版本的应用代码和可能的新环境变量集。 它最初不会接收任何生产流量,但可通过标记的完全限定域名 (FQDN) 进行访问。 |
测试并验证新修订后,可以将生产流量指向新修订。 如果遇到问题,可以轻松回滚到以前的版本。
操作 | 说明 |
---|---|
测试和验证 | 绿色修订版经过全面测试和验证,以确保应用程序的新版本按预期运行。 此测试可能涉及各种任务,包括功能测试、性能测试和兼容性检查。 |
流量切换 | 绿色修订版通过所有必要的测试后,将执行流量切换,以便绿色修订版开始提供生产负载。 此开关以受控方式完成,确保平稳过渡。 |
回退 | 如果绿色修订版中出现问题,则可以还原流量切换,将流量路由回稳定的蓝色修订版。 如果新版本中出现问题,此回滚可确保对用户的影响最小。 绿色修订版仍可用于下一部署。 |
角色更改 | 成功部署到绿色修订版后,蓝色和绿色修订版的角色会发生变化。 在下一个发布周期中,绿色修订版表示稳定的生产环境,而新版本的应用程序代码是在蓝色修订版中部署和测试的。 |
本文介绍如何在容器应用中实现蓝绿部署。 若要运行以下示例,需要一个可在其中创建新应用的容器应用环境。
注意
有关实现容器应用的蓝绿部署的 GitHub 工作流的完整示例,请参阅 containerapps-blue-green 存储库。
创建启用了多个活动修订的容器应用
容器应用必须将 configuration.activeRevisionsMode
属性设置为 multiple
才能启用流量拆分。 若要获取确定性的修订版名称,可以将 template.revisionSuffix
配置设置值设为唯一标识版本的字符串值。 例如,可以使用内部生成号,或者 git 提交短哈希。
对于以下命令,使用了一组提交哈希。
export APP_NAME=<APP_NAME>
export APP_ENVIRONMENT_NAME=<APP_ENVIRONMENT_NAME>
export RESOURCE_GROUP=<RESOURCE_GROUP>
# A commitId that is assumed to correspond to the app code currently in production
export BLUE_COMMIT_ID=fb699ef
# A commitId that is assumed to correspond to the new version of the code to be deployed
export GREEN_COMMIT_ID=c6f1515
# create a new app with a new revision
az containerapp create --name $APP_NAME \
--environment $APP_ENVIRONMENT_NAME \
--resource-group $RESOURCE_GROUP \
--image mcr.microsoft.com/k8se/samples/test-app:$BLUE_COMMIT_ID \
--revision-suffix $BLUE_COMMIT_ID \
--env-vars REVISION_COMMIT_ID=$BLUE_COMMIT_ID \
--ingress external \
--target-port 80 \
--revisions-mode multiple
# Fix 100% of traffic to the revision
az containerapp ingress traffic set \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--revision-weight $APP_NAME--$BLUE_COMMIT_ID=100
# give that revision a label 'blue'
az containerapp revision label add \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--label blue \
--revision $APP_NAME--$BLUE_COMMIT_ID
将以下代码添加到名为 main.bicep
的文件中。
targetScope = 'resourceGroup'
param location string = resourceGroup().location
@minLength(1)
@maxLength(64)
@description('Name of containerapp')
param appName string
@minLength(1)
@maxLength(64)
@description('Container environment name')
param containerAppsEnvironmentName string
@minLength(1)
@maxLength(64)
@description('CommitId for blue revision')
param blueCommitId string
@maxLength(64)
@description('CommitId for green revision')
param greenCommitId string = ''
@maxLength(64)
@description('CommitId for the latest deployed revision')
param latestCommitId string = ''
@allowed([
'blue'
'green'
])
@description('Name of the label that gets 100% of the traffic')
param productionLabel string = 'blue'
var currentCommitId = !empty(latestCommitId) ? latestCommitId : blueCommitId
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' existing = {
name: containerAppsEnvironmentName
}
resource blueGreenDeploymentApp 'Microsoft.App/containerApps@2022-11-01-preview' = {
name: appName
location: location
tags: {
blueCommitId: blueCommitId
greenCommitId: greenCommitId
latestCommitId: currentCommitId
productionLabel: productionLabel
}
properties: {
environmentId: containerAppsEnvironment.id
configuration: {
maxInactiveRevisions: 10 // Remove old inactive revisions
activeRevisionsMode: 'multiple' // Multiple active revisions mode is required when using traffic weights
ingress: {
external: true
targetPort: 80
traffic: !empty(blueCommitId) && !empty(greenCommitId) ? [
{
revisionName: '${appName}--${blueCommitId}'
label: 'blue'
weight: productionLabel == 'blue' ? 100 : 0
}
{
revisionName: '${appName}--${greenCommitId}'
label: 'green'
weight: productionLabel == 'green' ? 100 : 0
}
] : [
{
revisionName: '${appName}--${blueCommitId}'
label: 'blue'
weight: 100
}
]
}
}
template: {
revisionSuffix: currentCommitId
containers:[
{
image: 'mcr.microsoft.com/k8se/samples/test-app:${currentCommitId}'
name: appName
resources: {
cpu: json('0.5')
memory: '1.0Gi'
}
env: [
{
name: 'REVISION_COMMIT_ID'
value: currentCommitId
}
]
}
]
}
}
}
output fqdn string = blueGreenDeploymentApp.properties.configuration.ingress.fqdn
output latestRevisionName string = blueGreenDeploymentApp.properties.latestRevisionName
使用以下命令通过 Bicep 模板部署应用:
export APP_NAME=<APP_NAME>
export APP_ENVIRONMENT_NAME=<APP_ENVIRONMENT_NAME>
export RESOURCE_GROUP=<RESOURCE_GROUP>
# A commitId that is assumed to belong to the app code currently in production
export BLUE_COMMIT_ID=fb699ef
# A commitId that is assumed to belong to the new version of the code to be deployed
export GREEN_COMMIT_ID=c6f1515
# create a new app with a blue revision
az deployment group create \
--name createapp-$BLUE_COMMIT_ID \
--resource-group $RESOURCE_GROUP \
--template-file main.bicep \
--parameters appName=$APP_NAME blueCommitId=$BLUE_COMMIT_ID containerAppsEnvironmentName=$APP_ENVIRONMENT_NAME \
--query properties.outputs.fqdn
部署新的修订版并分配标签
蓝色标签当前是指采用到达应用 FQDN 的生产流量的修订版。 绿色标签是指即将推出到生产环境的新版应用。 新的提交哈希标识应用代码的新版本。 以下命令为该提交哈希部署新修订,并使用绿色标签标记。
#create a second revision for green commitId
az containerapp update --name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--image mcr.microsoft.com/k8se/samples/test-app:$GREEN_COMMIT_ID \
--revision-suffix $GREEN_COMMIT_ID \
--set-env-vars REVISION_COMMIT_ID=$GREEN_COMMIT_ID
#give that revision a 'green' label
az containerapp revision label add \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--label green \
--revision $APP_NAME--$GREEN_COMMIT_ID
#deploy a new version of the app to green revision
az deployment group create \
--name deploy-to-green-$GREEN_COMMIT_ID \
--resource-group $RESOURCE_GROUP \
--template-file main.bicep \
--parameters appName=$APP_NAME blueCommitId=$BLUE_COMMIT_ID greenCommitId=$GREEN_COMMIT_ID latestCommitId=$GREEN_COMMIT_ID productionLabel=blue containerAppsEnvironmentName=$APP_ENVIRONMENT_NAME \
--query properties.outputs.fqdn
以下示例演示如何配置流量部分。 蓝色 commitId
修订版占用 100% 的生产流量,而新部署的绿色 commitId
修订版不占用任何生产流量。
{
"traffic": [
{
"revisionName": "<APP_NAME>--fb699ef",
"weight": 100,
"label": "blue"
},
{
"revisionName": "<APP_NAME>--c6f1515",
"weight": 0,
"label": "green"
}
]
}
可以使用特定于标签的 FQDN 测试新部署的修订版:
#get the containerapp environment default domain
export APP_DOMAIN=$(az containerapp env show -g $RESOURCE_GROUP -n $APP_ENVIRONMENT_NAME --query properties.defaultDomain -o tsv | tr -d '\r\n')
#Test the production FQDN
curl -s https://$APP_NAME.$APP_DOMAIN/api/env | jq | grep COMMIT
#Test the blue lable FQDN
curl -s https://$APP_NAME---blue.$APP_DOMAIN/api/env | jq | grep COMMIT
#Test the green lable FQDN
curl -s https://$APP_NAME---green.$APP_DOMAIN/api/env | jq | grep COMMIT
将生产流量发送到绿色修订版
确认绿色修订版中的应用代码按预期工作后,100% 的生产流量将发送到该修订版。 绿色修订版现在成为生产修订版。
# set 100% of traffic to green revision
az containerapp ingress traffic set \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--label-weight blue=0 green=100
# make green the prod revision
az deployment group create \
--name make-green-prod-$GREEN_COMMIT_ID \
--resource-group $RESOURCE_GROUP \
--template-file main.bicep \
--parameters appName=$APP_NAME blueCommitId=$BLUE_COMMIT_ID greenCommitId=$GREEN_COMMIT_ID latestCommitId=$GREEN_COMMIT_ID productionLabel=green containerAppsEnvironmentName=$APP_ENVIRONMENT_NAME \
--query properties.outputs.fqdn
以下示例演示如何在此步骤后配置 traffic
部分。 包含新应用程序代码的绿色修订版会占用所有用户流量,而使用旧应用程序版本的蓝色修订版不接受用户请求。
{
"traffic": [
{
"revisionName": "<APP_NAME>--fb699ef",
"weight": 0,
"label": "blue"
},
{
"revisionName": "<APP_NAME>--c6f1515",
"weight": 100,
"label": "green"
}
]
}
出现问题时回滚部署
如果在生产环境中运行后,发现新修订版存在 bug,则可以回滚到以前的良好状态。 回滚后,100% 的流量将发送到蓝色修订版中的旧版本,并将该修订版再次指定为生产修订版。
# set 100% of traffic to green revision
az containerapp ingress traffic set \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--label-weight blue=100 green=0
# rollback traffic to blue revision
az deployment group create \
--name rollback-to-blue-$GREEN_COMMIT_ID \
--resource-group $RESOURCE_GROUP \
--template-file main.bicep \
--parameters appName=$APP_NAME blueCommitId=$BLUE_COMMIT_ID greenCommitId=$GREEN_COMMIT_ID latestCommitId=$GREEN_COMMIT_ID productionLabel=blue containerAppsEnvironmentName=$APP_ENVIRONMENT_NAME \
--query properties.outputs.fqdn
修复 bug 后,新版本的应用程序将再次部署为绿色修订版。 绿色版本最终成为生产修订版。
下一个部署周期
现在,绿色标签标记当前正在运行稳定生产代码的修订版。
在下一个部署周期中,蓝色通过推出到生产的新应用程序版本来标识修订版。
以下命令演示如何准备下一个部署周期。
# set the new commitId
export BLUE_COMMIT_ID=ad1436b
# create a third revision for blue commitId
az containerapp update --name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--image mcr.microsoft.com/k8se/samples/test-app:$BLUE_COMMIT_ID \
--revision-suffix $BLUE_COMMIT_ID \
--set-env-vars REVISION_COMMIT_ID=$BLUE_COMMIT_ID
# give that revision a 'blue' label
az containerapp revision label add \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--label blue \
--revision $APP_NAME--$BLUE_COMMIT_ID
# set the new commitId
export BLUE_COMMIT_ID=ad1436b
# deploy new version of the app to blue revision
az deployment group create \
--name deploy-to-blue-$BLUE_COMMIT_ID \
--resource-group $RESOURCE_GROUP \
--template-file main.bicep \
--parameters appName=$APP_NAME blueCommitId=$BLUE_COMMIT_ID greenCommitId=$GREEN_COMMIT_ID latestCommitId=$BLUE_COMMIT_ID productionLabel=green containerAppsEnvironmentName=$APP_ENVIRONMENT_NAME \
--query properties.outputs.fqdn