# Kubernetes 部署 本项目镜像已做 k8s 兼容(健康探针、非 root 运行、可挂载 PVC 的输出与任务存储、重启后的孤儿任务恢复)。本目录提供单副本部署清单。 > 构建并推送镜像到 Harbor 的完整步骤见仓库根目录 [`docs/DEPLOYMENT.md`](../../docs/DEPLOYMENT.md) 的「Kubernetes 部署」章节。 --- ## 前置要求 - 一个可用 k8s 集群(1.24+),已配置默认 StorageClass(PVC 需要动态供给)。 - `kubectl` 已指向目标集群。 - 已把镜像推送到 Harbor(见上文链接),并知道镜像地址,例如: `harbor.example.com/library/pipeline:latest` ## 1. 替换镜像地址 编辑 [`03-deployment.yaml`](03-deployment.yaml),把 ```yaml image: harbor.example.com/library/pipeline:latest ``` 改成你 Harbor 上的实际镜像。 ## 2. 生成密钥(Secret) 应用本身从 `.env` 读取密钥。把仓库根目录的 `.env`(含 `OPENAI_API_KEY`、`OPENAI_TTS_API_KEY`、`OSS_*`、`FEISHU_*` 等)一次性灌进同名 Secret: ```bash kubectl create secret generic pipeline-env-secret \ --from-env-file=.env \ -n pipeline ``` > `--from-env-file` 会把 `.env` 中每一行 `KEY=VALUE` 转成 Secret 的一个键,并通过 Deployment 的 `envFrom: secretRef` 全部注入容器环境变量。 > 之后修改密钥:`kubectl create secret generic pipeline-env-secret --from-env-file=.env -n pipeline --dry-run=client -o yaml | kubectl apply -f -`,再 `kubectl rollout restart deployment/pipeline -n pipeline`。 ## 3. Harbor 私有仓库的镜像拉取凭据(可选) 若 Harbor 项目是私有的,创建 imagePullSecret,并取消 `03-deployment.yaml` 里 `imagePullSecrets` 的注释: ```bash kubectl create secret docker-registry harbor-creds \ --docker-server=harbor.example.com \ --docker-username=<你的用户名> \ --docker-password=<密码或 Harbor CLI secret> \ -n pipeline ``` ## 4. 应用清单 ```bash kubectl apply -f deploy/k8s/ ``` 包含:Namespace、ConfigMap、两个 PVC、Deployment(单副本)、Service、Ingress(可选)。 ## 5. 验证 ```bash kubectl -n pipeline get pods -w # 等 READY 1/1(startup 探针通过) kubectl -n pipeline describe pod -l app.kubernetes.io/name=pipeline # 看探针/事件 kubectl -n pipeline logs -f deploy/pipeline ``` 集群内访问 Service `pipeline:80`;经 Ingress 用你配置的域名访问。 --- ## 注意事项 ### 为什么是单副本(replicas: 1) WebUI 把任务元数据存在**本地文件** `jobs.json`,渲染是 Web 进程 **spawn CLI 子进程**完成的,没有共享状态、没有分布式锁。多副本会各自维护一份 `jobs.json`,任务视图不一致,且可能重复执行同一任务。要水平扩展需先把任务存储外置(Redis/DB)并加任务调度——目前不在范围内。PVC 用 `ReadWriteOnce` + `strategy: Recreate` 与之匹配。 ### 持久化 | PVC | 挂载点 | 用途 | | --- | --- | --- | | `pipeline-output` | `/app/output` | 渲染产物 + 临时目录(`OUTPUT_DIR`) | | `pipeline-jobs` | `/app/jobs` | 任务元数据 `jobs.json`(`PIPELINE_JOBS_DIR`) | 两个 PVC 都通过 `fsGroup: 1000` 让非 root 的 `node` 用户可写。删除 PVC 会丢失对应数据。 ### 重启与中断 Pod 重启(滚动更新、OOM、节点驱逐)会打断进行中的渲染。Web 进程下次启动时会扫描 `jobs.json`,把仍处于 `running`/`pending` 的任务标记为 `failed`(`interrupted by pod restart`),避免 UI 卡在幽灵任务上。被中断的渲染需要手动重跑。`terminationGracePeriodSeconds: 60` 给在途请求留出收尾窗口,但长渲染通常仍会超时。 ### 时区 ConfigMap 同时设了 `TZ` 与 `TIMEZONE=Asia/Shanghai`,保证首屏日期、输出日期子目录、日志时间一致。如需改时区编辑 `01-configmap.yaml` 后重新 apply。 ### DNS 不再使用 docker-compose 的自定义 DNS(`DNS_SERVER_*` 仅 compose 生效)。k8s 下走集群 CoreDNS;若飞书/OSS 域名需走内部解析,配置集群级别的 DNS 或 `dnsConfig`。 ### 资源 渲染(Remotion headless Chrome + ffmpeg)较重,清单里给的 `requests/limits` 是起点,按集群实际调。OOM 会被 k8s 杀掉并重启——任务会被下次启动的孤儿扫描标为 failed。