Entrega contínua no estilo GitOps com o Cloud Build

Nesta página, você aprenderá como criar um pipeline de integração e entrega contínuas (CI/CD, na sigla em inglês) no Google Cloud Platform usando apenas produtos hospedados e a famosa metodologia GitOps.

Há muito tempo que os engenheiros do Google armazenam arquivos de configuração e implantação em nosso repositório de código-fonte principal. Essa metodologia está descrita no capítulo 8 do livro Engenharia de Confiabilidade do Site (Beyer et. al., 2016) e foi demonstrada por Kelsey Hightower durante a apresentação feita no Google Cloud Next de 2017 (páginas em inglês). O termo “GitOps” foi cunhado pela Weaveworks. Uma parte fundamental do GitOps é a ideia de “ambientes como código”: descrever as implementações de maneira declarativa, usando arquivos, como manifestos do Kubernetes, armazenados em um repositório Git.

Neste tutorial, você criará um pipeline de CI/CD que automaticamente construirá uma imagem de contêiner a partir do código confirmado, armazenará a imagem no Container Registry, atualizará um manifesto do Kubernetes em um repositório Git e implantará o aplicativo no Google Kubernetes Engine usando esse manifesto.

Arquitetura do pipeline de CI/CD

Neste tutorial, usaremos dois repositórios Git:

  • Repositório do aplicativo: contém o código-fonte do próprio aplicativo.
  • Repositório do ambiente: contém os manifestos para a implantação no Kubernetes.

Quando você envia uma alteração para o repositório do aplicativo, o pipeline do Cloud Build executa testes, cria uma imagem de contêiner e a envia para o Container Registry. Depois de enviar a imagem, o Cloud Build atualiza o manifesto de implantação e o envia para o repositório do ambiente. Isso aciona outro pipeline do Cloud Build que aplica o manifesto ao cluster do GKE e, se bem-sucedido, armazena o manifesto em outro branch do repositório do ambiente.

Mantemos os repositórios do aplicativo e do ambiente separados porque eles têm utilidades e ciclos de vida diferentes. O repositório do aplicativo é dedicado a um aplicativo específico e é usado principalmente por pessoas reais. Por outro lado, os principais usuários do repositório do ambiente são sistemas automatizados, como o Cloud Build, e ele pode ser compartilhado por vários aplicativos. O repositório do ambiente pode ter vários branches, cada um mapeando para um ambiente específico (você usará apenas o de produção neste tutorial). Ele referencia uma imagem de contêiner específica, o que não acontece com o repositório do aplicativo.

Ao terminar este tutorial, você terá um sistema em que facilmente poderá:

  • distinguir entre implantações com falha e bem-sucedidas observando o histórico do Cloud Build;
  • acessar o manifesto usado atualmente observando o branch de produção do repositório do ambiente;
  • reverter para qualquer versão anterior bastando executar novamente a versão correspondente do Cloud Build.

Fluxo do pipeline de CI/CD

Sobre este tutorial

Neste tutorial, usamos o Cloud Source Repositories para hospedar repositórios Git. No entanto, é possível chegar aos mesmos resultados com produtos de terceiros, como GitHub, Bitbucket ou GitLab.

Este pipeline não implementa um mecanismo de validação antes da implantação. Se você usa o GitHub, o Bitbucket ou o GitLab, é possível modificar o pipeline para usar uma solicitação pull com essa finalidade.

Recomendamos o Spinnaker para as equipes que querem implementar padrões avançados de implantação (azul/verde, análise canário, várias nuvens etc.). No entanto, o conjunto de recursos dessa solução talvez não seja necessário para que organizações e projetos menores tenham uma estratégia de CI/CD bem-sucedida. Neste tutorial, você aprenderá como criar um ajuste de pipeline de CI/CD para aplicativos hospedados no GKE com ferramentas simples.

Para simplificar, este tutorial usa um único ambiente, o de produção, no repositório do ambiente, mas é possível estendê-lo à implantação em vários ambientes, se necessário.

Custos

