🇧🇷GitLab CI – Para Pipelines CI/CD & DevOps

🇬🇧 – To read this article in English click here

Neste artigo, explico sobre CI/CD na prátixa, mais especificamente o GitLab CI/CD. CI/CD é uma prática de desenvolvimento que facilita e automatiza o processo de criação e entrega de software. CI (Continuous Integration) faz com que os desenvolvedores integrem o código com frequência, rodando testes automáticos para garantir que nada quebre. CD (Continuous Delivery ou Continuous Deployment) automatiza o envio de novas versões para produção ou outros ambientes, tornando o processo mais rápido e seguro. Isso significa atualizações mais rápidas e menos erros manuais. Vamos falar sobre build, deploy, segurança, verificações, Runners e muito mais.

Vamos começar:

Criando um ambiente para trabalharmos:

Acesse o meu repositório no github:

https://github.com/GustavoSantanaData/Git-CI-CD

Instalando o gitlab localemnte:

no arquivo install  ./04-install-gitlab.sh alterar o endereço ip. (esse passo somente se for usar o gitlab localmente)

#!/bin/bash

sudo mkdir -p /storage/docker-homol/deploy/gitlab/{data,logs,config}

docker run -dit \

 -p "2222:22" \

 -p "8080:80" \

 -p "443:443" \

 --name gitlab \

 --hostname endereço-server \

 -v /storage/docker-homol/deploy/gitlab/data:/var/opt/gitlab \

 -v /storage/docker-homol/deploy/gitlab/logs:/var/log/gitlab \

 -v /storage/docker-homol/deploy/gitlab/config:/etc/gitlab \

 --shm-size 256m \

 gitlab/gitlab-ce:14.7.6-ce.0

rode o arquivo no terminal

./04-install-gitlab.sh

acessar

localhost:8080

usuario: root

senha: 123456789

Nesse ponto, o seu gitlab ja estará disponivel localmente. Agora, crie um repositório.

Runner:

Os runners no GitLab são os “executores” dos jobs dos pipelines de CI/CD. Eles rodam em servidores configurados para compilar, testar e fazer deploy dos projetos. Existem dois tipos: shared runners, que são fornecidos pelo GitLab e usados por vários projetos, e specific runners, que você configura para atender às necessidades específicas do seu projeto, como rodar em uma máquina com configurações próprias. Essencialmente, são eles que pegam as tarefas do CI/CD e fazem acontecer.

Dentro do repositório, no menu lateral direito, entre em ci/cd e pegue o token de registro

no arquivo 05-config-runners.sh

rode o primeiro trecho de código acrescentando o token do gitlab para criar o runner

sudo gitlab-runner register -n \

 --url http://seu -ip:8080 \

 --registration-token GR1348941w5eCWTWhMTxorW_RB4Qu \

 --executor shell \

 --description "Runner Shell"

rode o arquivo no seu terminal

voltando no site do gitlab o runner vai aparecer verdinho, clicar em alterar e deixar assim

rodar os comandos

sudo systemctl restart gitlab-runner

sudo systemctl enable gitlab-runner

rodar segundo trecho do arquivo  para criar o container do runner

docker run -dit \

 --name runner-docker \

 --restart always \

 -v /var/run/docker.sock:/var/run/docker.sock \

 -v /opt/gitlab-runner/config:/etc/gitlab-runner \

 gitlab/gitlab-runner:ubuntu-v14.9.1

rodar o terceiro código ajustado com o token e o url com endereço ip do runner

docker exec -it runner-docker \

gitlab-runner register -n \

 --url http://seu-ip:8080/ \

 --registration-token GR1348941w5eCWTWhMTxorW_RB4Qu \

 --clone-url http://seu-ip:8080/ \

 --executor docker \

 --docker-image "docker:latest" \

 --docker-privileged

Prontinho, seu ambiente gitlab está configurado e pronto para começarmos a criar nossas pipelines CI/CD

CI:

no repositório, crie um arquivo .gitlab-ci.yml

