k8s multiple regions config

This commit is contained in:
2026-08-21 14:24:31 -03:00
parent c0a657b7f7
commit b1fce379cd
8 changed files with 213 additions and 68 deletions

View File

@@ -48,10 +48,10 @@ A solução tem os seguintes objetivos:
+--------------------+--------------------+
| |
v v
Deployment ORD Deployment IAD
Deployment Target A Deployment Target B / ... / N
| |
+--------+--------+ +--------+--------+
| Pod TIA ORD | | Pod TIA IAD |
| Pod TIA A | | Pod TIA B/N |
| | | |
| bridge | | bridge |
| agent/livekit | | agent/livekit |
@@ -62,10 +62,20 @@ A solução tem os seguintes objetivos:
+-------+---------+ +-------+---------+
| |
v v
OCI xAI ORD OCI xAI IAD
OCI xAI endpoint A OCI xAI endpoint B/N
```
O mesmo `Service` Kubernetes seleciona Pods ORD e IAD. Cada deployment acrescenta o label `tia-region`, útil para métricas e operação, mas ambos compartilham `app=${APP_NAME}-regional`.
O mesmo `Service` Kubernetes seleciona Pods de todos os targets configurados em `XAI_TARGETS`. Cada deployment acrescenta o label `tia-region`, útil para métricas e operação, e todos compartilham `app=${APP_NAME}-regional`. A quantidade de targets é arbitrária e dois targets podem inclusive apontar para endpoints diferentes na mesma região OCI.
## 4.1 Configuração dinâmica de targets
A topologia não possui lista fixa de regiões. `XAI_TARGETS` declara os pools/endpoints lógicos, por exemplo:
```bash
XAI_TARGETS="ORD IAD GRU FRA"
```
Cada target define `REGION_ID`, réplicas, endpoint upstream e Secret por prefixo. Um target é uma unidade de pool/deployment, portanto vários targets podem apontar para endpoints distintos na mesma região OCI. Adicionar ou remover target não exige alteração dos scripts nem dos templates Kubernetes.
## 5. Componentes
@@ -126,8 +136,9 @@ Cada deployment recebe seu endpoint próprio por `XAI_POOL_UPSTREAM_URL`.
Exemplo:
```text
ORD -> wss://...us-chicago-1.../xai/v1/tts
IAD -> wss://...us-ashburn-1.../xai/v1/tts
TARGET_A -> wss://<endpoint-a>/xai/v1/tts
TARGET_B -> wss://<endpoint-b>/xai/v1/tts
TARGET_N -> wss://<endpoint-n>/xai/v1/tts
```
As credenciais reais ficam somente no sidecar de pool. O container `agent` usa uma credencial local dummy porque se conecta apenas a `localhost`.
@@ -303,13 +314,13 @@ Operação normal:
```text
LB
|-- ORD Pod 1 -> ready
|-- ORD Pod 2 -> ready
|-- IAD Pod 1 -> ready
`-- IAD Pod 2 -> ready
|-- Target A Pod 1 -> ready
|-- Target A Pod 2 -> ready
|-- Target B Pod 1 -> ready
`-- Target B Pod 2 -> ready
```
Se ORD perder saúde/capacidade xAI, os slots começam a falhar e a quantidade de conexões saudáveis/livres cai. Quando a readiness cruza o threshold, os Pods ORD saem dos endpoints e novas chamadas passam a ser atendidas pelos Pods IAD disponíveis.
Se qualquer target perder saúde/capacidade xAI, seus slots começam a falhar e a quantidade de conexões saudáveis/livres cai. Quando a readiness cruza o threshold, os Pods desse target saem dos endpoints e novas chamadas passam a ser atendidas pelos demais targets Ready.
Não há necessidade de alterar o cliente ou o LiveKit para escolher a região.
@@ -324,16 +335,16 @@ capacidade regional de sockets = replicas_region * XAI_POOL_SIZE
Exemplo:
```text
ORD: 2 pods x 25 sockets = 50
IAD: 2 pods x 25 sockets = 50
Target A: 2 pods x 25 sockets = 50
Target B: 2 pods x 25 sockets = 50
TOTAL = 100 sockets prewarmed
```
ou, se a OCI conceder capacidade independente suficiente:
```text
ORD: 2 pods x 50 = 100
IAD: 2 pods x 50 = 100
Target A: 2 pods x 50 = 100
Target B: 2 pods x 50 = 100
TOTAL = 200
```
@@ -355,24 +366,24 @@ e deve ser comparado com a **capacidade efetivamente negociada/provisionada** pa
Carga baixa
=========
LB
|-- ORD-1 [pool 50: 10 leased / 40 free]
`-- IAD-1 [pool 50: 8 leased / 42 free]
|-- target-a-1 [pool 50: 10 leased / 40 free]
`-- target-b-1 [pool 50: 8 leased / 42 free]
Carga aumenta
=============
LB
|-- ORD-1 [47 leased / 3 free] READY
`-- IAD-1 [30 leased /20 free] READY
|-- target-a-1 [47 leased / 3 free] READY
`-- target-b-1 [30 leased /20 free] READY
ORD satura
Target A satura
===========
LB
|-- ORD-1 [48 leased /2 free] NOT READY -> sem novas chamadas
`-- IAD-1 [31 leased /19 free] READY -> recebe novas chamadas
|-- target-a-1 [48 leased /2 free] NOT READY -> sem novas chamadas
`-- target-b-1 [31 leased /19 free] READY -> recebe novas chamadas
ORD recupera
Target A recupera
=============
ORD-1 chega a 45 leased /5 free
target-a-1 chega a 45 leased /5 free
/readyz volta a 200
LB volta a considerá-lo para novas conexões
```
@@ -445,7 +456,7 @@ Estas métricas devem ser correlacionadas com as métricas já existentes no TIA
| conexão presa a uma chamada | lease somente durante utterance |
| LB envia tráfego a Pod sem capacidade TTS | `/readyz` baseado no pool |
| flapping de health | histerese unavailable/recover |
| indisponibilidade regional | Deployments ORD/IAD no mesmo Service |
| indisponibilidade regional | N deployments/targets no mesmo Service |
| rollout derruba novas sessões | drain + RollingUpdate |
| chave xAI em todos os processos | credencial real somente no sidecar |
| observabilidade de capacidade | `/pool/status` + `/metrics` |

