Развертывание Blue-Green в приложениях контейнеров Azure

Blue-Green Deployment — это стратегия выпуска программного обеспечения, которая направлена на минимизацию простоя и снижение риска, связанного с развертыванием новых версий приложения. В сине-зеленом развертывании настраиваются две идентичные среды, называемые "голубым" и "зеленым". Одна среда (синяя) выполняет текущую версию приложения, а одна среда (зеленая) выполняет новую версию приложения.

После тестирования зеленой среды динамический трафик направляется в него, а синяя среда используется для развертывания новой версии приложения во время следующего цикла развертывания.

Вы можете включить сине-зеленое развертывание в приложениях контейнеров Azure, объединив редакции контейнерных приложений, вес трафика и метки редакции.

Screenshot of Azure Container Apps: Blue/Green deployment.

Для создания экземпляров синих и зеленых версий приложения используются редакции.

Исправление Description
Синяя редакция Редакция, помеченная как синяя , является текущей и стабильной версией приложения. Эта редакция является тем, с которыми взаимодействуют пользователи, и это цель рабочего трафика.
Зеленая редакция Редакция, помеченная как зеленая , является копией синей редакции, за исключением того, что она использует более новую версию кода приложения и, возможно, новый набор переменных среды. Изначально он не получает рабочий трафик, но доступен через полное доменное имя (FQDN).

После тестирования и проверки новой редакции можно указать рабочий трафик на новую редакцию. При возникновении проблем можно легко выполнить откат к предыдущей версии.

Действия Description
Тестирование и проверка Зеленая редакция тщательно проверяется и проверяется, чтобы новая версия функций приложения была правильной. Это тестирование может включать различные задачи, включая функциональные тесты, тесты производительности и проверка совместимости.
Коммутатор трафика После прохождения всех необходимых тестов зеленая редакция выполняется переключатель трафика, чтобы зеленая редакция начала обслуживать рабочую нагрузку. Этот переключатель выполняется в управляемом режиме, обеспечивая плавный переход.
Откат Если проблемы возникают в зеленой редакции, вы можете отменить изменения коммутатор трафика, перенаправив трафик обратно в стабильную синюю редакцию. Этот откат гарантирует минимальное влияние на пользователей при возникновении проблем в новой версии. Зеленая редакция по-прежнему доступна для следующего развертывания.
Изменение роли Роли синих и зеленых редакций изменяются после успешного развертывания на зеленую редакцию. Во время следующего цикла выпуска зеленая редакция представляет стабильную рабочую среду, а новая версия кода приложения развертывается и проверяется в синей редакции.

В этой статье показано, как реализовать сине-зеленое развертывание в приложении-контейнере. Для выполнения следующих примеров требуется среда приложения контейнера, в которой можно создать новое приложение.

Примечание.

Полный пример рабочего процесса 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

Развертывание новой редакции и назначение меток

Голубая метка в настоящее время относится к редакции, которая принимает рабочий трафик, поступающий на полное доменное имя приложения. Зеленая метка ссылается на новую версию приложения, которое будет развернуто в рабочей среде. Новый хэш фиксации определяет новую версию кода приложения. Следующая команда развертывает новую редакцию для хэша фиксации и помечает ее зеленой меткой.

#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"
    }
  ]
}

Недавно развернутая редакция может быть проверена с помощью полного доменного имени для меток:

#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"
    }
  ]
}

Откат развертывания, если возникли проблемы

Если после выполнения в рабочей среде новая редакция найдена с ошибками, можно выполнить откат к предыдущему хорошему состоянию. После отката 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

После исправления ошибок новая версия приложения развертывается в виде зеленой редакции еще раз. Зеленая версия в конечном итоге становится рабочей редакцией.

Следующий цикл развертывания

Теперь зеленая метка помечает редакцию, выполняющую стабильный рабочий код.

В следующем цикле развертывания синий определяет редакцию с новой версией приложения, развернутой в рабочей среде.

В следующих командах показано, как подготовиться к следующему циклу развертывания.

# 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

Следующие шаги