O ChatCLI pode ser empacotado como container Docker e deployado no Kubernetes usando o Helm chart oficial. Esta página cobre todos os cenários de deployment.
Imagens Oficiais (GHCR)
As imagens Docker oficiais são publicadas automaticamente no GitHub Container Registry a cada release:
Servidor ChatCLI Última versão: 1.139.0
ghcr.io/diillson/chatcli:1.139.0
Kubernetes Operator Última versão: 1.139.0
ghcr.io/diillson/chatcli-operator:1.139.0
# Puxar a imagem do servidor (versão específica — recomendado)
docker pull ghcr.io/diillson/chatcli:1.139.0
# Ou a última versão disponível
docker pull ghcr.io/diillson/chatcli:latest
# Puxar a imagem do operator
docker pull ghcr.io/diillson/chatcli-operator:1.139.0
As imagens suportam multi-arch (linux/amd64 e linux/arm64).
Docker
Build da Imagem (Local)
# Na raiz do projeto
docker build -t chatcli .
O Dockerfile usa multi-stage build para produzir uma imagem mínima (~20MB):
Build stage : golang:1.25-alpine compila o binário
Runtime stage : alpine:3.21 com usuário não-root, health check integrado
Build da Imagem do Operator (Local)
# IMPORTANTE: deve ser construído a partir da raiz do repositório
# (go.mod do operator usa replace directive apontando para ../)
docker build -f operator/Dockerfile -t ghcr.io/diillson/chatcli-operator:latest .
O Dockerfile do operator usa:
Build stage : golang:1.25 com suporte multi-arch (TARGETARCH)
Runtime stage : gcr.io/distroless/static:nonroot (segurança máxima, sem shell)
Básico
Com Auth
Com Persistência
docker run -p 50051:50051 \
-e LLM_PROVIDER=OPENAI \
-e OPENAI_API_KEY=sk-xxx \
chatcli
docker run -p 50051:50051 \
-e CHATCLI_SERVER_TOKEN=meu-token \
-e LLM_PROVIDER=CLAUDEAI \
-e ANTHROPIC_API_KEY=sk-ant-xxx \
chatcli
docker run -p 50051:50051 \
-v chatcli-sessions:/home/chatcli/.chatcli/sessions \
-e LLM_PROVIDER=OPENAI \
-e OPENAI_API_KEY=sk-xxx \
chatcli
Docker Compose
O projeto inclui um docker-compose.yml pronto para desenvolvimento:
Defina as variáveis
export LLM_PROVIDER = OPENAI
export OPENAI_API_KEY = sk-xxx
Conecte do seu terminal
chatcli connect localhost:50051
O Docker Compose configura:
Porta 50051 exposta
Volumes persistentes para sessões e plugins
Restart automático (unless-stopped)
Todas as variáveis de LLM via environment
Hardening de segurança : filesystem read-only, no-new-privileges, limites de CPU/memória, tmpfs para /tmp
Arquivo docker-compose.yml
version : "3.9"
services :
chatcli-server :
build :
context : .
dockerfile : Dockerfile
container_name : chatcli-server
ports :
- "50051:50051"
environment :
CHATCLI_SERVER_PORT : "50051"
CHATCLI_SERVER_TOKEN : "${CHATCLI_SERVER_TOKEN:-}"
LLM_PROVIDER : "${LLM_PROVIDER:-}"
OPENAI_API_KEY : "${OPENAI_API_KEY:-}"
ANTHROPIC_API_KEY : "${ANTHROPIC_API_KEY:-}"
GOOGLEAI_API_KEY : "${GOOGLEAI_API_KEY:-}"
OLLAMA_ENABLED : "${OLLAMA_ENABLED:-}"
OLLAMA_BASE_URL : "${OLLAMA_BASE_URL:-}"
GITHUB_COPILOT_TOKEN : "${GITHUB_COPILOT_TOKEN:-}"
COPILOT_MODEL : "${COPILOT_MODEL:-}"
OPENROUTER_API_KEY : "${OPENROUTER_API_KEY:-}"
LOG_LEVEL : "${LOG_LEVEL:-info}"
volumes :
- chatcli-sessions:/home/chatcli/.chatcli/sessions
- chatcli-plugins:/home/chatcli/.chatcli/plugins
restart : unless-stopped
read_only : true
tmpfs :
- /tmp:size=100M
security_opt :
- no-new-privileges:true
deploy :
resources :
limits :
cpus : "2.0"
memory : 1G
volumes :
chatcli-sessions :
chatcli-plugins :
O container roda com filesystem read-only e no-new-privileges por padrão. O diretório /tmp usa tmpfs em memória (limitado a 100MB). Os volumes nomeados (chatcli-sessions, chatcli-plugins) são os únicos pontos graváveis. Veja a documentação de segurança para detalhes.
Kubernetes (Helm)
Os Helm charts do ChatCLI estão disponíveis como artefatos OCI no GHCR — não é necessário clonar o repositório.
Pré-requisitos
Cluster Kubernetes (kind, minikube, EKS, GKE, AKS, etc.)
Helm 3.8+ instalado (suporte a OCI)
kubectl configurado para o cluster
Instalação Básica
OpenAI
Anthropic (com Auth)
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set llm.provider=OPENAI \
--set secrets.openaiApiKey=sk-xxx
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set llm.provider=CLAUDEAI \
--set secrets.anthropicApiKey=sk-ant-xxx \
--set server.token=meu-token-secreto
Se preferir usar o chart local (após clonar o repo), substitua oci://ghcr.io/diillson/charts/chatcli por ./deploy/helm/chatcli/ em todos os comandos abaixo.
Para deployments com segurança completa, incluindo rate limiting, autenticação JWT e modo agente seguro:
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set security.rateLimitRps= 20 \
--set security.agentSecurityMode=strict \
--set security.jwtSecretRef.name=chatcli-jwt \
--set security.jwtSecretRef.key=secret
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set llm.provider=OPENAI \
--set secrets.openaiApiKey=sk-xxx \
--set watcher.enabled= true \
--set watcher.deployment=myapp \
--set watcher.namespace=production
Para monitorar múltiplos deployments com métricas Prometheus, use um values.yaml:
# values-multi.yaml
llm :
provider : CLAUDEAI
secrets :
anthropicApiKey : sk-ant-xxx
watcher :
enabled : true
interval : "15s"
maxContextChars : 32000
targets :
- deployment : api-gateway
namespace : production
metricsPort : 9090
metricsFilter : [ "http_requests_*" , "http_request_duration_*" ]
- deployment : auth-service
namespace : production
metricsPort : 9090
- deployment : worker
namespace : batch
helm install chatcli oci://ghcr.io/diillson/charts/chatcli -f values-multi.yaml
O chart automaticamente:
Cria ServiceAccount com RBAC para o watcher ler pods, eventos, logs
Auto-detecta multi-namespace : se targets estão em namespaces diferentes, usa ClusterRole em vez de Role
Gera ConfigMap <name>-watch-config com o YAML multi-target
Monta o config como volume e passa --watch-config ao container
Passa corretamente as flags --token, --model e --mcp-config ao servidor
Usa health probes gRPC nativas (liveness, readiness e startup) em vez de pidof
Inclui todos os 17 CRDs do operator no diretório crds/
Valores do Helm Chart
Servidor
Valor Descrição Padrão replicaCountNúmero de réplicas 1image.repositoryRepositório da imagem ghcr.io/diillson/chatcliimage.tagTag da imagem latestserver.portPorta gRPC 50051server.metricsPortPorta HTTP para Prometheus metrics (0 = desabilitado) 9090server.tokenToken de autenticação ""server.grpcReflectionHabilitar gRPC reflection (debugging) falseserviceMonitor.enabledCriar ServiceMonitor (requer Prometheus Operator) falseserviceMonitor.intervalIntervalo de scrape do Prometheus 30s
TLS
Valor Descrição Padrão tls.enabledHabilitar TLS falsetls.certFileCaminho do certificado ""tls.keyFileCaminho da chave ""tls.existingSecretSecret existente com certs ""
LLM
Valor Descrição Padrão llm.providerProvedor padrão ""llm.modelModelo padrão ""
Secrets (API Keys)
Valor Descrição secrets.existingSecretSecret existente (em vez de criar um novo) secrets.openaiApiKeyChave da OpenAI secrets.anthropicApiKeyChave da Anthropic secrets.googleaiApiKeyChave do Google AI secrets.xaiApiKeyChave da xAI secrets.openrouterApiKeyChave do OpenRouter secrets.stackspotClientIdStackSpot Client ID secrets.stackspotClientKeyStackSpot Client Key secrets.stackspotRealmStackSpot Realm secrets.stackspotAgentIdStackSpot Agent ID secrets.githubCopilotTokenToken OAuth do GitHub Copilot
GitHub Copilot
Valor Descrição Padrão COPILOT_MODELModelo padrão do Copilot (ex: gpt-4o, claude-sonnet-4) gpt-4oCOPILOT_MAX_TOKENSMáximo de tokens para resposta ""COPILOT_API_BASE_URLURL base da API (para ambientes enterprise) https://api.githubcopilot.com
Para autenticação, use secrets.githubCopilotToken com um token obtido via /auth login github-copilot, ou defina GITHUB_COPILOT_TOKEN como variável de ambiente.
Ollama
Valor Descrição Padrão ollama.enabledHabilitar Ollama falseollama.baseUrlURL base do Ollama http://ollama:11434ollama.modelModelo Ollama ""
K8s Watcher
Valor Descrição Padrão watcher.enabledHabilitar o watcher falsewatcher.targetsLista de targets multi-deployment (ver abaixo) []watcher.deploymentDeployment único - legado ""watcher.namespaceNamespace do deployment - legado ""watcher.intervalIntervalo de coleta 30swatcher.windowJanela de observação 2hwatcher.maxLogLinesLinhas de log por pod 100watcher.maxContextCharsBudget de contexto LLM 32000
Campos de cada target (watcher.targets[].):
Campo Descrição Obrigatório deploymentNome do deployment Sim namespaceNamespace (padrão: default) Não metricsPortPorta Prometheus (0 = desabilitado) Não metricsPathPath HTTP das métricas Não (/metrics) metricsFilterFiltros glob para métricas Não
Fallback de Provedores
Valor Descrição Padrão fallback.enabledHabilitar cadeia de failover automático falsefallback.providersLista ordenada de provedores [{name, model}] []fallback.maxRetriesTentativas por provedor antes de avançar 2fallback.cooldownBaseCooldown base após falha 30sfallback.cooldownMaxCooldown máximo (backoff exponencial) 5m
MCP (Model Context Protocol)
Valor Descrição Padrão mcp.enabledHabilitar integração MCP falsemcp.serversLista de servidores MCP [{name, transport, command, args, url, enabled}] []mcp.existingConfigMapConfigMap existente com mcp_servers.json ""
Bootstrap e Memória
Valor Descrição Padrão bootstrap.enabledCarregar arquivos bootstrap (SOUL.md, USER.md, etc.) falsebootstrap.definitionsDefinições inline de arquivos bootstrap {}bootstrap.existingConfigMapConfigMap existente com arquivos bootstrap ""memory.enabledHabilitar memória persistente falsesafety.enabledHabilitar regras de segurança configuráveis false
Skill Registry
Valor Descrição Padrão skillRegistry.enabledHabilitar variáveis de ambiente para skill registry falseskillRegistry.registryUrlsURLs adicionais de registries (separadas por vírgula) ""skillRegistry.registryDisableNomes de registries a desabilitar (separados por vírgula) ""skillRegistry.installDirDiretório de instalação de skills dentro do container ""
Quando habilitado, os valores são passados como variáveis CHATCLI_REGISTRY_* no ConfigMap. O container ChatCLI cria automaticamente ~/.chatcli/registries.yaml com os registries padrão (chatcli, clawhub). Use /skill search e /skill install para gerenciar skills via registries.
Persistência
Valor Descrição Padrão persistence.enabledPersistir sessões em PVC truepersistence.storageClassStorage class ""persistence.sizeTamanho do volume 1Gi
Segurança
Valor Descrição Padrão podSecurityContext.runAsNonRootObriga execução como não-root truepodSecurityContext.runAsUserUID do processo 1000podSecurityContext.seccompProfile.typePerfil seccomp RuntimeDefaultsecurityContext.allowPrivilegeEscalationPermite escalação de privilégios falsesecurityContext.readOnlyRootFilesystemFilesystem somente-leitura truesecurityContext.capabilities.dropCapabilities removidas ALLrbac.clusterWideUsa ClusterRole em vez de Role namespace-scoped false
Quando readOnlyRootFilesystem está true, o chart monta automaticamente um tmpfs em /tmp e um emptyDir em /home/chatcli/.chatcli (200Mi) para dados de runtime. A variável HOME=/home/chatcli é definida automaticamente. Para monitorar múltiplos namespaces, habilite rbac.clusterWide: true. Veja a documentação de segurança para detalhes.
Nota : O ConfigMap e o Secret referenciados via envFrom são marcados como optional: true, permitindo criar o Instance/Deployment antes dos recursos dependentes. O operator observa Secrets automaticamente e dispara rolling updates quando são criados ou atualizados.
Autoscaling (HPA)
Valor Descrição Padrão autoscaling.enabledHabilitar HorizontalPodAutoscaler falseautoscaling.minReplicasMínimo de réplicas 1autoscaling.maxReplicasMáximo de réplicas 10autoscaling.targetCPUUtilizationPercentageMeta de uso de CPU (%) 80autoscaling.targetMemoryUtilizationPercentageMeta de uso de memória (%) ""
Quando autoscaling.enabled é true, o replicaCount é ignorado e o HPA controla o número de réplicas automaticamente.
Pod Disruption Budget
Valor Descrição Padrão podDisruptionBudget.enabledCriar PodDisruptionBudget falsepodDisruptionBudget.minAvailableMínimo de pods disponíveis durante disruptions 1podDisruptionBudget.maxUnavailableMáximo de pods indisponíveis (alternativa a minAvailable) ""
O PDB garante alta disponibilidade durante upgrades de nó, drain e manutenção do cluster.
Network Policy
Valor Descrição Padrão networkPolicy.enabledCriar NetworkPolicy falsenetworkPolicy.allowIngressFromRegras de ingress permitidas []networkPolicy.allowEgressToRegras de egress permitidas []
A NetworkPolicy restringe tráfego de rede no nível do pod. Requer um CNI com suporte a NetworkPolicy (Calico, Cilium, etc.).
Rede
Valor Descrição Padrão service.typeTipo do Service ClusterIPservice.portPorta do Service 50051service.headlessHabilita Service headless para balanceamento gRPC client-side (recomendado quando replicaCount > 1) falseingress.enabledHabilitar Ingress false
gRPC e múltiplas réplicas : O gRPC usa conexões HTTP/2 persistentes que fixam em um único pod. Para replicaCount > 1, habilite service.headless: true para ativar balanceamento round-robin via DNS. O client já possui keepalive e round-robin integrados.
Ingress gRPC : Quando o Ingress está habilitado com className: nginx, o chart adiciona automaticamente a annotation nginx.ingress.kubernetes.io/backend-protocol: "GRPC" para rotear tráfego gRPC corretamente.
Usando Secret Existente
Se você já tem um Secret com as API keys:
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set llm.provider=OPENAI \
--set secrets.existingSecret=my-llm-keys
O Secret deve conter as chaves esperadas:
apiVersion : v1
kind : Secret
metadata :
name : my-llm-keys
type : Opaque
stringData :
OPENAI_API_KEY : "sk-xxx"
ANTHROPIC_API_KEY : "sk-ant-xxx"
OPENROUTER_API_KEY : "sk-or-xxx" # opcional
GITHUB_COPILOT_TOKEN : "ghu_xxx" # opcional
Acessar o Servidor
Port Forward (Dev)
NodePort
LoadBalancer
kubectl port-forward svc/chatcli 50051:50051
chatcli connect localhost:50051
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set service.type=NodePort
chatcli connect < node-i p > : < node-por t >
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--set service.type=LoadBalancer
# Aguarde o IP externo
kubectl get svc chatcli -w
chatcli connect < external-i p > :50051
# values-prod.yaml
ingress :
enabled : true
className : nginx
annotations :
cert-manager.io/cluster-issuer : letsencrypt-prod
hosts :
- host : chatcli.meudominio.com
paths :
- path : /
pathType : ImplementationSpecific
tls :
- secretName : chatcli-tls
hosts :
- chatcli.meudominio.com
helm install chatcli oci://ghcr.io/diillson/charts/chatcli -f values-prod.yaml
Upgrade e Rollback
# Atualizar
helm upgrade chatcli oci://ghcr.io/diillson/charts/chatcli --set llm.model=gpt-4-turbo
# Rollback
helm rollback chatcli 1
Configuração de Segurança
O Helm chart suporta configuração de segurança avançada para ambientes de produção:
Valor Descrição Padrão security.rateLimitRpsLimite de requisições por segundo (rate limiting) 0 (desabilitado)security.bindAddressEndereço de bind do servidor. Auto-detecta 0.0.0.0 em Kubernetes via KUBERNETES_SERVICE_HOST. 127.0.0.1 / 0.0.0.0 (K8s)security.agentSecurityModeModo de segurança do agente (strict ou permissive) strictsecurity.jwtSecretRef.nameNome do Secret Kubernetes contendo o segredo JWT ""security.jwtSecretRef.keyChave dentro do Secret com o valor do segredo JWT ""security.auditLogHabilitar log de auditoria de segurança falsesecurity.sessionEncryptionHabilitar criptografia de sessões em repouso false
# values-security.yaml
security :
rateLimitRps : 20
# bindAddress: "0.0.0.0" # Opcional — auto-detectado em Kubernetes
agentSecurityMode : strict
auditLog : true
sessionEncryption : true
jwtSecretRef :
name : chatcli-jwt
key : secret
Em Kubernetes, o bindAddress é automaticamente detectado como 0.0.0.0 via a variável de ambiente KUBERNETES_SERVICE_HOST. Não é necessário configurar manualmente.
Em produção, sempre configure security.jwtSecretRef para habilitar autenticação JWT. Sem isso, o servidor aceita conexões sem autenticação.
Exemplo Completo: Produção
Single-Target (Legado)
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--namespace chatcli --create-namespace \
--set llm.provider=CLAUDEAI \
--set secrets.anthropicApiKey=sk-ant-xxx \
--set server.token=super-secret-token \
--set tls.enabled= true \
--set tls.existingSecret=chatcli-tls-certs \
--set watcher.enabled= true \
--set watcher.deployment=production-app \
--set watcher.namespace=production \
--set persistence.enabled= true \
--set persistence.size=5Gi \
--set resources.requests.memory=256Mi \
--set resources.limits.memory=1Gi
# values-prod.yaml
llm :
provider : CLAUDEAI
secrets :
existingSecret : chatcli-llm-keys
server :
token : super-secret-token
tls :
enabled : true
existingSecret : chatcli-tls-certs
watcher :
enabled : true
interval : "15s"
maxContextChars : 10000
targets :
- deployment : api-gateway
namespace : production
metricsPort : 9090
metricsFilter : [ "http_requests_*" , "http_request_duration_*" ]
- deployment : auth-service
namespace : production
metricsPort : 9090
- deployment : payment-service
namespace : production
metricsPort : 9090
metricsFilter : [ "payment_*" , "stripe_*" ]
- deployment : worker
namespace : batch
persistence :
enabled : true
size : 5Gi
resources :
requests :
memory : 256Mi
limits :
memory : 1Gi
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
--namespace chatcli --create-namespace \
-f values-prod.yaml
Quando targets estão em namespaces diferentes (ex: production e batch), o chart cria automaticamente um ClusterRole em vez de Role namespace-scoped.
Próximos Passos
Servidor Configurar o servidor gRPC
Conexão Remota Conectar ao servidor
K8s Watcher Monitorar Kubernetes