Um dos recursos mais populares do Heroku é a solução de Review Apps. Ela cria um ambiente descartável e uma instância da aplicação durante um pull request (PR) e, depois que o PR é mesclado, derruba esse ambiente temporário.
Inspirado nesse conceito e em uma reunião recente com um cliente da DoiT International, resolvi recriar esse comportamento no Google Cloud Platform (GCP) com uma abordagem nativa da nuvem e ferramentas open source bem conhecidas.
Experiência do desenvolvedor (demo de 20 minutos)
Seguindo os princípios do GitOps, o time de desenvolvimento só precisa se preocupar em escrever código: ao abrir um PR, em poucos segundos ou minutos uma versão pronta para revisão do código mais recente já fica acessível online.
Os commits seguintes vão atualizando o review app até que revisores e testadores estejam satisfeitos e aprovem ou mesclem o PR. Assim que o app sobe para um ambiente superior, o review app é derrubado — e o ciclo se repete a cada nova feature.
Demo de review app no estilo Heroku e pipeline de CI/CD com GitOps (20 minutos)
Componentes envolvidos
- Github — controle de versão
- Kustomize — gerenciamento de configuração nativo do Kubernetes
- Argo CD — CD declarativo com GitOps para Kubernetes
- Kong Ingress Controller — API gateway
- Google Kubernetes Engine (GKE) — Kubernetes gerenciado
- Google Cloud Build — servidor de CI
- Google Container Registry (GCR) — registro privado de imagens de container
- Google Secret Manager — gestão centralizada de secrets
- Google Cloud DNS — serviço de DNS com API ( opcional)
Arquitetura
A funcionalidade central dos review apps é a seguinte: quando um desenvolvedor abre um pull request (PR) no controle de versão, o pipeline de deploy compila uma cópia do app e a hospeda em um ambiente isolado, com uma URL única para que outras pessoas possam revisar.

O PR do desenvolvedor cria o Review App
Como funcionalidade adicional, ao mesclar o PR a aplicação é promovida para produção e o review app é removido.

