Skip to content

Integração SP-Franca

Integracao SP-Franca — Arquitetura

Objetivo

Integrar os sites Franca e Sao Paulo numa malha unificada onde:

  • GPU jobs flutuam entre sites conforme disponibilidade
  • Servicos de dados (Qdrant, Neo4j, PostgreSQL) sao acessiveis de qualquer cluster transparentemente
  • Cada site opera autonomamente durante particoes de rede
  • VMs e bare metal participam da mesma malha de rede que os pods K8s

Principio central

Cada ferramenta resolve exatamente UM problema. Nenhuma e a plataforma inteira.

Rede, federation, scheduling e roteamento de IA sao camadas independentes. Nenhuma ferramenta substitui outra — elas se complementam.


Visao geral: quem faz o que

┌────────────────────────────────────────────────────────────────────┐
│ PLANO DE CONTROLE │
│ │
│ ArgoCD ──→ Karmada API ──→ PropagationPolicy ──→ Member Clusters │
│ (o que) (para onde) (como distribuir) │
│ │
│ TensorZero ──→ vLLM/Whisper (qual backend usar, qual cluster) │
│ (roteamento de requests GPU em tempo real) │
├────────────────────────────────────────────────────────────────────┤
│ PLANO DE REDE │
│ │
│ VyOS WireGuard ──→ tunel L3 entre sites │
│ Cilium ──→ CNI dentro de cada cluster │
│ Cilium Cluster Mesh ──→ service discovery cross-cluster │
│ Cilium External Workloads ──→ VMs e bare metal na malha │
├────────────────────────────────────────────────────────────────────┤
│ PLANO DE EXECUCAO (por cluster) │
│ │
│ K3s ──→ container runtime │
│ Kueue ──→ fila local de GPU jobs │
│ KAI Scheduler ──→ GPU sharing dentro do node │
├────────────────────────────────────────────────────────────────────┤
│ CROSS-SITE BATCH │
│ │
│ MultiKueue ──→ despacha jobs para o cluster com GPU livre │
└────────────────────────────────────────────────────────────────────┘

Catalogo de ferramentas

Cada ferramenta responde UMA pergunta

FerramentaPergunta que respondeEscopo
VyOS WireGuard”Como os sites se conectam via IP?”Rede L3 entre sites
Cilium”Como pods ganham IP e policies?”CNI dentro de cada cluster
Cilium Cluster Mesh”Como um pod em SP encontra um service em Franca?”Service discovery cross-cluster
Cilium External Workloads”Como VMs e bare metal participam da mesma malha?”Estender Cilium para fora do K8s
Karmada”Onde esse Deployment roda? E se um site cair?”Placement + failover de workloads
ArgoCD”O que deve estar deployed? O Git e a fonte de verdade”GitOps, sync de manifests
Kueue”Tem GPU livre para esse job? Se nao, espere na fila”Fila de jobs dentro do cluster
MultiKueue”Franca esta lotada, SP tem GPU livre?”Fila de jobs cross-cluster
KAI Scheduler”Como 2 pods compartilham a mesma A5000?”GPU sharing dentro do node
TensorZero”Qual backend atende esse request agora?”Roteamento HTTP model-aware

Detalhamento por camada

1. VyOS WireGuard — tunel L3 entre sites

O que e: tunel criptografado ponto-a-ponto entre os dois roteadores VyOS (Franca e SP).

Papel: criar conectividade IP entre as redes internas dos dois sites. Sem isso, os clusters nao se enxergam.

Topologia:

Franca (192.168.0.0/23) SP (192.168.2.0/23)
VyOS 200.145.122.96 ←── WireGuard ──→ VyOS <IP-publico-SP>
wg0: 10.0.0.1/30 wg0: 10.0.0.2/30
Rotas:
Franca: 192.168.2.0/23 via 10.0.0.2 (wg0)
SP: 192.168.0.0/23 via 10.0.0.1 (wg0)

Por que WireGuard e nao Headscale: Headscale e mesh (N-to-N), bom para laptops e nodes dinamicos. WireGuard site-to-site e mais simples e deterministico para dois roteadores fixos. Menos pecas moveis.

Risco: a rede entre sites (UNESP/ANSP) pode ter latencia ou particoes — por isso clusters autonomos e nao cluster unico.


2. Cilium — CNI (Container Network Interface)

O que e: o “driver de rede” do Kubernetes. Substitui o Flannel padrao do K3s.

