在 Kubernetes 上部署 SkillFlaw 生产环境
本指南描述 SkillFlaw 面向生产的 Kubernetes 形态:稳定的 backend API 部署、外置状态、显式密钥处理,以及可选的 UI / docs 暴露。
与旧的历史文档不同,SkillFlaw 并未提供可直接运行的 Helm Chart。当前支持的生产基线,是基于参考 compose 栈所使用的相同镜像与环境变量契约构建的。
生产目标
在生产环境中,backend 是关键路径,它负责:
- 通过
/api/v1/run/{flow_id_or_alias}执行流程 - 通过
/api/v1/responses提供 OpenAI 兼容访问 - 通过
/api/v1/mcp/streamable提供 MCP 服务 - 在启用 UI 时,为 frontend 提供管理 API
如果你的调用方是其他服务或 SDK,只部署 backend 就够了。只有当生产环境确实需要浏览器访问时,才添加 frontend 与 docs。
前置条件
- 一个 Kubernetes 集群
kubectl- 能够访问
ghcr.io/cwinux/*镜像 - 生产级 PostgreSQL 部署
- 如果启用了 Redis 缓存,则需要 Redis 部署
- 为
SKILLFLAW_CONFIG_DIR准备的持久化存储 - 一个安全地挂载
SKILLFLAW_SECRET_KEY_FILE所需 secret key 文件的方案
推荐生产拓扑
最低限度的生产环境应包括:
- backend deployment
- PostgreSQL
- Redis
- ingress 或 gateway
- backend 管理文件所需的 persistent volume claim
可选服务:
- frontend deployment,仅当需要浏览器 UI 时部署
- docs deployment,仅当 docs 需要独立生产域名时部署
1. 扩容前先外置状态
不要先扩 backend,再回头补状态管理。
在你运行多副本之前,请确保这三部分都已经明确:
- PostgreSQL 连接
- Redis 连接
SKILLFLAW_CONFIG_DIR的可写持久化存储
继续复用 docker/docker-compose.yml 中已经存在的环境契约:
_15apiVersion: v1_15kind: ConfigMap_15metadata:_15 name: skillflaw-backend-config_15 namespace: skillflaw_15data:_15 SKILLFLAW_CONFIG_DIR: /var/lib/skillflaw_15 SKILLFLAW_DATABASE_URL: postgresql://skillflaw:skillflaw@postgresql:5432/skillflaw_15 SKILLFLAW_CONFIG_MODEL: local_15 SKILLFLAW_CACHE_TYPE: redis_15 SKILLFLAW_REDIS_HOST: redis_15 SKILLFLAW_REDIS_PORT: "6379"_15 SKILLFLAW_HOST: 0.0.0.0_15 SKILLFLAW_PORT: "7860"_15 SKILLFLAW_OPEN_BROWSER: "false"
secret key 必须以文件方式挂载,不要把它内联写进镜像构建时常量里。
2. 使用探针与存储部署 backend
backend 镜像会启动 uvicorn --factory skillflaw.main:create_app,并监听 7860 端口。
_68apiVersion: apps/v1_68kind: Deployment_68metadata:_68 name: skillflaw-backend_68 namespace: skillflaw_68spec:_68 replicas: 2_68 selector:_68 matchLabels:_68 app: skillflaw-backend_68 template:_68 metadata:_68 labels:_68 app: skillflaw-backend_68 spec:_68 containers:_68 - name: backend_68 image: ghcr.io/cwinux/skillflaw_backend:latest_68 ports:_68 - containerPort: 7860_68 envFrom:_68 - configMapRef:_68 name: skillflaw-backend-config_68 env:_68 - name: SKILLFLAW_SECRET_KEY_FILE_68 value: /run/secrets/skillflaw_secret_key_68 volumeMounts:_68 - name: backend-data_68 mountPath: /var/lib/skillflaw_68 - name: secret-key_68 mountPath: /run/secrets/skillflaw_secret_key_68 subPath: skillflaw_secret_key_68 readOnly: true_68 readinessProbe:_68 httpGet:_68 path: /health_68 port: 7860_68 livenessProbe:_68 httpGet:_68 path: /health_68 port: 7860_68 resources:_68 requests:_68 cpu: 500m_68 memory: 1Gi_68 limits:_68 cpu: "2"_68 memory: 4Gi_68 volumes:_68 - name: backend-data_68 persistentVolumeClaim:_68 claimName: skillflaw-backend-data_68 - name: secret-key_68 secret:_68 secretName: skillflaw-runtime-secrets_68---_68apiVersion: v1_68kind: Service_68metadata:_68 name: skillflaw-backend_68 namespace: skillflaw_68spec:_68 selector:_68 app: skillflaw-backend_68 ports:_68 - name: http_68 port: 7860_68 targetPort: 7860
资源值不要拍脑袋定死。先保守起步,做压测,再按结果扩。
3. 安全地暴露 API
在 ingress 或 gateway 层面,请先明确哪些公网能力是真正需要的:
/api/:当环境要承接应用流量时/:只有在你也要公开浏览器 UI 时才需要- 独立 docs 域名:只有在你需要公开文档时才需要
一个简单的生产入口形态可以是:
api.example.com→skillflaw-backendapp.example.com→skillflaw-frontend(可选)docs.example.com→skillflaw-docs(可选)
4. 只有在需要时才部署 frontend
如果生产用户确实需要 Web UI,再单独部署 frontend 镜像:
_23apiVersion: apps/v1_23kind: Deployment_23metadata:_23 name: skillflaw-frontend_23 namespace: skillflaw_23spec:_23 replicas: 2_23 selector:_23 matchLabels:_23 app: skillflaw-frontend_23 template:_23 metadata:_23 labels:_23 app: skillflaw-frontend_23 spec:_23 containers:_23 - name: frontend_23 image: ghcr.io/cwinux/skillflaw_frontend:latest_23 env:_23 - name: BACKEND_URL_23 value: https://api.example.com/_23 ports:_23 - containerPort: 80
frontend 是无状态的,应与 backend 独立扩缩容。
5. 验证线上部署
在宣布生产可用之前,至少验证以下内容:
GET /health通过 Service 与 Ingress 都返回成功- 使用真实
x-api-key头时,API 鉴权正常 - 至少有一个代表性流程能通过
/api/v1/run/{flow_id}成功执行 - 如果客户端依赖 OpenAI 兼容接口,则验证
/api/v1/responses - 如果客户端依赖 MCP,则验证
/api/v1/mcp/streamable - 如果启用了 UI,则确认 frontend 可以鉴权并对接生产 backend 执行流程
安全与发布说明
- 通过 Kubernetes Secret 或外部 Secret 管理系统轮换挂载的 secret-key 文件
- PostgreSQL 凭据与外部 API Key 必须放在 Secret 中,而不是镜像层里
- docs 是否暴露应是明确决策,而不是默认行为
- 优先采用滚动更新,并在新副本通过 readiness 检查前保留旧 backend 副本