View File

@@ -1,3 +1,12 @@
## Correção multi-target / N regiões
- removido hardcode `render_region ORD` / `render_region IAD`;
- nova variável `XAI_TARGETS` define qualquer quantidade de pools/endpoints;
- `XAI_REGIONS` mantida somente como alias de compatibilidade;
- deployment e rollout descobrem dinamicamente todos os manifests renderizados;
- suporte a múltiplos targets na mesma região OCI usando `REGION_ID` distintos;
- documentação e plano de testes generalizados para N targets.
# Changelog — TIA Regional / xAI Pool
## Implementação adicionada

View File

@@ -1,5 +1,8 @@
# Deployment — TIA Regional com Pool xAI
> **Modelo multi-target:** a lista de regiões/pools não é fixa. Declare `XAI_TARGETS="TARGET_A TARGET_B ..."` em `k8s/regional/regions.env`. Cada target define `<TARGET>_REGION_ID`, `<TARGET>_REGION_REPLICAS`, `<TARGET>_XAI_UPSTREAM_URL` e `<TARGET>_XAI_SECRET_NAME`. Para adicionar uma região ou um segundo pool na mesma região, altere somente configuração; os scripts e manifests não precisam ser modificados. `XAI_REGIONS` é aceito apenas como alias de compatibilidade.
## 1. Pré-requisitos
- cluster Kubernetes/OKE funcional;
@@ -312,20 +315,21 @@ Um Pod NotReady não deve ser usado para novas conexões do Service.
## 15. Testar failover regional
### Teste controlado de ORD
### Teste controlado de qualquer target
Coloque ORD em drain:
Escolha um `TARGET_REGION_ID` e coloque esse target em drain:
```bash
ORD_POD=$(kubectl -n "$K8S_NAMESPACE" get pod \
-l app=${APP_NAME}-regional,tia-region=ord \
TARGET_REGION_ID=${TARGET_REGION_ID:-ord}
TARGET_POD=$(kubectl -n "$K8S_NAMESPACE" get pod \
-l app=${APP_NAME}-regional,tia-region=${TARGET_REGION_ID} \
-o jsonpath='{.items[0].metadata.name}')
kubectl -n "$K8S_NAMESPACE" exec "$ORD_POD" -c xai-pool -- \
kubectl -n "$K8S_NAMESPACE" exec "$TARGET_POD" -c xai-pool -- \
python -c "import urllib.request; urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:18100/drain', method='POST')).read()"
```
Confirme `/readyz=503` e gere **nova chamada**. Ela deve ser entregue a um Pod IAD ainda Ready.
Confirme `/readyz=503` e gere **nova chamada**. Ela deve ser entregue a qualquer outro target que permaneça Ready.
Esse teste não deve ser interpretado como migração de uma chamada existente; somente novas conexões são rebalanceadas.
@@ -334,7 +338,7 @@ Esse teste não deve ser interpretado como migração de uma chamada existente;
O drain manual é intencional e não é revertido. Para voltar o Pod, reinicie-o:
```bash
kubectl -n "$K8S_NAMESPACE" delete pod "$ORD_POD"
kubectl -n "$K8S_NAMESPACE" delete pod "$TARGET_POD"
```
O novo Pod deve:
@@ -378,7 +382,7 @@ A alteração não remove suporte ao modo anterior.
## 20. Checklist de produção
- [ ] confirmar quota real de WebSockets por endpoint/região/tenancy;
- [ ] confirmar se ORD e IAD têm pools de capacidade independentes;
- [ ] confirmar capacidade independente/adequada para cada target configurado;
- [ ] validar `XAI_POOL_SIZE * replicas` por região;
- [ ] validar Secret/Vault;
- [ ] medir tempo de prewarm dos 50 sockets;
@@ -388,7 +392,7 @@ A alteração não remove suporte ao modo anterior.
- [ ] testar recovery -> `/readyz=200`;
- [ ] testar drain durante chamada ativa;
- [ ] testar rollout sem perda de novas chamadas;
- [ ] testar perda total de ORD e entrada em IAD;
- [ ] testar perda total de cada target e redistribuição para os demais targets Ready;
- [ ] correlacionar TTFB/gap/underflow com `pool_free`;
- [ ] validar LB/Service com WebSocket real;
- [ ] executar stress test com perfil semelhante ao tráfego de produção.