O arquivo .gitlab-ci.yml é onde você define os pipelines de CI/CD no GitLab. Nele, você especifica os estágios do pipeline, como build, test e deploy, e os comandos que serão executados em cada fase. Esse arquivo fica na raiz do projeto e é lido automaticamente pelo GitLab para orquestrar as tarefas. É totalmente configurável, permitindo definir jobs, variáveis de ambiente, dependências e até em quais máquinas (runners) os jobs devem rodar. Basicamente, o .gitlab-ci.yml é o cérebro que controla todo o processo de automação no GitLab.

criando um job com trigger manual pra iniciar

job1:

 when: manual

 tags:

   - "shell"

 scripts:

   - echo "Executa somente manual"

Esse código define um job chamado job1 no pipeline de CI/CD do GitLab. Explicação:

  • job1:: Nome do job, usado para identificar essa etapa no pipeline.
  • when: manual: Especifica que este job deve ser executado manualmente, ou seja, ele não será disparado automaticamente quando o pipeline rodar. Alguém precisará clicar em “play” no GitLab para executá-lo.
  • tags:: Define que este job deve ser executado por um runner que tenha a tag “shell”. Isso é útil quando você tem diferentes runners configurados para diferentes tipos de tarefas.
  • script:: Lista de comandos que serão executados no job. Neste caso, o job vai apenas rodar o comando echo “Executa somente manual”, que imprime essa mensagem no terminal.

agendando play da pipeline

job2:

 when: delayed

 start_in: 1 minute

 script: echo "execução em 1 muinuto"

Já esse código define um job chamado job2 que será executado com um atraso programado no pipeline de CI/CD do GitLab. explicação:

  • job2:: Nome do job, usado para identificar essa etapa no pipeline.
  • when: delayed: Indica que o job será executado com um atraso, ou seja, ele não rodará imediatamente quando o pipeline for iniciado.
  • start_in: 1 minute: Define o tempo de atraso antes de o job começar a ser executado. Nesse caso, o job vai começar 1 minuto após o início do pipeline.
  • script:: Define o comando que será executado. Neste caso, o job vai rodar o comando echo “execução em 1 minuto”, que imprime essa mensagem no terminal.

adicionando estagios(tarefas) para o pipeline

caso a etapa 1 execute com sucesso ele executa um script

na etapa 2 caso a etapa1 falhe ele executa o script da etapa 2. um exemplo pratico disso é envio de email, se der sucesso ele envia um email de sucesso e se der falha faz outra coisa

stages:

 - e1

 - e2

 - e3

Etapa1:

 stage: e1

 when: on_success

 script:

   - echo "Etapa1"

Etapa2:

 stage: e2

 when: on_failure

 script:

   - echo "Falha na etapa 1"

Etapa3:

 stage: e3

 when: always

 script:

   - echo "sempre sera executado"

resultado:

Esse código possui três estágios e três jobs, cada um com condições específicas de execução. 

1. Definição dos Estágios

stages:

 - e1

 - e2

 - e3

Aqui, o pipeline é dividido em três estágios: e1, e2 e e3. O GitLab executa os estágios na ordem definida. Cada job é atribuído a um desses estágios.

2. Job Etapa1

Etapa1:

 stage: e1

 when: on_success

 script:

   – echo “Etapa1”

  • stage: e1: Esse job pertence ao estágio e1.
  • when: on_success: O job Etapa1 será executado apenas se o estágio anterior (se houver) for bem-sucedido. Neste caso, ele será executado automaticamente, já que é o primeiro estágio.
  • script:: O job executa o comando echo “Etapa1”, imprimindo essa mensagem no terminal.

3. Job Etapa2

Etapa2:

 stage: e2

 when: on_failure

 script:

   – echo “Falha na etapa 1”

  • stage: e2: Esse job pertence ao estágio e2.
  • when: on_failure: O job Etapa2 só será executado se o job anterior (Etapa1) falhar.
  • script:: Se for executado, o job imprime a mensagem echo “Falha na etapa 1”.

4. Job Etapa3

Etapa3:

 stage: e3

 when: always

 script:

   – echo “sempre sera executado”

  • stage: e3: Esse job pertence ao estágio e3.
  • when: always: Esse job será executado sempre, independentemente do sucesso ou falha dos estágios anteriores.
  • script:: O job imprime a mensagem echo “sempre sera executado”.

