首页 产品 为什么选 OCTO 解决方案 文档 关于
文档中心 / 部署运维 / Kubernetes Helm 部署
← 返回文档中心

Kubernetes Helm 部署

OCTO 文档中心 · 部署运维

  • source-repos-internal/octo-deployment/helm/octo/values.yaml
  • source-repos-internal/octo-deployment/helm/octo/README.md
  • source-repos-internal/octo-deployment/helm/octo/deploy.sh
  • 02-architecture/OCTO全组件服务清单.md
  • 03-deployment-ops/基础设施依赖映射.md
  • 03-deployment-ops/OCTO部署形态总览.md

Kubernetes Helm 部署 SOP v1.0

本文档面向多节点/生产环境 K8s 部署场景,基于 OCTO Helm Chart 提供完整部署手册。

所有配置项、端口、参数均来自 `helm/octo/values.yaml` 和 `helm/octo/README.md`,不确定处标注待验证。


一、前置要求

1.1 Kubernetes 集群

组件 版本要求 验证命令
Kubernetes ≥ 1.24 kubectl version --short
Helm ≥ 3.10 helm version
kubectl 匹配集群版本 kubectl version --short
默认 StorageClass 必须存在 kubectl get sc
Ingress Controller 必须安装(nginx-ingress / traefik / qcloud TKE 等) kubectl get ingressclass
CoreDNS 正常运行 kubectl -n kube-system get pods -l k8s-app=kube-dns

Helm Chart README 明确声明 K8s ≥ 1.24 / Helm ≥ 3.10。

1.2 节点资源建议

⚠️ 以下为参考值(基于 docker-compose 资源占用推断),生产资源规格待产品管家/交付侧确认。

部署规模 节点数 每节点 CPU 每节点内存 系统盘
最小(核心7件套) 1+ 4核 8 GiB ≥50 GiB SSD
标准(含主要模块) 3+ 8核 16 GiB ≥100 GiB SSD
全套(含search HA) 3+ 16核 32 GiB ≥200 GiB SSD
  • OpenSearch(3节点HA):每个节点 requests 500m CPU / 1GiB RAM,limits 2 CPU / 2GiB RAM;JVM 堆默认 -Xms512m -Xmx512m
  • Kafka(3节点KRaft):每个节点 requests 250m CPU / 512MiB RAM,limits 1 CPU / 1GiB RAM
  • es-indexer / doc-indexer / drive-indexer:每实例 ~100-500m CPU / 128-512MiB RAM

1.3 存储要求

组件 默认 PVC 大小 StorageClass 重要性
MySQL 20 GiB 默认 SC 🔴极高
Redis 10 GiB 默认 SC 🟡中
MinIO 50 GiB 默认 SC 🔴极高
WuKongIM 10 GiB 默认 SC 🔴极高
OpenSearch 20 GiB 默认 SC 🟠高(可重建)
Kafka 10 GiB 默认 SC 🟠高
es-indexer DLQ spill 10 GiB 默认 SC 🟡中
Fleet PostgreSQL 10 GiB 默认 SC 🔴高(fleet模块)
Speech storage 10 GiB 默认 SC 🟡中(speech模块)

PVC 大小可通过 `*.storage.size` values 覆盖。

