7.4 Implantação automática no Google Kubernetes Engine (GKE)
Para automatizar nosso fluxo de entrega e integração, vimos nas seções passadas que as automações são, geralmente, realizadas em servidores. Assim, levamos o versionamento de código para um repositório centralizado: Gitlab. Também publicamos a nossa imagem Docker em um repositório centralizado: Docker Hub. Por fim, vamos servir nosso classificador em um serviço de Kubernetes e não mais na nossa própria máquina.
Para fins didáticos, vamos buscar um serviço de Kubernetes que possa ser utilizado de forma gratuita. O link abaixo nos apresenta algumas opções:
Opções Free Tier de Kubernetes
Nesse tutorial utilizaremos a Google Kubernetes Engine (GKE) da Google Cloud Platform (GCP).
7.4.1 Setup
Configurando uma conta Google Cloud
O primeiro passo para provisionarmos um cluster Kubernetes é criarmos uma conta na google cloud.

Através desse link você pode configurar a sua conta. Para novos usuários, a GCP oferece U$300 de crédito para o uso de alguns serviços.
ATENÇÃO: Uma ferramenta cloud possui políticas de preço para cada serviço, então esteja sempre atento aos serviços que você está utilizando. De preferência, elimine os objetos criados após a aula para evitar cobranças inesperadas.
Para conferir os seus créditos e o período de trial, acesse o Menu do console > Faturamento > Visão Geral.

Utilizando e Instalando a Gcloud CLI
Para interagir com os serviços da GCP, podemos utilizar a UI do console Web ou podemos utilizar o terminal com o utilitário de linha de comando gcloud.
É recomendado o uso do utilitário gcloud, pois permite a reproducibilidade e automação das configurações que estamos realizando futuramente.
Temos duas opções para utilizar o gcloud CLI:
Via terminal do Cloud Shell
Via terminal da nossa estação de trabalho: Guia de instalação
Quickstart da configuração local
Para configuração local, devemos adicionar o pacote adicional gke-auth:
sudo apt-get install google-cloud-cli-gke-gcloud-auth-plugin
Na sequência, finalizamos a configuração da CLI com o comando abaixo:
gcloud init
Uma vez configurada, podemos listar a contas autenticadas:
gcloud auth list
Também podemos verificar informações da instalação:
gcloud info
Criando um cluster GKE
Agora que já temos o pré-requisito da gcloud CLI atendido, podemos criar um cluster GKE usando a linha de comando:
Primeiro vamos criar um projeto
gcloud projects create mba-mle-ufscar --name="mba-mle-ufscar"
Vamos ativar esse projeto
gcloud config set project mba-mle-ufscar
Habilitando o uso da API do GKE
gcloud services enable container.googleapis.com
Conferindo se o serviço está habilitado
gcloud services list --enabled
Criando um cluster no formato Autopilot
gcloud container clusters create-auto "autopilot-cluster-ufscar" --region "us-east1"
Conferindo o status do nosso cluster Kubernetes
gcloud container clusters list
Podemos conferir também pela UI, usando a rota: Console GCP > Kubernetes Engine > Clusters

7.4.2 Realizando o deploy na nuvem de forma manual
Como fizemos nas seções anteriores, vamos primeiro realizar a implantação do nosso serviço "classificador" de forma manual para entendermos todos os passos e requisitos necessários. Assim, ficará mais claro como deve ser formato o script de automação.
Configurando o Kubectl
Como vimos na sessão 5.3, para interagir e realizar o deploy de aplicações no Kubernetes, podemos utilizar o utilitário de linha de comando kubectl. Portanto, se você ainda não realizou a instalação desse binário volte na sessão mencionada e siga o tutorial de instalação.
Conferindo a instalação do kubectl:
kubectl version
Configurando os parâmetros de acesso ao GKE Cloud:
gcloud container clusters get-credentials autopilot-cluster-ufscar
Agora podemos fazer um deployment "hello-world" para validar a configuração
kubectl create deployment hello-server --image=matheusvmleite/classificador-produtos
Agora, vamos expor o serviço do classificador para acesso público:
kubectl expose deployment hello-server --type LoadBalancer --port 80 --target-port 80
Podemos validar o nosso serviço classificador entrando no endereço IP onde nossa aplicação está exposta:
kubectl get service hello-server
Devemos ter um output com o External IP que podemos usar no nosso navegador para validar a aplicação

Também podemos analisar o output em yaml dos serviços criados, pois isso vai nos auxiliar na automação:
kubectl get svc hello-server -o yaml
Na interface do GKE, podemos conferir o deployment criado pela rota: Console GCP > Kubernetes Engine > Cargas de trabalho:

