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 ghcr.io/diillson/chatcli:latest
Kubernetes Operator ghcr.io/diillson/chatcli-operator:latest
# Puxar a imagem do servidor
docker pull ghcr.io/diillson/chatcli:latest
# Ou uma versão específica
docker pull ghcr.io/diillson/chatcli:v1.57.0
# Puxar a imagem do operator
docker pull ghcr.io/diillson/chatcli-operator:latest
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:-}"
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)
O ChatCLI inclui um Helm chart completo em deploy/helm/chatcli/.
Pré-requisitos
Cluster Kubernetes (kind, minikube, EKS, GKE, AKS, etc.)
Helm 3.x instalado
kubectl configurado para o cluster
Instalação Básica
OpenAI
Anthropic (com Auth)
helm install chatcli deploy/helm/chatcli \
--set llm.provider=OPENAI \
--set secrets.openaiApiKey=sk-xxx
helm install chatcli deploy/helm/chatcli \
--set llm.provider=CLAUDEAI \
--set secrets.anthropicApiKey=sk-ant-xxx \
--set server.token=meu-token-secreto
helm install chatcli deploy/helm/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 deploy/helm/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
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 ""serviceMonitor.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.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.
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.
Usando Secret Existente
Se você já tem um Secret com as API keys:
helm install chatcli deploy/helm/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"
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 deploy/helm/chatcli \
--set service.type=NodePort
chatcli connect < node-i p > : < node-por t >
helm install chatcli deploy/helm/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 deploy/helm/chatcli -f values-prod.yaml
Upgrade e Rollback
# Atualizar
helm upgrade chatcli deploy/helm/chatcli --set llm.model=gpt-4-turbo
# Rollback
helm rollback chatcli 1
Exemplo Completo: Produção
Single-Target (Legado)
helm install chatcli deploy/helm/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 deploy/helm/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