1.4 域名与证书

  • 一个可解析到 Ingress Controller LB 外部 IP 的域名(如 octo.example.com)
  • TLS 证书(两种方式):
  • 方式A:提前创建 K8s TLS Secret:
  •     kubectl create secret tls octo-tls --cert=tls.crt --key=tls.key -n octo
  • 方式B:使用 cert-manager 自动签发(Let's Encrypt 等)
  • 方式C:TKE/CLB 场景使用 ingress.tls.certId(腾讯云 SSL 证书 ID)

1.5 镜像仓库

  • 默认镜像从 Docker Hub(docker.io/mininglamposs/*)拉取
  • 内网环境需设置 global.imageRegistry 指向私有镜像仓库(如 hub2.intra.mlamp.cn/octo)
  • 私有仓库需配置 global.imagePullSecrets:
  •   kubectl create secret docker-registry regcred \
        --docker-server= --docker-username= \
        --docker-password= -n octo
  • ⚠️ search.opensearch.image 默认 octo-search-opensearch-ik:2.17.0 是本地构建名,不能直接拉取。必须自行构建(docker/opensearch/Dockerfile,analysis-ik baked in)并推到可访问的仓库,然后在 values 中设置 repository/tag。

二、添加 Helm 仓库(或使用本地 Chart)

方式A:本地 Chart(推荐用于内部/定制部署)

# octo-deployment 仓库位于本地
cd octo-deployment/helm/octo

方式B:OCI Registry(如有发布)

helm install octo oci://ghcr.io/mininglamp-oss/octo --version  \
  --namespace octo --create-namespace \
  -f my-values.yaml

三、values.yaml 关键配置

3.1 创建 my-values.yaml

# my-values.yaml

# ── 域名与外部URL ──
domain: "octo.example.com"
externalBaseURL: "https://octo.example.com"
timezone: "Asia/Shanghai"

# ── 镜像仓库(内网场景) ──
global:
  imageRegistry: "hub2.intra.mlamp.cn/octo"   # 按需修改
  # imagePullSecrets:
  #   - name: regcred
  storageClass: ""   # 使用集群默认 StorageClass;指定则填名字

# ── 密钥(必填!必须生成强密码/令牌) ──
secrets:
  mysqlRootPassword: ""
  minioRootPassword: ""   # ≥8字符
  minioAppPassword: ""
  summaryDbPassword: ""
  summaryReaderPassword: ""
  octoMasterKey: ""        # 恰好32hex=16字节
  userApiKeySecret: ""
  notifyInternalToken: ""
  wukongimManagerToken: ""
  adminPwd: ""            # 超管初始密码
  # redisPassword: ""                            # 如Redis启用密码
  llmApiKey: ""                          # LLM API Key(summary需要)

  # 启用对应模块时才需要:
  marketplaceDbPassword: ""
  speechDbPassword: ""
  speechAdminUsername: "admin"
  speechAdminPassword: ""
  speechAdminJwtSecret: ""
  speechQwenKey: ""               # qwen引擎
  docsDbPassword: ""
  docsCollabSecret: ""     # ≥32hex
  docsAttachmentSecret: "" # ≥32hex
  docsHtmlInternalRegisterToken: ""
  driveDbPassword: ""
  fleetDbPassword: ""
  fleetJwtSecret: ""       # ≥32hex
  fleetLoopCredentialHmacKey: ""  # ≥32hex

# ── LLM 配置 ──
llm:
  apiURL: "https://llm-gateway.example.com/v1"   # 按需修改
  model: "claude-sonnet-4-6"                     # 默认模型

# ── octo-server 配置 ──
server:
  replicas: 2                                    # 生产建议≥2副本
  config:
    mode: "release"
    register:
      disabled: true                             # 禁止公开注册
    fileService: "minio"                         # minio/tencentCOS/aliOSS/s3/qiniu

# ── Web / Admin ──
web:
  replicas: 2
admin:
  replicas: 2

# ── WuKongIM ──
wukongim:
  replicas: 1                                    # 单节点;HA设3
  auth:
    jwtSecret: ""          # 多副本必须设JWT

# ── 存储 ──
mysql:
  storage:
    size: "20Gi"
redis:
  storage:
    size: "10Gi"
minio:
  storage:
    size: "50Gi"
wukongim:
  storage:
    size: "10Gi"

# ── Ingress(启用TLS) ──
ingress:
  enabled: true
  className: "nginx"                             # 替换为你的IngressClass
  host: "octo.example.com"
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "1000m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
  tls:
    enabled: true
    secretName: "octo-tls"                       # 对应提前创建的TLS Secret

# ── Nginx Service ──
nginx:
  service:
    type: "ClusterIP"                            # 通过Ingress暴露;可设LoadBalancer

⚠️ 不要把 `$(openssl rand ...)` 直接写进 YAML 文件——Helm 不执行 shell 命令。先在终端生成值,再复制粘贴到 my-values.yaml,或使用 `--set` 命令行传参。

3.2 密钥生成命令速查

# 生成一组密钥并保存
cat < secrets.txt
MYSQL_ROOT_PASSWORD=$(openssl rand -hex 16)
MINIO_ROOT_PASSWORD=$(openssl rand -hex 16)
OCTO_MINIO_APP_PASSWORD=$(openssl rand -hex 24)
OCTO_SUMMARY_DB_PASSWORD=$(openssl rand -hex 16)
OCTO_SUMMARY_READER_PASSWORD=$(openssl rand -hex 16)
OCTO_MARKETPLACE_DB_PASSWORD=$(openssl rand -hex 16)
OCTO_MASTER_KEY=$(openssl rand -hex 16)
OCTO_USER_API_KEY_SECRET=$(openssl rand -hex 16)
OCTO_NOTIFY_INTERNAL_TOKEN=$(openssl rand -hex 32)
OCTO_WUKONGIM_MANAGER_TOKEN=$(openssl rand -hex 32)
OCTO_ADMIN_PWD=$(openssl rand -base64 18 | tr -d '/+=')
OCTO_DOCS_DB_PASSWORD=$(openssl rand -hex 16)
OCTO_DOCS_COLLAB_SECRET=$(openssl rand -hex 32)
OCTO_DOCS_ATTACHMENT_SECRET=$(openssl rand -hex 32)
OCTO_DRIVE_DB_PASSWORD=$(openssl rand -hex 16)
SPEECH_DB_PASSWORD=$(openssl rand -hex 16)
SPEECH_ADMIN_PASSWORD=$(openssl rand -hex 16)
SPEECH_ADMIN_JWT_SECRET=$(openssl rand -hex 32)
FLEET_POSTGRES_PASSWORD=$(openssl rand -hex 16)
FLEET_JWT_SECRET=$(openssl rand -hex 32)
FLEET_LOOP_CREDENTIAL_HMAC_KEY=$(openssl rand -hex 32)
DOCS_BACKEND_INTERNAL_REGISTER_TOKEN=$(openssl rand -hex 32)
EOF
cat secrets.txt
# ⚠️ 安全保存此文件,后续升级需要复用相同密钥!

四、helm install 命令

4.1 创建命名空间

kubectl create namespace octo

4.2 方式A:deploy.sh 脚本(推荐)

cd octo-deployment/helm/octo

./deploy.sh -n octo -f my-values.yaml
# 其他参数:
#   -c      指定 kubeconfig context
#   --registry    镜像仓库
#   --llm-api-key sk-...  LLM Key
#   --dry-run             只渲染不安装
#   --uninstall           卸载

⚠️ 务必保存 `secrets.generated.yaml`——未来升级需要相同密钥。存入密钥管理器。

4.3 方式B:纯 Helm 命令

cd octo-deployment/helm/octo

helm install octo ./octo \
  --namespace octo \
  --create-namespace \
  --timeout 10m \
  -f my-values.yaml
helm install octo ./octo \
  --namespace octo --create-namespace \
  -f my-values.yaml \
  --set secrets.mysqlRootPassword="$(openssl rand -hex 16)" \
  --set secrets.minioRootPassword="$(openssl rand -hex 16)" \
  --set secrets.minioAppPassword="$(openssl rand -hex 24)" \
  --set secrets.octoMasterKey="$(openssl rand -hex 16)" \
  --set secrets.notifyInternalToken="$(openssl rand -hex 32)" \
  --set secrets.wukongimManagerToken="$(openssl rand -hex 32)" \
  --set secrets.adminPwd="$(openssl rand -base64 18 | tr -d '/+=')"

五、必装模块安装顺序

# 1. 等待所有 Pod Ready
kubectl get pods -n octo -w

# 预期 11 个左右核心 Pod 在 2-3 分钟内达到 Running:
#   octo-mysql-0 (StatefulSet)
#   octo-redis-0 (StatefulSet)
#   octo-minio-0 (StatefulSet)
#   octo-wukongim-0 (StatefulSet)
#   octo-server-* (Deployment)
#   octo-web-* (Deployment)
#   octo-admin-* (Deployment)
#   octo-nginx-* (Deployment)
#   octo-marketplace-* (如启用)
#   init container (minio-bootstrap, botfather-robot 等 Job)
# 检查 PVC 绑定
kubectl get pvc -n octo

# 检查 Service
kubectl get svc -n octo

# 检查 Ingress
kubectl get ingress -n octo

# 端口转发本地测试(如无 Ingress)
kubectl port-forward -n octo svc/octo-nginx 8080:80
# curl http://localhost:8080/_nginx_up → 200 ok

六、可选 Profile 模块开启

第一批(独立旁路):summary → speech
第二批(文档能力):docsBackend → docsHtml
第三批(网盘能力):drive
第四批(回路能力):fleet (+ fleet.postgres.enabled=true)
第五批(搜索基础):search
第六批(搜索扩展):docIndexer → driveIndexer

6.1 开启 Marketplace(技能市场)

# my-values.yaml 追加
marketplace:
  enabled: true
# 还需设置 marketplace DB 密码(首次启用)
helm upgrade octo ./octo -n octo --reuse-values \
  -f my-values.yaml \
  --set secrets.marketplaceDbPassword="$(openssl rand -hex 16)"

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=marketplace
kubectl exec -n octo deploy/octo-marketplace -- wget -qO- localhost:8092/healthz

⚠️ marketplace 要求 MinIO 存储(不支持云存储 COS/OSS/S3),且 Redis 不能设密码(chart render 时校验)。

6.2 开启 Summary(智能摘要)

summary:
  enabled: true
  api:
    replicas: 1
  worker:
    replicas: 1
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=summary-api
kubectl get pods -n octo -l app.kubernetes.io/component=summary-worker

需要 `secrets.llmApiKey` 和 `llm.apiURL/model` 已配置。

6.3 开启 Speech(语音)

speech:
  enabled: true
  replicas: 1
  config:
    engine: "qwen"   # qwen/gemini/gpt/local
    qwenURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
    qwenModels: "qwen3.5-omni-plus"
  admin:
    replicas: 1
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml \
  --set secrets.speechDbPassword="$(openssl rand -hex 16)" \
  --set secrets.speechAdminPassword="$(openssl rand -hex 16)" \
  --set secrets.speechAdminJwtSecret="$(openssl rand -hex 32)" \
  --set secrets.speechQwenKey=""

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=speech
kubectl get pods -n octo -l app.kubernetes.io/component=speech-admin

6.4 开启 Docs(文档协同)

docsBackend:
  enabled: true
  replicas: 1
  config:
    attachmentReadUrlTtl: 86400
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml \
  --set secrets.docsDbPassword="$(openssl rand -hex 16)" \
  --set secrets.docsCollabSecret="$(openssl rand -hex 32)" \
  --set secrets.docsAttachmentSecret="$(openssl rand -hex 32)"

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=docs-backend
kubectl exec -n octo deploy/octo-docs-backend -- curl -s localhost:3000/healthz

⚠️ docsBackend 要求 MinIO 存储,且 Redis 不能设密码。

现有集群需手动创建 `octo_docs` 库和 `docs` 用户(chart init 脚本仅在首次安装时运行)。

6.5 开启 docs-html(依赖docs)

docsHtml:
  enabled: true
  replicas: 1
  config:
    botToken: false   # 设true需配置 secrets.docsHtmlBotToken
    corsOrigins: "https://octo.example.com"
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml \
  --set secrets.docsHtmlInternalRegisterToken="$(openssl rand -hex 32)"

要求 `docsBackend.enabled: true`。

6.6 开启 Drive(网盘)

drive:
  enabled: true
  replicas: 1
  config:
    storage:
      provider: s3
      bucket: octo-drive
      region: us-east-1
      forcePathStyle: true
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml \
  --set secrets.driveDbPassword="$(openssl rand -hex 16)"

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=drive

drive-migrate Job 会自动执行 schema migration。

6.7 开启 Fleet/Loop

# Option A: 内置 PostgreSQL(开发/评估)
fleet:
  enabled: true
  replicas: 1
  postgres:
    enabled: true
    storage:
      size: "10Gi"
  config:
    allowSignup: false

# Option B: 外部 PostgreSQL(生产推荐)
# fleet:
#   enabled: true
#   postgres:
#     enabled: false
#   config:
#     postgres:
#       host: "postgres.example.com"
#       port: 5432
#       database: "fleet"
#       user: "fleet"
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml \
  --set secrets.fleetDbPassword="$(openssl rand -hex 16)" \
  --set secrets.fleetJwtSecret="$(openssl rand -hex 32)" \
  --set secrets.fleetLoopCredentialHmacKey="$(openssl rand -hex 32)"

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=fleet
kubectl exec -n octo deploy/octo-fleet -- wget -qO- localhost:8080/healthz

⚠️ `secrets.fleetLoopCredentialHmacKey` 加密存储的凭证,绝不能轮换(否则历史加密数据全部失效)。

⚠️ `secrets.fleetDbPassword` 只在 PostgreSQL 首次 initdb 时生效,后续修改密码不会自动更新。

6.8 开启 Search(消息搜索)

search:
  enabled: true
  # 单节点开发/评估配置(生产设3)
  opensearch:
    replicas: 1
    storage:
      size: "20Gi"
    resources:
      requests: { cpu: 500m, memory: 1Gi }
      limits:   { cpu: "2", memory: 2Gi }
  kafka:
    replicas: 1              # 🔴 kafka.replicas 安装后不可变(KRaft静态quorum)
    storage: { size: "10Gi" }
    clusterId: "3kNqlPkyT16sjDguh9qqKA"   # 🔴 clusterId 首次安装后不可变
  indexer:
    indexReplicas: 0         # 单节点OS设0,否则索引yellow
  producer:
    enabled: true
    replicas: 1              # 独立producer(chart默认启用,与server内置mutex互斥)
    mysqlAutoWire: true
# ⚠️ 必须先构建并推送 opensearch-ik 镜像到可访问仓库
# docker build -t /octo-search-opensearch-ik:2.17.0 -f docker/opensearch/Dockerfile .
# docker push /octo-search-opensearch-ik:2.17.0

helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml

# 验证
kubectl get pods -n octo -l app.kubernetes.io/component=opensearch
kubectl get pods -n octo -l app.kubernetes.io/component=kafka
kubectl get pods -n octo -l app.kubernetes.io/component=search-indexer

# OpenSearch 健康
kubectl exec -n octo sts/octo-opensearch -- curl -s localhost:9200/_cluster/health
# Kafka topics
kubectl exec -n octo sts/octo-kafka -- /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

🔴 `search.kafka.replicas` 和 `search.kafka.clusterId` 在首次安装后不可变(KRaft 静态 quorum 机制)。

🔴 `search.opensearch.image` 默认为本地构建名,必须替换为实际可拉取的镜像。

开启 search 后,chart 自动将 octo-server 的 `OCTO_SEARCH_BACKEND=es`、OS 地址、read alias 等注入。producer 默认启用(`search.producer.enabled=true`, `replicas=1`),通过 runtime mutex-guard 保证单实例活跃。

6.9 开启 doc-index(文档索引,依赖docs+search)

docIndexer:
  enabled: true
  indexReplicas: 0           # 单节点OS设0
  docsBackend:
    indexEnabled: false      # 先false,backfill后再开
    searchEnabled: false     # 先false,验证后再开
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml

# 等 Pod Ready 后执行历史文档 backfill
helm upgrade octo ./octo -n octo --reuse-values \
  --set docIndexer.backfill.enabled=true

# backfill完成后关闭backfill Job,开启producer和search
helm upgrade octo ./octo -n octo --reuse-values \
  --set docIndexer.backfill.enabled=false \
  --set docIndexer.docsBackend.indexEnabled=true \
  --set docIndexer.docsBackend.searchEnabled=true

要求 `docsBackend.enabled=true` 和 `search.enabled=true`。

6.10 开启 drive-index(网盘索引,依赖drive+search)

driveIndexer:
  enabled: true
  indexReplicas: 0           # 单节点OS设0
  tika:
    replicas: 1
helm upgrade octo ./octo -n octo --reuse-values -f my-values.yaml

# 同时需开启 drive 的 kafka producer
# drive.config.kafka.disabled 和 search.disabled 默认null=跟随driveIndexer.enabled,会自动开启

要求 `drive.enabled=true` 和 `search.enabled=true`。自动部署 Tika 文本提取服务。


七、PVC / StatefulSet 说明

组件 Workload类型 存储卷 数据说明
MySQL StatefulSet octo-mysql PVC octo-mysql-data 🔴用户/消息/群组/所有业务数据
Redis StatefulSet octo-redis PVC octo-redis-data 缓存/会话/bot_task队列
MinIO StatefulSet octo-minio PVC octo-minio-data 🔴所有文件/附件/头像/文档/网盘
WuKongIM StatefulSet octo-wukongim PVC octo-wukongim-data 🔴IM消息/通道/离线消息/集群元数据
OpenSearch StatefulSet octo-opensearch PVC octo-opensearch-data 🟠搜索索引(可从MySQL重建)
Kafka StatefulSet octo-kafka PVC octo-kafka-data 🟠Kafka消息日志
Fleet PostgreSQL StatefulSet octo-fleet-postgres(fleet.postgres.enabled=true时) PVC octo-fleet-postgres-data 🔴Fleet/Loop业务数据
speech StatefulSet(待确认) PVC octo-speech-data(speech.storage.enabled=true时) 语音文件存储
es-indexer Deployment emptyDir/ephemeral(DLQ spill通过volumeClaimTemplate?待确认) DLQ spill持久化
  • 支持动态扩容的 StorageClass 可直接 patch PVC:
  •   kubectl patch pvc octo-mysql-data-octo-mysql-0 -n octo \
        -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
  • 不支持扩容的 SC 需要手动迁移数据。

八、Ingress 配置 / TLS

8.1 Ingress 配置示例

ingress:
  enabled: true
  className: "nginx"
  host: "octo.example.com"
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "1000m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-buffering: "off"   # SSE流需要
  tls:
    enabled: true
    secretName: "octo-tls"
ingress:
  enabled: true
  className: "qcloud"
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "1000m"
  tls:
    enabled: true
    certId: "your-cert-id"   # 腾讯云SSL证书ID

8.2 创建 TLS Secret(自备证书)

kubectl create secret tls octo-tls \
  --cert=/path/to/fullchain.pem \
  --key=/path/to/privkey.pem \
  -n octo

8.3 cert-manager 自动签发(可选)

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    # ... 其他 annotations
  tls:
    enabled: true
    secretName: "octo-tls"

8.4 不使用 Ingress(LoadBalancer 或 NodePort)

nginx:
  service:
    type: LoadBalancer    # 或 NodePort
    port: 80
    # nodePort: 30080    # NodePort时指定

九、健康检查 kubectl 命令

# 所有 Pod 状态
kubectl get pods -n octo

# 核心服务健康检查
kubectl exec -n octo deploy/octo-nginx -- wget -qO- http://localhost/_nginx_up
kubectl exec -n octo deploy/octo-server -- wget -qO- http://localhost:8090/v1/ping
kubectl exec -n octo sts/octo-mysql -- mysqladmin ping -h 127.0.0.1 -u root -p"$MYSQL_ROOT_PASSWORD" --silent
kubectl exec -n octo sts/octo-redis -- redis-cli ping
kubectl exec -n octo sts/octo-minio -- curl -fsS http://localhost:9000/minio/health/live
kubectl exec -n octo sts/octo-wukongim -- wget -qO- --header="token: $TOKEN" http://localhost:5001/health

# 可选模块健康检查
kubectl exec -n octo deploy/octo-marketplace -- wget -qO- localhost:8092/healthz
kubectl exec -n octo deploy/octo-docs-backend -- curl -s localhost:3000/healthz
kubectl exec -n octo deploy/octo-fleet -- wget -qO- localhost:8080/healthz
kubectl exec -n octo deploy/octo-doc-indexer -- wget -qO- http://localhost:3100/readyz

# OpenSearch/Kafka
kubectl exec -n octo sts/octo-opensearch -- curl -s localhost:9200/_cluster/health
kubectl exec -n octo sts/octo-kafka -- /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

# 端到端测试(通过Ingress)
curl -s http://octo.example.com/_nginx_up
curl -s http://octo.example.com/v1/ping

Pod 启动问题排查

# 查看 Pod 事件
kubectl describe pod -n octo 

# 查看 Pod 日志
kubectl logs -n octo  --tail=100

# 查看前一个容器的日志(CrashLoopBackOff时)
kubectl logs -n octo  --previous

# 进入容器
kubectl exec -it -n octo deploy/octo-server -- sh

十、扩缩容建议

10.1 水平扩缩容(HPA 待确认)

组件 建议副本数 说明
octo-server ≥2(生产) 无状态,可水平扩展;注意 session 存 Redis 已满足
octo-web ≥2 静态资源,无状态
octo-admin ≥2 静态资源,无状态
summary-api/worker 1+ 待确认是否有状态
speech 1+ 待确认
docs-backend 1+(多副本待确认) Hocuspocus 多实例策略待确认
octo-fleet 1+ 待确认
marketplace 1+ 待确认
nginx ≥2 无状态
es-indexer/doc-indexer/drive-indexer 1(Kafka consumer group,多副本需确认分区数) 单实例 Recreate 策略
search-producer 1(runtime mutex guard保证单活)

10.2 有状态服务扩缩容

组件 扩缩方式 注意事项
MySQL 主从/集群(外部) Chart 内置为单节点,生产建议使用外部 MySQL 集群
Redis Sentinel/Cluster(外部) Chart 内置为单节点;Chart 不支持 Redis AUTH 供 docs/marketplace 使用
WuKongIM 扩到 3 节点(奇数) 必须先设 wukongim.auth.jwtSecret 启用 JWT 认证;支持 seed-join 自动复制
MinIO 分布式模式(外部) Chart 内置为单节点;生产建议外部分布式 MinIO 或 S3/COS/OSS
OpenSearch 1/3/5 节点(奇数) 3 节点可容忍 1 节点丢失;配套 indexReplicas: 1
Kafka KRaft 1/3/5 节点(奇数) 安装后不可变;3 节点容忍 1 节点丢失
Fleet PostgreSQL 主从/集群(外部) Chart 内置为单节点
# 手动扩容无状态 Deployment
kubectl scale deploy/octo-server -n octo --replicas=3
kubectl scale deploy/octo-web -n octo --replicas=3
kubectl scale deploy/octo-nginx -n octo --replicas=3

10.3 外部基础设施(生产推荐)

mysql:
  enabled: false
externalMySQL:
  host: "mysql.prod.svc"
  port: 3306
  database: "octo"

redis:
  enabled: false
externalRedis:
  addr: "redis.prod.svc:6379"

minio:
  enabled: false
externalMinio:
  endpoint: "minio.prod.svc:9000"
  rootUser: "octoadmin"
  appUser: "octo-app"
secrets:
  minioAppPassword: "..."

wukongim:
  enabled: false
externalWukongim:
  apiURL: "http://wukongim.prod.svc:5001"
  wsEndpoint: "wukongim.prod.svc:5200"

Chart 会在 `.enabled: false` 时校验 `external` 块是否填写完整。


十一、升级

# 使用 deploy.sh(推荐,自动复用 secrets.generated.yaml)
./deploy.sh -n octo -f my-values.yaml

# 纯 Helm 升级
helm upgrade octo ./octo -n octo \
  --reuse-values \
  -f my-values.yaml \
  --timeout 10m

# 只升级特定模块(开启新模块)
helm upgrade octo ./octo -n octo \
  --reuse-values \
  --set summary.enabled=true
  1. 始终使用 `--reuse-values`,避免丢失首次安装时设置的密钥
  2. `secrets.fleetDbPassword` 只在 PG 首次 initdb 时生效,升级时改密码不会更新 DB
  3. `secrets.fleetLoopCredentialHmacKey` 绝不能轮换
  4. `search.kafka.replicas` 和 `search.kafka.clusterId` 首次安装后不可变
  5. 镜像 tag 在 values.yaml 中固定,升级前确认新版本兼容性
  6. 升级前备份数据库和 PVC 数据

十二、卸载与数据保留

12.1 只卸载应用,保留数据

helm uninstall octo -n octo
# PVC 不会被自动删除,数据保留
kubectl get pvc -n octo

12.2 完全卸载(含数据删除)

helm uninstall octo -n octo
# 删除所有 PVC(⚠️ 数据永久丢失,先备份!)
kubectl delete pvc --all -n octo
# 删除命名空间
kubectl delete namespace octo

12.3 备份建议(待验证)

  • MySQL 备份:使用 mysqldump 或 MySQL Operator 定时备份
  • MinIO 备份:使用 mc mirror 或 S3 版本控制/跨区域复制
  • PVC 快照:如果 StorageClass 支持 VolumeSnapshot,定期创建快照
  • Redis:RDB/AOF 持久化文件备份
  • 配置和密钥:备份 secrets.generated.yaml 和 my-values.yaml

十三、常见问题

1. helm install 报错:secret 字段为空

2. OpenSearch Pod CrashLoopBackOff,日志显示 "vm.max_map_count" 错误

sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" >> /etc/sysctl.conf

3. Kafka Pod CrashLoopBackOff

kubectl delete pvc -n octo -l app.kubernetes.io/component=kafka

4. WuKongIM 多副本集群不同步

5. docsBackend/marketplace enabled=true 但 helm template 报错

  • 确保 minio.enabled=true(或正确配置外部 MinIO)
  • 确保 secrets.redisPassword 为空(docs/marketplace 不支持 Redis 密码认证)