Compartilhar via


Implantação azul-verde nos Aplicativos de Contêiner do Azure

Implantação Azul-Verde é 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, conhecidos 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 em tempo real é 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 nos Aplicativos de Contêiner do Azure combinando revisões de aplicativos de contêiner, pesos de tráfegoe rótulos de revisão.

Captura de tela dos Aplicativos de Contêiner do Azure: implantação azul/verde.

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 destino 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. Não recebe nenhum tráfego de produção inicialmente, mas é acessível por meio de um FQDN (nome de domínio totalmente qualificado) rotulado.

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

Ações Descrição
Teste e verificação A revisão verde é cuidadosamente 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.
Comutador de tráfego Depois que a revisão verde passar em todos os testes necessários, um comutador de tráfego será executado para que a revisão verde comece a servir a carga de produção. Essa mudança é feita de maneira controlada, garantindo uma transição suave.
Reversão Se ocorrerem problemas na revisão verde, você poderá 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 sobre os usuários se houver problemas na nova versão. A revisão verde ainda está disponível para a próxima implantação.
Alteração 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 representará 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 em que possa criar um novo aplicativo.

Observação

Consulte repositório containerapps-blue-green para obter um exemplo completo de um fluxo de trabalho do GitHub que implementa a implantação azul-verde para Aplicativos de Contêiner.

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

O aplicativo de contêiner deve ter um conjunto de propriedades configuration.activeRevisionsMode definido como multiple para habilitar a separação de tráfego. Para obter nomes de revisão determinística, você pode definir a configuração de template.revisionSuffix como um valor de cadeia de caracteres que identifica exclusivamente uma versão. Por exemplo, você pode usar números de compilação ou hashes curtos de commits do Git.

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

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

O rótulo azul atualmente refere-se a uma revisão que recebe o tráfego de produção que chega no FQDN do aplicativo. O rótulo verde refere-se a uma nova versão de um aplicativo que está prestes a ser distribuída para produção. Um novo hash do commit identifica a nova versão do código do aplicativo. O comando a seguir implanta uma nova revisão para esse hash do commit e o marca com o rótuloverde.

#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 está configurada. A revisão com a azulcommitId está recebendo 100% do tráfego de produção, enquanto a revisão recém-implantada com verdecommitId não recebe 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 label FQDN
curl -s https://$APP_NAME---blue.$APP_DOMAIN/api/env | jq | grep COMMIT

#Test the green label 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 será enviado para a revisão. A revisão verde agora se torna a revisão de 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 traffic está configurada após essa 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 de 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 após a execução em produção, a nova revisão tiver bugs, você poderá reverter para o estado bom anterior. Após a reversão, 100% do tráfego será enviado para a versão antiga na revisão azul e essa revisão será 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 forem corrigidos, a nova versão do aplicativo será implantada como uma revisão verde novamente. A versão verde acaba se tornando a revisão de produção.

Próximo ciclo de implantação

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

Durante o próximo ciclo de implantação, o azul identificará a revisão com a nova versão do aplicativo sendo distribuída 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óximas etapas