Implantação azul-verde em aplicativos de contêiner do Azure

Blue-Green Deployment é uma estratégia de lançamento de software que visa minimizar o tempo de inatividade e reduzir o risco associado à implantação de novas versões de um aplicativo. Em uma implantação azul-verde, dois ambientes idênticos, referidos como "azul" e "verde", são configurados. Um ambiente (azul) está executando a versão atual do aplicativo e um ambiente (verde) está executando a nova versão do aplicativo.

Depois que o ambiente verde é testado, o tráfego ao vivo é direcionado para ele e o ambiente azul é usado para implantar uma nova versão do aplicativo durante o próximo ciclo de implantação.

Você pode habilitar a implantação azul-verde em Aplicativos de Contêiner do Azure combinando revisões de aplicativos de contêiner, pesos de tráfego e rótulos de revisão.

Screenshot of Azure Container Apps: Blue/Green deployment.

Você usa revisões para criar instâncias das versões azul e verde do aplicativo.

Revisão Descrição
Revisão azul A revisão rotulada como azul é a versão atualmente em execução e estável do aplicativo. Essa revisão é aquela com a qual os usuários interagem e é o alvo do tráfego de produção.
Revisão verde A revisão rotulada como verde é uma cópia da revisão azul , exceto que usa uma versão mais recente do código do aplicativo e, possivelmente, um novo conjunto de variáveis de ambiente. Ele não recebe nenhum tráfego de produção inicialmente, mas é acessível por meio de um nome de domínio totalmente qualificado (FQDN) rotulado.

Depois de testar e verificar a nova revisão, você pode apontar o tráfego de produção para a nova revisão. Se você encontrar problemas, você pode facilmente reverter para a versão anterior.

Ações Descrição
Testes e verificação A revisão verde é exaustivamente testada e verificada para garantir que a nova versão do aplicativo funcione conforme o esperado. Esse teste pode envolver várias tarefas, incluindo testes funcionais, testes de desempenho e verificações de compatibilidade.
Interruptor de tráfego Uma vez que a revisão verde passa por todos os testes necessários, uma mudança de tráfego é executada para que a revisão verde comece a servir a carga de produção. Esta mudança é feita de forma controlada, garantindo uma transição suave.
Reversão Se ocorrerem problemas na revisão verde, você pode reverter o comutador de tráfego, roteando o tráfego de volta para a revisão azul estável. Essa reversão garante um impacto mínimo nos usuários se houver problemas na nova versão. A revisão verde ainda está disponível para a próxima implantação.
Mudança de função As funções das revisões azul e verde mudam após uma implantação bem-sucedida na revisão verde . Durante o próximo ciclo de lançamento, a revisão verde representa o ambiente de produção estável enquanto a nova versão do código do aplicativo é implantada e testada na revisão azul.

Este artigo mostra como implementar a implantação azul-verde em um aplicativo de contêiner. Para executar os exemplos a seguir, você precisa de um ambiente de aplicativo de contêiner onde possa criar um novo aplicativo.

Nota

Consulte containerapps-blue-green repository para obter um exemplo completo de um fluxo de trabalho do GitHub que implementa a implantação azul-verde para Container Apps.

Criar um aplicativo de contêiner com várias revisões ativas habilitadas

O aplicativo contêiner deve ter a propriedade definida para multiple habilitar a configuration.activeRevisionsMode divisão de tráfego. Para obter nomes de revisão determinísticos, você pode definir a template.revisionSuffix configuração como um valor de cadeia de caracteres que identifique exclusivamente uma versão. Por exemplo, você pode usar números de compilação ou git commits hashes curtos.

Para os comandos a seguir, um conjunto de hashes commit foi usado.

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

Salve o código a seguir em um arquivo chamado 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

Implante o aplicativo com o modelo Bicep usando este comando:

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

Implantar uma nova revisão e atribuir rótulos

Atualmente , o rótulo azul refere-se a uma revisão que leva o tráfego de produção que chega ao FQDN do aplicativo. O rótulo verde refere-se a uma nova versão de um aplicativo que está prestes a ser lançado em produção. Um novo hash de confirmação identifica a nova versão do código do aplicativo. O comando a seguir implanta uma nova revisão para esse hash de confirmação e o marca com rótulo verde .

#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

O exemplo a seguir mostra como a seção de tráfego é configurada. A revisão com o azulcommitId está tomando 100% do tráfego de produção, enquanto a revisão recém-implantada com verdecommitId não leva nenhum tráfego de produção.

{ 
  "traffic": [
    {
      "revisionName": "<APP_NAME>--fb699ef",
      "weight": 100,
      "label": "blue"
    },
    {
      "revisionName": "<APP_NAME>--c6f1515",
      "weight": 0,
      "label": "green"
    }
  ]
}

A revisão recém-implantada pode ser testada usando o FQDN específico do rótulo:

#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

Enviar tráfego de produção para a revisão verde

Depois de confirmar que o código do aplicativo na revisão verde funciona conforme o esperado, 100% do tráfego de produção é enviado para a revisão. A revisão verde passa a ser a revisão da produção.

# 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

O exemplo a seguir mostra como a seção é configurada traffic após esta etapa. A revisão verde com o novo código do aplicativo recebe todo o tráfego do usuário, enquanto a revisão azul com a versão antiga do aplicativo não aceita solicitações do usuário.

{ 
  "traffic": [
    {
      "revisionName": "<APP_NAME>--fb699ef",
      "weight": 0,
      "label": "blue"
    },
    {
      "revisionName": "<APP_NAME>--c6f1515",
      "weight": 100,
      "label": "green"
    }
  ]
}

Reverter a implantação se houver problemas

Se depois de executar em produção, a nova revisão for encontrada com bugs, você pode reverter para o bom estado anterior. Após a reversão, 100% do tráfego é enviado para a versão antiga na revisão azul e essa revisão é designada como a revisão de produção novamente.

# 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

Depois que os bugs são corrigidos, a nova versão do aplicativo é implantada como uma revisão verde novamente. A versão verde acaba por se tornar a revisão de produção.

Próximo ciclo de implantação

Agora, o rótulo verde marca a revisão que atualmente executa o código de produção estável.

Durante o próximo ciclo de implantação, o azul identifica a revisão com a nova versão do aplicativo sendo implementada para produção.

Os comandos a seguir demonstram como se preparar para o próximo ciclo de implantação.

# 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

Próximos passos