Hi, I'm João Vanzuita, a Backend software developer.

Deploy manual no Kubernetes usando pipeline do GitLab com ARM64

Uso um Raspberry Pi p/ rodar Kubernetes em single node p/ experimentar algumas coisas com Kubernetes, e o problema sempre foi criar as imagens p/ a arquitetura do Raspberry Pi (ARM64). Encontrei no GitLab a facilidade que procurava p/ rodar meus projetos experimentais usando a arquitetura ARM64.

1. Como fazer o GitLab criar as imagens OCI(Docker) p/ arquitetura ARM64?

1image: golang:1.17
2stages:
3  - test
4  - build
5test:
6  stage: test
7  script:
8    - go test -v ./...
9build:
10  stage: build
11  image: jdrouet/docker-with-buildx:stable
12  services:
13    - docker:dind
14  variables:
15    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
16    DOCKER_HOST: tcp://docker:2375
17    DOCKER_DRIVER: overlay2
18  script:
19    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
20    - docker buildx create --use
21    - docker buildx build --platform linux/arm64/v8 -t $IMAGE_TAG . --push

1.1 Quebrando o .gitlab-ci.yml em pedacos (image)

1image: golang:1.17

Define que nossa pipeline vai rodar usando a imagem golang:1.17 , ela é necessária p/ que nosso teste rode.

1.2 Quebrando o .gitlab-ci.yml em pedacos (stages)

1stages:
2  - test
3  - build

Define os estágios da pipeline.

1.3 Quebrando o .gitlab-ci.yml em pedacos (test)

1test:
2  stage: test
3  script:
4    - go test -v ./...

Nesse estágio os testes são executados.

1.4 Quebrando o .gitlab-ci.yml em pedacos (build)

1build:
2  stage: build
3  image: jdrouet/docker-with-buildx:stable

O estágio de build usa a imagem acima que basicamente instala o buildx na imagem, p/ que possamos usar o buildx posteriormente (essa imagem esta desatualizada, pretendo fazer um fork e atualiza-la).

1  services:
2    - docker:dind

`dind` significa Docker in Docker, e é uma maneira que o GitLab disponibiliza p/ os casos em que há necessidade de rodar o build da pipeline usando uma imagem específica.

1variables:
2    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
3    DOCKER_HOST: tcp://docker:2375
4    DOCKER_DRIVER: overlay2

Nesse ponto são definidas algumas variáveis que serão posteriormente utilizadas. IMAGE_TAG irá definir o nome da imagem que está sendo criada, os valor vem de outras variáveis de ambiente previamente definidas CI_REGISTRY_IMAGE e CI_COMMIT_REF_SLUG.

DOCKER_HOST é uma valor hardcoded que indica onde o Docker que está executando e ouvindo novas requisições, é este host que irá fazer o trabalho de executar nossa imagem e rodar alguns comandos que serão descritos no próximo passo abaixo.

DOCKER_DRIVER define qual driver de disco que deve ser usado, por padrão o vfs é utilizado, nessa variável de ambiente o GitLab prefere que seja usado o driver overlay2. Aqui tem uma explicação muito boa do porque.

1script:
2    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
3    - docker buildx create --use
4    - docker buildx build --platform linux/arm64/v8 -t $IMAGE_TAG . --push

O script é onde podemos executar "coisas" dentro do nosso container no momento da criação da nossa nova imagem. Em resumo, o que está sendo feito é locar no seu Registro de imagem, que é onde suas imagens ficam hospedadas e posteriormente seu Kubernetes(por exemplo) pode fazer download da imagem que você está solicitando p/ rodar o seu serviço. Em seguida uma instância p/ criação de imagem isolada é criada e finalmente a imagem é criada e enviada p/ o seu registro de container(onde seu container fica armazenado p/ download posterior).

Agora com os comandos p/ ficar mais claro:

- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY faz login no seu registro de container.

- docker buildx create --use cria uma instância isolada p/ criação da imagem

- docker buildx build --platform linux/arm64/v8 -t $IMAGE_TAG . --push faz a criação da imagem, p/ a plataforma ARM64 (plataforma do RaspberryPi, MacOS M1 e outros), e o --push envia a imagem p/ o registro de container.

obs: a imagem jdrouet/docker-with-buildx:stable está desatualizada, lembre-se de usar uma versão mais recente ou criar uma fork e utilizar a sua própria imagem se for utiliza-la p/ o seu projeto real.

# Deploy p/ o Kubernetes

Agora que nossa imagem está criada e pronta, podemos usa-la e fazer deploy no Kubernetes. Configurar o custer Kuberntes está fora do escopo desse artigo, mas indico o K3S se for criar o cluster usando Raspberry Pi.

Com o seu cluster funcionando, o manifesto(especificação de deploy) do Kubernetes pode seguir esse caminho p/ utilizar a imagem que está em nosso registro de container.

1apiVersion: apps/v1    
2kind: Deployment    
3metadata:    
4  name: go-nome-do-seu-projeto    
5spec:    
6  replicas: 1    
7  selector:    
8    matchLabels:    
9      name: go-nome-do-seu-projeto    
10  template:    
11    metadata:    
12      labels:    
13        name: go-nome-do-seu-projeto    
14    spec:    
15      containers:    
16        - name: go-nome-do-seu-projeto    
17          image: registry.gitlab.com/jacquin-home/go-nome-do-seu-projeto:main     
18          imagePullPolicy: Always    
19          ports:    
20            - containerPort: 7001    
21      imagePullSecrets:    
22        - name: gitlab-auth

O que há de mais relevante no manifesto é:

image: registry.gitlab.com/jacquin-home/go-migrate-best-practices:main

que está definindo onde está localizada sua imagem. E também:

imagePullSecrets: - name: gitlab-auth

Que usa este local p/ localizar as credenciais de autenticação p/ que possa acessar o seu registro de imagens privado (GitLab).