Antes de começar

  1. Selecione ou crie um projeto do GCP.

    ACESSAR A PÁGINA "GERENCIAR RECURSOS"

  2. Ative o faturamento do projeto.

    ATIVAR FATURAMENTO

  3. Abra o Cloud Shell para executar os comandos listados neste tutorial.

    ACESSAR O CLOUD SHELL

  4. Se o comando gcloud config get-value project não retornar o código do projeto que você acabou de selecionar, configure o Cloud Shell para usar seu projeto.

    gcloud config set project [PROJECT_ID]
    
  5. No Cloud Shell, ative as APIs necessárias.

    gcloud services enable container.googleapis.com \
        cloudbuild.googleapis.com \
        sourcerepo.googleapis.com \
        containeranalysis.googleapis.com
    
  6. No Cloud Shell, crie um cluster do GKE que você usará para implantar o aplicativo de amostra deste tutorial.

    gcloud container clusters create hello-cloudbuild \
        --num-nodes 1 --zone us-central1-b
    
  7. Se você nunca usou o Git no Cloud Shell, configure-o com seu nome e endereço de e-mail. O Git usará essas informações para identificar você como autor das confirmações a serem criadas no Cloud Shell.

    git config --global user.email "[YOUR_EMAIL_ADDRESS]"
    git config --global user.name "[YOUR_NAME]"
    

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Veja mais detalhes em Como fazer a limpeza.

Criar repositórios Git no Cloud Source Repositories

Nesta seção, você criará os dois repositórios Git, do aplicativo e do ambiente, que serão usados neste tutorial e inicializará o repositório do aplicativo com um código de amostra.

  1. No Cloud Shell, crie os dois repositórios Git.

    gcloud source repos create hello-cloudbuild-app
    gcloud source repos create hello-cloudbuild-env
    
  2. Clone o código de amostra do GitHub.

    cd ~
    git clone https://github.com/GoogleCloudPlatform/gke-gitops-tutorial-cloudbuild \
        hello-cloudbuild-app
    
  3. Configure o Cloud Source Repositories como remoto.

    cd ~/hello-cloudbuild-app
    PROJECT_ID=$(gcloud config get-value project)
    git remote add google \
        "https://source.developers.google.com/p/${PROJECT_ID}/r/hello-cloudbuild-app"
    

O código que você clonou contém um aplicativo simples "Hello World".

from flask import Flask
app = Flask('hello-cloudbuild')

@app.route('/')
def hello():
  return "Hello World!\n"

if __name__ == '__main__':
  app.run(host = '0.0.0.0', port = 8080)

Criar uma imagem de contêiner com o Cloud Build

O código que você clonou já contém o Dockerfile a seguir.

FROM python:3.7-slim
RUN pip install flask
WORKDIR /app
COPY app.py /app/app.py
ENTRYPOINT ["python"]
CMD ["/app/app.py"]

Com esse Dockerfile, crie uma imagem de contêiner com o Cloud Build e armazene-a no Container Registry.

  1. No Cloud Shell, crie uma versão do Cloud Build com base na confirmação mais recente usando o comando abaixo.

    cd ~/hello-cloudbuild-app
    COMMIT_ID="$(git rev-parse --short=7 HEAD)"
    gcloud builds submit --tag="gcr.io/${PROJECT_ID}/hello-cloudbuild:${COMMIT_ID}" .
    

    O Cloud Build faz o streaming dos registros gerados pela criação da imagem do contêiner para seu terminal quando você executa esse comando.

  2. Depois de concluir a versão, verifique se a nova imagem do contêiner está realmente disponível no Container Registry.

    ACESSAR O CONTAINER REGISTRY

    Imagem de hello-cloudbuild no Container Registry

Criar o pipeline de integração contínua

Nesta seção, você configurará o Cloud Build para executar automaticamente um teste de unidade pequeno, construirá a imagem do contêiner e, por fim, enviará essa imagem para o Container Registry. Enviar uma confirmação nova para o Cloud Source Repositories aciona automaticamente o pipeline. O arquivo cloudbuild.yaml, já incluso no código, é a configuração do pipeline.

steps:
# This step runs the unit tests on the app
- name: 'python:3.7-slim'
  id: Test
  entrypoint: /bin/sh
  args:
  - -c
  - 'pip install flask && python test_app.py -v'

# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'
  id: Build
  args:
  - 'build'
  - '-t'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  - '.'

