Pular para o conteúdo principal
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)

Rodar com Docker

docker run -p 50051:50051 \
  -e LLM_PROVIDER=OPENAI \
  -e OPENAI_API_KEY=sk-xxx \
  chatcli

Docker Compose

O projeto inclui um docker-compose.yml pronto para desenvolvimento:
1

Defina as variáveis

export LLM_PROVIDER=OPENAI
export OPENAI_API_KEY=sk-xxx
2

Inicie o container

docker compose up -d
3

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

helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --set llm.provider=OPENAI \
  --set secrets.openaiApiKey=sk-xxx
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.

Instalação com Segurança (Helm)

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

Instalação com K8s Watcher (Single-Target)

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

Instalação com Multi-Target + Prometheus

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

ValorDescriçãoPadrão
replicaCountNúmero de réplicas1
image.repositoryRepositório da imagemghcr.io/diillson/chatcli
image.tagTag da imagemlatest
server.portPorta gRPC50051
server.metricsPortPorta HTTP para Prometheus metrics (0 = desabilitado)9090
server.tokenToken de autenticação""
server.grpcReflectionHabilitar gRPC reflection (debugging)false
serviceMonitor.enabledCriar ServiceMonitor (requer Prometheus Operator)false
serviceMonitor.intervalIntervalo de scrape do Prometheus30s

TLS

ValorDescriçãoPadrão
tls.enabledHabilitar TLSfalse
tls.certFileCaminho do certificado""
tls.keyFileCaminho da chave""
tls.existingSecretSecret existente com certs""

LLM

ValorDescriçãoPadrão
llm.providerProvedor padrão""
llm.modelModelo padrão""

Secrets (API Keys)

ValorDescriçã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

ValorDescriçãoPadrão
COPILOT_MODELModelo padrão do Copilot (ex: gpt-4o, claude-sonnet-4)gpt-4o
COPILOT_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

ValorDescriçãoPadrão
ollama.enabledHabilitar Ollamafalse
ollama.baseUrlURL base do Ollamahttp://ollama:11434
ollama.modelModelo Ollama""

K8s Watcher

ValorDescriçãoPadrão
watcher.enabledHabilitar o watcherfalse
watcher.targetsLista de targets multi-deployment (ver abaixo)[]
watcher.deploymentDeployment único - legado""
watcher.namespaceNamespace do deployment - legado""
watcher.intervalIntervalo de coleta30s
watcher.windowJanela de observação2h
watcher.maxLogLinesLinhas de log por pod100
watcher.maxContextCharsBudget de contexto LLM32000
Campos de cada target (watcher.targets[].):
CampoDescriçãoObrigatório
deploymentNome do deploymentSim
namespaceNamespace (padrão: default)Não
metricsPortPorta Prometheus (0 = desabilitado)Não
metricsPathPath HTTP das métricasNão (/metrics)
metricsFilterFiltros glob para métricasNão

Fallback de Provedores

ValorDescriçãoPadrão
fallback.enabledHabilitar cadeia de failover automáticofalse
fallback.providersLista ordenada de provedores [{name, model}][]
fallback.maxRetriesTentativas por provedor antes de avançar2
fallback.cooldownBaseCooldown base após falha30s
fallback.cooldownMaxCooldown máximo (backoff exponencial)5m

MCP (Model Context Protocol)

ValorDescriçãoPadrão
mcp.enabledHabilitar integração MCPfalse
mcp.serversLista de servidores MCP [{name, transport, command, args, url, enabled}][]
mcp.existingConfigMapConfigMap existente com mcp_servers.json""

Bootstrap e Memória

ValorDescriçãoPadrão
bootstrap.enabledCarregar arquivos bootstrap (SOUL.md, USER.md, etc.)false
bootstrap.definitionsDefinições inline de arquivos bootstrap{}
bootstrap.existingConfigMapConfigMap existente com arquivos bootstrap""
memory.enabledHabilitar memória persistentefalse
safety.enabledHabilitar regras de segurança configuráveisfalse

Skill Registry

ValorDescriçãoPadrão
skillRegistry.enabledHabilitar variáveis de ambiente para skill registryfalse
skillRegistry.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

ValorDescriçãoPadrão
persistence.enabledPersistir sessões em PVCtrue
persistence.storageClassStorage class""
persistence.sizeTamanho do volume1Gi

Segurança

ValorDescriçãoPadrão
podSecurityContext.runAsNonRootObriga execução como não-roottrue
podSecurityContext.runAsUserUID do processo1000
podSecurityContext.seccompProfile.typePerfil seccompRuntimeDefault
securityContext.allowPrivilegeEscalationPermite escalação de privilégiosfalse
securityContext.readOnlyRootFilesystemFilesystem somente-leituratrue
securityContext.capabilities.dropCapabilities removidasALL
rbac.clusterWideUsa ClusterRole em vez de Role namespace-scopedfalse
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)

ValorDescriçãoPadrão
autoscaling.enabledHabilitar HorizontalPodAutoscalerfalse
autoscaling.minReplicasMínimo de réplicas1
autoscaling.maxReplicasMáximo de réplicas10
autoscaling.targetCPUUtilizationPercentageMeta de uso de CPU (%)80
autoscaling.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

ValorDescriçãoPadrão
podDisruptionBudget.enabledCriar PodDisruptionBudgetfalse
podDisruptionBudget.minAvailableMínimo de pods disponíveis durante disruptions1
podDisruptionBudget.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

ValorDescriçãoPadrão
networkPolicy.enabledCriar NetworkPolicyfalse
networkPolicy.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

ValorDescriçãoPadrão
service.typeTipo do ServiceClusterIP
service.portPorta do Service50051
service.headlessHabilita Service headless para balanceamento gRPC client-side (recomendado quando replicaCount > 1)false
ingress.enabledHabilitar Ingressfalse
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

kubectl port-forward svc/chatcli 50051:50051
chatcli connect localhost:50051

Ingress (com TLS)

# 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:
ValorDescriçãoPadrã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)strict
security.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çafalse
security.sessionEncryptionHabilitar criptografia de sessões em repousofalse
# 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

Multi-Target com Prometheus (Recomendado)

# 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