Construindo Pipelines Reutilizáveis com o Gitlab

Thiago Soares
5 min readApr 10, 2021

Implementar um pipeline rápido e saudável é uma das tarefas mas difíceis que possam aparecer, ainda mais quando existem uma quantidade grande de aplicações e cada qual com a sua particularidade; porém algumas etapas costumas ser comuns as aplicações de determinadas linguagens.

Felizmente o Gitlab é possível usar templates, https://docs.gitlab.com/ee/ci/yaml/includes.html, que possibilitam escrever etapas comuns a todas as aplicações, como por exemplo:

  • Setup
  • Lint
  • Testes unitários
  • Segurança
  • Testes de carga
  • Deploy

O que esses templates representam?, melhoria e padronização do fluxo de deploy das aplicações.

Você escreve o template em um repositório que queira que as configurações fiquem guardadas e posteriormente em cada serviço/aplicação que for fazer deploy simplesmente herda das configurações padronizadas já escritas.

Configurações do Repositório

Exemplo de configuração no repositório que no exemplo está em um projeto no próprio gitlab :

  • project: 'config/configs'
    branch: master
    file: '/gitlab-ci-files/gitlab-ci-basic.yml'
include:###Jobs
- local: "/gitlab-ci-files/jobs/k6_load_test.yml"
- local: "/gitlab-ci-files/jobs/deploy.yml"
- local: "/gitlab-ci-files/jobs/huskyci.yml"
### Install
.install:
image: docker-pull.artifactory.com/node-workspace:1.0
script:
- npm ci
artifacts:
paths:
- node_modules/
- builds/
- build/
expire_in: 1h
### Lint
.lint:
image: docker-pull.artifactory.com/node-workspace:1.0
script:
- npm run lint
### Test
.test:
image: docker-pull.artifactory.com/node-workspace:1.0
script:
- npm run test:coverage
coverage: '/All files\s*\|\s*([0-9.]+)/'
allow_failure: true
artifacts:
paths:
- .test_coverage/lcov.info
- ./coverage/*
### Security
.huskyCI:
extends: .huskyCI_cli
allow_failure: true
### QA
.k6Quality:
extends: .k6load_test
only:
- master
- merge_requests
### Deploy App
.DeployApp:
extends: .deploy_app
allow_failure: true

Obs: Os templates também podem herdar configurações de outros templates é isso que o include representa, as configurações herdadas serão utilizadas nessa configuração.

Tudo que tiver o . somente será executando quando for chamado no arquivo de ci/cd da aplicação, sem o . será executado de forma automática pela herança da configuração.

Maiores dúvidas pode ser consultado a doc do Gitlab — https://docs.gitlab.com/ee/ci/yaml/includes.html

Configurações da Aplicação

Exemplo de configuração na aplicação que vai executar o pipeline:

include:
### Imports Base Pipeline
include:
- project: 'config/configs'
ref: master
file: '/gitlab-ci-files/gitlab-ci-basic.yml'
## Pipeline Stages
stages:
- setup
- test
- huskyCI
- quality
- deployProd
### Default Pipeline step
install:
stage: setup
extends: .install
only:
- merge_requests
- /release\/\d+.\d+.\d+/
- master
### Lint
lint:
stage: test
extends: .lint
only:
- merge_requests
- /release\/\d+.\d+.\d+/
- master
### Test
test:
stage: test
extends: .test
only:
- merge_requests
- /release\/\d+.\d+.\d+/
- master
### Husky
huskyCI:
stage: huskyCI
extends: .huskyCI
only:
- merge_requests
- /release\/\d+.\d+.\d+/
- master
### k6QA2 Prod
k6QualityProd:
stage: quality
extends: .k6Quality
variables:
K6_TEST_FILE: loadtests/graphql.js
### DeployProd
deployAppProd:
stage: deployProd
extends: .DeployApp
variables:
APP_NAME: test-prod
environment:
name: production
url: http://test-app.com/
allow_failure: false
retry: 1
when: manual
only:
- master
- merge_requests

Como já informei acima, na aplicação que vai sofrer o deploy, basta inserir o include referenciando o repositório de configurações , criar as configurações de cada step inserindo os extends isso irá executar os steps escritos no template

Quais as vantagens de usar templates no Pipeline

Usar o template simplifica na hora de escrever o arquivo do gitlab-ci.yml ; pois as configurações estão centralizadas no repositório base no arquivo gitlab-ci-base.yml

Quaisquer configurações adicionais, é possível implementar no próprio arquivo da aplicação ; inclusive sobreescrevendo as configurações criadas no template ; fiz como exemplo o allow_failure: true , diferente na aplicaçãoe no template — Tudo que não for especificado na aplicação, herdará do template.

Padronização, quando se tem muitas aplicações é difícil ficar inserindo todos os steps do pipeline nos arquivos do gitlab-ci.yml das aplicações.

Possibilidade de padronizar a utilização de artifacts e cache na etapa do pipeline, nesse exemplo está na etapa do install

Possíbilidade de criação de novos serviços no ci/cd e fácil replicação para todas as aplicações/micro-serviços ; um exemplo é o serviço de segurança o Husky

Quais as desvantagens de usar templates no Pipeline

Usar o template simplifica padronizar as configurações principais do pipeline o arquivo do gitlab-ci-base.yml ; qualquer alteração nessas configuraçõe que não forem testadas, implicará em parar/interromper o pipeline de todas as aplicações que herdam esse pipeline; pois é nem tudo é uma bala de prata

Então recomendo cuidado e sempre testar as configurações em branches específicos e em aplicações específicas antes de implementar na master

Rodar step de Segurança no Pipeline

Para a segurança dos pipelines, usamos o Husky , que é uma ferramenta do time de segurança da informação da empresa.

Maiores informações pode ser consultada em:

https://huskyci.opensource.globo.com/

Rodar Testes no Pipeline

Abaixo tem um medium que já escrevi sobre como rodar testes de carga com o K6.io , durante o pipeline.

O exemplo abaixo de um .yml do Gitlab (k6_load_test.yml) de como ser configurado, no template; nesse exemplo ele está no “/gitlab-ci-files/jobs/k6_load_test.yml” e será herado no include do gitlab-ci-base.yml :

.load_performance:
variables:
K6_IMAGE: loadimpact/k6
K6_VERSION: latest
K6_TEST_FILE: ''
K6_OPTIONS: ''
K6_DOCKER_OPTIONS: ''
script:
- docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_DOCKER_OPTIONS $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS --out influxdb=http://grafana.com:8086/myk6db
artifacts:
reports:
load_performance: load-performance.json

Rodar testes de carga durante o pipeline é bastante útil, não só para saber o comportamento da sua aplicação antes de colocá-la em produção, mas para testar micro-serviços/funcionalidades agregados à ela.
Acessos e micro-serviços externos, costumam ser pontos bem comuns de falhas, em caso de alto assédio ou problemas não mapeados; esses testes visam possibilitar a visão/mitigação desses pontos de falha.

Resultado Final

O resultado final, é o pipeline abaixo:

Conclusões Finais

Como informei nas vantagens e desvantagens, essa possibilidade de centralização de configurações, supera em muito a vantagem do que a desvantagem.

Aumenta e muito a capacidade de reutilização do pipeline e simplificação do arquivo de ci/cd em cada aplicação.

Possibilita a implementação de novos serviços no pipeline, como testes , steps de segurança e outros, que uma vez implementados no gitlab-ci-base.yml ; todos as aplicações/seviços podem estar utilizando e tendo significativas melhorias.

Algo que pode ser implementado de forma simples, fácil e que pode ser utlizado nas mais diversas empresas e organizações.

O Gitlab, possui um repositório de exemplos de templates , das mais diversas tecnologias que vale a pena uma observação.

https://docs.gitlab.com/ee/ci/examples/README.html

Recomendo a utilização da padronização.

--

--