===========================================================

timeout:

o timeout define maximo de tempo que uma pipeline pode esperar o script rodar

job3:

 timeout: 1m

 script:

   - sleep 20

   - echo "executa com timeout de 1 minuto"

before_script e after_script:

executa algo antes de começar os jobs e depois que os jobs terminam ele executa alguma outra coisa

before_script:

 - echo "Antes do script"

after_script:

 - echo "Depois do script"

job4:

 script:

   - echo "executando script"

Only merge_requests, tags e variables

executa os jobs somente em situações específicas

job6:

 script:

   - echo "Executando quando há uma mesclagem"

 only:

   - merge_request

job7:

 only:

   - tags

 script:

   - echo "Executando quando a tag é criada"

 when: manual

job8:

 only:

   variables:

     - $RELEASE == 'staging'

 script:

   - echo "Executado porque declarou a variavel RELEASE com valor staging"

explicação do código:

Esse código define três jobs no arquivo .gitlab-ci.yml do GitLab, cada um com condições específicas de execução. Vamos detalhar cada job:

1. Job job6

job6:

 script:

   – echo “Executando quando há uma mesclagem”

 only:

   – merge_request

  • script:: Este job executa o comando echo “Executando quando há uma mesclagem”, que imprime a mensagem no terminal.
  • only:: O job será executado apenas em situações de merge requests. Isso significa que ele só será ativado quando houver uma solicitação de mesclagem, ou seja, quando um desenvolvedor solicitar a fusão de uma branch em outra.

2. Job job7

job7:

 only:

   – tags

 script:

   – echo “Executando quando a tag é criada”

 when: manual

  • only:: Este job será executado apenas quando uma tag for criada no repositório. Tags são marcadores usados para identificar versões específicas do código.
  • script:: Quando o job for ativado, ele executará echo “Executando quando a tag é criada”, imprimindo essa mensagem.
  • when: manual: Isso significa que, mesmo que a tag seja criada, a execução desse job precisará ser iniciada manualmente. O usuário deve clicar em “play” para que o job seja executado.

3. Job job8

job8:

 only:

   variables:

     – $RELEASE == ‘staging’

 script:

   – echo “Executado porque declarou a variavel RELEASE com valor staging”

  • only:: Este job é condicionado a uma variável de ambiente chamada RELEASE. Ele será executado somente se RELEASE tiver o valor staging.
  • script:: Se as condições forem atendidas, o job executa o comando echo “Executado porque declarou a variavel RELEASE com valor staging”, imprimindo a mensagem que explica o motivo da execução.

Execução dos jobs

executando job8:

ir em pipeline>executar pipeline e executar com  o valor staging o pipeline será criado e executado

executando job7:

ir em repositório>tags>novo tag e criar uma tag. o pipeline será criado e executado

executando job6:

criar nova ramificação no repositório chamada developer

alterar um arquivo exemplo(README) e iniciar uma solicitação de merge request da branch developer para a branch main. apó isso, ao clicar em merge ele irá realizar o job 6  que está com o gatilho only merge request

parallel:

executa jobs em paralelo

job8:

 parallel: 3

 script: echo "sleep 5"

Cache de arquivos:

Armazena arquivos do repositório em cache e você poderá baixa-los ou realizar uma série de comandos para ele.

job18:

 script:

   - echo "Exemplo de cache de arquivos."

 name: "artefato-exemplo"

 artifacts:

   expire_in: 2 minutes

   paths:

     - ./teste.txt

Utilizando os runners Docker e Shell e aprendendo needs:

build_a:

 image: alpine

 script:

   - echo "Executando um build"

   - sleep 10

 tags:

   - docker

teste_a:

 needs: [build_a]

 script:

   - docker run -dit --name teste ubuntu

 tags:

   - shell

o build_a baixa a imagem no alpine e imprime uma imagem. isso usando o runner de tag docker

o teste_a usa o need para indicar que precisa aguardar o build_a terminar a execução para iniciar. Ele usa o script pra subir uma imagem do ubuntu na minha máquina local. tudo isso utilizando o runner de tag shell

Debug e exibição de todas as variáveis:

Exibe todas as variáveis do job e podem ser utilizadas para algum tipo de gatilho