# This step pushes the image to Container Registry
# The PROJECT_ID and SHORT_SHA variables are automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/docker'
  id: Push
  args:
  - 'push'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  1. Abra a página Acionadores do Cloud Build.

    ACESSAR “ACIONADORES”

  2. Clique em Criar acionador.

  3. Selecione “Cloud Source Repositories” como origem e clique em Continuar.

  4. Selecione o repositório hello-cloudbuild-app e clique em Continuar.

  5. Na tela “Configurações dos acionadores”, insira os seguintes parâmetros:

    • Nome: hello-cloudbuild
    • Branch (regex): master
    • Configuração da versão: cloudbuild.yaml
  6. Clique em Criar acionador.

    Dica: se você precisar criar acionadores de versão para vários projetos, use a API Build Triggers.

  7. No Cloud Shell, envie o código do aplicativo para o Cloud Source Repositories para acionar o pipeline de CI no Cloud Build.

    cd ~/hello-cloudbuild-app
    git push google master
    
  8. Abra o console do Cloud Build.

    ACESSAR O CLOUD BUILD

    Você verá uma versão em execução ou finalizada recentemente. Se quiser, clique na versão para acompanhar a execução e examinar os registros.

Criar o pipeline de entrega contínua

O Cloud Build também é usado para o pipeline de entrega contínua. Esse pipeline é executado sempre que uma confirmação é enviada para o branch candidato do repositório hello-cloudbuild-env. O pipeline aplica a versão nova do manifesto ao cluster do Kubernetes e, se bem-sucedido, copia o manifesto para o branch de produção. Esse processo tem as seguintes propriedades:

  • O branch candidato é um histórico das tentativas de implantação.
  • O branch de produção é um histórico das implantações bem-sucedidas.
  • É possível ver as implantações bem-sucedidas e com falha no Cloud Build.
  • É possível reverter para qualquer implantação anterior, bastando executar novamente a versão correspondente no Cloud Build. A reversão também atualiza o branch de produção para refletir fielmente o histórico de implantações.

Você modificará o pipeline de integração contínua para atualizar o branch candidato do repositório hello-cloudbuild-env, acionando o pipeline de entrega contínua.

Conceder ao Cloud Build acesso ao GKE

Para implantar o aplicativo no cluster do Kubernetes, o Cloud Build precisa do papel do IAM de Desenvolvedor do Kubernetes Engine.

Shell

No Cloud Shell, execute o comando a seguir:

PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} --format='get(projectNumber)')"
gcloud projects add-iam-policy-binding ${PROJECT_NUMBER} \
    --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
    --role=roles/container.developer

Console

  1. No Console do Google Cloud Platform, abra a página "Configurações do Cloud Build":

    Abrir a página "Configurações do Cloud Build"

    Você verá a página Permissões da conta do Service:

    Captura de tela da página de permissões da conta de Service

  2. Defina o status do papel Desenvolvedor do Kubernetes Engine como Ativado.

Inicializar o repositório hello-cloudbuild-env

