O GitHub é a plataforma padrão para projetos open-source e para a maioria dos times que trabalham com código público ou semi-público. Mas o GitLab ocupa um espaço diferente no mercado: é a escolha preferida de organizações que precisam de uma plataforma DevOps completa, auto-suficiente e, frequentemente, instalada em infraestrutura própria.
A diferença filosófica é importante. O GitHub nasceu como plataforma de hospedagem de código e foi adicionando funcionalidades ao longo do tempo — Actions, Packages, Security, Projects. O GitLab nasceu com a proposta de ser uma plataforma DevOps completa desde o início: repositório, CI/CD, registro de containers, gerenciamento de issues, wiki, monitoramento, segurança e muito mais, tudo integrado em um único produto.
Para o engenheiro que já domina o GitHub Actions, o GitLab CI/CD é a segunda plataforma mais importante para conhecer — não porque seja "melhor", mas porque ela aparece com frequência em contextos enterprise e em organizações que valorizam soberania sobre seus dados e pipelines.
A Estrutura do GitLab CI/CD
O arquivo de pipeline no GitLab é o .gitlab-ci.yml, que fica na raiz do repositório — equivalente ao .github/workflows/nome.yml do GitHub Actions. Mas há uma diferença estrutural importante: no GitHub Actions, cada arquivo de workflow é independente. No GitLab, há um único arquivo de pipeline por projeto (embora ele possa incluir outros arquivos via include).
O mapeamento de conceitos é o seguinte. No GitHub Actions, um workflow contém jobs que contêm steps. No GitLab CI/CD, um pipeline contém stages que agrupam jobs, e cada job contém um script. Os stages definem a ordem de execução — todos os jobs de um stage executam em paralelo, e o próximo stage só começa quando todos os jobs do stage anterior terminam.
# .gitlab-ci.yml
# Stages definem a ordem de execução
stages:
- verificacao
- build
- testes
- seguranca
- deploy-staging
- deploy-producao
# Variáveis globais (equivalente ao env: global do GitHub Actions)
variables:
NODE_VERSION: "20"
DOCKER_DRIVER: overlay2
# Variáveis sensíveis vêm das CI/CD Variables do projeto (Settings → CI/CD)
# ── Job: Lint ────────────────────────────────────────────────────
lint:
stage: verificacao
image: node:20-alpine
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
script:
- npm ci
- npm run lint
rules:
# Executar em qualquer branch ou merge request
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
# ── Job: Testes Unitários ────────────────────────────────────────
testes-unitarios:
stage: testes
image: node:20-alpine
services:
# Services são containers auxiliares — equivalente ao services: do GitHub Actions
- name: postgres:16-alpine
alias: postgres
variables:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
- name: redis:7-alpine
alias: redis
variables:
DATABASE_URL: "postgresql://testuser:testpass@postgres:5432/testdb"
REDIS_URL: "redis://redis:6379"
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
script:
- npm ci
- npm test -- --coverage
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/' # Regex para extrair cobertura do output
artifacts:
when: always
reports:
# Equivalente ao PublishTestResults do Azure DevOps
junit: test-results.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
paths:
- coverage/
expire_in: 7 days
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
Cache e Artifacts: Conceitos Distintos
O GitLab separa explicitamente dois conceitos que o GitHub Actions trata de maneira mais unificada com actions/cache e actions/upload-artifact.
O cache no GitLab é para acelerar execuções — node_modules, dependências Maven, cache do pip. Ele é armazenado no runner e reutilizado entre jobs e pipelines. A chave do cache pode ser baseada em arquivos (como o package-lock.json) para invalidar automaticamente quando as dependências mudam.
Os artifacts são saídas do job que precisam ser passadas para jobs subsequentes ou preservadas para download. Um job de build gera o binário como artifact; um job de deploy consome esse artifact. A propriedade expire_in define por quanto tempo o artifact é mantido — sem isso, o GitLab usa a configuração padrão da instância.
# Job de build que gera artifact para o job de deploy
build-imagem:
stage: build
image: docker:24
services:
- docker:24-dind # Docker-in-Docker
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
before_script:
# Login no GitLab Container Registry (equivalente ao ECR/ACR)
# CI_REGISTRY, CI_REGISTRY_USER e CI_REGISTRY_PASSWORD são variáveis automáticas
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
# Também taggear como latest na branch main
- |
if [ "$CI_COMMIT_BRANCH" == "main" ]; then
docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
docker push $CI_REGISTRY_IMAGE:latest
fi
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
Variáveis Automáticas do GitLab
O GitLab injeta dezenas de variáveis de ambiente automaticamente em cada job. Para quem vem do GitHub Actions (onde as variáveis equivalentes ficam no contexto github.*), é útil conhecer as mais usadas:
CI_COMMIT_SHA é o SHA completo do commit — equivalente ao ${{ github.sha }}. CI_COMMIT_SHORT_SHA são os primeiros 8 caracteres — muito usado para taggear imagens Docker. CI_COMMIT_BRANCH é o nome da branch atual — equivalente ao ${{ github.ref_name }}. CI_COMMIT_TAG é a tag do commit, se existir — equivalente ao ${{ github.ref }} quando é uma tag. CI_PIPELINE_SOURCE indica o que disparou o pipeline: push, merge_request_event, schedule, web e outros — equivalente ao ${{ github.event_name }}. CI_REGISTRY_IMAGE é a URL da imagem no GitLab Container Registry deste projeto — sem equivalente direto no GitHub, que precisa construir a URL manualmente. CI_PROJECT_PATH é o caminho do projeto no formato grupo/subgrupo/projeto. CI_ENVIRONMENT_URL é a URL do environment de deploy, configurada no job.
Segurança no Pipeline: SAST, DAST e Dependency Scanning
Um diferencial significativo do GitLab em relação ao GitHub Actions é a integração nativa de ferramentas de segurança. O GitLab oferece SAST (Static Application Security Testing), DAST (Dynamic Application Security Testing), Dependency Scanning e Container Scanning como templates prontos para incluir no pipeline — sem precisar configurar actions de terceiros ou criar scripts customizados.
# Incluir templates de segurança do GitLab
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
# Os jobs de segurança são adicionados automaticamente pelo include
# e executam no stage 'test' por padrão
# Configuração do Container Scanning (scan da imagem Docker)
container_scanning:
stage: seguranca
variables:
CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
CS_SEVERITY_THRESHOLD: HIGH # Falhar apenas em HIGH ou CRITICAL
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
# Configuração do SAST
sast:
stage: seguranca
variables:
SAST_EXCLUDED_PATHS: "spec,test,tests,tmp,node_modules"
Os resultados de todas as ferramentas de segurança aparecem na interface do GitLab no painel de Security do projeto e nos Merge Requests — o revisor vê os findings de segurança diretamente no MR, sem precisar navegar para outro sistema.
Deploy com Environments e Revisão Manual
O GitLab tem um sistema de Environments robusto que rastreia o histórico de deploys, permite rollback visual e suporta revisão manual antes de deploys em ambientes críticos.
# ── Deploy em Staging ────────────────────────────────────────────
deploy-staging:
stage: deploy-staging
image: bitnami/kubectl:latest
environment:
name: staging
url: https://staging.minha-app.com
variables:
KUBECONFIG: $KUBECONFIG_STAGING # Secret file configurada nas CI/CD Variables
script:
- kubectl set image deployment/minha-app
app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
-n staging
- kubectl rollout status deployment/minha-app -n staging --timeout=5m
- |
# Smoke test
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://staging.minha-app.com/health)
if [ "$HTTP_STATUS" != "200" ]; then
echo "Smoke test falhou: $HTTP_STATUS"
exit 1
fi
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
# ── Deploy em Produção com Revisão Manual ─────────────────────────
deploy-producao:
stage: deploy-producao
image: bitnami/kubectl:latest
environment:
name: producao
url: https://minha-app.com
variables:
KUBECONFIG: $KUBECONFIG_PRODUCAO
# when: manual — o job só executa quando alguém clicar no botão na interface
# Equivalente ao environment com required reviewers do GitHub Actions
when: manual
# allow_failure: false garante que o pipeline fica em pausa esperando a aprovação
allow_failure: false
script:
- kubectl set image deployment/minha-app
app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
-n producao
- kubectl rollout status deployment/minha-app -n producao --timeout=10m
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
# ── Rollback Manual ───────────────────────────────────────────────
rollback-producao:
stage: deploy-producao
image: bitnami/kubectl:latest
environment:
name: producao
action: stop # Marca o environment como parado no histórico
when: manual
script:
- kubectl rollout undo deployment/minha-app -n producao
- kubectl rollout status deployment/minha-app -n producao
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
Pipelines Agendados e Multi-projeto
O GitLab suporta pipelines agendados (equivalente ao schedule trigger do GitHub Actions) configurados via interface ou API — úteis para testes noturnos, relatórios periódicos e rotações de credenciais.
Para projetos que precisam disparar pipelines em outros projetos (por exemplo, um repositório de infraestrutura que, ao mudar, deve redesenhar aplicações dependentes), o GitLab oferece o trigger:
# Pipeline que dispara outro pipeline em outro projeto
notificar-downstream:
stage: deploy-producao
trigger:
project: minha-empresa/infraestrutura-kubernetes
branch: main
strategy: depend # Aguardar o pipeline downstream terminar
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
GitLab Runners: Onde o Pipeline Executa
Os GitLab Runners são os agentes que executam os jobs — equivalente aos runners hospedados do GitHub (ubuntu-latest, windows-latest) e aos self-hosted runners. O GitLab.com oferece runners compartilhados gratuitos para projetos públicos e com limites para projetos privados. Para ambientes on-premises ou com requisitos específicos de segurança e performance, é comum instalar runners próprios.
Um runner próprio é instalado em qualquer máquina Linux, Windows ou macOS com o gitlab-runner e registrado no projeto ou grupo GitLab com um token. O executor (como o job executa) pode ser Shell (diretamente na máquina), Docker (em containers isolados — o mais comum), Kubernetes (em pods do cluster — excelente para escalonamento automático) ou VirtualBox/Parallels (em VMs).
Para registrar um runner Kubernetes no cluster:
# helm values para o GitLab Runner no Kubernetes
# helm install gitlab-runner gitlab/gitlab-runner -f values.yml
gitlabUrl: https://gitlab.com/ # Ou a URL do GitLab self-hosted
runnerToken: "TOKEN-DO-RUNNER" # Obtido em Settings → CI/CD → Runners
rbac:
create: true
runners:
config: |
[[runners]]
[runners.kubernetes]
namespace = "gitlab-runners"
image = "ubuntu:22.04"
privileged = false
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-certs"
mount_path = "/certs/client"
medium = "Memory"
O Que Vem a Seguir
Este artigo cobriu o GitLab CI/CD como plataforma SaaS e o padrão de pipelines para times que hospedam código no gitlab.com. O próximo artigo vai mais fundo: o GitLab instalado em infraestrutura própria (self-hosted), que é onde a plataforma mostra todo o seu potencial para organizações com requisitos de soberania de dados, compliance rigoroso ou simplesmente custos de licença mais previsíveis.
Referências para Aprofundamento
— Documentação do GitLab CI/CD: https://docs.gitlab.com/ee/ci/ — Variáveis Predefinidas do GitLab CI/CD: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html — GitLab Security Dashboard: https://docs.gitlab.com/ee/user/application_security/security_dashboard/ — GitLab Runner — Executor Kubernetes: https://docs.gitlab.com/runner/executors/kubernetes/ — Templates de Segurança do GitLab: https://docs.gitlab.com/ee/user/application_security/