Papel dentro de cada cluster:

  • Atribui IPs a pods
  • Aplica NetworkPolicies (L3/L4/L7)
  • Faz load balancing entre pods (kube-proxy replacement)
  • Observabilidade de rede (Hubble)

Por que trocar Flannel por Cilium: Flannel e L3 puro, sem policies, sem observabilidade, e nao suporta Cluster Mesh. Cilium e pre-requisito para conectar os clusters.

Instalacao (cluster novo):

Terminal window
# K3s SP (novo, limpo):
k3s server --flannel-backend=none --disable-network-policy --disable=servicelb
# Cilium via Helm:
helm install cilium cilium/cilium \
--namespace kube-system \
--set cluster.name=sp \
--set cluster.id=2 \
--set ipam.mode=kubernetes \
--set kubeProxyReplacement=true

3. Cilium Cluster Mesh — service discovery cross-cluster

O que e: extensao do Cilium que conecta dois (ou mais) clusters numa malha de servicos.

Papel: tornar um Service de um cluster visivel no outro transparentemente. Um pod em SP pode chamar qdrant.default.svc.cluster.local e o Cilium roteia para Franca se e la que o Qdrant roda.

Como funciona:

Cluster Franca (cluster.id=1) Cluster SP (cluster.id=2)
┌──────────────────────┐ ┌──────────────────────┐
│ clustermesh-apiserver │←── mTLS ────→│ clustermesh-apiserver │
│ (expoe services) │ (via WG) │ (expoe services) │
└──────────────────────┘ └──────────────────────┘

Annotations em Services:

metadata:
annotations:
service.cilium.io/global: "true" # visivel cross-cluster
service.cilium.io/affinity: "local" # prefere local, fallback remoto
service.cilium.io/shared: "true" # ambos os clusters servem

Roteamento por tipo de servico:

Tipo de chamadaQuem roteiaPor que
GPU (vLLM, Whisper, embeddings)TensorZeroModel-aware, A/B test, fallback cloud
Batch GPU (fine-tuning, OCR lote)Kueue MultiKueueQueue-aware, despacha para cluster com GPU livre
Dados (Trino, Neo4j, PostgreSQL, Qdrant)Cilium Global ServicesService discovery transparente cross-cluster

4. Cilium External Workloads — VMs e bare metal na malha

O que e: extensao do Cilium que permite VMs e hosts bare metal participarem da mesma malha de rede dos pods K8s, com identidade, policies e observabilidade.

Impacto na topologia:

Hoje (3 mundos separados):
VyOS (rede) ←→ VMs (IPs fixos) ←→ K3s (pods, outro mundo de rede)
Cada fronteira = NAT rules, firewall rules, IPs hardcoded
Com Cilium External Workloads (malha unica):
Cilium mesh (tudo: pods + VMs + bare metal)
└── identidade unica por workload
└── policy unica (L3/L4/L7)
└── observabilidade unica (Hubble)
└── VyOS so faz borda internet ↔ rede interna

Casos de uso concretos:

WorkloadOnde rodaBeneficio
debian-proxy (Traefik)VM standaloneAcessa pods diretamente com mTLS, sem NodePort/NAT
vm-cpps-03VMCrawlers e processos Python ganham identidade Cilium
Nodes Proxmox com GPUBare metalLINSTOR satellite visivel como endpoint, com health check
DRBD replication cross-siteBare metalComunicacao via malha criptografada do Cilium

Comparacao com e sem:

| Sem Cilium (hoje) | Com Cilium External Workloads | |---|---|---| | Traefik → K3s via NodePort + IP fixo | Traefik → pods via service discovery direto | | VMs acessam cluster via kubectl/kubeconfig | VMs sao parte da malha, mesmas policies | | NetworkPolicy so dentro do K3s | NetworkPolicy se estende para VMs | | Observabilidade de rede para na borda do cluster | Hubble ve fluxos VM↔pod | | Acesso a LINSTOR via IP hardcoded | LINSTOR como endpoint Cilium |

Limitacao: replicacao DRBD high-throughput dentro do mesmo site deve usar rede L2 direta — o overhead de criptografia pode impactar. Para storage cross-site, o custo e aceitavel.


5. Karmada — orquestracao multi-cluster

O que e: control plane Kubernetes que distribui recursos para multiplos clusters. Voce fala com a API do Karmada como se fosse um cluster — ele propaga para os clusters reais.

Papel: decidir onde cada workload roda, com que configuracao, e o que fazer quando um cluster falha.

3 conceitos centrais:

a) PropagationPolicy — para onde vai

apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: vllm-spread
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: vllm
placement:
clusterAffinity:
clusterNames: [franca, sp]
replicaScheduling:
replicaDivisionPreference: Weighted
weightPreference:
staticWeightList:
- targetCluster:
clusterNames: [franca]
weight: 1
- targetCluster:
clusterNames: [sp]
weight: 1

“vLLM roda nos dois clusters, distribuido igualmente.” Karmada olha a capacidade real (via ResourceEstimator) e ajusta.

b) OverridePolicy — ajustes por cluster

apiVersion: policy.karmada.io/v1alpha1
kind: OverridePolicy
metadata:
name: vllm-franca
spec:
targetCluster:
clusterNames: [franca]
overriders:
plaintext:
- path: /spec/template/spec/nodeSelector/gpu.model
operator: replace
value: "a5500"

“Em Franca, o vLLM usa nodeSelector para A5500.” Sem override, usaria o default do manifest.

c) Failover — o que acontece quando um cluster cai

placement:
spreadConstraints:
- spreadByField: cluster
maxGroups: 2
minGroups: 1
clusterTolerations:
- effect: NoExecute
tolerationSeconds: 300 # 5min para failover

Se SP cai, apos 5 minutos o Karmada reschedula os workloads de SP para Franca (se tiver capacity).

Onde roda: no cluster Franca como “host cluster”. Instala apiserver + controller-manager + scheduler proprios. Os clusters reais se registram como members.


6. ArgoCD + Karmada — integracao

Modelo escolhido: ArgoCD → Karmada API (Opcao A)

Git repo (colabhd/devops)
↓ sync
ArgoCD (Franca)
↓ deploy para
Karmada API Server
↓ PropagationPolicy + OverridePolicy
├── K3s Franca (member cluster)
└── K3s SP (member cluster)

Um ArgoCD so. Ele deploya no Karmada, que propaga para os member clusters. Se o control plane Karmada cair, os clusters continuam rodando o que ja tem deployed.

Alternativa futura (Opcao B): ArgoCD em cada cluster. Mais resiliente (se Franca cai, SP continua com ArgoCD proprio), mas mais pecas. Migrar quando a autonomia do SP se tornar critica.


7. Kueue — fila local de GPU jobs

O que e: admission controller que gerencia filas de jobs dentro de um cluster.

Papel: quando chega um job batch (fine-tuning, OCR em lote, eval), o Kueue coloca na fila e libera conforme a GPU fica disponivel. Evita overcommit.

Job "fine-tuning-llama" chega
Kueue ClusterQueue "gpu-batch" (quota: 2 GPUs)
↓ GPU livre?
sim → admite o job, pod inicia
nao → fila, espera outro job terminar

Sem Kueue: o job seria agendado pelo scheduler e disputaria GPU com servicos interativos (vLLM), degradando a API.


8. MultiKueue — batch cross-site

O que e: plugin do Kueue que conhece filas em multiplos clusters.

Papel: quando um job batch chega e o cluster local esta lotado, o MultiKueue despacha para o outro cluster.

Job "ocr-lote-500pdfs" chega em Franca
Kueue Franca: fila cheia (3 GPUs ocupadas)
MultiKueue consulta Kueue SP: 1 GPU livre
Job e despachado para SP via Karmada

Sem MultiKueue: o job ficaria na fila de Franca esperando, mesmo com GPU livre em SP.


9. TensorZero — gateway de requests GPU em tempo real

O que e: API gateway OpenAI-compatible que roteia requests para backends de IA.

Papel diferente do Karmada: Karmada distribui Deployments (onde o pod roda). TensorZero roteia requests HTTP (qual backend atende essa chamada).

Pesquisador chama POST /v1/chat/completions
TensorZero avalia:
- modelo pedido: llama-3.1-70b
- backends disponiveis: vLLM-Franca (latencia 50ms), vLLM-SP (latencia 120ms)
- A/B test ativo? sim → 80% Franca, 20% SP
- rate limit do usuario? ok
Roteia para vLLM-Franca

Por que TensorZero e nao so Cilium load balancing: Cilium faz L4/L7 generico. TensorZero entende modelos de IA — sabe que llama-70b precisa de mais VRAM, sabe fazer fallback para cloud se ambos os sites estao lotados, faz A/B testing entre modelos.


Topologia alvo

