Pipeline de várias ramificações do Jenkins no GKE

1. Visão geral

O Jenkins é uma das soluções de integração contínua mais conhecidas. Ele é usado para automatizar as partes não humanas essenciais do processo de desenvolvimento de software. Ao implantar o Jenkins no Kubenetes no Google Cloud e usar o plug-in do GKE, podemos dimensionar de forma rápida e automática os executores de build conforme a necessidade. Em combinação com o Cloud Storage, podemos criar e testar um aplicativo com o mínimo de esforço.

O que você aprenderá

  • Implantar o Jenkins em um cluster do Kubernetes
  • Implante e configure o plug-in do GKE do Jenkins para permitir que o Jenkins crie e destrua pods como nós de execução
  • Criar e testar um aplicativo SpringBoot de exemplo
  • Criar e publicar um contêiner no Google Container Registry
  • Implantar o aplicativo de exemplo em um ambiente de testes e de produção do GKE

O que é necessário

  • Um projeto do Google Cloud com faturamento configurado. Se você não tiver uma, crie uma.

2. Etapas da configuração

Este codelab pode ser executado completamente no Google Cloud Platform sem nenhuma instalação ou configuração local.

Cloud Shell

Neste codelab, vamos provisionar e gerenciar diferentes recursos e serviços de nuvem usando a linha de comando pelo Cloud Shell.

Ativar as APIs

Estas são as APIs que precisamos ativar no projeto:

  • API Compute Engine: cria e executa máquinas virtuais.
  • API Kubernetes Engine: cria e gerencia aplicativos baseados em contêineres.
  • API Cloud Build: plataforma de integração e entrega contínua do Google Cloud
  • API Service Management: permite que os produtores de serviços publiquem serviços no Google Cloud Platform.
  • API Cloud Resource Manager: cria, lê e atualiza metadados para contêineres de recursos do Google Cloud.

Ative as APIs necessárias com o seguinte comando gcloud:

gcloud services enable compute.googleapis.com \
container.googleapis.com \
cloudbuild.googleapis.com \
servicemanagement.googleapis.com \
cloudresourcemanager.googleapis.com \
--project ${GOOGLE_CLOUD_PROJECT}

Crie um bucket do GCS

Vamos precisar de um bucket do GCS para fazer o upload do nosso trabalho de teste. Vamos criar um bucket usando o ID do projeto no nome para garantir a exclusividade:

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket/ 

3. Criação de clusters do Kubernetes

Criar o cluster

Em seguida, vamos criar um cluster do GKE que hospedará nosso sistema Jenkins, incluindo os pods que serão enviados como nós de trabalho. O escopo adicional indicado pela flag --scopes permite que o Jenkins acesse o Cloud Source Repositories e o Container Registry. No console do Cloud, execute o seguinte:

gcloud container clusters create jenkins-cd \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--scopes "https://www.googleapis.com/auth/source.read_write,cloud-platform" \
--cluster-version latest

Vamos implantar dois clusters para hospedar os builds de preparação e produção do nosso aplicativo de exemplo:

gcloud container clusters create staging \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--cluster-version latest
gcloud container clusters create prod \
--machine-type n1-standard-2 --num-nodes 2 \
--zone us-east1-d \
--cluster-version latest

28b45298e1e82748.png Verificar

Depois que os clusters forem criados, podemos confirmar que eles estão em execução com gcloud container clusters list

A saída precisa ter RUNNING na coluna STATUS:

NAME        LOCATION    MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jenkins-cd  us-east1-d  1.15.9-gke.9    34.74.77.124  n1-standard-2  1.15.9-gke.9  2          RUNNING
prod        us-east1-d  1.15.9-gke.9    35.229.98.12  n1-standard-2  1.15.9-gke.9  2          RUNNING
staging     us-east1-d  1.15.9-gke.9    34.73.92.228  n1-standard-2  1.15.9-gke.9  2          RUNNING

