Neste tutorial, mostraremos como configurar um pipeline de entrega contínua usando Jenkins e Google Kubernetes Engine (GKE), conforme descrito no diagrama a seguir.
Objetivos
- Compreender um aplicativo simples.
- Implantar um aplicativo no GKE.
- Fazer upload de código para o Cloud Source Repositories.
- Criar pipelines de implantação no Jenkins.
- Implantar ambientes de desenvolvimento.
- Implantar uma versão canário.
- Implantar ambientes de produção.
Custos
Neste tutorial, há componentes faturáveis do Google Cloud, entre eles:
- Compute Engine
- Google Kubernetes Engine
- Cloud Source Repositories
- Cloud Build
Use a calculadora de preços para gerar uma estimativa de custo baseada na projeção de uso deste tutorial.
Antes de começar
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, GKE, and Cloud Build APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, GKE, and Cloud Build APIs.
Como preparar o ambiente
Conclua o tutorial Como configurar o Jenkins no GKE. Certifique-se de que você tem uma instalação do Jenkins em execução no GKE.
No Cloud Shell, clone o código de amostra:
cd ~/ git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes
Acesse o diretório do app de exemplo:
cd ~/continuous-deployment-on-kubernetes/sample-app
Aplique o papel
cluster-admin
à conta de serviço do Jenkins:kubectl create clusterrolebinding jenkins-deploy \ --clusterrole=cluster-admin --serviceaccount=default:cd-jenkins
Neste tutorial, a conta de serviço do Jenkins precisa das permissões de
cluster-admin
para criar namespaces do Kubernetes e outros recursos necessários ao aplicativo. Para uso em produção, catalogue as permissões individuais necessárias e aplique-as à conta de serviço individualmente.
Entender o aplicativo
Você implementará o aplicativo de amostra gceme
no pipeline de implantação contínua. O aplicativo, escrito na linguagem Go, está no diretório sample-app
do repositório. Quando você executa o binário gceme
em uma instância do Compute Engine, o aplicativo exibe os metadados da instância em um card de informações.
O aplicativo simula um microsserviço aceitando dois modos de operação:
No modo de back-end, o
gceme
detecta a atividade na porta 8080 e retorna metadados da instância do Compute Engine no formato JSON.No modo de front-end, o
gceme
consulta o serviçogceme
de back-end e renderiza o JSON resultante na interface do usuário.
Os modos de front-end e back-end aceitam dois URLs adicionais:
/version
imprime a versão em execução./healthz
informa a integridade do aplicativo. No modo de front-end, a integridade será exibida comoOK
se o back-end for alcançável.
Como criar o app de exemplo
Execute os seguintes comandos para criar o app de amostra:
export PROJECT_ID=$(gcloud info --format='value(config.project)') find . -type f -name "*" -exec sed -i 's|gcr.io/cloud-solutions-images/gceme:1.0.0|gcr.io/'"${PROJECT_ID}"'/gceme:1.0.0|g' {} + gcloud builds submit --tag gcr.io/${PROJECT_ID}/gceme:1.0.0
Como implantar o aplicativo de amostra no Kubernetes
Implante o front-end e o back-end do gceme
no Kubernetes usando arquivos de manifesto que descrevem o ambiente de implantação. Os arquivos usam uma imagem padrão que é atualizada posteriormente neste tutorial.
Implante os aplicativos em dois ambientes.
Produção. O site ativo que os usuários acessam.
Canário. Um site de capacidade menor que recebe uma porcentagem do tráfego do usuário. Use esse ambiente para verificar a integridade do software com tráfego em tempo real antes de lançá-lo no ambiente de produção.
Primeiro, implante o aplicativo no ambiente de produção para enviar o código de trabalho ao pipeline.
Crie o namespace do Kubernetes para isolar logicamente a implantação da produção:
kubectl create ns production
Crie as implantações e serviços canário e de produção:
kubectl --namespace=production apply -f k8s/production kubectl --namespace=production apply -f k8s/canary kubectl --namespace=production apply -f k8s/services
Escalone os front-ends do ambiente de produção:
kubectl --namespace=production scale deployment gceme-frontend-production --replicas=4
Consulte o endereço IP externo dos serviços de produção: O endereço IP do balanceador de carga pode demorar alguns minutos para aparecer.
kubectl --namespace=production get service gceme-frontend
Quando o processo for concluído, o endereço IP externo será exibido na coluna
EXTERNAL-IP
.NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gceme-frontend LoadBalancer 10.35.254.91 35.196.48.78 80:31088/TCP 1m
Se o endereço IP externo não aparecer, aguarde alguns minutos e repita a etapa anterior até que o endereço IP externo seja exibido.
Depois que o endereço IP externo for exibido, armazene o endereço IP do balanceador de carga do serviço de front-end em uma variável de ambiente:
export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)
Para confirmar que os dois serviços estão funcionando, abra o endereço IP externo do front-end no navegador.
Pesquise o URL
/version
do endpoint de produção para observar as atualizações graduais na próxima seção:while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done
Pressione
Ctrl+C
para sair da repetição.
Crie um repositório para hospedar o código-fonte do aplicativo de amostra
Em seguida, crie uma cópia do aplicativo de amostra gceme
e envie-o por push para o Cloud Source Repositories.
Crie o repositório no Cloud Source Repositories:
gcloud services enable sourcerepo.googleapis.com gcloud source repos create gceme
Inicialize o repositório Git local:
rm -rf ../.git git config --global init.defaultBranch main git init git config credential.helper gcloud.sh export PROJECT_ID=$(gcloud config get-value project) git remote add origin https://source.developers.google.com/p/$PROJECT_ID/r/gceme
Defina o nome de usuário e o endereço de e-mail das confirmações do Git neste repositório para os valores da sua conta conectada:
git config --global user.email $(gcloud config list account --format "value(core.account)") git config --global user.name $(gcloud config list account --format "value(core.account)")
Adicione, confirme e envie os arquivos por push:
git add . git commit -m "Initial commit" git push origin main
Criar uma conta de serviço
Nesta seção, você cria uma conta de serviço que o Jenkins usará para acessar seu repositório Git e executar implantações no GKE.
Criar a conta de serviço e conceder papéis de origem e do GKE a ela.
export SA=jenkins-sa export SA_EMAIL=${SA}@${PROJECT_ID}.iam.gserviceaccount.com gcloud iam service-accounts create $SA gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SA_EMAIL \ --role roles/source.writer gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SA_EMAIL \ --role roles/container.developer
Crie e faça o download de uma chave de conta de serviço JSON para sua conta de serviço recém-criada:
gcloud iam service-accounts keys create ~/jenkins-gke-key.json --iam-account $SA_EMAIL
Anote onde o arquivo foi criado, porque você fará upload dele para o Jenkins em uma etapa posterior.
Para mais informações sobre como fazer o download de uma chave de conta de serviço, consulte Criar uma chave de conta de serviço.
Abrir a interface do usuário da Web do Jenkins
Configure o encaminhamento de portas se ainda não tiver feito isso para permitir o acesso à IU da Web do Jenkins:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-main" -l "app.kubernetes.io/instance=cd-jenkins" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward $POD_NAME 8080:8080 >> /dev/null 2>&1 &
Abra a interface do usuário do Jenkins, no Cloud Shell, clique em Visualização da Web e em Visualizar na porta 8080.
Configurar o Jenkins Cloud para o Kubernetes
- Na interface do usuário do Jenkins, selecione Gerenciar Jenkins > Gerenciar nós e nuvens.
- Clique em Configure Clouds (Configurar nuvens) no painel de navegação à esquerda.
- Clique em Add a new cloud (Adicionar uma nova nuvem) e selecione Kubernetes.
- Clique em Kubernetes Cloud Details.
- No campo URL do Jenkins, digite o seguinte valor:
http://cd-jenkins:8080
- No campo Jenkins tunnel, insira o seguinte valor:
cd-jenkins-agent:50000
- Clique em Save.
Como criar um pipeline
Use o Jenkins para definir e executar um pipeline para testar, criar e implantar a cópia do gceme
no cluster do Kubernetes.
Adicionar as credenciais da sua conta de serviço
Configure as credenciais para permitir que o Jenkins acesse o repositório do código.
- Na interface do usuário do Jenkins, selecione Manage Jenkins > Manage Credentials no painel de navegação à esquerda.
Clique no link (global).
Clique em Add Credentials, no menu de navegação à esquerda.
No menu Tipo, selecione Conta de serviço do Google da chave privada.
Insira o nome do projeto e selecione a chave JSON que foi criada em uma seção anterior.
Clique em Criar.
Anote o nome da credencial para uso posterior neste tutorial.
Criar um job Jenkins
Em seguida, use o recurso Jenkins Pipeline para configurar o pipeline de criação. Os arquivos do Jenkins Pipeline são escritos com uma sintaxe semelhante à do Groovy.
Navegue até a interface do usuário do Jenkins e siga estas etapas para configurar um job de pipeline.
- Clique no link Jenkins na parte superior esquerda da interface.
- Clique no link New Item na navegação à esquerda.
- Nomeie o projeto como sample-app, escolha a opção Multibranch Pipeline e clique em OK.
- Na seção Branch Sources, clique em Add Source e selecione git.
Cole o URL do clone HTTPS do repositório
sample-app
no Cloud Source Repositories no campo Repositório do projeto. Substitua[PROJECT_ID]
pelo ID do projeto.https://source.developers.google.com/p/[PROJECT_ID]/r/gceme
Na lista suspensa Credentials, selecione o nome das credenciais que você criou ao adicionar sua conta de serviço.
Na seção Scan Multibranch Pipeline, selecione a caixa Periodically if not otherwise run. Defina o valor de Interval para "1 minute".
Clique em Save.
Depois que você concluir essas etapas, um job denominado "Branch indexing" será executado.
Esse meta-job identifica os branches do repositório e garante que não ocorreram alterações nos branches existentes. Se você atualizar o Jenkins, o branch main
exibirá esse job.
A primeira execução do job falha até você fazer algumas alterações de código na próxima etapa.
Modificar a definição de pipeline
Crie um branch para o ambiente canário, denominado
canary
.git checkout -b canary
Atualize o
Jenkinsfile
para substituirREPLACE_WITH_YOUR_PROJECT_ID
na linha 2 pelo ID do projeto.sed -i 's|REPLACE_WITH_YOUR_PROJECT_ID|'"$PROJECT_ID"'|' Jenkinsfile
O contêiner Jenkinsfile que define esse pipeline é escrito com a sintaxe do Groovy para pipeline do Jenkins. O uso de um Jenkinsfile permite expressar todo um pipeline de criação em um único arquivo que subsiste com o código-fonte. Os canais aceitam recursos poderosos, como carregamento em paralelo e obrigatoriedade de aprovação manual do usuário.
Implantar uma versão canário
Agora que seu pipeline está configurado corretamente, é possível fazer uma alteração no aplicativo gceme
e deixar o pipeline testá-lo, empacotá-lo e implantá-lo.
O ambiente canário é configurado como uma versão canário.
Assim sendo, a alteração é lançada para uma pequena porcentagem desses pods que sustentam o balanceador de carga de produção. Isso é feito no Kubernetes com a manutenção de várias implantações que compartilham os mesmos rótulos. Para este aplicativo, os serviços gceme-frontend
fazem o balanceamento de carga em todos os pods com os rótulos app: gceme
e role: frontend
. O arquivo de manifesto canário k8s/frontend-canary.yaml
define as réplicas como 1
e inclui os rótulos necessários para o serviço gceme-frontend
.
Atualmente, um dos cinco pods de front-end executa o código canário, enquanto os outros quatro executam o código de produção. Isso ajuda a garantir que o código canário não prejudique os usuários antes de reverter para a frota completa de pods.
- Abra
html.go
e substitua as duas instâncias deblue
pororange
. Abra
main.go
e altere o número da versão de1.0.0
para2.0.0
:const version string = "2.0.0"
Em seguida, adicione e confirme esses arquivos no repositório local:
git add Jenkinsfile html.go main.go git commit -m "Version 2"
Por fim, envie as alterações por push ao servidor Git remoto:
git push origin canary
Após o push da alteração ao repositório Git, navegue até a interface do usuário do Jenkins, onde é possível ver que a compilação foi iniciada.
Depois que a versão estiver em execução, clique na seta para baixo ao lado dela na navegação à esquerda e selecione Console Output:
Durante a execução, você poderá notar o build esperando por um tempo com a seguinte mensagem:
Still waiting to schedule task ‘Jenkins’ doesn’t have label ‘sample-app’
Essa mensagem significa que o Jenkins está aguardando o GKE criar os pods necessários para as etapas do build. É possível acompanhar o progresso na página Cargas de trabalho do GKE.
Acompanhe a saída do build. Quando o build terminar, pesquise o endpoint em
/version
:while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done
A versão começa a mudar em algumas das solicitações. Agora você implantou essa alteração em um subconjunto de usuários.
Pressione
Ctrl+C
para sair da repetição.Depois que a alteração é implantada no ambiente canário, continue implantando no restante dos usuários, mesclando o código com o branch
main
e enviando-os por push ao servidor Git.git checkout main git merge canary git push origin main
Em aproximadamente 1 minuto, o job
main
na pastasample-app
é iniciado.Clique no link
main
para mostrar as etapas do pipeline, bem como informações de aprovação/reprovação e características de tempo.Pesquise o URL de produção para verificar se a nova versão 2.0.0 foi implantada e atende às solicitações de todos os usuários.
export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend) while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done
É possível observar o arquivo Jenkins no projeto para ver o fluxo de trabalho. O Jenkinsfile está localizado em https://source.cloud.google.com/[PROJECT_ID]/gceme/+/main:Jenkinsfile
.
Implantar um branch de desenvolvimento
Às vezes é preciso trabalhar com alterações não triviais que não podem ser enviadas por push diretamente ao ambiente canário. Um branch de desenvolvimento é um conjunto de ambientes que os desenvolvedores usam para testar as alterações de código antes de enviá-las para integração ao ambiente de produção. Esses ambientes são uma versão reduzida do aplicativo, mas são implantados usando os mesmos mecanismos que o ambiente de produção.
Se você quiser criar um ambiente para desenvolvedores em uma ramificação separada, precisará enviá-la por push ao servidor Git e deixar o Jenkins implantar o ambiente. Veja as etapas abaixo. Em um cenário de desenvolvimento, você não usaria um balanceador de carga voltado para o público. Para proteger o aplicativo, use o proxy kubectl. O proxy autentica-se na API Kubernetes e retransmite as solicitações da máquina local para o serviço no cluster sem expor o serviço à Internet.
Na primeira janela do terminal, crie outra ramificação e a envie para o servidor Git:
git checkout -b new-feature git push origin new-feature
Abra a IU da Web do Jenkins e revise o resultado do console no job
new-feature
. Um novo job é criado, e o ambiente de desenvolvimento é o processo de criação. Na parte inferior da saída do console do job, há instruções para acessar o ambiente.Após a conclusão do build, inicie o proxy em segundo plano:
kubectl proxy &
Verifique se o aplicativo pode ser acessado usando localhost.
curl http://localhost:8001/api/v1/namespaces/new-feature/services/gceme-frontend:80/proxy/
Agora é possível enviar o código por push a esse branch para atualizar o ambiente de desenvolvimento. Quando terminar, mescle o branch de volta ao
canary
para implantar esse código no ambiente canário.git checkout canary git merge new-feature git push origin canary
Quando você estiver seguro de que o código não causará problemas ao ambiente de produção, faça a mesclagem do branch
canary
com o branchmain
para iniciar a implantação:git checkout main git merge canary git push origin main
Quando terminar com o branch de desenvolvimento, exclua-o do servidor e exclua o ambiente do cluster do Kubernetes:
git push origin :new-feature kubectl delete ns new-feature
Limpar
Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.
Excluir o projeto
O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para o tutorial.
Para excluir o projeto:
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
A seguir
- Saiba mais sobre o Jenkins nas práticas recomendadas do GKE.
Confira arquiteturas de referência, diagramas e práticas recomendadas do Google Cloud. Confira o Centro de arquitetura do Cloud.