O merge feito por revisor ou admin promove e exclui o Review App
TL;DR
Para que tudo funcione como mostrado, é preciso seguir estes passos:
- Criar repositórios separados de App e Config no Github
- Habilitar as APIs do Google e fazer o bootstrap do cluster GKE e do Argo CD
- Instalar o Kong API Gateway (ingress controller) via repositório Config
- Criar um registro DNS A apontando para o IP externo do kong-proxy
- Conectar o Cloud Build ao seu repositório no Github
- Criar uma chave privada e armazená-la no Google Secret Manager
- Adicionar a chave pública ao repositório Config no Github
- Criar 3 triggers no Cloud Build ( push, PR, merge)
- Autorizar a service account do Cloud Build a acessar os Secrets
- Adicionar os arquivos de configuração do Cloud Build ao repositório App
- Adicionar os manifests do Kubernetes e os overlays do Kustomize ao repositório Config
Criar os repositórios de origem no Github
Os repositórios a seguir são exemplos funcionais, mas vou explicar nas próximas seções como construí-los passo a passo.
- Demo App — Dockerfile e scripts de CI do Cloud Build
- Demo App Config — scripts de configuração e manifests do Kubernetes para o Argo CD
Habilitar APIs e fazer o bootstrap do GKE e do Argo CD
No script abaixo, habilitei as APIs de serviço do Google Cloud e subi um cluster Kubernetes.
Em um artigo anterior, apresentei o conceito do app of apps pattern, usado inclusive pelo time de desenvolvimento do Argo na Intuit. Na hora de desenhar essa solução, a criação e remoção dinâmicas de uma " Application" se encaixa perfeitamente no nosso caso de uso de criar e destruir review apps.
Instalar o Kong API Gateway (ingress controller)
Para o Kong, basta adicionar um arquivo kong.yaml na pasta /apps do repositório Config. O Argo CD detecta e monitora qualquer repositório ou pasta que você indicar. Escolhi o Kong porque cada Ingress que eu criar configura um host, o que é ideal para gerar URLs novas de review app de forma dinâmica.
Adicione os arquivos de configuração do Kong nessa pasta e ele será instalado no seu cluster Kubernetes (repita o processo para os apps que quiser).
Repare no source.path (kong). É a pasta no repositório que vai conter os manifests YAML que o Argo CD irá instalar. Criei no repositório um arquivo chamado 01-install.yaml, usando o próprio manifest único do Kong na pasta /kong do repositório Config. ( https://bit.ly/k4k8s aponta para a configuração mais recente do Kong )
curl https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-dbless.yaml --output kong/01-install.yaml
Criar um registro DNS A para o Kong Proxy
Depois de instalado no cluster, o Kong cria um load balancer TCP externo (Service) com um IP externo.

Service de load balancer do Kong Proxy no cluster Kubernetes
Você precisa apontar seu domínio para esse IP, e isso pode ser feito manualmente no seu provedor. Na minha demo inicial, configurei só o registro A e alguns aliases CNAME, como abaixo.

Entradas de DNS configuradas manualmente
Outra abordagem é usar o Google Cloud DNS para gerenciar o domínio. Eu precisaria apontar para os nameservers do Google e, com isso, conseguiria criar URLs de review app dinamicamente com base no número do PR (ideal). Depois do bootstrap do GKE e do Kong, dá para usar os comandos a seguir para configurar isso.
Conectar o Cloud Build ao Github
Normalmente, detesto artigos que ficam jogando o leitor para outros artigos, mas, para encurtar, siga estes dois passos para conectar o Cloud Build ao Github e adicionar uma chave SSH ao Secret Manager. Eles estão bem descritos nestes dois artigos do Google:
- Conectar o Cloud Build ao Github
- Adicionar chave e secret para acessar repositórios privados — atenção: você precisa marcar a opção "commit" no repositório Config para que o pipeline de build do App consiga depois fazer commit das alterações na tag de versão da imagem Docker.
Criar 3 triggers no Cloud Build
Para reproduzir o comportamento desejado, tecnicamente bastaria criar os triggers de PR e de merge com seus respectivos arquivos de configuração. Mas, normalmente, você também vai querer builds e deploys para os desenvolvedores, então incluí um terceiro trigger de push para a branch develop.

Triggers do Cloud Build
Repare nos configs abaixo que adicionei variáveis de ambiente definidas pelo usuário (no fim de cada página). Elas permitem que os arquivos de configuração referenciem o nome do app e, se quiser, incluam etapas condicionais conforme o estágio.
Por simplicidade, criei 3 triggers e 3 arquivos de configuração separados (próxima seção), mas dá para consolidar tudo usando esses recursos.

Build e deploy da imagem Docker da branch develop a cada push

Pull request de outra branch para master (prod)

Merge do PR na branch master (prod)
Adicionar os arquivos de configuração do Cloud Build ao repositório App
A primeira parte dos arquivos de configuração de build é bem simples: ela apenas constrói uma imagem Docker e a envia para o Google Container Registry (GCR). Já as etapas seguintes usam o secret do Secret Manager para clonar o repositório de configuração, alterar arquivos e fazer push de um commit. Isso aciona o Argo CD para sincronizar as últimas mudanças e atualizar os apps no seu cluster GKE.
Repare que, neste arquivo, o sed -i ... é o que atualiza a tag da imagem para a do último build enviado ao GCR.
Repare também que, no estágio de PR, usamos v$_PR_NUMBER para taguear as imagens, de modo que possam ser atualizadas em commits subsequentes durante a revisão do PR (talvez eu mude isso em algum momento). Outro detalhe interessante é que copiamos o /templates/demo-app-review.yaml para a pasta /apps, para que o Argo CD passe a monitorar esse caminho.
O ponto único aqui é o "Removing review app…", em que executamos rm apps/demo-app-review.yaml. Como ativamos o autoSync e o prune na configuração da nossa Application, o ArgoCD detecta isso e remove o review app do cluster GKE.
Adicionar manifests do Kubernetes e overlays do Kustomize
Daria (e deveria render) um post inteiro só sobre o Kustomize e como ele viabiliza o gerenciamento de configuração nativo do Kubernetes. Tradicionalmente, você empacota os apps com Helm charts ou ferramentas "sonnet" usando código, mas prefiro manter tudo simples e extensível com o Kustomize.
O repositório Config está organizado da seguinte forma: cada app, no nosso caso /demo-app/base, contém seus manifests e um arquivo kustomization.yaml.
- namespace.yaml — namespace customizado
- ingress.yaml — configuração de Ingress que o Kong detecta e adiciona como rota
- service.yaml — "wrapper" de rede para os pods de backend
- deployment.yaml — sua aplicação propriamente dita (apontando para a imagem)
- kustomization.yaml — configuração do Kustomize
Em seguida, adicionamos overlays para representar nossos ambientes. Essas configurações substituem ou aplicam patches nos arquivos YAML com valores específicos do ambiente, como sufixo do nome do app, namespace e nome do host do Ingress (para permitir URLs dinâmicas dos review apps).
/overlays/develop— configurações do ambiente develop/overlays/review— configurações do ambiente de review apps/overlays/production— configurações do ambiente de produção
Você pode conferir tudo isso no repositório de configuração de exemplo no Github, mas abaixo segue um exemplo de configuração de overlay e arquivo de patch para criar URLs específicas por ambiente no Ingress.
Repare que a propriedade patchesStrategicMerge aponta para um arquivo. O Kustomize mescla o conteúdo desse arquivo (ou arquivos) para sobrescrever valores customizados, como o nome do host do Ingress abaixo, viabilizando URLs personalizadas por ambiente.
URLs dinâmicas opcionais para cada PR
Na demo inicial, usei sempre a mesma URL, mas, se você estiver usando o Cloud DNS, basta acrescentar mais uma etapa ao seu arquivo cloudbuild-pr.yaml, como abaixo, para tornar as URLs dinâmicas. Até o momento em que escrevo isto, ainda não testei, mas pretendo atualizar meus nameservers e testar também.
Você também precisaria adicionar outro comando sed -i ... no script de configuração para substituir dinamicamente o arquivo de patch ingress-host.yaml a cada deploy de PR.
Venha fazer parte do meu time
Junte-se à DoiT International e faça suas próprias descobertas incríveis como esta. Acesse nossa página de carreiras:
- https://careers.doit-intl.com (vagas remotas em fusos horários próximos)
Apesar de o post ser bem extenso, o processo no geral não é tão complicado. Aproveitando os repositórios de exemplo que compartilhei, você também pode dar aos seus engenheiros mais liberdade para se preocuparem menos com infraestrutura e focarem no que fazem de melhor.

Pipeline de CI/CD funcionando com GitOps e Review Apps no estilo Heroku durante o PR