← Blog

Deploy no CloudHub 2.0 a partir do Azure Pipelines: build único, aprovação e verificação

Referência: templates/jobs/deploy.yml · deployment/ · ADRs 5 e 6

A última parte do fluxo pega uma versão que já está no Anypoint Exchange e a coloca na frente dos usuários: test a partir do develop, depois uat e produção a cada release. Três ideias sustentam isso: construir uma vez, aprovar onde o ambiente é definido e verificar cada deploy.

Construir uma vez, fazer deploy a partir do Exchange

O CloudHub 2.0 faz deploy de aplicações a partir do Exchange. Isso torna o “build único” natural: o SNAPSHOT do develop e o release da main são publicados uma vez, e cada deploy se refere a eles pela versão.

O job de deploy nunca reconstrói. Ele usa o goal de deploy do Mule Maven plugin com um artefato fictício:

mvn $(MAVEN_ARGS) -q versions:set -DnewVersion="${APP_VERSION}" -DgenerateBackupPoms=false
mvn $(MAVEN_ARGS) mule:deploy -Dmule.artifact=dummy.jar -DmuleDeploy \
  -Ddeploy.environment="${ANYPOINT_ENV}" \
  -Ddeploy.applicationName="$(y .applicationName)" \
  -Ddeploy.target="$(y .target)" \
  -Ddeploy.runtimeVersion="$(y .runtimeVersion)" \
  -Ddeploy.replicas="$(y .replicas)" \
  -Ddeploy.vCores="$(y .vCores)" \
  -Ddeploy.clientId="${ANYPOINT_CLIENT_ID}" \
  -Ddeploy.clientSecret="${ANYPOINT_CLIENT_SECRET}"

O versions:set fixa o POM na versão que vai para o ambiente, e o -Dmule.artifact=dummy.jar impede o plugin de empacotar: o CloudHub 2.0 busca essa versão no Exchange. O log confirma — dois minutos, nenhuma compilação, Artifact mulesoft-orders-api-uat deployed. uat e produção recebem exatamente o artefato que o release produziu.

O bloco cloudhub2Deployment do POM lê propriedades deploy.*, e os valores de cada ambiente ficam no repositório da aplicação:

# deployment/prod.yaml
applicationName: mulesoft-orders-api-prod
target: Cloudhub-US-East-2
runtimeVersion: 4.9.0
replicas: 1
vCores: 0.1
healthUrl: https://mulesoft-orders-api-prod-aslzjy.5sc6y6-2.usa-e2.cloudhub.io/api/health

Dimensionar produção vira uma mudança revisada num pull request, e não um clique no Runtime Manager. A app também recebe o mule.env, que escolhe o config-<env>.yaml.

Promoção: test, uat, prod

Cada deploy é um job deployment apontando para um environment do Azure DevOps:

- deployment: deploy
  environment: ${{ parameters.environment }}
  strategy:
    runOnce:
      deploy:
        steps: ...

Na main, os stages se encadeiam: release, depois uat, depois prod. A versão vem da variável de saída do stage de release, então prod não consegue receber nada diferente do que uat recebeu:

- stage: deploy_prod
  dependsOn: [release, deploy_uat]
  variables:
    appVersion: $[ stageDependencies.release.release.outputs['release.appVersion'] ]

Aprovação onde o ambiente vive

O environment prod no Azure DevOps tem uma checagem de Approvals: aprovadores definidos, instruções (“confira o deploy em uat antes de aprovar”) e prazo. Quando o pipeline chega a prod, ele para. O aprovador recebe um e-mail e aprova no portal; a execução registra quem aprovou e quando.

Colocar a checagem no environment, e não no YAML, faz com que nenhuma aplicação consiga pular a aprovação, e a regra é configurada uma vez para todos os pipelines que fazem deploy em prod.

A aprovação também pode ser dada pelo Slack ou pelo Microsoft Teams, com os apps do Azure Pipelines, que publicam a aprovação pendente num canal com os botões Approve e Reject. Os dois apps exigem uma organização do Azure DevOps ligada ao Microsoft Entra ID — eles recusam contas pessoais da Microsoft, e por isso o projeto de referência aprova por e-mail e pelo portal. A maioria das organizações de empresa usa Entra ID, então na prática isso raramente é um bloqueio, mas vale saber antes de prometer ao time.

Verificar cada deploy

“Deployed” no log do Runtime Manager significa que a plataforma aceitou a aplicação, não que ela responde corretamente. Cada deploy termina com um smoke test contra o endpoint de health da app:

url=$(yq -r '.healthUrl // ""' "deployment/${ANYPOINT_ENV}.yaml")
for attempt in $(seq 1 20); do
  body=$(curl -fsS -m 10 "$url" || true)
  status=$(echo "$body" | jq -r '.status // empty' 2>/dev/null || true)
  env=$(echo "$body" | jq -r '.environment // empty' 2>/dev/null || true)
  if [[ "$status" == "UP" && "$env" == "${ANYPOINT_ENV}" ]]; then
    echo "Healthy: $body"; exit 0
  fi
  sleep 15
done
exit 1

Verificar o ambiente informado, e não só o status, pega um erro silencioso: um deploy que “funcionou”, mas está usando a configuração do ambiente errado.

Como foi um release

O primeiro release da aplicação de referência, na linha do tempo do pipeline:

Stage Resultado
Build sucesso
Release sucesso — tag v1.0.0, main em 1.1.0-SNAPSHOT, dois commits [skip ci]
Deploy uat sucesso
Aprovação aprovado
Deploy prod sucesso

Chegar lá exigiu um hotfix — o filtro por caminho e o problema de push dos artigos anteriores —, e essa é a parte mais realista do exercício.

Checklist

  • Todos os ambientes recebem o mesmo artefato publicado?
  • O dimensionamento de cada ambiente está no repositório e é revisado em pull request?
  • As aprovações estão configuradas no environment, de modo que nenhum pipeline consiga pulá-las?
  • Cada deploy prova que a aplicação responde, a partir do ambiente certo?