Instance e, em cima deles, um pipeline de AIOps que transforma alertas do watcher em incidentes, pede ao LLM a causa raiz e executa a remediação. Esta página é a jornada de quem opera: instalar, subir a primeira Instance de ponta a ponta, conectar, abrir o dashboard e endurecer tudo para produção.
Os detalhes internos do pipeline de AIOps (correlação, análise, ações de remediação, post-mortems) estão em AIOps Platform e Ciclo de vida do incidente. Esta página cobre tudo o que você precisa para operá-lo.
Como as peças se encaixam
O que você precisa saber antes de começar:- Uma
Instanceé um servidor gRPC do ChatCLI (chatcli server) que o operator implanta e mantém em ordem: um Deployment, um Service, ConfigMaps, uma ServiceAccount e, opcionalmente, um PVC e RBAC do watcher. - O operator sempre conecta no servidor com TLS 1.3. Não existe caminho em texto puro do operator até uma Instance. O endereço discado é
<name>.<namespace>.svc.cluster.local:<port>, então o certificado do servidor precisa valer para esse nome. - Toda Instance precisa de uma credencial. Dentro do cluster o servidor escuta em todas as interfaces e se recusa a subir sem token compartilhado, material JWT ou CA de cliente. O operator confere isso antes e não cria o Deployment quando o spec não tem nenhum.
- Uma Instance por cluster conduz o AIOps. O WatcherBridge lista todas as Instances do cluster e se conecta à primeira pronta que encontrar. Você pode rodar outras Instances para chat, mas só uma alimenta o pipeline de incidentes, e qual delas não é algo em que se possa confiar.
- A API REST e o dashboard web são servidos pelo operator, não pela Instance: Service
chatcli-operator, porta8090, autenticados por API key.
API group e CRDs
Todos os recursos são namespaced e ficam emplatform.chatcli.io/v1alpha1. O operator traz 17 CRDs:
Cada kind de AIOps tem sua página em AIOps Platform na barra lateral, por exemplo Notificações e escalação, SLOs e SLAs e Fluxo de aprovação.
Pré-requisitos
Instalar o operator
- Helm (recomendado)
- Manifestos crus (make deploy)
O chart é publicado como artefato OCI no GHCR; não é preciso clonar o repositório:O que é instalado: os 17 CRDs, o Deployment do operator (imagem
ghcr.io/diillson/chatcli-operator, tag = appVersion do chart), o Service chatcli-operator (portas metrics 8080, health 8081, api 8090), a ClusterRole do operator com seu binding e as ClusterRoles pré-provisionadas chatcli-watcher e chatcli-role-{viewer,operator,admin,superadmin}.CRDs no upgrade. O Helm só instala os arquivos de crds/ na primeira instalação e nunca os atualiza. Por isso o chart roda um Job de hook pre-install/pre-upgrade (crdUpgrade.enabled: true, imagem registry.k8s.io/kubectl:v1.31.10) que reaplica todos os CRDs, mantendo o schema sempre alinhado com o controller. Desligue só se você gerencia CRDs por fora; nesse caso aplique o crds/ do chart novo antes do upgrade.O nome do Service segue o nome do release do Helm: com o release
chatcli-operator ele é chatcli-operator. Outro nome, por exemplo aiops, gera aiops-chatcli-operator. Os comandos desta página assumem o release chatcli-operator em chatcli-system.Verificar a instalação
/readyz (porta 8081) responde. Até você criar API keys, o log mostra SECURITY: no API keys ConfigMap found and CHATCLI_OPERATOR_DEV_MODE is not set e toda chamada ao dashboard é recusada: é o esperado.
Values do chart do operator
Values do chart do operator
Sua primeira Instance
O passo a passo cria uma Instance chamadachatcli no namespace chatcli. O operator vai discar em chatcli.chatcli.svc.cluster.local:50051; se escolher outros nomes, troque em todos os lugares, inclusive no certificado.
1
Crie o namespace
2
Guarde a API key do LLM
O Secret inteiro é carregado no container do servidor (Os outros provedores leem
envFrom), então suas chaves são as variáveis do provedor:OPENAI_API_KEY, GOOGLEAI_API_KEY, XAI_API_KEY, ZAI_API_KEY, MINIMAX_API_KEY, MOONSHOT_API_KEY, OPENROUTER_API_KEY ou GITHUB_COPILOT_TOKEN. O Bedrock usa AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY (e, opcionalmente, AWS_SESSION_TOKEN) mais AWS_REGION ou BEDROCK_REGION, ou nenhuma chave com IRSA (veja serviceAccount.annotations). Coloque neste Secret a chave de todos os provedores de uma cadeia de fallback.Este não é o Secret de keys do dashboard. O
chatcli-api-keys (qualquer nome, referenciado por spec.apiKeys.name) fica ao lado da Instance e guarda chaves de LLM; o chatcli-operator-secrets fica no namespace do operator e guarda as API keys do dashboard.3
Crie o token do servidor
authorization: Bearer <token>; quem tem o token compartilhado é administrador no servidor. As outras opções de credencial estão em Opções de autenticação.4
Emita o certificado TLS
O certificado precisa valer para o nome que o operator disca. Inclua os nomes curtos para clientes dentro do cluster e O
localhost / 127.0.0.1 para o chatcli connect funcionar via kubectl port-forward (a CLI não tem como sobrescrever o nome do servidor). Acrescente seu nome DNS externo se for expor o servidor para fora do cluster.- openssl (CA privada)
- cert-manager
ca.crt é a raiz de confiança que o operator usa para esta Instance. Sem ele o operator recorre às CAs do sistema (ou a security.grpcTLS.caFile), o que só funciona com certificado de uma CA publicamente confiável.5
Crie a Instance
spec.image.tag fica de fora de propósito: o operator roda a imagem de servidor da mesma release que ele (ghcr.io/diillson/chatcli:1.212.1).6
Confira se subiu e está alcançável
READY significa que o Deployment está com todas as réplicas prontas. VERSION é o que o servidor em execução informou à sonda do próprio operator: só aparece depois que o operator alcançou o servidor via TLS com a sua credencial. Leia todas as conditions de uma vez:Condições da Instance
Uma Instance pronta é sondada de novo a cada cinco minutos, então
ServerReachable e VERSION acompanham um servidor que foi atualizado, reiniciado ou perdeu a credencial. O status.serverProbeTime muda quando o resultado muda e, fora isso, no máximo uma vez por intervalo (sem loop de escrita de status).
Uma Instance pronta cuja última sondagem falhou é sondada de novo em 30 segundos, então um False gravado enquanto os pods eram trocados some logo depois do rollout. Qualquer mudança na Instance, inclusive uma anotação, também dispara a reconciliação e a sondagem na hora, sem reiniciar os pods:
Logs que valem a leitura
Conectar a CLI
O Service da Instance éClusterIP (headless com mais de uma réplica). De uma estação de trabalho, faça o port-forward e conecte com TLS:
- Certificado de cliente (mTLS): não há flag. Defina
CHATCLI_TLS_CLIENT_CERTeCHATCLI_TLS_CLIENT_KEY; elas só são usadas junto com--tls. - Texto puro: sem
--tlsa CLI continua discando TLS com as CAs do sistema, a menos queCHATCLI_ALLOW_INSECURE=trueesteja definida. Servidor em texto puro só serve para desenvolvimento local; o operator não o alcança. - A referência completa do cliente está em Remote Connect.
Expor o servidor fora do cluster
O operator cria só o Service ClusterIP. Para expor uma Instance, coloque um recurso seu na frente e inclua o nome DNS externo nos SANs do certificado:- Load balancer L4 (por exemplo um NLB da AWS): crie um
Servicedo tipoLoadBalancerselecionandoapp.kubernetes.io/name: chatclieapp.kubernetes.io/instance: chatcli, porta 50051 paratargetPort: grpc, em passthrough TCP. O TLS fica de ponta a ponta, que também é o único jeito de certificados de cliente (mTLS) chegarem ao servidor. - ingress-nginx: o backend fala TLS, então use
nginx.ingress.kubernetes.io/backend-protocol: "GRPCS", ou TLS passthrough (nginx.ingress.kubernetes.io/ssl-passthrough: "true", que exige a flag--enable-ssl-passthroughno controller). Um ingress que termina o TLS não consegue levar certificados de cliente mTLS até o servidor. - Os clientes então conectam com
chatcli connect chatcli.example.com:443 --tls --token "$TOKEN"(acrescente--ca-certpara uma CA privada).
Dashboard e API REST
O operator serve o dashboard web em/ e a API REST em /api/v1/ na porta 8090 de toda réplica. A API exige o header X-API-Key. As keys são lidas do Secret chatcli-operator-secrets (chave api-keys) no namespace do operator, com o ConfigMap chatcli-operator-config (mesma chave) como alternativa, e relidas a cada 30 segundos: incluir, trocar ou remover uma key não exige restart.
- kubectl
- YAML
- Values do Helm
viewer (lê tudo), operator (reconhece, adia, resolve, aprova, revisa post-mortems, escreve runbooks), admin (tudo, inclusive apagar runbooks). Qualquer outro nome de papel não dá acesso a nada. Um name opcional numa entrada é a identidade registrada nas decisões de aprovação tomadas com aquela chave; um quorum conta cada chave uma vez, então dê a cada aprovador a sua própria chave.
Como o operator aplica uma mudança, na inicialização e em cada consulta de 30 segundos igualmente: um Secret sem a entrada api-keys cai para o ConfigMap; quando nenhum dos dois objetos a fornece (ambos apagados, ou nenhum tem a entrada), todas as chaves são revogadas em cerca de 30 segundos (401 a partir daí). Uma entrada api-keys que não é YAML válido mantém em vigor o último conjunto de chaves válido e é registrada no log uma vez por versão, para que um erro de digitação não tranque todo mundo do lado de fora; revogue uma chave removendo a entrada dela, não quebrando o YAML. Um erro de leitura que não seja “não encontrado” também mantém as chaves em vigor.
- Rate limit: 30 requisições por minuto por host de cliente para requisições sem key válida (o que limita adivinhação de keys) e 600 por minuto por key válida. Passar disso devolve
429comRetry-After. - Publicar: coloque um Ingress na frente do Service na raiz de um host só dele. A página chama
/api/v1/...com caminho absoluto, então um sub-path (/chatcli, com rewrite ou strip-path) carrega a página e quebra todos os painéis. Exemplos e notas por controller: Web Dashboard: Acessar e publicar. - TLS: defina
security.apiTLS.certFile/keyFilee monte o Secret comextraVolumes/extraVolumeMounts; a API passa a servir HTTPS só com TLS 1.3. - Dev mode:
security.devMode: true(CHATCLI_OPERATOR_DEV_MODE, lida como booleano:true,TRUE,1out) aceita toda chamada como admin quando não há keys configuradas; o log de startup informa o mesmo modo que a API aplica. Existe para experimentos locais; nunca ligue em cluster compartilhado. - Endpoints, códigos de erro e paginação: Referência da API REST. Tour do dashboard: Web Dashboard.
Ligar o AIOps
O watcher roda dentro do pod da Instance: coleta status dos pods, eventos, logs e, opcionalmente, métricas Prometheus dos alvos que você listar, e gera alertas. O WatcherBridge do operator transforma esses alertas no pipeline de incidentes.- Detecção. O WatcherBridge (no líder do operator) mantém aberto o stream
StreamAlertsdo servidor (heartbeat a cada 15s; um servidor sem essa RPC, anterior à 1.211.0, é consultado comGetAlertsa cada 30s, e o stream é tentado de novo a cada 10 minutos ou assim que esse servidor sai;alertTransport: pollforça o polling) e cria recursosAnomaly, deduplicados poraiops.dedupTTLMinutes(padrão 30). - Correlação. Anomalias no mesmo recurso são agrupadas numa
Issuecom risk score e severidade. - Análise. Um
AIInsighté criado e a RPCAnalyzeIssuedo servidor pede ao LLM a causa raiz, enriquecida com contexto do Kubernetes, logs, métricas, estado de GitOps e código-fonte vinculado. - Remediação. Um
RemediationPlanexecuta um Runbook compatível, um runbook gerado pela IA ou um loop agêntico observar-decidir-agir (RPCAgenticStep), com 54 ações tipadas (maisCustom, que as verificações de segurança rejeitam), snapshot antes das ações e rollback automático. ApprovalPolicies, o decision engine e o tier do cluster podem segurar um plano para um humano. - Resolução. A Issue é resolvida ou escalada depois de
aiops.maxRemediationAttempts, e umPostMortemé gerado. Notificação e escalação ficam por conta de NotificationPolicy e EscalationPolicy.
ExecDiagnostic Allowlist
OExecDiagnostic só roda um comando dentro de um pod quando ele bate, caractere por caractere, com uma entrada de um allowlist somente leitura de 100 comandos embutidos (inspeção de processos e sistema de arquivos, arquivos de cgroup v1/v2, /proc, introspecção de rede e DNS, curl/wget contra endpoints de health, métricas e pprof em localhost nas portas comuns, nc -zv até o API server e o DNS). Qualquer outro é recusado com command "..." not in approved diagnostic commands whitelist.
A lista é lida pelo processo do operator, então estenda no chart do operator, não na Instance. Vírgulas separam as entradas, então escape-as no --set, ou coloque o valor no seu arquivo de values (aqui operator-values.yaml):
Repositórios de código
UmSourceRepository vincula uma carga ao repositório git dela, para que a análise de incidentes veja os commits recentes e o código em volta dos stack traces. Crie-o, e o Secret dele, no namespace da carga. O operator faz um clone raso no emptyDir gravável /tmp dele (valor tmpVolume.sizeLimit do chart, padrão 1Gi) e sincroniza de novo a cada syncIntervalMinutes (padrão 30). A imagem do operator traz git e openssh-client.
As credenciais são entregues ao git a cada comando e nunca gravadas no
.git/config do clone. Um clone feito por uma versão anterior, que guardava o token na URL do origin, tem o token removido do origin e o reflog expirado na próxima sincronização. Sem known_hosts uma sincronização por SSH falha, a menos que spec.sshHostKeyPolicy: acceptNew confie na chave que o host apresenta no primeiro contato (e rejeite uma chave diferente depois, enquanto durar o pod do operator); o padrão é strict.
Acompanhar o pipeline
Opções de autenticação
O operator escolhe a própria credencial nesta ordem:
server.token, depois security.operatorTokenRef, depois security.jwtSecretRef (tokens emitidos por ele), depois security.operatorClientCertSecretName. Um certificado de cliente, quando configurado, é apresentado em toda conexão além de qualquer credencial bearer.
Token compartilhado
Token compartilhado
A opção mais simples, usada no passo a passo. Quem tem o token é
admin no servidor (subject legacy-token), e todos os chamadores por token dividem um único balde de rate limit. Para trocar, atualize o Secret: os pods reiniciam e o operator passa a usar o novo valor.JWT HS256 (o operator emite os próprios tokens)
JWT HS256 (o operator emite os próprios tokens)
exp (sem ele o token é recusado), são conferidos com 30 segundos de tolerância de relógio e respeitam nbf; iss e aud são conferidos quando configurados. A claim role mapeia admin para admin, operator e user para user, viewer e readonly para somente leitura; sem a claim, user. O operator emite os próprios tokens (sub: chatcli-operator, role: operator, uma hora, renovados após 45 minutos) com jwtIssuer e jwtAudience. Como emitir tokens para pessoas: autenticação no Server Mode.JWT RS256 (seu provedor de identidade assina)
JWT RS256 (seu provedor de identidade assina)
operatorTokenRef (ou de um certificado de cliente). Esse token também precisa de exp, então mantenha o Secret renovado antes de expirar (por exemplo com External Secrets); o operator reconecta quando o Secret muda, sem reiniciar os pods do servidor.mTLS (certificados de cliente)
mTLS (certificados de cliente)
mtlsRole (viewer, readonly, user, operator ou admin; padrão do servidor user); um token bearer enviado junto tem precedência. Emita os certificados de cliente com extendedKeyUsage = clientAuth a partir da mesma CA do passo de TLS.security.bindAddress: "127.0.0.1") podem rodar sem credencial, mas aí nada fora do pod os alcança, nem o operator: ServerReachable fica False. Só faz sentido para um servidor acessado a partir de um sidecar.
Referência do spec da Instance
Sóspec.provider é obrigatório. O schema do CRD é a única validação: não existe admission webhook.
Nível raiz
spec.server
spec.server.security
spec.watcher
targets[]: name (nome do recurso; deployment é o alias obsoleto), kind (Deployment, StatefulSet, DaemonSet, Job, CronJob; padrão Deployment), namespace (obrigatório), metricsPort (0 = sem métricas), metricsPath (padrão do servidor /metrics), metricsFilter (padrões glob).
spec.fallback
O operator coloca
spec.provider (com spec.model) na frente, a menos que a lista já o cite, caso em que a sua ordem é mantida. O servidor só monta a cadeia quando pelo menos dois dos provedores têm credencial, e a usa em requisições que não trazem credencial nem provedor explícito próprios. Coloque a chave de todos os provedores no Secret de apiKeys. Detalhes do comportamento: Provider Fallback.
spec.aiops
O pipeline de AIOps lê essas configurações da Instance de onde o WatcherBridge recebe os alertas (labels platform.chatcli.io/instance e platform.chatcli.io/instance-namespace em cada Anomaly e Issue); na falta delas, vale a primeira Instance pronta.
spec.features e spec.pipeline
spec.mcp, spec.agents, spec.plugins
Status
O que o operator cria
Tudo recebe o nome da Instance, os labelsapp.kubernetes.io/name: chatcli, app.kubernetes.io/instance: <name>, app.kubernetes.io/managed-by: chatcli-operator, e pertence à Instance (é apagado junto com ela).
O Deployment roda
chatcli server --port <port> --metrics-port <metricsPort> --provider ... [--model ...] [--tls-cert ... --tls-key ... [--tls-client-ca ...]] [--mcp-config ...] [--watch-config ... | --watch-deployment ...] com:
- estratégia
Recreatequandopersistence.enabled(o PVC de sessões é ReadWriteOnce, então o pod antigo o libera antes de o novo subir; cada rollout tem uma breve indisponibilidade), senãoRollingUpdate; - probes em
GET /healthzda portametrics(HTTP puro, sem credencial): startup a cada 5s por até 5 minutos, readiness a cada 10s (sai do Service após 30s de falhas), liveness a cada 20s (reinicia após 2 minutos); - security context do pod
runAsNonRoot, UID 1000,fsGroup: 1000comfsGroupChangePolicy: OnRootMismatch(para que um volume de sessões novo seja gravável seja qual for o provisioner),seccompProfile: RuntimeDefault(a menos que hajaspec.securityContext) e, em todo container, inclusive o init containerplugin-loader,allowPrivilegeEscalation: false,readOnlyRootFilesystem: truee todas as capabilities removidas: o pod passa no Pod Security Standardrestricted; - emptyDirs graváveis
/tmp(100Mi) e/home/chatcli/.chatcli(200Mi); tudo o que estiver fora do PVC de sessões se perde quando o pod reinicia; HOME=/home/chatcli, o ConfigMap<name>e o Secret deapiKeyscomoenvFrom, depoisextraEnv, depois as variáveis tipadas de credencial e features. As referências a Secret são opcionais, então um Secret ausente não trava o pod: ele sobe sem o valor.
Gatilhos de rollout
O pod lê a configuração na subida, então o operator grava hashes no template do pod e qualquer mudança reinicia os pods:
Mudanças no próprio template do pod (imagem, recursos, env, scheduling) reiniciam os pods como em qualquer Deployment. Todo Secret referenciado pela Instance é observado, então criar ou trocar um deles reconcilia a Instance na hora.
O que atualiza só o operator:
operatorTokenRef e operatorClientCertSecretName são lidos pelo operator, não pelo pod. Trocá-los não reinicia o servidor; o operator refaz a conexão com o material novo (a sonda de status disca do zero toda vez).
O que não reinicia os pods: uma imagem de plugins nova com a mesma tag. Rode kubectl -n <ns> rollout restart deploy/<name> depois de publicá-la.
Rodando em produção
Checklist
- O certificado TLS cobre
<name>.<namespace>.svc.cluster.local(mais os nomes curtos e, se exposto, o nome externo), e o Secret temca.crtpara CA privada. -
TLSConfigured,AuthenticationConfigured,OperatorCredentialConfigured,AvailableeServerReachableestão todasTrue. - Uma credencial por público: token compartilhado só para automações que você confia como admin; JWTs (HS256 ou RS256) ou mTLS para pessoas.
-
spec.resourcescom requests e limits em toda Instance. - As API keys do dashboard estão em
chatcli-operator-secrets, uma por time com o menor papel necessário, esecurity.devModeestá desligado. - NetworkPolicies restringem os pods da Instance e do operator, inclusive as portas de métricas em HTTP puro.
- Imagens fixadas (versão do chart do operator;
spec.image.tagsó se quiser desacoplar o servidor da release do operator). - Só uma Instance no cluster deve conduzir o AIOps.
- O allowlist do ExecDiagnostic cobre as portas de health dos seus workloads.
- Recursos customizados e Secrets referenciados estão no backup.
TLS e RBAC
- TLS em tudo que o operator conversa. O operator disca nas Instances só com TLS 1.3, validando o certificado contra o
ca.crtda Instance (ou as CAs do sistema, ousecurity.grpcTLS.caFile). O servidor também só aceita TLS 1.3. Faça a rotação com o cert-manager ou trocando o Secret: os pods reiniciam (chatcli.io/tls-hash) e o operator confia no novoca.crtna próxima conexão. - RBAC do operator. A ClusterRole do operator é ampla por necessidade: acesso total aos seus 17 CRDs; Deployments, Services, ConfigMaps, ServiceAccounts e PVCs; leitura e escrita de Secrets em todo o cluster (ele lê os Secrets referenciados e executa
RotateSecret); pods (inclusive create, para os pods de stress do chaos), eviction de pods (oDrainNodeusa a Eviction API), logs, e eventos do core e deevents.k8s.io; nodes (cordon/drain); create e update em todo kind que o allowlist doApplyManifestadmite (workloads, Jobs, CronJobs, Services, ConfigMaps, HPAs, PDBs, Ingresses e os kinds do Prometheus Operator e do Istio; regras para um API group não instalado ficam inertes), além de NetworkPolicies, para remediação; ReplicaSets só leitura; leases para o leader election. - Sem escalada de RBAC em tempo de execução. O operator nunca cria nem altera ClusterRoles. Ele só pode fazer
binddas pré-provisionadaschatcli-watcherechatcli-role-{viewer,operator,admin,superadmin}(restrito porresourceNames), então um operator comprometido não consegue vincular uma ClusterRole mais privilegiada. As ClusterRoleschatcli-role-*existem para você vincular a pessoas; o operator não vincula nada a usuários. - Barreiras da remediação. O
ApplyManifestsó cria ou atualiza os 16 kinds permitidos (Deployment, StatefulSet, DaemonSet, Service, ConfigMap, HorizontalPodAutoscaler, PodDisruptionBudget, Ingress, CronJob, Job, ServiceMonitor, PrometheusRule, PodMonitor, ServiceEntry, VirtualService, DestinationRule; estenda comsecurity.allowedResourceTypes) no namespace da Issue. O RBAC do operator (chart e kustomize) concede create e update em cada um deles, inclusive os kinds ServiceMonitor, PodMonitor, PrometheusRule, ServiceEntry, VirtualService e DestinationRule; um kind que você acrescenta comsecurity.allowedResourceTypestambém precisa de uma regra de ClusterRole que você adicione. ReplicaSet não está na lista: o Deployment dono dele reverteria uma escrita direta. OExecDiagnosticfica limitado ao allowlist. Os logs passam por 18 padrões de limpeza (chaves de nuvem e de API, JWTs, tokens bearer, senhas, strings de conexão, chaves privadas, endereços IPv4, e-mails, segredos longos em base64/hex) antes de chegarem ao LLM.
Credenciais e rotação
Trocar o token compartilhado reinicia o servidor e muda o operator ao mesmo tempo, mas todo usuário da CLI precisa do novo valor. Para rotação sem interrupção para usuários, prefira JWTs.
Recursos
O operator não aplica requests nem limits às Instances, o que deixa os pods como BestEffort: os primeiros a serem despejados sob pressão no nó. Comece comrequests: {cpu: 250m, memory: 256Mi} e limits: {cpu: "1", memory: 1Gi} e ajuste ao seu tráfego; watcher, servidores MCP e as RPCs de pipeline aumentam o consumo. O próprio operator vem com requests 100m/128Mi e limits 500m/256Mi; aumente em clusters com muitas Issues.
Alta disponibilidade
- Operator: rode
replicaCount: 2ou mais comleaderElect: true. Os controllers e o WatcherBridge rodam só no líder; a API REST e o dashboard são servidos por todas as réplicas, então o Service continua respondendo durante um failover. O chart não cria PodDisruptionBudget para o operator; crie um se você drena nós com frequência. - Instances:
replicas> 1 torna o Service headless e o operator balanceia em round-robin entre os pods. Cada pod é um servidor independente (memória, watcher e emptyDir próprios), e o stream de alertas se prende a um pod por vez. Para uma Instance de AIOps, uma réplica costuma ser o certo. - Persistência e réplicas: o PVC de sessões é ReadWriteOnce, então com
persistence.enabledo Deployment usa a estratégiaRecreate: o pod antigo para e libera o volume antes de o novo subir, e cada rollout (imagem, configuração ou credencial) tem uma breve indisponibilidade. Sem persistência a estratégia éRollingUpdate. Uma segunda réplica agendada em outro nó continua sem conseguir anexar o volume (Multi-Attach error): mantenha uma réplica com persistência e fixe-a comscheduling.affinityse o storage for zonal, ou rode sem persistência quando escalar horizontalmente. - O operator não cria PodDisruptionBudget, HorizontalPodAutoscaler nem NetworkPolicy para Instances.
Políticas de rede
-
Operator: ligue
networkPolicy.enabledno chart (oumake deploy-network-policynos manifestos crus). A entrada é liberada na porta da API (restrinja comnetworkPolicy.apiIngressFrom), na de métricas (metricsIngressFrom) e na de health. Comegress: restricted, a saída fica limitada a DNS, 443, a porta da API do Kubernetes (kubernetesApiPort, 6443), a porta gRPC das Instances (instanceGrpcPort, 50051) e a porta do Prometheus tirada deprometheusUrl; acrescenteegressExtraPortspara SMTP (587/465), git via SSH (22) ou webhooks em outras portas. -
Instances: o operator não cria nenhuma. Um ponto de partida:
Acrescente um
frompara os seus clientes na 50051, e saída para ometricsPortdos alvos do watcher quando coletar métricas deles. O tráfego das probes do kubelet fica isento de NetworkPolicy na maioria dos CNIs, mas não em todos, por isso o exemplo deixa a 9090 aberta para qualquer origem.
Pod Security
Os pods da Instance e do operator atendem ao Pod Security Standardrestricted com os padrões, então você pode rotular os namespaces com pod-security.kubernetes.io/enforce: restricted. Se definir spec.securityContext, ele substitui o padrão inteiro: mantenha runAsNonRoot: true e seccompProfile: {type: RuntimeDefault}. O padrão também define fsGroup: 1000 com fsGroupChangePolicy: OnRootMismatch, para que um volume de sessões novo seja gravável seja qual for o provisioner; mantenha fsGroup: 1000 no seu próprio contexto quando ligar a persistência.
Métricas e monitoramento
-
O servidor expõe
/metrics(e/healthz) na portametricsdo Service da Instance (9090); o operator expõe métricas de controllers e de AIOps (chatcli_operator_*) na 8080 (serviceMonitor.enabled: trueno chart). -
Os dois são HTTP puro sem autenticação, e o listener de métricas do servidor escuta em todas as interfaces independentemente de
bindAddress. Restrinja com NetworkPolicy. -
Para uma Instance, crie seu próprio ServiceMonitor:
-
Nomes de métricas, dashboards do Grafana e queries úteis: Web Dashboard. Alerte em
chatcli_operator_instance_ready == 0e na conditionServerReachable.
Imagens, versões e upgrades
-
As imagens do operator e do servidor são publicadas como
ghcr.io/diillson/chatcli-operator:<version>eghcr.io/diillson/chatcli:<version>(maislatest), multi-arch (amd64, arm64), com SBOM e provenance, assinadas keyless com cosign: -
Fixação. O chart fixa a imagem do operator no seu
appVersione passaCHATCLI_OPERATOR_APP_VERSION, então uma Instance semspec.image.tagroda a mesma release e umhelm upgradedo operator atualiza esses servidores também. Definaspec.image.tagsó para desacoplar uma Instance da release do operator. Evitelatestem produção. - Upgrade e desinstalação: veja Upgrade e desinstalação.
Backup
- Recursos customizados, por exemplo
kubectl get instances,runbooks,notificationpolicies,escalationpolicies,approvalpolicies,incidentslas,servicelevelobjectives,sourcerepositories,clusterregistrations -A -o yaml; acrescenteissues,postmortems,auditeventsse guarda histórico de incidentes no cluster. Ferramentas como o Velero fazem backup de namespaces com seus recursos customizados. - Os Secrets referenciados pelas Instances, e o
chatcli-operator-secrets, a partir do seu cofre de segredos. - O PVC de sessões guarda as sessões do servidor. Ele pertence à Instance: apagar a Instance apaga o claim (o volume segue a reclaim policy da StorageClass).
- O gasto com LLM registrado pelo pipeline fica nos ConfigMaps
chatcli-cost-ledgerdos namespaces onde as Issues acontecem.
O que não existe
- Nenhum admission ou validating webhook: o schema do CRD é a única validação, e o operator informa o resto como conditions.
- Nenhuma conexão em texto puro do operator até uma Instance.
- Nenhum gRPC reflection, a menos que você defina
spec.server.security.enableReflection. - Nenhum PodDisruptionBudget, HPA, NetworkPolicy, ServiceMonitor, Ingress ou LoadBalancer criado para Instances; o Service é sempre ClusterIP ou headless.
- Nenhum TLS ou autenticação nos endpoints de métricas.
- Nenhum SSO/OIDC no dashboard: só API keys.
- Nenhum arquivo de auditoria no operator: as ações dele são recursos AuditEvent. O servidor tem o próprio arquivo de auditoria (
security.auditLogPath). - Nenhum RBAC automático para pessoas: vincule as ClusterRoles
chatcli-role-*você mesmo.
Upgrade e desinstalação
Um upgrade troca o operator e, em toda Instance que segue a release do operator (semspec.image.tag), o servidor também. Dá para ir direto de qualquer release anterior para esta: o hook de CRDs reaplica o schema completo e o operator novo renderiza de novo cada Instance, então não há versões intermediárias para instalar. Leia Atravessando estas releases antes, se você vem de uma release antiga.
Antes de começar
- Faça backup dos recursos customizados e dos Secrets (veja Backup).
-
Salve os values com que a release roda e use esse arquivo como fonte das suas configurações daqui em diante:
Uma release instalada sem overrides, como o comando de instalação desta página, imprime
null; o arquivo funciona assim mesmo. - Confira em Atravessando estas releases se algo precisa ser feito antes do upgrade.
Rodar o upgrade
- Helm
- Manifestos crus
--reset-then-reuse-values (Helm 3.14+) parte dos padrões do chart novo e reaplica seus overrides anteriores. Não use o --reuse-values puro: ele ignora os padrões das chaves que o chart novo adicionou e pode falhar na renderização (nil pointer evaluating).O que acontece, em ordem
- CRDs. O Job de hook pre-upgrade reaplica os 17 CRDs (
kubectl apply --server-side) antes de qualquer outra mudança. - Operator. O Deployment do operator faz rollout: o pod novo fica Ready antes de o antigo parar, então o dashboard e a API REST continuam no ar. Os controllers reiniciam no pod novo.
- Instances. O operator novo renderiza de novo cada Instance. Uma Instance sem
spec.image.tagrecebe a imagem nova do servidor, e qualquer mudança no template do pod reinicia os pods dela. Compersistence.enableda estratégia éRecreate: os pods antigos param antes de os novos subirem, então cada Instance assim fica um breve período fora do ar. - Sondagem. O operator sonda cada servidor de novo. Uma sondagem que cai no meio do rollout pode gravar
ServerReachable=False/ProbeFailedcomDeadlineExceeded ... while waiting for connections to become ready,connection refusedoui/o timeout, mesmo que os pods novos já sirvam normalmente logo depois. Uma sondagem que falha é repetida em 30 segundos, então a condição viraTruelogo depois do rollout. - Alertas. O WatcherBridge reconecta. Se ele alcança um servidor anterior à 1.211.0, que não tem
StreamAlerts(tipicamente um pod antigo ainda rodando), ele logaServer has no StreamAlerts RPC; polling GetAlertse faz polling a cada 30 segundos. Quando esse pod antigo sai, o próximo polling falha comUnavailable, o bridge logaServer unavailable while polling; retrying the alert stream on reconnecte abre o stream no servidor novo. Nenhum alerta se perde nesse meio-tempo.
Verificar
True. Se o ServerReachable ainda mostra o False gravado durante o rollout, espere uns 30 segundos pela nova tentativa.
Atravessando estas releases
Desinstalar
Apague as Instances primeiro, com o operator ainda rodando: o finalizer delas (platform.chatcli.io/finalizer) é removido pelo operator, e uma Instance apagada depois que o operator já saiu fica em Terminating até você removê-lo à mão (kubectl patch instance <name> -n <ns> --type merge -p '{"metadata":{"finalizers":null}}'). Depois rode helm uninstall chatcli-operator -n chatcli-system (ou make undeploy nos manifestos crus, que também apaga os CRDs). O helm uninstall mantém os CRDs (o Helm nunca apaga crds/); apagá-los apaga todos os recursos customizados.
Solução de problemas
Desenvolvimento
make manifests só imprime o comando do controller-gen; os CRDs gerados ficam versionados em config/crd/bases/ e copiados para o crds/ dos dois charts.
Próximos passos
AIOps Platform
Como o pipeline funciona por dentro
Ciclo de vida do incidente
Estados, ações de remediação e rollback
Server Mode
Flags, autenticação e as RPCs gRPC
Setup de produção
Receita: um setup de AIOps em produção