DevOps

GitLab Self-Hosted: Soberania Total sobre Código e Pipelines Já leu

9 min de leitura

GitLab Self-Hosted: Soberania Total sobre Código e Pipelines
Há contextos em que usar um serviço SaaS para hospedar código e pipelines não é uma opção. Organizações financeiras reguladas, defesa, saúde com dados sensíveis de pacientes, governos e empresas com políticas rígidas de

Há contextos em que usar um serviço SaaS para hospedar código e pipelines não é uma opção. Organizações financeiras reguladas, defesa, saúde com dados sensíveis de pacientes, governos e empresas com políticas rígidas de residência de dados frequentemente precisam que toda a cadeia de desenvolvimento de software opere dentro de sua própria infraestrutura. Nenhum código, nenhuma credencial, nenhum log de pipeline deve sair do ambiente controlado.

O GitLab foi desenhado desde o início para ser instalado em infraestrutura própria — não como um produto secundário, mas como o modelo principal de distribuição por anos. O GitLab.com (SaaS) só veio depois. Isso significa que a experiência de self-hosting é madura, bem documentada e com suporte de longo prazo.

Há também uma razão financeira. O GitLab.com cobra por usuário por mês nos planos pagos. Para organizações com centenas ou milhares de desenvolvedores, o custo de uma instância self-hosted com licença Enterprise Edition (ou mesmo a Community Edition gratuita) pode ser significativamente menor do que o SaaS a longo prazo.

Arquitetura do GitLab Self-Hosted

O GitLab é uma aplicação complexa composta de múltiplos componentes. Compreender a arquitetura é essencial antes de instalar, porque as decisões de infraestrutura dependem de quais componentes serão gerenciados internamente e quais serão delegados a serviços gerenciados.

Os componentes principais são: Puma (servidor web Rails que serve a interface e a API), Sidekiq (processamento de jobs em background — notificações, mirrors, CI triggers), GitLab Workhorse (proxy reverso leve que lida com uploads e operações Git pesadas), Gitaly (serviço gRPC que gerencia todos os acessos ao repositório Git — isolado por razões de segurança e performance), PostgreSQL (banco de dados principal), Redis (cache e filas do Sidekiq), e Object Storage (para artifacts, LFS, uploads e backups — S3, Azure Blob ou GCS).

Para instalações pequenas (até 500 usuários), todos esses componentes podem rodar em uma única VM. Para instalações médias e grandes, a arquitetura de referência do GitLab recomenda separar os componentes: banco de dados gerenciado (RDS ou equivalente), Redis gerenciado (ElastiCache), object storage separado, e múltiplos nós Puma/Sidekiq atrás de um load balancer.

Instalação com Docker Compose (Ambientes Menores)

Para ambientes de desenvolvimento, staging e instalações com até algumas dezenas de usuários, o Docker Compose oferece a forma mais rápida de ter um GitLab funcional:

# docker-compose.yml
version: '3.8'