View File

@@ -6,7 +6,7 @@ Validar separadamente capacidade do pool, comportamento do Kubernetes, failover
## Camada 1 — Smoke
1. subir 1 Pod ORD com pool pequeno (`XAI_POOL_SIZE=3`);
1. subir 1 Pod de um target de teste com pool pequeno (`XAI_POOL_SIZE=3`);
2. confirmar 3 conexões healthy;
3. realizar uma chamada e uma síntese;
4. confirmar que `leased` vai 0 -> 1 -> 0;
@@ -91,15 +91,15 @@ Critérios:
## Camada 7 — Falha upstream
Bloqueie ORD ou aponte temporariamente para endpoint inválido.
Bloqueie um target (por exemplo TARGET_A) ou aponte temporariamente seu upstream para endpoint inválido.
Esperado:
- slots ORD tornam-se unhealthy;
- slots do TARGET_A tornam-se unhealthy;
- maintenance tenta recuperação;
- readiness ORD cai;
- Service deixa de enviar novas chamadas a ORD;
- IAD continua Ready.
- readiness do TARGET_A cai;
- Service deixa de enviar novas chamadas ao TARGET_A;
- os demais targets continuam Ready.
## Camada 8 — Latência
@@ -141,7 +141,7 @@ Rodar pelo menos:
Com chamadas ativas:
```bash
kubectl rollout restart deployment/<tia-ord>
kubectl rollout restart deployment/<tia-target>
```
Validar:
@@ -153,11 +153,11 @@ Validar:
## Camada 10 — Failover regional
1. ORD e IAD Ready;
1. configurar pelo menos dois targets Ready;
2. iniciar tráfego contínuo;
3. tornar ORD NotReady;
4. verificar novas chamadas em IAD;
5. recuperar ORD;
3. tornar um target NotReady;
4. verificar novas chamadas nos demais targets Ready;
5. recuperar o target;
6. verificar reentrada progressiva.
## Evidências a guardar