Kubernetes Helm 部署
- 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
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
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"}}}}'
八、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
- 始终使用 `--reuse-values`,避免丢失首次安装时设置的密钥
- `secrets.fleetDbPassword` 只在 PG 首次 initdb 时生效,升级时改密码不会更新 DB
- `secrets.fleetLoopCredentialHmacKey` 绝不能轮换
- `search.kafka.replicas` 和 `search.kafka.clusterId` 首次安装后不可变
- 镜像 tag 在 values.yaml 中固定,升级前确认新版本兼容性
- 升级前备份数据库和 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 密码认证)