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/