Também na UI, podemos conferir os serviços criados e ter fácil acesso ou link do serviço pela rota: Console GCP > Kubernetes Engine > Serviços e Entradas:

Pra finalizar, vamos deletar os objetos criados:
kubectl delete svc,deploy hello-server
Criando manifestos YAML
Para implantar nossa aplicação no GKE de forma consistente e automatizada, vamos precisar usar um arquivo manifesto YAML para definir o estado desejado dos recursos do Kubernetes.
Crie o arquivo classificador.yaml
com a seguinte especificação:
apiVersion: apps/v1
kind: Deployment
metadata:
name: classificador-server
labels:
app: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: matheusvmleite/classificador-produtos
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: classificador-svc
spec:
selector:
app: api
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
Esse arquivo especifica dois objetos: Deployment e Service. O deployment faz o uso da imagem que estamos utilizando no curso para rodar a API do nosso classificador de produtos. Já o Service expõe essa API para acesso público por meio de um LoadBalance.
Criando objetos no K8S
Após criar os manifestos dos objetos que vamos criar no GKE, basta utilizarmos o comando abaixo para realizar o deploy:
kubectl apply -f classificador.yaml
Podemos validar nossa aplicação listando o serviço criado e acessando o external IP.
Finalizado o teste do deploy manual, basta remover o deployment:
kubectl delete -f classificador.yaml
7.4.3 Automatizando o deploy na Nuvem
Com toda experimentação que realizamos, alguns pré-requisitos para a automação do nosso deploy ficam claros:
Precisamos dos binários da gcloud e do kubectl
Precisamos de uma autenticação na GCP
Precisamos da configuração do cluster GKE no kubectl
Na sequência, vamos resolver cada um desses items e criar nossa automação.
Configurando uma conta de serviço
No deploy manual utilizamos nossa credencial pessoal para realizar a autenticação com o GCP. Na prática, automações de serviços cloud devem utilizar contas de serviço para se autenticar.
Para criar uma conta de serviço, podemos seguir os passos abaixo:
Criar uma conta de serviço
gcloud iam service-accounts create gitlab-gke \
--description "Conta para pipeline Gitlab" --display-name "gitlab-gke"
Uma identificação será criada para a conta de serviço com o seguinte padrão:
my-service-account@my-project.iam.gserviceaccount.com
No caso de uma conta com o nome "gitlab-gke" e projeto com nome "mba-mle-ufscar":
gitlab-gke@mba-mle-ufscar.iam.gserviceaccount.com
Adicionar permissão de Agente de Serviço de Kubernetes Engine
gcloud projects add-iam-policy-binding mba-mle-ufscar \ --member="serviceAccount:gitlab-gke@mba-mle-ufscar.iam.gserviceaccount.com" \
--role="roles/container.serviceAgent"
Criar uma chave json de acesso
gcloud iam service-accounts keys create ./key.json --iam-account cgitlab-gke@mba-mle-ufscar.iam.gserviceaccount.com
Encondar chave de acesso em base64
base64 -w 0 key.json > encoded_key.json
Criando uma variável no Gitlab com a chave de acesso
Agora, vamos utilizar o conteúdo do arquivo json encoded para criar nossa variável de ambiente no gitlab. Pra isso:
Acessar opção "Settings" no menu lateral do repositório no Gitlab
Opção CI/CD
Seção "Variables"
Criar a variável
GKE_SERVICE_ACCOUNT
com o conteúdo base64 do arquivo json.
Adicionando script de automação para o pipeline
Com todos os pré-requisitos configurados, podemos enfim atualizar o nosso arquivo .gitlab-ci.yaml
:
default:
image: python:3.9.6-slim
stages:
- verify
- quality
- publish
+ - deploy
verify-python:
stage: verify
script:
- python --version
- whoami
verify-pip:
stage: verify
script:
- pip --version
run-tests:
stage: quality
script:
- pip install -r requirements.txt
- python -m unittest
analyze-coverage:
stage: quality
script:
- pip install -r requirements.txt
- coverage run -m unittest
- coverage report --fail-under=100 -m
publish-docker-hub:
image: docker:19.03.12
stage: publish
services:
- docker:19.03.12-dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
- docker push "$CI_REGISTRY_IMAGE"
only:
- main
+gcloud-deploy:
+ stage: deploy
+ image: google/cloud-sdk
+ script:
+ - echo $GKE_SERVICE_ACCOUNT | base64 -d > ~/encoded_serviceaccount.json
+ - gcloud auth activate-service-account --key-file ~/encoded_serviceaccount.json
+ - gcloud container --project "mba-mle-ufscar" clusters get-credentials autopilot-cluster-ufscar --region us-east1
+ - kubectl apply -f classificador.yaml
+ only:
+ - main
Essa alteração adiciona uma stage de deploy que será responsável por criar a nossa aplicação dentro do GKE.
De forma detalhada, o script cumpre as seguintes funções:
Cria um arquivo de autenticação com a CLI do gcloud.
Autentica com a Google Cloud usando a conta de serviço configurada
Configura o cluster 'autopilot-cluster-ufscar' pra ser utilizado pelo utilitário kubectl
Aplica os manifestos dos objetos do Kubernetes, efetivando o deploy.
Melhorando o deploy
Na nossa automação estamos utilizando o comando de apply para criar a nossa aplicação.
Porém, como não estamos versionando as imagens docker com tags, nas próximas execuções do pipeline vamos nos deparar com um cenário indesejado. Ao realizar o apply de uma imagem com o mesmo nome, os manifestos yaml não apresentam nenhuma alteração. Assim, o Kubernetes entender que não alterações a serem aplicadas.