4. Implantar o Jenkins com o Helm

Instalar o Helm

Vamos usar o Helm, um gerenciador de pacotes de aplicativos para Kubernetes, para instalar o Jenkins no cluster. Para começar, faça o download do projeto que inclui os manifestos do Kubernetes que serão usados para implantar o Jenkins:

git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes

Mude o diretório de trabalho atual para o diretório do projeto:

cd ~/continuous-deployment-on-kubernetes/

Crie uma vinculação de papel do cluster para conceder a si mesmo permissões de administrador do cluster:

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)

Conecte-se ao cluster do Jenkins para receber as credenciais dele:

gcloud container clusters get-credentials jenkins-cd --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

E faça o download do binário do Helm no Cloud Console:

wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz

Descompacte o arquivo e copie o arquivo helm incluído para o diretório de trabalho atual:

tar zxfv helm-v2.14.1-linux-amd64.tar.gz && \
cp linux-amd64/helm .

O Tiller é o lado do servidor do Helm que é executado no cluster do Kubernetes. Vamos criar uma conta de serviço chamada tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

E vincule-o à função de cluster cluster-admin para que ele possa fazer alterações:

kubectl create clusterrolebinding tiller-admin-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller

Agora podemos inicializar o Helm e atualizar o repositório:

./helm init --service-account=tiller && \
./helm repo update

28b45298e1e82748.png Verificar

Confirme se o Helm está pronto para uso com ./helm version. Isso vai retornar os números de versão do cliente e do servidor:

Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}

Instalar o Jenkins

Agora que o Helm está instalado no cluster, podemos prosseguir com a instalação do Jenkins:

./helm install stable/jenkins -n cd \
-f jenkins/values.yaml \
--version 1.2.2 --wait

28b45298e1e82748.png Verificar

Vamos verificar os pods:

kubectl get pods

A saída vai mostrar o pod do Jenkins com o status RUNNING:

NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-vbhg4   1/1       Running   0          1m

Confirme se o serviço do Jenkins foi criado corretamente:

kubectl get svc

A resposta será semelhante a esta:

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         ClusterIP   10.35.241.170   <none>        8080/TCP    2m27s
cd-jenkins-agent   ClusterIP   10.35.250.57    <none>        50000/TCP   2m27s
kubernetes         ClusterIP   10.35.240.1     <none>        443/TCP     75m

A instalação do Jenkins vai usar o plug-in do Kubernetes para criar agentes de criador. Eles serão iniciados automaticamente pelo mestre do Jenkins conforme necessário. Quando o trabalho for concluído, eles serão finalizados de maneira automática, e os respectivos recursos serão adicionados novamente ao pool de recursos do cluster.

Conectar ao Jenkins

O Jenkins está em execução no cluster, mas, para acessar a interface, vamos configurar o encaminhamento de portas no Cloud Shell:

export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

Uma senha de administrador foi gerada durante a instalação. Vamos recuperá-lo:

printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

Na parte de cima do Cloud Shell, clique no ícone de visualização da Web 7ddf5a65fd556dd6.png e selecione "Visualizar na porta 8080".

1d614c831a621cff.png

Uma tela de login do Jenkins vai aparecer, onde podemos inserir o admin para o nome de usuário e a senha retornada na etapa anterior:

9cba23e856cbc84f.png

Quando clicamos em Fazer login, somos direcionados à página principal do Jenkins.

9261f3e914829137.png

5. Instalar e configurar o plug-in do GKE

O plug-in do Google Kubernetes Engine permite que publiquemos implantações criadas no Jenkins nos clusters do Kubernetes em execução no GKE. É necessário fazer algumas configurações com as permissões do IAM no seu projeto. Vamos implantar essa configuração usando o Terraform.

Primeiro, faça o download do projeto do plug-in do GKE:

git clone https://github.com/jenkinsci/google-kubernetes-engine-plugin.git ~/google-kubernetes-engine-plugin

