Usaremos Gitlab CI e GitOps manual para implementar e utilizar o Canary deployment no Kubernetes

Artigos desta série:
- (este artigo)
- Canary Deployment usando Istio
- Canary Deployment usando Jenkins-X Istio Flagger
Faremos o Canary deployment manualmente através de GitOps e criação/modificação de recursos principais do Kubernetes. Este artigo é destinado principalmente para familiarização com o funcionamento do Canary deployment no Kubernetes, pois existem métodos mais eficientes de automação que abordaremos nos próximos artigos.

Canary Deployment
Na estratégia de Canary, as atualizações são inicialmente aplicadas apenas para uma parte dos usuários. Por meio de monitoramento, dados de logs, testes manuais ou outros canais de feedback, a versão é testada antes de sua aplicação para todos os usuários.
Kubernetes Deployment (atualização gradual)
A estratégia padrão para o Kubernetes Deployment é a atualização gradual, onde um determinado número de pods com novas versões de imagens é iniciado. Se forem criados sem problemas, os pods com as versões antigas das imagens são encerrados e novos pods são criados em paralelo.
GitOps
Usamos GitOps neste exemplo, pois:
- usamos o Git como a única fonte da verdade
- usamos operações Git para construção e deployment (sem comandos, exceto git tag/merge são necessários)
Exemplo
Vamos seguir uma boa prática — ter um repositório para o código dos aplicativos e outro para a infraestrutura.
Repositório para aplicativos
Esta é uma API muito simples em Python+Flask, que retorna uma resposta em formato JSON. Compilaremos o pacote através do GitlabCI e enviaremos o resultado para o Gitlab Registry. No registry temos duas versões diferentes de releases:
wuestkamp/k8s-deployment-example-app:v1wuestkamp/k8s-deployment-example-app:v2
A única diferença entre elas é a alteração no arquivo JSON retornado. Usamos esta aplicação para visualização máxima do qual versão estamos interagindo.
Repositório de infraestrutura
Neste repositório, faremos o deployment através do GitlabCI no Kubernetes, .gitlab-ci.yml fica da seguinte forma:
image: traherom/kustomize-docker
before_script:
- printenv
- kubectl version
stages:
- deploy
deploy test:
stage: deploy
before_script:
- echo $KUBECONFIG
script:
- kubectl get all
- kubectl apply -f i/k8s
only:
- master
Para executá-lo por conta própria, você precisará de um cluster, podendo usar o Gcloud:
gcloud container clusters create canary --num-nodes 3 --zone europe-west3-b
gcloud compute firewall-rules create incoming-80 --allow tcp:80Você precisa fazer um fork e criar uma variável KUBECONFIG no GitlabCI, que conterá a configuração para acesso kubectl ao seu cluster.
Sobre como obter credenciais para o cluster (Gcloud) você pode ler .
Yaml de infraestrutura
No repositório de infraestrutura, temos um service:
apiVersion: v1
kind: Service
metadata:
labels:
id: app
name: app
spec:
ports:
- port: 80
protocol: TCP
targetPort: 5000
selector:
id: app
type: LoadBalancerE deployment em deploy.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 10
selector:
matchLabels:
id: app
type: main
template:
metadata:
labels:
id: app
type: main
spec:
containers:
- image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v1
name: app
resources:
limits:
cpu: 100m
memory: 100MiE outro deployment em deploy-canary.yaml:
kind: Deployment
metadata:
name: app-canary
spec:
replicas: 0
selector:
matchLabels:
id: app
type: canary
template:
metadata:
labels:
id: app
type: canary
spec:
containers:
- image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v2
name: app
resources:
limits:
cpu: 100m
memory: 100MiObserve que o app-deploy ainda não tem réplicas definidas.
Execução da implantação inicial
Para iniciar o deployment inicial, você pode executar o pipeline do GitlabCI manualmente no branch principal. Depois disso, kubectl deve apresentar o seguinte:

Nós vemos app deployment com 10 réplicas e app-canary com 0. Também há um LoadBalancer que podemos acessar através do curl IP Externo:
while true; do curl -s 35.198.149.232 | grep label; sleep 0.1; done

Nós vemos que nosso aplicativo de teste retorna apenas 'v1'.
Execução do Canary deployment
Passo 1: liberar uma nova versão para parte dos usuários
Definimos o número de réplicas como 1 no arquivo deploy-canary.yaml e a imagem da nova versão:
kind: Deployment
metadata:
name: app-canary
spec:
replicas: 1
selector:
matchLabels:
id: app
type: canary
template:
metadata:
labels:
id: app
type: canary
spec:
containers:
- image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v2
name: app
resources:
limits:
cpu: 100m
memory: 100MiNo arquivo deploy.yaml nós mudamos o número de réplicas para 9:
kind: Deployment
metadata:
name: app
spec:
replicas: 9
selector:
matchLabels:
id: app
...Estamos enviando essas alterações para o repositório, de onde o deployment será iniciado (via GitlabCI) e vemos o resultado:

Nosso Service apontará para ambos os deployments, já que ambos têm o seletor app. Devido à distribuição aleatória padrão no Kubernetes, devemos ver respostas diferentes em ~ 10% das solicitações:

O estado atual do nosso aplicativo (GitOps, retirado do Git como a Única Fonte da Verdade) consiste na presença de dois deployments com réplicas ativas, um para cada versão.
~10% dos usuários estão se familiarizando com a nova versão e testando-a inadvertidamente. Agora é hora de verificar se há erros nos logs e nos dados de monitoramento para encontrar problemas.
Passo 2: liberar uma nova versão para todos os usuários
Decidimos que tudo correu bem e agora precisamos implementar a nova versão para todos os usuários. Para isso, simplesmente atualizamos deploy.yaml instalando a nova versão da imagem e setando o número de réplicas igual a 10. No deploy-canary.yaml Definimos o número de réplicas como igual a zero. Após o deployment, o resultado será o seguinte:

Resumindo
Para mim, iniciar o deployment manualmente dessa forma ajuda a entender como ele pode ser facilmente configurado com o k8s. Como o Kubernetes permite atualizar tudo através da API, esses passos podem ser automatizados por scripts.
Outra coisa que precisamos implementar é a entrada do testador (LoadBalancer ou através do Ingress), pela qual podemos acessar apenas a nova versão. Isso pode ser usado para visualização manual.
Nos próximos artigos, iremos explorar outras soluções automatizadas que implementam a maior parte do que fizemos.
Leia também outros artigos em nosso blog:
Fonte: habr.com