Para corrigir esse cenário, vamos criar um script bash chamado apply_and_restart.sh
que irá verificar se após o commando apply
temos um output de deployment unchanged
. Se esse for o cenário encontrado, faremos um restart do deployment. Isso irá forçar que o Kubernetes sempre baixe a versão do classificador mais recente disponível no Docker Hub.
#!/bin/bash
DEPLOYMENT_NAME="classificador-server"
# Apply the deployment and capture the output
output=$(kubectl apply -f classificador.yaml)
echo $output
# Check if the output contains "unchanged"
if [[ $output == *"unchanged"* ]]; then
echo "No changes detected. Performing rollout restart..."
kubectl rollout restart deployment $DEPLOYMENT_NAME
else
echo "Changes detected. Deployment not restarted."
fi
Por fim, basta adicionar a chamada do script na nossa automação de CI/CD:
default:
image: python:3.9.6-slim
stages:
- verify
- quality
- publish
- deploy
verify-python:
stage: verify
script:
- python --version
- whoami
verify-pip:
stage: verify
script:
- pip --version
run-tests:
stage: quality
script:
- pip install -r requirements.txt
- python -m unittest
analyze-coverage:
stage: quality
script:
- pip install -r requirements.txt
- coverage run -m unittest
- coverage report --fail-under=100 -m
publish-docker-hub:
image: docker:19.03.12
stage: publish
services:
- docker:19.03.12-dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
- docker push "$CI_REGISTRY_IMAGE"
only:
- main
gcloud-deploy:
stage: deploy
image: google/cloud-sdk
script:
- echo $GKE_SERVICE_ACCOUNT | base64 -d > ~/encoded_serviceaccount.json
- gcloud auth activate-service-account --key-file ~/encoded_serviceaccount.json
- gcloud container --project "mba-mle-ufscar" clusters get-credentials autopilot-cluster-ufscar --region us-east1
- - kubectl apply -f classificador.yaml
+ - bash apply_and_restart.sh
only:
- main
7.4.4 Limpando nosso ambiente cloud
Como falamos no início dessa seção, é importante ter ciência das cobranças envolvidas em um ambiente cloud. Para finalizar nossa aula e evitar cobranças indevidas, vamos remover nosso cluster kubernetes utilizando a gcloud cli:
gcloud container clusters delete CLUSTER_NAME
Documentação oficial: Como excluir um cluster GKE
7.4.5 Conclusão e próximos passos
Nesta seção demonstramos como configurar um ambiente de deploy Kubernetes na cloud com o serviço GKE. Também passamos por todo o passo a passo de automação desses tipos de deployment.
Apesar de ser um cenário inicial, os conceitos aplicados aqui permitem uma série de melhorias que podem ser utilizadas tanto em casos práticos como na continuidade da exploração de Continuous Deployment com esse exemplo. Seguem algumas sugestões:
Como configurar um ambiente de homologação e automatizar o deploy com múltiplas etapas
Como versionar as imagens docker por meio de tags de forma automatizada
Como criar templates de manifestos yaml de objetos Kubernetes para realizar configurações dinâmicas
Como adicionar probes na aplicação e automatizar um smoke test após deployment
Como realizar o rollback automático nos casos de deploys mal sucedidos
Como otimizar o tempo de execução do pipeline
Last updated