Configuração automática de permissões do IAM

Mude o diretório de trabalho atual para o diretório rbac do projeto do GKE clonado anteriormente:

cd ~/google-kubernetes-engine-plugin/docs/rbac/

gcp-sa-setup.tf é um arquivo de configuração do Terraform que cria um papel personalizado do IAM do GCP com permissões restritas e uma conta de serviço do GCP para conceder esse papel. O arquivo exige valores para as variáveis de nome do projeto, da região e da conta de serviço. Fornecemos esses valores declarando primeiro as seguintes variáveis de ambiente:

export TF_VAR_project=${GOOGLE_CLOUD_PROJECT}
export TF_VAR_region=us-east1-d
export TF_VAR_sa_name=kaniko-role

Inicialize o Terraform, gere um plano e aplique-o:

terraform init
terraform plan -out /tmp/tf.plan
terraform apply /tmp/tf.plan && rm /tmp/tf.plan

A conta de serviço precisa de permissões de administrador de armazenamento para salvar no bucket do Cloud Storage:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \
--role 'roles/storage.admin'

Também são necessárias permissões de contêiner para os estágios de implantação do pipeline:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} --member \
serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com --role 'roles/container.developer'

Agora podemos usar o Helm para configurar as permissões de cluster do plug-in do GKE usando o deployer do robô do GKE. Mude o diretório de trabalho para o diretório do helm do projeto do GKE:

cd ~/google-kubernetes-engine-plugin/docs/helm/

E instale usando o gráfico do Helm fornecido:

export TARGET_NAMESPACE=kube-system && \
envsubst < gke-robot-deployer/values.yaml | helm install ./gke-robot-deployer --name gke-robot-deployer -f -

6. Configurar o Jenkins

Chaves da conta de serviço

Para que a conta de serviço funcione corretamente, precisamos gerar um arquivo de chave privada e adicioná-lo como um segredo do Kubernetes. Primeiro, gere o arquivo com o seguinte comando gcloud:

gcloud iam service-accounts keys create /tmp/kaniko-secret.json --iam-account kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

Vamos criar uma chave secreta na loja de segredos do Kubernetes com esse arquivo:

kubectl create secret generic jenkins-int-samples-kaniko-secret --from-file=/tmp/kaniko-secret.json 

Faça o download do arquivo JSON no seu disco local acessando o item "Fazer o download do arquivo" no menu de três pontos do Cloud Shell:

c40378e72013b843.png

Insira o caminho do arquivo /tmp/kaniko-secret.json e clique em "Fazer o download".

Na página do Jenkins, no painel à esquerda, clique em Credentials e depois em System.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

Na seção da página intitulada Sistema,clique em Credenciais globais e em Adicionar credenciais à esquerda:

4350c0e68561119b.png

3d3526551cdae8b.png

No menu suspenso "Kind", selecione Google Service Account from private key. Insira "kaniko-role" como o nome, faça o upload da chave JSON criada nas etapas anteriores e clique em "OK".

b0502213408e730e.png

Variáveis de ambiente

Há algumas variáveis de ambiente que precisamos definir no Jenkins antes de criar o pipeline de várias ramificações. São eles:

  • JENK_INT_IT_ZONE: a zona do cluster do Kubernetes. No nosso caso, us-east1-d
  • JENK_INT_IT_PROJECT_ID: refere-se ao ID do projeto do GCP que hospeda esta instância do Jenkins.
  • JENK_INT_IT_STAGING: o nome do cluster de "preparação", para fins de demonstração, é staging.
  • JENK_INT_IT_PROD: o nome do cluster "prod". Para fins de demonstração, é prod
  • JENK_INT_IT_BUCKET: o bucket do Google Cloud Storage criado na etapa anterior
  • JENK_INT_IT_CRED_ID: refere-se às credenciais criadas usando o JSON na etapa anterior. O valor precisa corresponder ao nome que demos a ele, kaniko-role

