refactor: migrar GitLab → Gitea (aulas 10, 11, 13)
- 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
This commit is contained in:
409
aula-13/README.md
Normal file
409
aula-13/README.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# Aula 13 - Container Factory + Lazy Pulling (eStargz)
|
||||
|
||||
Crie suas próprias imagens Docker e aprenda **quando** usar eStargz para lazy pulling.
|
||||
|
||||
## Conexão com as aulas anteriores
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Aula 10: Gitea │
|
||||
│ Git server + Container Registry + Gitea Actions (habilitado) │
|
||||
│ Chart: gitea-charts/gitea │ Chart: gitea-charts/actions │
|
||||
│ Pods: gitea, postgresql, │ Pod: act-runner + DinD │
|
||||
│ valkey │ (executa os workflows) │
|
||||
└────────────────────┬───────────────────────┬──────────────────┘
|
||||
│ │
|
||||
│ push código │ roda workflow
|
||||
│ │ (.gitea/workflows/)
|
||||
▼ ▼
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Aula 13: Container Factory │
|
||||
│ │
|
||||
│ 1. git push → Gitea recebe o código │
|
||||
│ 2. act_runner detecta .gitea/workflows/ci.yml │
|
||||
│ 3. Runner executa: docker buildx build --compression=estargz │
|
||||
│ 4. Runner faz push da imagem pro Gitea Container Registry │
|
||||
│ 5. kubectl apply → Kubernetes puxa do registry │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
O **act_runner** (Gitea Actions Runner) é a peça que conecta o `git push` ao build da imagem.
|
||||
Ele foi instalado na aula-10 via `gitea-charts/actions` — um StatefulSet com dois containers:
|
||||
|
||||
| Container | Função |
|
||||
|-----------|--------|
|
||||
| `act-runner` | Escuta o Gitea por jobs, executa workflows (sintaxe GitHub Actions) |
|
||||
| `dind` (Docker-in-Docker) | Daemon Docker privilegiado que o runner usa para `docker build`, `docker push` |
|
||||
|
||||
Sem o runner, os arquivos `.gitea/workflows/*.yml` existem no repo mas nunca executam.
|
||||
Nesta aula usamos o runner para **build automatizado de imagens eStargz** — o ciclo completo de Container Factory.
|
||||
|
||||
## Visão Geral
|
||||
|
||||
| Parte | Tema | Valor |
|
||||
|-------|------|-------|
|
||||
| **1** | Container Factory | Prático - criar imagens independentes |
|
||||
| **2** | eStargz e Lazy Pulling | Educacional - quando usar e quando NÃO usar |
|
||||
| **3** | Alternativas para Cold Start | Prático - soluções para KEDA/auto-scaling |
|
||||
|
||||
---
|
||||
|
||||
# Parte 1: Container Factory
|
||||
|
||||
## Por que criar suas próprias imagens?
|
||||
|
||||
### O Problema Bitnami
|
||||
|
||||
A partir de **28 de agosto de 2025**, a Broadcom descontinuou imagens gratuitas:
|
||||
|
||||
- Imagens movidas para repositório **legacy** (sem atualizações de segurança)
|
||||
- Tags estáveis (`postgresql:13.7.0`) não disponíveis no tier gratuito
|
||||
- Imagens atualizadas só via **Bitnami Secure** (~$72k/ano)
|
||||
|
||||
Referência: [Bitnami Issue #83267](https://github.com/bitnami/containers/issues/83267)
|
||||
|
||||
### A Solução: Container Factory
|
||||
|
||||
Criar imagens próprias baseadas nas imagens oficiais:
|
||||
- Gratuitas e mantidas pela comunidade
|
||||
- Menores e mais seguras
|
||||
- Totalmente customizáveis
|
||||
|
||||
## Estrutura do Projeto
|
||||
|
||||
```
|
||||
aula-13/
|
||||
├── README.md
|
||||
├── setup.sh
|
||||
├── cleanup.sh
|
||||
│
|
||||
├── images/
|
||||
│ ├── postgresql/ # Exemplo principal
|
||||
│ │ ├── Dockerfile
|
||||
│ │ └── postgresql.conf
|
||||
│ └── devops-toolbox/ # Demonstração eStargz
|
||||
│ ├── Dockerfile
|
||||
│ └── entrypoint.sh
|
||||
│
|
||||
├── pipelines/
|
||||
│ └── postgresql/
|
||||
│ ├── ci.yml # Gitea Actions workflow
|
||||
│ └── .gitlab-ci.yml # (legado - referência)
|
||||
│
|
||||
├── k8s/
|
||||
│ ├── postgresql/
|
||||
│ │ ├── deployment.yaml
|
||||
│ │ ├── service.yaml
|
||||
│ │ └── pvc.yaml
|
||||
│ └── prepull-daemonset.yaml # Alternativa para cold start
|
||||
│
|
||||
└── benchmarks/
|
||||
├── benchmark-postgresql.sh
|
||||
└── benchmark-toolbox.sh
|
||||
```
|
||||
|
||||
## Instalação
|
||||
|
||||
### 1. Executar Setup
|
||||
|
||||
```bash
|
||||
cd aula-13
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
### 2. Criar Projeto no Gitea
|
||||
|
||||
1. Criar org `factory` em `https://gitea.kube.quest/-/admin/orgs`
|
||||
2. Criar repositório `postgresql` na org
|
||||
3. Push dos arquivos:
|
||||
|
||||
```bash
|
||||
git clone git@gitea.kube.quest:factory/postgresql.git
|
||||
cd postgresql
|
||||
cp /path/to/aula-13/images/postgresql/* .
|
||||
mkdir -p .gitea/workflows
|
||||
cp /path/to/aula-13/pipelines/postgresql/ci.yml .gitea/workflows/ci.yml
|
||||
git add . && git commit -m "Initial commit" && git push
|
||||
```
|
||||
|
||||
### 3. Deploy
|
||||
|
||||
```bash
|
||||
kubectl apply -f k8s/postgresql/ -n factory
|
||||
kubectl get pods -n factory -w
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Parte 2: eStargz e Lazy Pulling
|
||||
|
||||
## O que é eStargz?
|
||||
|
||||
**eStargz** (Externally Seekable Stargz) permite **lazy pulling** - o container inicia ANTES de baixar a imagem completa:
|
||||
|
||||
```
|
||||
Imagem Tradicional:
|
||||
Download 100% (30s) → Extract (10s) → Start (1s) = 41s total
|
||||
|
||||
Imagem eStargz:
|
||||
Download 5% (1s) → Start (1s) → Download resto em background = 2s para iniciar
|
||||
```
|
||||
|
||||
## Quando eStargz FUNCIONA (casos reais)
|
||||
|
||||
| Empresa | Melhoria | Cenário |
|
||||
|---------|----------|---------|
|
||||
| **CERN** | 13x mais rápido | Pipelines de análise nuclear |
|
||||
| **BuildBuddy** | 10x redução latência | Executor images |
|
||||
| **AWS (SOCI)** | 10-15x melhoria | ML containers |
|
||||
|
||||
**Condições para sucesso:**
|
||||
- Imagem > 250MB (comprimida)
|
||||
- < 10% dos dados necessários no boot
|
||||
- Container que NÃO precisa de todos os arquivos para iniciar
|
||||
|
||||
## Quando eStargz NÃO ajuda
|
||||
|
||||
### Aplicações que NÃO se beneficiam:
|
||||
|
||||
| Aplicação | Tamanho | Por que NÃO funciona |
|
||||
|-----------|---------|---------------------|
|
||||
| PostgreSQL | ~100MB | Database precisa de 100% dos arquivos |
|
||||
| MongoDB | ~500MB | Database precisa de 100% dos arquivos |
|
||||
| CockroachDB | ~400MB | Database precisa de 100% dos arquivos |
|
||||
| n8n | ~500MB | Carrega TODAS as 400+ integrações no boot |
|
||||
| Laravel Octane | ~400MB | Precarrega TODA a aplicação na RAM |
|
||||
|
||||
### Por que não funcionou nos testes?
|
||||
|
||||
Benchmark com PostgreSQL mostrou **performance idêntica** entre eStargz e GZIP:
|
||||
|
||||
| Imagem | Tempo (cold start) |
|
||||
|--------|-------------------|
|
||||
| PostgreSQL eStargz | ~10s |
|
||||
| PostgreSQL GZIP | ~10s |
|
||||
|
||||
**Razões:**
|
||||
1. Imagem pequena (~100MB) - overhead do lazy pull > benefício
|
||||
2. PostgreSQL precisa de TODOS os arquivos para iniciar
|
||||
3. Não há arquivos "opcionais" para lazy load
|
||||
|
||||
## Matriz de Decisão
|
||||
|
||||
| Cenário | Usar eStargz? | Motivo |
|
||||
|---------|---------------|--------|
|
||||
| Imagem < 250MB | ❌ **Não** | Overhead > benefício |
|
||||
| Database (PostgreSQL, MySQL, MongoDB) | ❌ **Não** | Precisa de ~100% dos arquivos |
|
||||
| Apps que precarregam (Laravel Octane, n8n) | ❌ **Não** | Carrega tudo no boot |
|
||||
| Imagem > 1GB com uso parcial | ✅ **Sim** | Lazy pulling efetivo |
|
||||
| ML/AI com múltiplos modelos | ✅ **Sim** | Só baixa modelo usado |
|
||||
| DevOps toolbox (terraform, kubectl) | ✅ **Sim** | Só baixa ferramenta usada |
|
||||
| Serverless/FaaS | ✅ **Sim** | Cold start crítico |
|
||||
|
||||
## Demonstração: DevOps Toolbox (eStargz vantajoso)
|
||||
|
||||
Para demonstrar quando eStargz **realmente funciona**, criamos uma imagem grande com uso parcial:
|
||||
|
||||
```dockerfile
|
||||
# images/devops-toolbox/Dockerfile
|
||||
FROM alpine:3.21
|
||||
|
||||
# Camada 1: Base (~50MB)
|
||||
RUN apk add --no-cache bash curl wget jq git
|
||||
|
||||
# Camada 2: Terraform (~100MB)
|
||||
RUN wget -q https://releases.hashicorp.com/terraform/1.9.0/terraform_1.9.0_linux_arm64.zip && \
|
||||
unzip terraform_*.zip && mv terraform /usr/local/bin/ && rm terraform_*.zip
|
||||
|
||||
# Camada 3: Kubectl + Helm (~150MB)
|
||||
RUN curl -sLO "https://dl.k8s.io/release/v1.31.0/bin/linux/arm64/kubectl" && \
|
||||
chmod +x kubectl && mv kubectl /usr/local/bin/
|
||||
|
||||
# Camada 4: AWS CLI (~200MB)
|
||||
RUN apk add --no-cache aws-cli
|
||||
|
||||
# Camada 5: Ansible (~150MB)
|
||||
RUN apk add --no-cache python3 py3-pip && \
|
||||
pip3 install ansible --break-system-packages --quiet
|
||||
|
||||
# Total: ~650MB - mas você só usa UMA ferramenta por vez!
|
||||
```
|
||||
|
||||
**Resultado esperado:**
|
||||
- GZIP: Baixa 650MB inteiro → ~60s
|
||||
- eStargz: Baixa só camada necessária (~100MB) → ~10s
|
||||
- **Melhoria: 6x mais rápido**
|
||||
|
||||
---
|
||||
|
||||
# Parte 3: Alternativas para Cold Start
|
||||
|
||||
Se suas aplicações são databases ou apps que precarregam, use estas alternativas:
|
||||
|
||||
## Opção 1: Pre-pull DaemonSet (Recomendado)
|
||||
|
||||
Garante que imagens já estão em TODOS os nodes antes do KEDA escalar:
|
||||
|
||||
```yaml
|
||||
# k8s/prepull-daemonset.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: image-prepuller
|
||||
namespace: kube-system
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: image-prepuller
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: image-prepuller
|
||||
spec:
|
||||
initContainers:
|
||||
- name: prepull-postgres
|
||||
image: gitea.kube.quest/factory/postgresql:17
|
||||
command: ["echo", "Image pulled"]
|
||||
imagePullPolicy: Always
|
||||
- name: prepull-n8n
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
command: ["echo", "Image pulled"]
|
||||
imagePullPolicy: Always
|
||||
containers:
|
||||
- name: pause
|
||||
image: gcr.io/google_containers/pause:3.2
|
||||
imagePullSecrets:
|
||||
- name: gitea-registry
|
||||
```
|
||||
|
||||
**Resultado:** Quando KEDA escalar, imagens já estão em cache em todos os nodes.
|
||||
|
||||
## Opção 2: Over-provisioning
|
||||
|
||||
Manter `minReplicas > 0` para evitar cold starts:
|
||||
|
||||
```yaml
|
||||
# ScaledObject com mínimo de 1 réplica
|
||||
apiVersion: keda.sh/v1alpha1
|
||||
kind: ScaledObject
|
||||
spec:
|
||||
minReplicaCount: 1 # Sempre tem pelo menos 1 pod rodando
|
||||
maxReplicaCount: 10
|
||||
```
|
||||
|
||||
## Opção 3: Imagens menores
|
||||
|
||||
Reduzir tamanho da imagem para downloads mais rápidos:
|
||||
|
||||
| Base | Tamanho típico | Uso |
|
||||
|------|----------------|-----|
|
||||
| `alpine` | ~5MB | Apps Go, binários estáticos |
|
||||
| `distroless` | ~20MB | Java, Node.js |
|
||||
| `debian-slim` | ~80MB | Quando Alpine não funciona |
|
||||
|
||||
## Comparação de Soluções
|
||||
|
||||
| Solução | Cold Start | Complexidade | Custo |
|
||||
|---------|------------|--------------|-------|
|
||||
| Pre-pull DaemonSet | ⭐⭐⭐⭐⭐ | Baixa | Nenhum |
|
||||
| Over-provisioning | ⭐⭐⭐⭐ | Baixa | $$ (pods sempre rodando) |
|
||||
| Imagens menores | ⭐⭐⭐ | Média | Nenhum |
|
||||
| eStargz | ⭐⭐ (só imagens grandes) | Alta | Nenhum |
|
||||
|
||||
---
|
||||
|
||||
# Apêndice: Configuração Técnica
|
||||
|
||||
## Pipeline CI com eStargz (Gitea Actions)
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/ci.yml
|
||||
name: Build PostgreSQL
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
env:
|
||||
REGISTRY: gitea.kube.quest
|
||||
IMAGE_NAME: factory/postgresql
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ gitea.actor }} --password-stdin
|
||||
- run: |
|
||||
docker buildx build \
|
||||
--output type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest,push=true,compression=estargz,force-compression=true,oci-mediatypes=true \
|
||||
.
|
||||
```
|
||||
|
||||
| Parâmetro | Descrição |
|
||||
|-----------|-----------|
|
||||
| `compression=estargz` | Formato para lazy pulling |
|
||||
| `force-compression=true` | Recomprime camadas da base |
|
||||
| `oci-mediatypes=true` | Media types OCI (requerido) |
|
||||
|
||||
## Verificar stargz-snapshotter no Talos
|
||||
|
||||
```bash
|
||||
# Extensão instalada
|
||||
talosctl get extensionstatuses | grep stargz
|
||||
|
||||
# Configuração
|
||||
talosctl read /etc/cri/conf.d/10-stargz-snapshotter.part
|
||||
# Output: snapshotter = "stargz"
|
||||
```
|
||||
|
||||
## Testar PostgreSQL
|
||||
|
||||
```bash
|
||||
# Obter senha
|
||||
PGPASSWORD=$(kubectl get secret postgresql-secret -n factory -o jsonpath='{.data.password}' | base64 -d)
|
||||
|
||||
# Conectar
|
||||
kubectl run pg-client --rm -it --restart=Never \
|
||||
--image=postgres:17-alpine \
|
||||
--env=PGPASSWORD=$PGPASSWORD \
|
||||
-- psql -h postgresql.factory.svc.cluster.local -U postgres -d app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Conclusão
|
||||
|
||||
## Resumo
|
||||
|
||||
| Tema | Aprendizado |
|
||||
|------|-------------|
|
||||
| **Container Factory** | Crie imagens próprias para independência de terceiros |
|
||||
| **eStargz** | Só vale para imagens > 250MB com uso parcial |
|
||||
| **Cold Start** | Para databases, use pre-pull DaemonSet |
|
||||
|
||||
## Regra de Ouro
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ eStargz funciona quando: │
|
||||
│ - Imagem > 250MB │
|
||||
│ - < 10% dos dados necessários no boot │
|
||||
│ - Container NÃO precisa de todos os arquivos para iniciar │
|
||||
│ │
|
||||
│ Para databases e apps que precarregam: │
|
||||
│ → Use Pre-pull DaemonSet │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Referências
|
||||
|
||||
- [CERN: Lazy Pulling](https://indico.cern.ch/event/1338689/) - 13x mais rápido
|
||||
- [BuildBuddy: SOCI](https://www.buildbuddy.io/blog/image-streaming/) - 10x redução latência
|
||||
- [AWS: SOCI Snapshotter](https://aws.amazon.com/blogs/containers/under-the-hood-lazy-loading-container-images-with-seekable-oci-and-aws-fargate/)
|
||||
- [NTT Labs: eStargz](https://medium.com/nttlabs/startup-containers-in-lightning-speed-with-lazy-image-distribution-on-containerd-243d94522361)
|
||||
- [stargz-snapshotter](https://github.com/containerd/stargz-snapshotter)
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
./cleanup.sh
|
||||
```
|
||||
Reference in New Issue
Block a user