job12:

  script:

    - export

resultado:

Variáveis do CI-CD:

criando variaveis dentro do gitlab para chama-las no código de ci/cd

Vá até as configurações>CI/CD>variáveis e criar uma nova variável

job12:

script:

  - echo $senha

Esse código mostra o valor da variavel

Variáveis no arquivo .gitlab-ci.yaml:

variables:

 VAR1: "teste1"

 VAR2: "teste2"

job12_a:

script:

  - echo $VAR1

  - echo $VAR2

Executando pipeline com condições de User e branch:

se branch main e user root ele inicia um processo de pipeline manual. se branch developer ele não executa nenhuma pipeline

job13:

script:

 - echo "Pipeline executada somente na branch main e usuario executor gustavo"

rules:

 - if: '$CI_COMMIT_BRANCH == "main" && $GITLAB_USER_LOGIN == "root" '

   when: manual

 - if: '$CI_COMMIT_BRANCH == "developer" '

   when: never

Executando pipeline com except:

Executa a pipeline exceto se estiver com uma mensagem específica

job14:

script:

 - echo "Executa a pipeline exceto se tiver com mensagem push-teste"

except:

  variables:

    - $CI_COMMIT_MESSAGE =~ /push-test/

Âncora:

A âncora pega os comandos do job em que foi declarado, no caso o job10 vai utilizar todos os comandos do job9 que não estão declarados no job10

por exemplo, no job10 temos um comando de script então ele não pega o script do job 9, somente os outros comandos.

job9: &ancora

when: manual

script:

 - echo "Executa o job"

job10:

 <<: *ancora

 script: echo "Pelomenos o script foi substituido"

Ancora somente no only:

Job10 usa a âncora somente para pegar os comandos do only no job1

job1:

 only:

   variables: &variavel

     - $GATILHO == 'valor'

 script: echo "Ancora em uma sessao do Job"

job10:

 only: *variavel

 script: echo "Pelomenos o script foi substituido"

mais exemplos de uso da âncora:

.before-script: &before

 - echo "Executa script antes"

.script: &script

 - echo "Executa script por segundo"

.after-script: &after

- echo "Execute este script por ultimo"

job1:

 before_script:

   - *before

 script:

   - *script

   - echo "Execute somente, para este job"

 after_script:

   - *after

Executar pipeline via API:

Executando por tag:

adicionar novo gatilho em configurações>ci/cd>gatilho de pipeline

pegar curl e substituir pelo token gerado e referenciar

curl -X POST \

     --fail \

     -F token=TOKEN \

     -F ref=0.0.1 \

     http://seu-ip:sua-porta/api/v4/projects/2/trigger/pipeline

criar uma nova tag 0.0.1

rodar comando no .git-ci

job1:

 script: echo "Executando via API"

e depois, rodar o curl no terminal:

curl -X POST \

     --fail \

     -F token=TOKEN \

     -F ref=0.0.1 \

     http://seu-ip:sua-porta/api/v4/projects/2/trigger/pipeline

toda vez que você rodar esse comando no terminal a pipeline vai iniciar automaticamente

Executando com verificação de branch e variável:

incluir código:

job1:

 only:

   variables:

     - $GATILHO == "valor"

 script: echo "Executando via API com branch main e variável"

rodar no terminal o seguinte comando passando uma variável com valor “valor” e referênciar a branch main

o gitlab vai receber esses parâmetros e rodar o pipeline utilizando eles na verificação.

docker exec -it runner-docker \

gitlab-runner register -n \

  --url http://172.17.0.1:8080/ \

  --registration-token GR1348941ig4xM7hguPgAvLL5hkst \

  --clone-url http://172.17.0.1:8080/ \

  --executor docker \

  --docker-image "docker:latest" \

  --docker-privileged

Conclusão:

 Neste artigo, vimos como criar e configurar o GitLab localmente e exploramos diversos exemplos de comandos de CI/CD. Esses exemplos ajudam a entender como automatizar o fluxo de trabalho de desenvolvimento, utilizando pipelines para integrar e entregar software de forma mais eficiente. Espero que isso tenha esclarecido como aplicar esses conceitos em seus projetos.