Para adicionar esses itens, acesse Manage Jenkins:

d54f279190a07878.png

Em seguida, Configure System:

ce79d218b2799640.png

Há uma seção chamada Propriedades globais. Quando marcamos a caixa de Variáveis de ambiente, um botão Adicionar aparece. Clique nele para adicionar as variáveis acima como pares de chave-valor:

81aa222a2b17b2cc.png

Clique no botão Salvar na parte de baixo da página para aplicar as alterações.

7. Configurar um pipeline

No Jenkins, clique em "New Item":

8d1270ce4d7b6a8a.png

Insira "jenkins-integration-sample" como o nome, selecione "Multibranch Pipeline" como o tipo de projeto e clique em OK:

eb071ecfbb4d775b.png

Você vai ser redirecionado para a página de configuração do pipeline. Em Branch Sources, insira https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git como o Project Repository. Em Configuração da compilação, digite "gke/Jenkinsfile" como o caminho do script.

5135bd6b0374508c.png

Clique em Salvar para aplicar essas configurações. Após a gravação, o Jenkins inicia uma verificação do repositório e um build subsequente para cada ramificação. À medida que o processo avança, você vai notar que os pods são criados, executados e destruídos conforme os builds avançam na página Cargas de trabalho do Kubernetes.

Quando os builds forem concluídos, você vai encontrar dois itens na página "Kubernetes Workloads", chamados "jenkins-integration-samples-gke", cada um correspondendo ao cluster de produção ou de teste. O status será OK:

bdec6b1753d1ba07.png

Usando o comando gcloud a seguir, vamos conferir que enviamos uma imagem do contêiner para o Google Container Registry correspondente ao nosso pipeline:

gcloud container images list

Para conferir a carga de trabalho no navegador, confira as credenciais do cluster de produção:

gcloud container clusters get-credentials prod --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

E execute o seguinte para configurar um encaminhamento de porta da porta 8081 do shell para a porta 8080 da carga de trabalho:

export POD_NAME=$(kubectl get pods -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8081:8080 >> /dev/null &

Na parte de cima do Cloud Shell, clique no ícone "Visualização da Web" e selecione "Visualizar na porta 8081".

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. Limpeza

Explicamos como implantar um Jenkins e um pipeline de vários ramos no Kubernetes. Agora é hora de limpar o projeto de todos os recursos que criamos.

Excluir o projeto

Se preferir, exclua todo o projeto. No Console do GCP, acesse a página Cloud Resource Manager:

Na lista de projetos, selecione o projeto em que estamos trabalhando e clique em Excluir. Você precisará digitar o ID do projeto. Depois de fazer isso, clique em Desligar.

Também é possível excluir todo o projeto diretamente do Cloud Shell com gcloud:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Se preferir excluir os diferentes componentes faturáveis um por um, avance para a próxima seção.

Cluster do Kubernetes

Exclua todo o cluster do Kubernetes com o gcloud:

gcloud container clusters delete jenkins-cd --zone=us-east1-d

Buckets de armazenamento

Remova todos os arquivos enviados e exclua o bucket com o gsutil:

gsutil rm -r gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket

Imagens do Google Container Registry

Vamos excluir as imagens do Google Container Registry usando os resumos de imagem. Primeiro, extraia os resumos com o seguinte comando:

gcloud container images list-tags gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke --format="value(digest)"

Em seguida, para cada resumo retornado:

gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>

9. Parabéns!

Uhu! Você conseguiu! Você aprendeu a implantar o Jenkins no GKE e enviar jobs para clusters do Kubernetes.

O que aprendemos

  • Implantamos um cluster do Kubernetes e usamos o Helm para instalar o Jenkins.
  • Instalamos e configuramos o plug-in do GKE para permitir que o Jenkins implante artefatos de build em clusters do Kubernetes.
  • Configuramos o Jenkins para configurar um pipeline com várias ramificações que envia trabalhos para clusters do GKE.