k8s multiple regions config
This commit is contained in:
@@ -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` |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,6 +8,11 @@ TERMINATION_GRACE_SECONDS=600
|
||||
DRAIN_SECONDS=30
|
||||
PDB_MIN_AVAILABLE=2
|
||||
|
||||
# Logical xAI targets. Add/remove targets here without modifying scripts/YAML.
|
||||
# A target represents one pool/upstream endpoint and does not need to be 1:1
|
||||
# with an OCI region. This also supports multiple pools in the same region.
|
||||
XAI_TARGETS="ORD IAD"
|
||||
|
||||
# Existing TIA resources
|
||||
CPU_TIA_BRIDGE_REQ=250m
|
||||
MEM_TIA_BRIDGE_REQ=512Mi
|
||||
@@ -22,9 +27,8 @@ MEM_XAI_POOL_REQ=256Mi
|
||||
CPU_XAI_POOL_LIM=1000m
|
||||
MEM_XAI_POOL_LIM=768Mi
|
||||
|
||||
# Pool profile - 50 means 50 prewarmed upstream WebSockets PER POD.
|
||||
# Tamanho do pool por réplica TIA. NÃO representa limite do OCI/xAI.
|
||||
# Ajuste conforme capacidade negociada para o ambiente.
|
||||
# Pool profile - XAI_POOL_SIZE means prewarmed upstream WebSockets PER POD.
|
||||
# It is NOT the OCI/xAI service limit; tune it to the negotiated capacity.
|
||||
XAI_POOL_SIZE=50
|
||||
XAI_POOL_UNAVAILABLE_FREE=2
|
||||
XAI_POOL_RECOVER_FREE=5
|
||||
@@ -36,19 +40,37 @@ XAI_TTS_VOICE=c8x2ieiocufs
|
||||
XAI_TTS_LANGUAGE=pt-BR
|
||||
XAI_UPSTREAM_AUTH_METHOD=API_KEY
|
||||
|
||||
# HPA. replicas * XAI_POOL_SIZE deve respeitar a capacidade efetivamente negociada/provisionada para cada região/endpoint.
|
||||
# HPA. replicas * XAI_POOL_SIZE must fit each target/endpoint capacity.
|
||||
HPA_MIN_REPLICAS=1
|
||||
HPA_MAX_REPLICAS=3
|
||||
HPA_CPU_TARGET=65
|
||||
|
||||
# ORD
|
||||
# Example target ORD
|
||||
ORD_REGION_ID=ord
|
||||
ORD_REGION_REPLICAS=1
|
||||
ORD_XAI_UPSTREAM_URL=wss://peordagnt002prd.pe.inference.generativeai.us-chicago-1.oci.oraclecloud.com/xai/v1/tts
|
||||
ORD_XAI_SECRET_NAME=xai-ord-credentials
|
||||
|
||||
# IAD
|
||||
# Example target IAD
|
||||
IAD_REGION_ID=iad
|
||||
IAD_REGION_REPLICAS=1
|
||||
IAD_XAI_UPSTREAM_URL=wss://peiadagnt003prd.pe.inference.generativeai.us-ashburn-1.oci.oraclecloud.com/xai/v1/tts
|
||||
IAD_XAI_SECRET_NAME=xai-iad-credentials
|
||||
|
||||
# Add another region without changing code:
|
||||
# XAI_TARGETS="ORD IAD GRU"
|
||||
# GRU_REGION_ID=gru
|
||||
# GRU_REGION_REPLICAS=1
|
||||
# GRU_XAI_UPSTREAM_URL=wss://<endpoint>/xai/v1/tts
|
||||
# GRU_XAI_SECRET_NAME=xai-gru-credentials
|
||||
|
||||
# Multiple independent pools in one OCI region are also supported:
|
||||
# XAI_TARGETS="ORD_PRIMARY ORD_SECONDARY IAD"
|
||||
# ORD_PRIMARY_REGION_ID=ord-primary
|
||||
# ORD_PRIMARY_REGION_REPLICAS=1
|
||||
# ORD_PRIMARY_XAI_UPSTREAM_URL=wss://<endpoint-a>/xai/v1/tts
|
||||
# ORD_PRIMARY_XAI_SECRET_NAME=xai-ord-primary-credentials
|
||||
# ORD_SECONDARY_REGION_ID=ord-secondary
|
||||
# ORD_SECONDARY_REGION_REPLICAS=1
|
||||
# ORD_SECONDARY_XAI_UPSTREAM_URL=wss://<endpoint-b>/xai/v1/tts
|
||||
# ORD_SECONDARY_XAI_SECRET_NAME=xai-ord-secondary-credentials
|
||||
|
||||
@@ -3,13 +3,23 @@ set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_FILE="${1:-$ROOT/k8s/regional/regions.env}"
|
||||
OUT="${2:-$ROOT/k8s/regional/rendered}"
|
||||
|
||||
"$ROOT/scripts/render-regional-k8s.sh" "$ENV_FILE" "$OUT"
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
kubectl apply -f "$OUT/service.yaml"
|
||||
kubectl apply -f "$OUT/pdb.yaml"
|
||||
kubectl apply -f "$OUT/deployment-ord.yaml"
|
||||
kubectl apply -f "$OUT/deployment-iad.yaml"
|
||||
kubectl apply -f "$OUT/hpa-ord.yaml"
|
||||
kubectl apply -f "$OUT/hpa-iad.yaml"
|
||||
kubectl rollout status -f "$OUT/deployment-ord.yaml" --timeout=10m
|
||||
kubectl rollout status -f "$OUT/deployment-iad.yaml" --timeout=10m
|
||||
kubectl get pods -l app="$(grep '^APP_NAME=' "$ENV_FILE" | cut -d= -f2)-regional" -o wide
|
||||
|
||||
shopt -s nullglob
|
||||
deployments=("$OUT"/deployment-*.yaml)
|
||||
hpas=("$OUT"/hpa-*.yaml)
|
||||
((${#deployments[@]} > 0)) || { echo "No regional deployments rendered" >&2; exit 2; }
|
||||
|
||||
for manifest in "${deployments[@]}"; do kubectl apply -f "$manifest"; done
|
||||
for manifest in "${hpas[@]}"; do kubectl apply -f "$manifest"; done
|
||||
for manifest in "${deployments[@]}"; do kubectl rollout status -f "$manifest" --timeout=10m; done
|
||||
|
||||
kubectl -n "$K8S_NAMESPACE" get pods -l "app=${APP_NAME}-regional" -o wide
|
||||
|
||||
@@ -4,21 +4,61 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_FILE="${1:-$ROOT/k8s/regional/regions.env}"
|
||||
OUT="${2:-$ROOT/k8s/regional/rendered}"
|
||||
[[ -f "$ENV_FILE" ]] || { echo "Missing $ENV_FILE (copy regions.env.example)" >&2; exit 2; }
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
command -v envsubst >/dev/null || { echo "envsubst is required (gettext package)" >&2; exit 2; }
|
||||
rm -rf "$OUT"; mkdir -p "$OUT"
|
||||
render_region() {
|
||||
local prefix="$1"
|
||||
|
||||
XAI_TARGETS="${XAI_TARGETS:-${XAI_REGIONS:-}}"
|
||||
[[ -n "${XAI_TARGETS// }" ]] || {
|
||||
echo 'XAI_TARGETS is required. Example: XAI_TARGETS="ORD IAD GRU"' >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
rm -rf "$OUT"
|
||||
mkdir -p "$OUT"
|
||||
|
||||
required_target_var() {
|
||||
local target="$1" suffix="$2" var value
|
||||
var="${target}_${suffix}"
|
||||
value="${!var:-}"
|
||||
[[ -n "$value" ]] || { echo "Missing required configuration: $var" >&2; exit 2; }
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
render_target() {
|
||||
local target="$1"
|
||||
[[ "$target" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || {
|
||||
echo "Invalid XAI target '$target'. Use letters, numbers and underscores only." >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
export REGION_ID REGION_REPLICAS XAI_UPSTREAM_URL XAI_SECRET_NAME
|
||||
REGION_ID="$(eval echo \"\${${prefix}_REGION_ID}\")"
|
||||
REGION_REPLICAS="$(eval echo \"\${${prefix}_REGION_REPLICAS}\")"
|
||||
XAI_UPSTREAM_URL="$(eval echo \"\${${prefix}_XAI_UPSTREAM_URL}\")"
|
||||
XAI_SECRET_NAME="$(eval echo \"\${${prefix}_XAI_SECRET_NAME}\")"
|
||||
REGION_ID="$(required_target_var "$target" REGION_ID)"
|
||||
REGION_REPLICAS="$(required_target_var "$target" REGION_REPLICAS)"
|
||||
XAI_UPSTREAM_URL="$(required_target_var "$target" XAI_UPSTREAM_URL)"
|
||||
XAI_SECRET_NAME="$(required_target_var "$target" XAI_SECRET_NAME)"
|
||||
|
||||
[[ "$REGION_ID" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]] || {
|
||||
echo "Invalid ${target}_REGION_ID='$REGION_ID'. Use a lowercase Kubernetes label." >&2
|
||||
exit 2
|
||||
}
|
||||
[[ ! -e "$OUT/deployment-${REGION_ID}.yaml" ]] || {
|
||||
echo "Duplicate REGION_ID '$REGION_ID'. Each target must have a unique REGION_ID." >&2
|
||||
echo "For multiple pools in one OCI region use ids such as ord-primary and ord-secondary." >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
envsubst < "$ROOT/k8s/regional/deployment-region.yaml" > "$OUT/deployment-${REGION_ID}.yaml"
|
||||
envsubst < "$ROOT/k8s/regional/hpa-region.yaml" > "$OUT/hpa-${REGION_ID}.yaml"
|
||||
echo "Rendered target=$target region_id=$REGION_ID"
|
||||
}
|
||||
render_region ORD
|
||||
render_region IAD
|
||||
|
||||
for target in $XAI_TARGETS; do
|
||||
render_target "$target"
|
||||
done
|
||||
|
||||
envsubst < "$ROOT/k8s/regional/service.yaml" > "$OUT/service.yaml"
|
||||
envsubst < "$ROOT/k8s/regional/pdb.yaml" > "$OUT/pdb.yaml"
|
||||
echo "Rendered manifests in $OUT"
|
||||
|
||||
49
tests/test_render_regional_multi_target.sh
Normal file
49
tests/test_render_regional_multi_target.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
mkdir -p "$TMP/repo/scripts" "$TMP/repo/k8s/regional" "$TMP/bin"
|
||||
cp "$ROOT/scripts/render-regional-k8s.sh" "$TMP/repo/scripts/"
|
||||
cat > "$TMP/bin/envsubst" <<'PY'
|
||||
#!/usr/bin/env python3
|
||||
import os,re,sys
|
||||
s=sys.stdin.read()
|
||||
s=re.sub(r'\$\{([A-Za-z_][A-Za-z0-9_]*)\}',lambda m:os.environ.get(m.group(1),m.group(0)),s)
|
||||
sys.stdout.write(s)
|
||||
PY
|
||||
chmod +x "$TMP/bin/envsubst"
|
||||
cat > "$TMP/repo/k8s/regional/deployment-region.yaml" <<'EOF2'
|
||||
id=${REGION_ID};replicas=${REGION_REPLICAS};url=${XAI_UPSTREAM_URL};secret=${XAI_SECRET_NAME}
|
||||
EOF2
|
||||
cat > "$TMP/repo/k8s/regional/hpa-region.yaml" <<'EOF2'
|
||||
hpa=${REGION_ID}
|
||||
EOF2
|
||||
cat > "$TMP/repo/k8s/regional/service.yaml" <<'EOF2'
|
||||
service=${APP_NAME}
|
||||
EOF2
|
||||
cat > "$TMP/repo/k8s/regional/pdb.yaml" <<'EOF2'
|
||||
pdb=${APP_NAME}
|
||||
EOF2
|
||||
cat > "$TMP/regions.env" <<'EOF2'
|
||||
APP_NAME=tia
|
||||
XAI_TARGETS="ORD IAD GRU"
|
||||
ORD_REGION_ID=ord
|
||||
ORD_REGION_REPLICAS=1
|
||||
ORD_XAI_UPSTREAM_URL=wss://ord
|
||||
ORD_XAI_SECRET_NAME=secret-ord
|
||||
IAD_REGION_ID=iad
|
||||
IAD_REGION_REPLICAS=2
|
||||
IAD_XAI_UPSTREAM_URL=wss://iad
|
||||
IAD_XAI_SECRET_NAME=secret-iad
|
||||
GRU_REGION_ID=gru
|
||||
GRU_REGION_REPLICAS=3
|
||||
GRU_XAI_UPSTREAM_URL=wss://gru
|
||||
GRU_XAI_SECRET_NAME=secret-gru
|
||||
EOF2
|
||||
PATH="$TMP/bin:$PATH" "$TMP/repo/scripts/render-regional-k8s.sh" "$TMP/regions.env" "$TMP/out"
|
||||
test -f "$TMP/out/deployment-ord.yaml"
|
||||
test -f "$TMP/out/deployment-iad.yaml"
|
||||
test -f "$TMP/out/deployment-gru.yaml"
|
||||
grep -q 'replicas=3' "$TMP/out/deployment-gru.yaml"
|
||||
echo 'test_render_regional_multi_target: PASS'
|
||||
Reference in New Issue
Block a user