Gitlab CI/CD Pipelines
O projeto itflex/itflex
possui uma configuração de pipelines com diversos stages para diferentes propósitos. Como é um repositório monorepo, ele possui diferentes produtos, como FWFLEX, CDM, VPNFLEX e outros recursos compartilhados, como imagens de container, LIBs e Chat bot.
Abaixo a imagem de todos os stages do projeto, com uma breve explicação:

O pipeline executa um conjunto de tarefas para uma determinada finalidade. Quando uma tarefa não depende de outra, é comum que elas estejam no mesmo stage (etapa). Quando há dependência entre tarefas, elas são separadas em stages distintos, para garantir que uma tarefa só seja executada se a precedente executar com sucesso.
As tarefas são executadas através de runners do Gitlab. Hoje há 5 runners (VMs) configuradas, que são alocadas automaticamente, quando necessário. Mais informações na documentação do Gitlab Runners.
Stages e includes
O arquivo de configuração principal é o .gitlab-ci.yml
. Nele são especificados todos os stages e includes de demais arquivos.
Stages:
stages:
- ci-build
- ci-publish
- pre-build
- test
- build
- package
- publish
- staging
- hotfix
- release
- production
- clean-review
Includes:
include:
- local: "ci/.gitlab-ci.yml"
- local: "bots/devbot/.gitlab-ci.yml"
- local: "cdm/.gitlab-ci.yml"
- local: "libs/js/validation/.gitlab-ci.yml"
- local: "libs/js/validation-ts/.gitlab-ci.yml"
- local: "libs/python/accel/.gitlab-ci.yml"
- local: "libs/python/hadron/.gitlab-ci.yml"
- local: "libs/python/apps_pack_info/.gitlab-ci.yml"
- local: "libs/python/ipset/.gitlab-ci.yml"
- local: "libs/python/if_ldap/.gitlab-ci.yml"
- local: "server/.gitlab-ci.yml"
- local: "server/.gitlab-ci-bot.yml"
- local: "tasks/.gitlab-ci.yml"
- local: "third_party/rpms/.gitlab-ci.yml"
- local: "vpn_company/.gitlab-ci.yml"
Gatilhos de pipelines
Quando o projeto possui a função CI/CD ativada e possui a configuração .gitlab-ci.yml
na raiz do projeto, Algumas condições podem disparar um pipeline:
- Push de commits para o repositório
- Pipeline é iniciado para a branch que o commit foi realizado
- Merge de branch
- Pipeline é iniciado para a branche que recebeu o merge
- Gitlab Schedules
- Agendamentos de pipelines feito através da interface web do Gitlab, especificando a branch e horário para o pipeline
- Triggers
- Pipelines acionados através de API, autenticado por token no Gitlab
Quando o pipeline é acionado, o Gitlab lê e executa toda a configuração especificada no .gitlab-ci.yml
. Porém, nem todos os stages estarão presentes nas pipelines, pois existem condicionais configuradas nas tasks, que especificam quando uma task deve ou não ser executada.
Condições para uma task ser executada
Não é desejado que um build em branch de desenvolvimento seja publicado em ambiente de produção. Por este motivo, existem condições para garantir o funcionamento.
Alguns stages são executados em todas as branches:
- pre-build (gera documentação das APIs openapi)
- test (testes de front, back, migrações)
- build (compila as aplicações)
- package (build dos pacotes RPM)
Outros são executados somente em branches de desenvolvimento:
- ci-build (testa build das imagens do docker)
Outros somente na branch master:
- ci-publish (build + push das imagens do docker)
- staging (ansible prov ambiente de staging)
- Nas branches/tags de produção (server-prod):
- publish (gera pacotes do repo)
- production (deployment do CDM)
Ainda há as branches de release e hotfix, que fazem deploy para seus ambientes de teste específicos. Essas configurações são especificadas nas tarefas.
Exemplo 1 abaixo. Condições para executar a task:
- Somente quando houver alterações em
ci/**/**
- Exceto quando for na branch master
- Exceto quando o pipeline for acionado via triggers (chat bot ou outros via API)
.build-ci: &build-ci
stage: ci-build
image: docker.itflex.com.br/ci/docker:dind
tags:
- docker
only:
changes:
- ci/**/*
except:
refs:
- master
- triggers
before_script:
- ./helpers/ci-docker-auth.sh
Exemplo 2 abaixo. Condições para executar a task:
- Somente quando o pipeline for acionado via triggers (chatbot ou outros via API).
- Somente quando a variável atender o valor especificado.
.branch-deploy-staging: &branch-deploy-staging
tags:
- docker
only:
refs:
- triggers
variables:
- $DEPLOY == "server-testing"
- $DEPLOY == "server-staging"
- $DEPLOY == "testing-rpm"
Execução da task
A tag docker
especificada em todas as tasks, serve simplesmente para alocar os runners que possuem esta tag. Caso a tag seja removida de uma task, não haverá runners disponíveis para sua execução.
Os runners da iTFLEX, são VMs do CentOS 7 com o serviço do docker. A task no Gitlab sempre especifica uma imagem do docker para executar os comandos.
No exemplo abaixo, O Gitlab irá alocar um runner do CentOS 7, subir um container do CentOS 8 e executar os comandos especificados no bloco script
. O before_script
especifica comandos que devem ser executados antes de quaisquer comandos. No exemplo abaixo, é executado um script helper, que configura a autenticação SSH do Gitlab com a VM de staging.
server:staging:deploy:
tags:
- docker
only:
refs:
- triggers
variables:
- $DEPLOY == "server-staging"
image: docker.itflex.com.br/ci/deploy:centos8
stage: staging
dependencies:
- server:staging:package:rpms
before_script:
- ./helpers/ci-ssh-key.sh
script:
- cd server/
- ./helpers/clean-repo.sh "centos/8/v3/${CI_COMMIT_REF_NAME}"
- cd pkgs/
- REPO="centos/8/v3/${CI_COMMIT_REF_NAME}" RPM_RELEASE="${CI_PIPELINE_ID}" make deploy
- cd ..
- ./helpers/rpm-update-repo.sh "centos/8/v3/${CI_COMMIT_REF_NAME}"
- ./helpers/rollback-snapshot.sh "${STAGING_DOMAIN}" "${PROXMOX_SERVER}" "${PROXMOX_VM_ID}" "${PROXMOX_ROLLBACK}" "${PROXMOX_SNAPSHOT_NAME}" "${CI_COMMIT_REF_NAME}"
- |
ANSIBLE_CONFIG=./ansible.cfg ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \
-u deploy \
-i "${STAGING_DOMAIN}", \
--extra-vars "@ansible/vars/staging.yml" \
ansible/playbooks/all.yml
Manutenção do Pipeline
Alterações no pipeline são muito críticas e devem ser feitas com atenção. É necessário sempre abrir uma branch para testes, antes de fazer qualquer alteração na master. Quando a alteração estiver vinculada ao produto (nova funcionalidade, melhoria), deverá seguir o padrão de desenvolvimento do produto. Quando a alteração for em recursos auxiliares, como o bot ou imagens do docker, uma branch de atividade deve ser aberta para execução dos testes corretamente.