┌─── Site Franca ──────────────────────────────────────────────────────┐
│ │
│ VyOS (200.145.122.96) │
│ ├── NAT/Firewall (borda internet) │
│ └── WireGuard wg0: 10.0.0.1/30 ──────────────────────┐ │
│ │ │
│ K3s Cluster Franca (Cilium CNI, cluster.id=1) │ │
│ ├── Control Plane │ │
│ ├── GPU Nodes: 3x A5500 (24GB) = 72 GB VRAM │ │
│ ├── Karmada Control Plane (host cluster) │ │
│ ├── ArgoCD (single instance → Karmada API) │ │
│ ├── Cilium Cluster Mesh apiserver │ │
│ ├── Kueue + MultiKueue │ │
│ ├── TensorZero (AI gateway) │ │
│ ├── vLLM, Whisper, Docling, BGE-M3 │ │
│ └── Servicos de dados: Qdrant, Neo4j, PostgreSQL │ │
│ │ │
│ Cilium External Workloads: │ │
│ ├── debian-proxy (Traefik) ← malha Cilium │ │
│ ├── vm-cpps-03 ← malha Cilium │ │
│ └── pve-labri-31/32/33 (LINSTOR) ← malha Cilium │ │
│ │ │
└──────────────────────────────────────────────────────────┼───────────┘
WireGuard (UNESP/ANSP) │
Cilium Cluster Mesh (mTLS) │
Karmada federation │
MultiKueue cross-site │
┌─── Site SP ──────────────────────────────────────────────┼───────────┐
│ │ │
│ VyOS (<IP-publico-SP>) │ │
│ ├── NAT/Firewall (borda internet) │ │
│ └── WireGuard wg0: 10.0.0.2/30 ──────────────────────┘ │
│ │
│ K3s Cluster SP (Cilium CNI, cluster.id=2) │
│ ├── Control Plane │
│ ├── GPU Nodes: 3x A5000 (24GB) = 72 GB VRAM │
│ ├── Karmada member cluster │
│ ├── Cilium Cluster Mesh apiserver │
│ ├── Kueue (local) │
│ ├── vLLM, Whisper, Docling, BGE-M3 │
│ └── Replicas de servicos web │
│ │
│ Cilium External Workloads: │
│ └── pve-ippri-31/33/34 (LINSTOR + GPU) ← malha Cilium │
│ │
└──────────────────────────────────────────────────────────────────────┘

Fases de implementacao

Cada fase funciona independente das seguintes. Ordem ditada por dependencias tecnicas.

Phase A — Cilium como CNI

Pre-requisito: nenhum (pode comecar imediatamente no cluster SP novo)

StepTarefaDetalhe
A.1Provisionar K3s SP com Cilium--flannel-backend=none --disable-network-policy --disable=servicelb + Helm install Cilium (cluster.id=2)
A.2Migrar K3s Franca para CiliumOpcao segura: criar K3s Franca novo com Cilium, redeployar via ArgoCD (GitOps = manifests sao fonte de verdade). Opcao rapida: migrar in-place com janela de manutencao (downtime)
A.3Onboard VMs na malha CiliumInstalar cilium-agent em debian-proxy, vm-cpps-03. Testar: pod → VM e VM → pod sem NAT
A.4Onboard nodes ProxmoxInstalar cilium-agent em pve-labri-31/32/33 e pve-ippri-31/33/34. LINSTOR acessivel como endpoint Cilium

Validacao: cilium connectivity test em cada cluster. Hubble mostrando fluxos pod ↔ VM.

Risco principal: migracao Flannel→Cilium no cluster Franca de producao. Mitigacao: usar a via GitOps (criar cluster novo, ArgoCD sincroniza tudo).

Artefatos no repo:

apps/cilium/
├── values-franca.yaml # cluster.name=franca, cluster.id=1
└── values-sp.yaml # cluster.name=sp, cluster.id=2

Phase B — Conectividade cross-site

Pre-requisito: Phase A (Cilium em ambos os clusters)

StepTarefaDetalhe
B.1VyOS WireGuard site-to-siteConfigurar tunel wg0 entre VyOS Franca e VyOS SP. Rotas estaticas para subnets remotas
B.2Cilium Cluster Meshcilium clustermesh enable em ambos. Conectar via cilium clustermesh connect
B.3Testar Global ServicesCriar service de teste com service.cilium.io/global: "true" em Franca, acessar de SP

Validacao: cilium clustermesh status mostra ambos os clusters connected. Pod em SP resolve DNS de service em Franca.

Artefatos no repo:

config/vyos/wireguard/
├── franca.conf # interface wg0, peer SP
└── sp.conf # interface wg0, peer Franca

Phase C — Karmada (federation)

Pre-requisito: Phase B (clusters conectados via Cluster Mesh)