services:
  gitlab:
    image: gitlab/gitlab-ee:latest  # EE para funcionalidades enterprise; CE para community
    container_name: gitlab
    restart: always
    hostname: 'gitlab.empresa.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.empresa.com'

        # PostgreSQL externo (recomendado para produção)
        gitlab_rails['db_adapter'] = 'postgresql'
        gitlab_rails['db_host'] = 'postgres'
        gitlab_rails['db_port'] = 5432
        gitlab_rails['db_database'] = 'gitlabhq_production'
        gitlab_rails['db_username'] = 'gitlab'
        gitlab_rails['db_password'] = ENV['DB_PASSWORD']

        # Redis externo
        gitlab_rails['redis_host'] = 'redis'
        gitlab_rails['redis_port'] = 6379

        # Object storage (S3 ou compatível — MinIO no self-hosted)
        gitlab_rails['object_store']['enabled'] = true
        gitlab_rails['object_store']['connection'] = {
          'provider' => 'AWS',
          'region' => 'us-east-1',
          'aws_access_key_id' => ENV['MINIO_ACCESS_KEY'],
          'aws_secret_access_key' => ENV['MINIO_SECRET_KEY'],
          'endpoint' => 'http://minio:9000',
          'path_style' => true
        }
        gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts'
        gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs'
        gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads'
        gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages'

        # SSL — Let's Encrypt automático (precisa de porta 80 pública)
        # letsencrypt['enable'] = true
        # Para certificado próprio:
        nginx['ssl_certificate'] = '/etc/gitlab/ssl/gitlab.empresa.com.crt'
        nginx['ssl_certificate_key'] = '/etc/gitlab/ssl/gitlab.empresa.com.key'

        # SMTP para notificações
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = 'smtp.empresa.com'
        gitlab_rails['smtp_port'] = 587
        gitlab_rails['smtp_user_name'] = 'gitlab@empresa.com'
        gitlab_rails['smtp_password'] = ENV['SMTP_PASSWORD']
        gitlab_rails['smtp_domain'] = 'empresa.com'
        gitlab_rails['smtp_authentication'] = 'login'
        gitlab_rails['smtp_enable_starttls_auto'] = true

        # Integração com Active Directory / LDAP (muito comum em enterprise)
        gitlab_rails['ldap_enabled'] = true
        gitlab_rails['ldap_servers'] = YAML.load <<-EOS
          main:
            label: 'Active Directory'
            host: 'ad.empresa.com'
            port: 636
            uid: 'sAMAccountName'
            encryption: 'simple_tls'
            bind_dn: 'CN=gitlab-svc,OU=ServiceAccounts,DC=empresa,DC=com'
            password: '#{ENV["LDAP_PASSWORD"]}'
            base: 'OU=Users,DC=empresa,DC=com'
            group_base: 'OU=Groups,DC=empresa,DC=com'
        EOS

        # Limites de performance
        puma['worker_processes'] = 4
        sidekiq['concurrency'] = 20

    ports:
      - '80:80'
      - '443:443'
      - '22:22'  # SSH para Git
    volumes:
      - gitlab-config:/etc/gitlab
      - gitlab-logs:/var/log/gitlab
      - gitlab-data:/var/opt/gitlab
      - ./ssl:/etc/gitlab/ssl:ro
    env_file:
      - .env

  postgres:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: gitlabhq_production
      POSTGRES_USER: gitlab
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redis-data:/data

  minio:
    image: minio/minio:latest
    restart: always
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
      MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
    volumes:
      - minio-data:/data
    ports:
      - '9001:9001'  # Console MinIO (apenas interno)

volumes:
  gitlab-config:
  gitlab-logs:
  gitlab-data:
  postgres-data:
  redis-data:
  minio-data:

Instalação no Kubernetes com Helm (Produção)

Para instalações de produção com alta disponibilidade, o GitLab oferece um chart Helm oficial que distribui os componentes em pods separados, com escalonamento independente e alta disponibilidade:

# values.yml para o GitLab Helm Chart
# helm repo add gitlab https://charts.gitlab.io/
# helm install gitlab gitlab/gitlab -f values.yml -n gitlab --create-namespace

global:
  hosts:
    domain: empresa.com
    # gitlab.empresa.com, registry.empresa.com, minio.empresa.com

  ingress:
    configureCertmanager: true
    class: nginx

  # PostgreSQL externo — usar RDS ou Azure Database em produção
  psql:
    host: rds-gitlab.xxxxxx.sa-east-1.rds.amazonaws.com
    port: 5432
    database: gitlabhq_production
    username: gitlab
    password:
      secret: gitlab-postgres-secret
      key: password

  # Redis externo
  redis:
    host: gitlab-redis.xxxxxx.cache.amazonaws.com
    auth:
      secret: gitlab-redis-secret
      key: password

  # Object storage — S3
  minio:
    enabled: false  # Usar S3 real em produção
  appConfig:
    object_store:
      enabled: true
      proxy_download: true
      connection:
        secret: gitlab-s3-secret
        key: connection

  # LDAP / Active Directory
  appConfig:
    ldap:
      enabled: true
      servers:
        main:
          label: 'Active Directory'
          host: 'ad.empresa.com'
          port: 636
          uid: 'sAMAccountName'
          encryption: 'simple_tls'
          bind_dn: 'CN=gitlab-svc,OU=ServiceAccounts,DC=empresa,DC=com'
          base: 'OU=Users,DC=empresa,DC=com'

# Componentes gerenciados pelo chart
gitlab:
  webservice:
    replicaCount: 3
    resources:
      requests:
        cpu: "500m"
        memory: "1.5Gi"
      limits:
        cpu: "2"
        memory: "3Gi"

  sidekiq:
    replicaCount: 2
    resources:
      requests:
        cpu: "250m"
        memory: "1Gi"

  gitaly:
    persistence:
      size: 500Gi
      storageClass: gp3

# Nginx Ingress Controller
nginx-ingress:
  enabled: true

# Cert-Manager para SSL automático
certmanager-issuer:
  email: ops@empresa.com

Backups e Recuperação

O backup do GitLab self-hosted é uma responsabilidade que não existe no SaaS — e é onde muitas instalações falham. O GitLab fornece um rake task oficial para backups que cobre todos os dados da aplicação:

#!/bin/bash
# scripts/backup-gitlab.sh
# Executado diariamente via cron ou pipeline agendado

