- Aula 10: Gitea + Registry + Actions + Runner (substituiu GitLab) - gitea-values.yaml: PostgreSQL standalone, Valkey standalone, ~800Mi RAM - setup.sh/cleanup.sh: namespace gitea, Helm gitea-charts/gitea + actions - README.md: documentação completa com de→para (GitLab/Harbor/Tekton vs Gitea) - Aula 11: ArgoCD (GitOps) — removido GitLab Runner (runner vive na aula-10) - setup.sh: só ArgoCD, integração SSH com Gitea - node-bugado/.gitea/workflows/ci.yml: pipeline convertida - Aula 13: Container Factory — atualizado para Gitea - setup.sh/cleanup.sh: referências GitLab → Gitea - pipelines/postgresql/ci.yml: Gitea Actions workflow - README.md: conexão com act_runner explicada - CLAUDE.md: tabela de aulas atualizada
Aula 10 - Plataforma de Desenvolvimento (Gitea)
Git Server + Container Registry + CI/CD Runner — tudo num único deploy.
Por que esta aula existe
Nas aulas anteriores construímos um cluster Kubernetes na Hetzner com autoscaling, ingress e storage. Agora precisamos de uma plataforma de desenvolvimento para:
- Hospedar código (Git)
- Armazenar imagens Docker (Container Registry)
- Automatizar builds e deploys (CI/CD)
Normalmente, isso exigiria 3 ferramentas separadas. Nesta aula, mostramos como o Gitea entrega as 3 em um único binário.
Por que Gitea (e não GitLab, Harbor, Tekton)?
A escolha de ferramentas é uma decisão de arquitetura. No ecossistema Kubernetes, existem opções especializadas para cada peça:
De → Para
| Função | Opção "Enterprise" | O que usamos | Por quê |
|---|---|---|---|
| Git Server | GitLab CE/EE | Gitea | GitLab pede ~5Gi RAM, 8 pods, 2 nodes. Gitea pede ~500Mi, 1 pod, 1 node. |
| Container Registry | Harbor | Gitea (integrado) | Harbor é um projeto separado (~1Gi RAM, PostgreSQL, Redis, storage backend). Gitea já tem registry OCI embutido. |
| CI/CD | Tekton / GitLab CI | Gitea Actions | Tekton é poderoso mas complexo (CRDs, pipelines, tasks, triggers — curva de aprendizado alta). Gitea Actions usa sintaxe GitHub Actions, que a maioria já conhece. |
A conta fecha assim
Abordagem "enterprise" (GitLab + Harbor + Tekton):
GitLab: ~5Gi RAM, 8 pods, 40Gi storage, 2 nodes ($12.92/mês)
Harbor: ~1Gi RAM, 5 pods, 20Gi storage ($5/mês)
Tekton: ~512Mi RAM, 4 CRDs, curva de aprendizado
Total: ~6.5Gi RAM, 17+ pods (~$18/mês)
Abordagem Gitea (tudo integrado):
Gitea: ~500Mi RAM, 3 pods, 21Gi storage, 1 node ($7.41/mês)
Total: ~500Mi RAM, 3 pods (~$7/mês)
Para um workshop com cluster pequeno na Hetzner (CAX11 com 4GB RAM), a conta não fecha com a abordagem enterprise.
Mas e a sintaxe do CI?
Esse é o ponto decisivo. Gitea Actions usa sintaxe GitHub Actions — o padrão de fato da indústria:
# .gitea/workflows/ci.yml — mesma sintaxe do GitHub Actions
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t minha-app .
Se você sabe GitHub Actions, sabe Gitea Actions. Se você sabe Gitea Actions, sabe GitHub Actions. Tekton tem sua própria DSL (PipelineRun, TaskRun, etc.) que não transfere pra nenhuma outra plataforma.
Comparação visual: GitLab vs Gitea
| GitLab | Gitea | |
|---|---|---|
| RAM | ~5 Gi (request) | ~500 Mi |
| Pods | 8 (webservice, sidekiq, gitaly, shell, postgres, redis, minio, registry) | 3 (gitea, postgresql, valkey) |
| Storage | 40 Gi (4 PVCs) | 21 Gi (3 PVCs) |
| Nodes mínimos | 2 (antiAffinity webservice/sidekiq) | 1 |
| Install time | 10-15 min | 2-3 min |
| CI Syntax | .gitlab-ci.yml (proprietária) |
.gitea/workflows/*.yml (GitHub Actions) |
| Registry | Componente separado (+ MinIO/S3) | Integrado (OCI nativo) |
| Runner | gitlab-runner (Helm chart separado) |
act_runner (Helm chart separado) |
Arquitetura
Hetzner LoadBalancer
│
┌───────────────────┼──────────────┐
│ │ │
:80/:443 :22 │
│ │ │
▼ ▼ │
┌───────────────┐ ┌─────────────┐ │
│ NGINX Ingress │ │ TCP Service │ │
└───────┬───────┘ └──────┬──────┘ │
│ │ │
▼ ▼ │
┌──────────────────────────────────────────┐
│ Namespace: gitea │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Gitea Pod │ │
│ │ Web UI + API + Git + SSH │◄────┘
│ │ Container Registry (OCI) │
│ │ Gitea Actions (habilitado) │
│ └──────────────┬──────────────────┘
│ │
│ ┌──────────────┼──────────────┐
│ │ │ │
│ ▼ ▼ ▼
│ PostgreSQL Valkey act_runner
│ (10Gi) (1Gi) + DinD
│ (builds Docker)
└──────────────────────────────────────────┘
O act_runner em detalhe
O runner é instalado como um StatefulSet com 2 containers:
| Container | O que faz |
|---|---|
act-runner |
Conecta ao Gitea, escuta por jobs, executa workflows |
dind (Docker-in-Docker) |
Daemon Docker privilegiado — permite docker build e docker push dentro dos workflows |
Quando você faz git push num repo que tem .gitea/workflows/ci.yml, o fluxo é:
git push → Gitea recebe → act_runner detecta workflow
→ Runner cria container temporário
→ Executa steps (checkout, build, push)
→ Imagem vai pro Gitea Container Registry
→ Kubernetes puxa a imagem no deploy
Pré-requisitos
- Cluster Talos na Hetzner (aula-08) com:
- Hetzner CSI Driver (StorageClass: hcloud-volumes)
- NGINX Ingress Controller com LoadBalancer
- kubectl instalado
- Helm 3.x instalado
Instalação
cd aula-10
export KUBECONFIG=$(pwd)/../aula-08/kubeconfig
chmod +x setup.sh
./setup.sh
O script é interativo e pergunta:
- Hostname do Gitea (ex:
gitea.kube.quest) - FQDN completo - Usa CloudFlare? (com proxy/CDN)
- Ativar Let's Encrypt? (se não usar CloudFlare)
O que o setup.sh instala
1. cert-manager (se Let's Encrypt)
2. Gitea via Helm (gitea-charts/gitea)
- Web UI + API + Git + SSH
- Container Registry (packages)
- PostgreSQL standalone
- Valkey (cache)
3. Gitea Actions Runner via Helm (gitea-charts/actions)
- act_runner + Docker-in-Docker
- Registration token obtido automaticamente
4. TCP passthrough no NGINX para SSH (porta 22)
Opções de TLS
| Cenário | TLS Provider | Configuração |
|---|---|---|
| CloudFlare (proxy) | CloudFlare Edge | Sem cert-manager, TLS na borda |
| Outro DNS + Let's Encrypt | cert-manager | HTTP-01 challenge automático |
| Outro DNS + HTTP | Nenhum | Apenas HTTP (dev/workshop) |
Componentes e Recursos
| Componente | Chart | Memory Request | Memory Limit | Volume |
|---|---|---|---|---|
| Gitea | gitea-charts/gitea | 512Mi | 1Gi | 10Gi |
| PostgreSQL | (subchart) | 128Mi | 256Mi | 10Gi |
| Valkey | (subchart) | 32Mi | 64Mi | 1Gi |
| act_runner + DinD | gitea-charts/actions | 128Mi | 256Mi | 5Gi |
| Total | ~800Mi | ~1.6Gi | ~26Gi |
Funcionalidades
1. Container Registry (OCI)
O Gitea inclui um Container Registry OCI integrado. Sem Harbor, sem MinIO, sem componentes extras.
# Login no registry
docker login gitea.kube.quest
# Push de imagem
docker tag minha-app:v1 gitea.kube.quest/usuario/minha-app:v1
docker push gitea.kube.quest/usuario/minha-app:v1
2. Gitea Actions (CI/CD)
CI/CD integrado com sintaxe GitHub Actions. Sem Tekton, sem CRDs extras, sem DSL proprietária.
# .gitea/workflows/build.yml
name: Build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.kube.quest -u ${{ gitea.actor }} --password-stdin
docker build -t gitea.kube.quest/${{ gitea.repository }}:${{ github.sha }} .
docker push gitea.kube.quest/${{ gitea.repository }}:${{ github.sha }}
3. SSH
# Clonar via SSH
git clone git@gitea.kube.quest:usuario/projeto.git
# Configurar chave SSH: Settings → SSH/GPG Keys
Acesso
Web UI
URL: https://gitea.kube.quest
Usuário: gitea_admin
Senha: (exibida no final do setup.sh)
Container Registry
docker login gitea.kube.quest
# Username: gitea_admin
# Password: (mesma senha do admin)
Verificar Runner
# Pod do runner
kubectl get pods -n gitea -l app.kubernetes.io/name=actions
# Logs
kubectl logs -n gitea -l app.kubernetes.io/name=actions -c act-runner -f
# Workflows executados
# Via UI: https://gitea.kube.quest/{owner}/{repo}/actions
Comandos Úteis
# Ver todos os pods
kubectl get pods -n gitea
# Ver logs do Gitea
kubectl logs -n gitea -l app.kubernetes.io/name=gitea -f
# Reiniciar Gitea
kubectl rollout restart deployment -n gitea gitea
# Ver certificados (se Let's Encrypt)
kubectl get certificate -n gitea
# Desinstalar
./cleanup.sh
Troubleshooting
Pods não iniciam
kubectl get events -n gitea --sort-by='.lastTimestamp'
kubectl get pvc -n gitea
SSH não conecta
# Verificar TCP passthrough
kubectl get configmap tcp-services -n ingress-nginx -o yaml
Registry não funciona
curl -v https://gitea.kube.quest/v2/
Runner não executa workflows
# Verificar se o runner está registrado
kubectl logs -n gitea -l app.kubernetes.io/name=actions -c act-runner --tail=20
# Verificar se DinD está rodando
kubectl logs -n gitea -l app.kubernetes.io/name=actions -c dind --tail=10
# Erro "Docker connection failed" → DinD não compartilha socket
# Verificar se extraVolumeMounts do dind inclui docker-socket
Runner crashando (OOM)
O Gitea pode usar mais memória durante migrações de repos grandes. Se ocorrer OOM:
# Aumentar limit temporariamente
helm upgrade gitea gitea-charts/gitea -n gitea \
--reuse-values \
--set resources.limits.memory=1Gi
Custos
| Recurso | Custo/mês |
|---|---|
| Worker (1x CAX11) | ~$4.59 |
| Volumes (~26Gi) | ~$1.26 |
| LoadBalancer (compartilhado) | ~$1.80 (1/3) |
| Total | ~$7.65 |
Lições do Workshop
- Nem sempre precisa da ferramenta "enterprise" — Gitea substitui GitLab + Harbor + parcialmente Tekton com 10x menos recursos
- Registry integrado é suficiente para a maioria dos casos — Harbor justifica-se quando você precisa de vulnerability scanning, replicação multi-site, ou compliance (assinatura de imagens)
- Sintaxe GitHub Actions é portável — o que você aprende aqui transfere direto pro GitHub, e vice-versa
- Docker-in-Docker no Kubernetes requer namespace com PodSecurity
privileged— é o trade-off pra ter builds Docker no cluster