É necessário inicializar o repositório hello-cloudbuild-env com dois branches, de produção e candidato, e um arquivo de configuração do Cloud Build que descreve o processo de implantação.

  1. No Cloud Shell, clone o repositório hello-cloudbuild-env e crie o branch de produção. Ele ainda estará vazio.

    cd ~
    gcloud source repos clone hello-cloudbuild-env
    cd ~/hello-cloudbuild-env
    git checkout -b production
    
  2. Copie o arquivo cloudbuild-delivery.yaml disponível no repositório hello-cloudbuild-app e confirme a alteração.

    cd ~/hello-cloudbuild-env
    cp ~/hello-cloudbuild-app/cloudbuild-delivery.yaml ~/hello-cloudbuild-env/cloudbuild.yaml
    git add .
    git commit -m "Create cloudbuild.yaml for deployment"
    

    O arquivo cloudbuild-delivery.yaml descreve o processo de implantação a ser executado no Cloud Build. Isso é feito em duas etapas:

    1. O Cloud Build aplica o manifesto no cluster do GKE.

    2. Se bem-sucedido, o Cloud Build copia o manifesto no branch de produção.

    steps:
    # This step deploys the new version of our container image
    # in the hello-cloudbuild Kubernetes Engine cluster.
    - name: 'gcr.io/cloud-builders/kubectl'
      id: Deploy
      args:
      - 'apply'
      - '-f'
      - 'kubernetes.yaml'
      env:
      - 'CLOUDSDK_COMPUTE_ZONE=us-central1-b'
      - 'CLOUDSDK_CONTAINER_CLUSTER=hello-cloudbuild'
    
    # This step copies the applied manifest to the production branch
    # The COMMIT_SHA variable is automatically
    # replaced by Cloud Build.
    - name: 'gcr.io/cloud-builders/git'
      id: Copy to production branch
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        # Configure Git to create commits with Cloud Build's service account
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)') && \
        # Switch to the production branch and copy the kubernetes.yaml file from the candidate branch
        git fetch origin production && git checkout production && \
        git checkout $COMMIT_SHA kubernetes.yaml && \
        # Commit the kubernetes.yaml file with a descriptive commit message
        git commit -m "Manifest from commit $COMMIT_SHA
        $(git log --format=%B -n 1 $COMMIT_SHA)" && \
        # Push the changes back to Cloud Source Repository
        git push origin production

  3. Crie um branch candidato e envie os dois branches para que fiquem disponíveis no Cloud Source Repositories.

    git checkout -b candidate
    git push origin production
    git push origin candidate
    
  4. Conceda o papel de IAM de Gravador do repositório de origem à conta de serviço do Cloud Build para o repositório hello-cloudbuild-env.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    cat >/tmp/hello-cloudbuild-env-policy.yaml <<EOF
    bindings:
    - members:
      - serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com
      role: roles/source.writer
    EOF
    gcloud source repos set-iam-policy \
        hello-cloudbuild-env /tmp/hello-cloudbuild-env-policy.yaml
    

Criar o acionador do pipeline de entrega contínua

Nesta seção, você configurará o Cloud Build para que seja acionado por um envio no branch candidato do repositório hello-cloudbuild-env.

  1. Abra a página Acionadores do Cloud Build.

    ACESSAR “ACIONADORES”

  2. Clique em Adicionar acionador.

  3. Selecione “Cloud Source Repositories” como origem e clique em Continuar.

  4. Selecione o repositório hello-cloudbuild-env e clique em Continuar.

  5. Na tela “Configurações dos acionadores”, insira os seguintes parâmetros:

    • Nome: hello-cloudbuild-deploy
    • Branch (regex): candidate
    • Configuração da versão: cloudbuild.yaml
  6. Clique em Criar acionador.

Modificar o pipeline de integração contínua para acionar o pipeline de entrega contínua

Nesta seção, você adicionará algumas etapas ao pipeline de integração contínua que gerará uma nova versão do manifesto do Kubernetes e, depois, enviará esse manifesto para o repositório hello-cloudbuild-env para acionar o pipeline de entrega contínua.

  1. Copie a versão estendida do arquivo cloudbuild.yaml para o repositório do aplicativo.

    cd ~/hello-cloudbuild-app
    cp cloudbuild-trigger-cd.yaml cloudbuild.yaml
    

    O arquivo cloudbuild-trigger-cd.yaml é uma versão estendida de cloudbuild.yaml. Com ele, é feita a adição das etapas abaixo para que seja gerado o novo manifesto do Kubernetes e seja acionado o pipeline de entrega contínua.

    # This step clones the hello-cloudbuild-env repository
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Clone env repository
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        gcloud source repos clone hello-cloudbuild-env && \
        cd hello-cloudbuild-env && \
        git checkout candidate && \
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)')
    
    # This step generates the new manifest
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Generate manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
         sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" kubernetes.yaml.tpl | \
         sed "s/COMMIT_SHA/${SHORT_SHA}/g" > hello-cloudbuild-env/kubernetes.yaml
    
    # This step pushes the manifest back to hello-cloudbuild-env
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Push manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        cd hello-cloudbuild-env && \
        git add kubernetes.yaml && \
        git commit -m "Deploying image gcr.io/${PROJECT_ID}/hello-cloudbuild:${SHORT_SHA}
        Built from commit ${COMMIT_SHA} of repository hello-cloudbuild-app
        Author: $(git log --format='%an <%ae>' -n 1 HEAD)" && \
        git push origin candidate
    

  2. Confirme as modificações e envie-as para o Cloud Source Repositories.

    cd ~/hello-cloudbuild-app
    git add cloudbuild.yaml
    git commit -m "Trigger CD pipeline"
    git push google master
    

    Isso aciona o pipeline de integração contínua no Cloud Build.

  3. Examine a versão de integração contínua.

    ACESSAR O CLOUD BUILD

    Você verá uma versão do repositório hello-cloudbuild-app em execução ou finalizada recentemente. Se quiser, clique na versão para acompanhar a execução e examinar os registros. A última etapa desse pipeline envia o manifesto novo para o repositório hello-cloudbuild-env, que aciona o pipeline de entrega contínua.

  4. Examine a versão de entrega contínua.

    ACESSAR O CLOUD BUILD

    Você verá uma versão do repositório hello-cloudbuild-env em execução ou finalizada recentemente. Se quiser, clique na versão para acompanhar a execução e examinar os registros.