set -euo pipefail
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BUCKET="s3://empresa-gitlab-backups"

echo "[$TIMESTAMP] Iniciando backup do GitLab..."

# Para instalação Docker:
docker exec gitlab gitlab-backup create \
  BACKUP=backup_$TIMESTAMP \
  SKIP=registry  # Registry tem volume próprio — backup separado

# Para instalação Kubernetes:
# kubectl exec -n gitlab deploy/gitlab-webservice -- \
#   gitlab-backup create BACKUP=backup_$TIMESTAMP

echo "Backup criado. Enviando para S3..."

# O GitLab já envia para object storage se configurado
# Mas para garantia extra, copiar também para um bucket de backup:
aws s3 cp \
  /var/opt/gitlab/backups/backup_${TIMESTAMP}_gitlab_backup.tar \
  $BUCKET/gitlab/ \
  --storage-class STANDARD_IA

# Backup das configurações (não incluídas no backup padrão)
# ATENÇÃO: contém chaves secretas — criptografar antes de armazenar
tar -czf /tmp/gitlab-config-$TIMESTAMP.tar.gz /etc/gitlab/
aws kms encrypt \
  --key-id alias/gitlab-backup-key \
  --plaintext fileb:///tmp/gitlab-config-$TIMESTAMP.tar.gz \
  --output text \
  --query CiphertextBlob | \
  aws s3 cp - $BUCKET/config/gitlab-config-$TIMESTAMP.tar.gz.enc

# Limpar arquivos temporários
rm -f /tmp/gitlab-config-$TIMESTAMP.tar.gz

echo "[$TIMESTAMP] Backup concluído."

# Verificar que backups antigos estão sendo removidos (retenção 30 dias)
aws s3 ls $BUCKET/gitlab/ | \
  awk '{print $4}' | \
  sort | \
  head -n -30 | \
  xargs -I{} aws s3 rm $BUCKET/gitlab/{}

Atualizações: O Maior Desafio do Self-Hosted

Manter um GitLab self-hosted atualizado é o aspecto operacional mais trabalhoso. O GitLab lança uma nova versão minor todo mês (no dia 22) e patches de segurança conforme necessário. Saltar versões sem seguir o caminho de upgrade pode corromper o banco de dados.

A regra fundamental é: nunca pular mais de uma versão minor por vez, e sempre passar pelas versões marcadas como "upgrade stops" pelo GitLab. O path de upgrade de 16.0 para 17.2, por exemplo, precisa passar por versões intermediárias específicas.

Para instalações Docker, o processo de atualização é:

# Verificar a versão atual
docker exec gitlab gitlab-rake gitlab:env:info | grep "GitLab version"

# Verificar o caminho de upgrade recomendado em:
# https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/

# Fazer backup antes de qualquer upgrade
docker exec gitlab gitlab-backup create

# Atualizar a imagem (substituir pela versão específica do upgrade path)
docker pull gitlab/gitlab-ee:17.1.0-ee.0

# Atualizar o docker-compose.yml e recriar o container
docker compose up -d gitlab

# Aguardar o GitLab reconfigure e as migrações de banco
docker logs -f gitlab | grep -E "gitlab Reconfigured|Running reconfigure"

 

Vimos a instalação e operação do GitLab self-hosted — do Docker Compose para ambientes menores até o Helm Chart para produção em Kubernetes, passando por backups e estratégia de atualizações. O próximo artigo sai do ecossistema GitLab e cobre o Bitbucket, a plataforma Git do ecossistema Atlassian, relevante para organizações que já usam Jira e Confluence como ferramentas centrais de gestão.

Referências para Aprofundamento

— GitLab Helm Chart — Documentação Oficial: https://docs.gitlab.com/charts/ — GitLab Backup e Restore: https://docs.gitlab.com/ee/administration/backup_restore/ — GitLab Upgrade Path Tool: https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/ — GitLab Reference Architectures: https://docs.gitlab.com/ee/administration/reference_architectures/ — GitLab LDAP Integration: https://docs.gitlab.com/ee/administration/auth/ldap/

Comentários

Mais em DevOps

AWS na Prática: EC2, VPC e IAM em Profundidade
AWS na Prática: EC2, VPC e IAM em Profundidade

Os artigos anteriores introduziram EC2, VPC e IAM como parte da prática com T...

O Que é CI/CD e Por Que Sua Empresa Precisa Disso
O Que é CI/CD e Por Que Sua Empresa Precisa Disso

Para compreender o valor do CI/CD, é necessário primeiro entender o que exist...

Introdução ao Monitoramento: Métricas, Logs e Traces
Introdução ao Monitoramento: Métricas, Logs e Traces

Existe uma diferença fundamental entre um sistema que funciona e um sistema q...