Os dois jeitos de escalar
Réplicas de uma Instance
spec.replicas: N. Um Service, uma credencial, uma configuração; o operator distribui entre os pods.Várias Instances
Uma
Instance por finalidade (AIOps, chat de um time, outro provider). Cada uma tem Deployment, Service, credenciais e chave de criptografia próprios.Réplicas
- Com
replicas> 1 o Service é headless, e cada conexão nova resolve para um dos pods prontos. - Cada pod é um servidor independente: memória, watcher e estado em
emptyDirpróprios. As réplicas não compartilham nada além do volume de sessões, quando existe. - O stream de alertas do operator se conecta a um pod por vez, então a Instance que conduz o AIOps não ganha nada com réplicas extras.
Várias Instances
- Crie quantas precisar, num namespace ou em vários.
- O AIOps se liga a exatamente uma Instance, a fixada com
aiops.instanceno chart do operator (CHATCLI_OPERATOR_AIOPS_INSTANCE=<namespace>/<nome>). As outras Instances atendem chat e API e nunca são escolhidas implicitamente. - Cada Instance ganha seu próprio Secret de chave de criptografia em repouso,
<instance>-atrest-key. Faça backup de cada um (veja Criptografia em Repouso).
A persistência decide o rollout
spec.persistence.enabled dá às sessões um PVC ReadWriteOnce. Essa única opção muda como a Instance pode escalar e como ela é atualizada:
A drenagem no desligamento
Quando um pod é substituído, ele sai dos endpoints do Service e do DNS do cluster alguns segundos depois de receber o SIGTERM (o DNS guarda os registros de Service por 5 segundos). Um servidor que parasse de escutar na hora recusaria as conexões que ainda o resolvem. ComCHATCLI_SERVER_SHUTDOWN_DELAY, o servidor responde NOT_SERVING aos health checks na hora, para que load balancers e clientes que fazem health check se afastem, mas continua atendendo requisições durante o intervalo, e só então para.
- O operator define
5sem toda Instance sem persistência. Uma entradaCHATCLI_SERVER_SHUTDOWN_DELAYemspec.extraEnvsubstitui o valor (0sdesliga). - O Helm chart do servidor o define por
server.shutdownDelay(veja Docker & Kubernetes). - Mantenha bem abaixo do
terminationGracePeriodSecondsdo pod (30 segundos por padrão).
Layout recomendado
Uma Instance para o AIOps que guarda seu estado, e um pool de réplicas sem estado para o tráfego de chat.1
Mantenha a Instance do AIOps com uma réplica e persistência
Recreate). Nesse meio-tempo o WatcherBridge loga Alert stream ended; reopening e reconecta sozinho.2
Acrescente um pool sem estado para o chat
- A anti-afinidade
preferredespalha os pods entre os nós quando dá, e ainda os agenda quando há menos nós do que réplicas. Userequiredsó quando tiver pelo menos tantos nós quanto réplicas. - O certificado TLS precisa valer para
chat-pool.<namespace>.svc.cluster.local. Dá para reusar um Secret em várias Instances se os SANs dele cobrirem todos os nomes. - As sessões ficam em
emptyDir: um cliente cujo pod é substituído começa uma sessão nova.
3
Confira as duas
READY true, os pods do pool estão em nós diferentes, a estratégia dele é RollingUpdate, e a linha Connected to Instance do operator cita só a Instance do AIOps.Quanto custa um rollout, medido
Um pod de sonda rodouchatcli healthcheck contra o Service de cada Instance a cada 0,3 segundo enquanto uma mudança em spec.extraEnv fazia o rollout. O cluster era um kind com um control plane e dois workers, storage local do nó, ChatCLI 1.221.1, mais um build do servidor com a drenagem.
As duas réplicas com persistência caíram no mesmo nó, aquele em que o volume local-path foi criado. Exigir que ficassem em nós diferentes deixou o segundo pod
Pending, como descrito no aviso acima.
Para reproduzir, monte um pod de sonda a partir do busybox com um binário chatcli da arquitetura do nó e a CA da Instance montada, e rode o laço:
Limites que vale conhecer
- O operator não cria HorizontalPodAutoscaler nem PodDisruptionBudget para Instances. Acrescente os seus se usar autoscaling ou drenar nós com frequência; um HPA numa Instance disputa com
spec.replicas, então prefira ajustarspec.replicas. - Réplicas não compartilham memória nem sessões. Estado que precisa sobreviver a um pod vai na persistência (uma réplica) ou fora do servidor.
- O próprio operator escala à parte:
replicaCount: 2ou mais comleaderElect: trueno chart dele. Os controllers rodam no líder; o dashboard e a API REST respondem em todas as réplicas.