StepTarefaDetalhe
C.1Instalar Karmada control planeHelm chart karmada-io/karmada no cluster Franca (host cluster)
C.2Registrar member clusterskarmadactl join franca + karmadactl join sp
C.3Configurar ArgoCD → Karmada APIArgoCD destination aponta para Karmada API server em vez de kubernetes.default.svc
C.4Instalar ResourceEstimatorPara Karmada ter visao de GPU capacity em cada cluster
C.5Definir PropagationPoliciesGPU services (spread), data services (affinity Franca), web services (replicas)
C.6Definir OverridePoliciesnodeSelector por cluster (a5500 vs a5000), resource limits
C.7Testar failoverSimular queda de SP, verificar rescheduling para Franca

Validacao: karmadactl get clusters mostra ambos Ready. Deploy via ArgoCD propaga para os dois clusters. Failover funciona em <5min.

Artefatos no repo:

apps/karmada/
├── values.yaml # Helm values do control plane
├── propagation-policies/
│ ├── gpu-services.yaml # vLLM, Whisper, Docling — spread
│ ├── data-services.yaml # Qdrant, Neo4j — affinity Franca
│ └── web-services.yaml # Open WebUI, Backstage — replicas
├── override-policies/
│ ├── franca.yaml # gpu.model=a5500
│ └── sp.yaml # gpu.model=a5000

Phase D — MultiKueue (batch cross-site)

Pre-requisito: Phase C (Karmada) + Kueue local em cada cluster (Phase 5 do gpu-platform.md)

StepTarefaDetalhe
D.1Kueue em cada clusterHelm install Kueue com ClusterQueues locais (gpu-interactive, gpu-batch)
D.2MultiKueue admission controllerConfigurar no Karmada para despacho cross-site
D.3ClusterQueues cross-siteFairness: dinamico baseado em GPU livre, nao peso fixo
D.4Testar batch cross-siteSubmeter job (fine-tuning Unsloth) com Franca lotada, verificar despacho para SP

Validacao: job batch submetido em Franca e despachado para SP quando GPUs de Franca estao ocupadas.

Artefatos no repo:

apps/kueue/
├── values-franca.yaml
├── values-sp.yaml
├── cluster-queues/
│ ├── gpu-franca.yaml
│ └── gpu-sp.yaml
apps/karmada/multikueue/
├── multikueue-config.yaml

Sequencia consolidada

StepO quePre-requisitoRisco
A.1K3s SP com CiliumNodes SP prontosBaixo
A.2K3s Franca com CiliumJanela manutencaoAlto (mitigar via GitOps)
A.3VMs na malha CiliumA.1 ou A.2Baixo
A.4Nodes Proxmox na malhaA.1 ou A.2Baixo
B.1VyOS WireGuard site-to-siteIPs publicosBaixo
B.2Cilium Cluster MeshA.1 + A.2 + B.1Medio
B.3Testar Global ServicesB.2Baixo
C.1Karmada control planeB.2Medio
C.2Registrar clustersC.1Baixo
C.3ArgoCD → Karmada APIC.2Medio
C.4-C.7Policies + failoverC.3Baixo-Medio
D.1Kueue localClusters federadosBaixo
D.2-D.4MultiKueue cross-siteC.1 + D.1Medio

Decisoes em aberto

DecisaoOpcoesQuando decidir
Migrar Franca in-place vs criar cluster novoIn-place (rapido, downtime) vs novo cluster (seguro, mais trabalho)Antes de A.2
Karmada host cluster vs VM dedicadaNo cluster Franca (menos infra) vs VM separada (isolamento)Antes de C.1
ArgoCD Opcao A vs BSingle ArgoCD → Karmada (simples) vs ArgoCD por cluster (resiliente)Antes de C.3
IP publico do site SPFixo da UNESP/ANSP ou dinamicoAntes de B.1
DRBD cross-site via Cilium ou rede diretaCilium (criptografado, overhead) vs L2 direto (rapido, sem crypto)Antes de A.4

Relacao com outros roadmaps

  • gpu-platform.md Phase 8: este documento detalha e expande a Phase 8
  • gpu-platform.md Phases 0-7: pre-requisitos (GPU no K3s, Kueue, servicos de IA)
  • data-platform.md: servicos de dados (Qdrant, Neo4j, Trino) serao distribuidos via Cilium Global Services + Karmada PropagationPolicy
  • iac.md: Pulumi provisiona K3s SP, Ansible configura nodes, ArgoCD sincroniza apps — mesma divisao