Testar o pipeline completo

O pipeline de CI/CD completo agora está configurado. Nesta seção, você testará o pipeline inteiro.

  1. Acesse a página “Serviços” do GKE.

    ACESSAR A PÁGINA “SERVIÇOS” DO GOOGLE KUBERNETES ENGINE

    Provavelmente, haverá um único serviço chamado hello-cloudbuild na lista. Ele foi criado pela versão de entrega contínua recém-executada.

  2. Clique no endpoint do serviço hello-cloudbuild. Você verá “Hello World!”. Se não houver um endpoint ou ocorrer um erro no balanceador de carga, talvez seja necessário aguardar alguns minutos até que o balanceador de carga seja totalmente inicializado. Clique em Atualizar para atualizar a página, se necessário.

  3. No Cloud Shell, substitua “Hello World” por “Hello Cloud Build” no aplicativo e no teste de unidade.

    cd ~/hello-cloudbuild-app
    sed -i 's/Hello World/Hello Cloud Build/g' app.py
    sed -i 's/Hello World/Hello Cloud Build/g' test_app.py
    
  4. Confirme e envie a alteração para o Cloud Source Repositories.

    git add app.py test_app.py
    git commit -m "Hello Cloud Build"
    git push google master
    

    Isso aciona o pipeline de CI/CD inteiro.

  5. Após alguns minutos, atualize o aplicativo no seu navegador. Agora você verá “Hello Cloud Build!”.

Testar a reversão

Nesta seção, você reverterá para a versão do aplicativo que dizia “Hello World!”.

  1. Abra o console do Cloud Build no repositório hello-cloudbuild-env.

    ACESSAR O CLOUD BUILD

  2. Clique na segunda versão mais recente disponível.

  3. Clique em Recriar.

  4. Quando a versão estiver concluída, atualize o aplicativo no seu navegador. Você verá “Hello World!” novamente.

Como fazer a limpeza

Para evitar que os recursos usados neste tutorial sejam cobrados na conta do Google Cloud Platform:

  1. No Console do GCP, acesse a página Projetos.

    Acessar a página Projetos

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir delete.
  3. Na caixa de diálogo, digite o código do projeto e clique em Encerrar para excluí-lo.

Excluir os recursos

Se você quiser manter o projeto do GCP usado neste tutorial, exclua os recursos individuais:

  1. Exclua os repositórios Git locais.

    cd ~
    rm -rf ~/hello-cloudbuild-app
    rm -rf ~/hello-cloudbuild-env
    
  2. Exclua os repositórios Git no Cloud Source Repositories.

    gcloud source repos delete hello-cloudbuild-app --quiet
    gcloud source repos delete hello-cloudbuild-env --quiet
    
  3. Exclua os acionadores do Cloud Build.

    1. Abra a página Acionadores do Cloud Build.

      ACESSAR “ACIONADORES”

    2. Clique nos três pontos verticais à direita de cada acionador e em Excluir.

  4. Exclua as imagens no Container Registry.

    gcloud beta container images list-tags \
        gcr.io/${PROJECT_ID}/hello-cloudbuild \
        --format="value(tags)" | \
        xargs -I {} gcloud beta container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT_ID}/hello-cloudbuild:{}
    
  5. Remova a permissão concedida ao Cloud Build para se conectar ao GKE.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    gcloud projects remove-iam-policy-binding ${PROJECT_NUMBER} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    
  6. Exclua o cluster do GKE.

    gcloud container clusters delete hello-cloudbuild \
        --zone us-central1-b
    

A seguir

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Tutoriais do Kubernetes Engine