news 2026/8/6 16:25:01

Helm 实战指南(四):生产环境 Helm 部署 CVAT 全记录:Ceph 存储、GPU 节点污点调度与 HTTPS 指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Helm 实战指南(四):生产环境 Helm 部署 CVAT 全记录:Ceph 存储、GPU 节点污点调度与 HTTPS 指南

前言

刚好!最近公司业务需求,需要搭建一套CVAT (Computer Vision Annotation Tool)计算机视觉标注系统,开源标注工具。

虽然官方提供了 Helm Chart,但在面对内网环境、老版本 K8s (v1.21)、Ceph 存储以及特定节点调度等现实需求时,官方文档过于 “简洁” 了。

本文完整记录了从 Chart 下载到最终成功登录的全过程,重点分析了部署过程中遇到的OPA 服务连接拒绝浏览器安全策略报错等“深坑”及其解决方案。

  • 官方 GitHub: cvat-ai/cvat
  • Helm 版本: v3.19
  • CVAT Chart 版本: 2.56.0
  • Kubernetes 版本: 1.21.10 (注:官方要求 >=1.23,本文包含强行兼容方案)

一、 背景与硬性需求

在开始之前,明确一下我们的部署环境限制,这也是后续修改配置的依据:

  1. 节点调度限制
  • CVAT 必须运行在名为gpusrv14的特定节点上。
  • 难点:该节点被打上了污点(Taint)dedicated=ceph:NoSchedule,普通 Pod 无法调度上去。我们需要配置容忍度(Tolerations)。
  1. 持久化存储
  • 必须对接公司现有的Ceph集群(StorageClass:rook-cephfs),且容量要求大。
  1. 内网环境
  • 服务器无法直接连接公网,依赖 HTTP Proxy。

二、 部署准备与 Chart 处理

1. 下载 Chart

首先拉取官方 Chart 包并解压:

helm pull oci://registry-1.docker.io/cvat/cvat --version2.55.0tar-xzf cvat-2.55.0.tgzcdcvat

2. 解决 K8s 版本兼容性问题(K8s 1.21 版本)

官方 Chart 的Chart.yaml里硬性规定了kubeVersion: '>= 1.23.0-0'。如果你像我一样还在用 K8s 1.21,直接 install 安装会报错。

解决方案
修改Chart.yaml,强行降低版本要求。虽然有风险,但实测 CVAT 2.56 在 1.21 上核心 API 依然兼容。

# Chart.yamldescription:A Helm chart for KuberneteskubeVersion:'>= 1.21.0-0'# 修改此处

3. 初始化配置文件

为了保持原文件整洁,我们复制一份配置进行覆盖:

cpvalues.yaml values.override2.yaml# 或(一样)helm show values.>values.override2.yaml

三、 核心配置修改(values.yaml)

1. 存储配置:对接 Ceph

默认的 PVC 只有 20Gi 且不指定 StorageClass。我们需要修改cvatkvrocks(Redis) 两处的存储配置。

修改values.override2.yaml

defaultStorage:enabled:truestorageClassName:rook-cephfs# 重点:指定你的 Ceph SC 名称accessModes:-ReadWriteMany# 建议多读写模式,方便扩展size:1000Gi# 生产环境,给大点

2. 调度配置:亲和性与污点容忍(重点)

这是最复杂的一步。我们要把 Pod 钉死在gpusrv14节点上,并且要能“忍受”它的污点。

步骤 A:给节点打标签

kubectl labelnodegpusrv14.aa.com -n gpu cvat-node=true

步骤 B:检查节点污点

kubectl describe node/gpusrv14.aa.com -n gpu|grepTaints# 输出: dedicated=ceph:NoSchedule# 这意味着如果没有对应的 toleration,Pod 无法调度上来。

步骤 C:修改 Helm 配置
找到cvat.backend部分。CVAT Chart 设计比较好的一点是,backend 下的配置会被 worker 等子组件继承,所以不需要每个微服务都改一遍。

cvat:backend:# 1. 强行指定节点(双重保险)affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:-matchExpressions:-key:kubernetes.io/hostnameoperator:Invalues:-gpusrv14.aa.com# 2. 简单的节点选择器nodeSelector:cvat-node:true# 3. 污点容忍(必须配置,否则 Pending)tolerations:-key:"group"# 多余的operator:"Equal"value:"gpu"effect:"NoSchedule"-key:"dedicated"# 对应 dedicated=ceph:NoScheduleoperator:"Equal"value:"ceph"effect:"NoSchedule"

四、 启动安装与踩坑实录

执行安装命令:

helminstallgpu-cvat.-n gpu-cvat --create-namespace -f values.yaml -f values.override2.yaml

安装命令下去后,并没有想象中的“一键成功”,而是迎来了两个深坑。

坑一:OPA 服务无限重启 (Connection refused)

现象
gpu-cvat-opaPod 状态异常,查看日志发现健康检查失败:

requests.exceptions.ConnectionError: HTTPConnectionPool(host='opa', port=8181): ... Connection refused

原因分析
OPA (Open Policy Agent) 是 CVAT 的权限策略引擎。

  • 默认情况下,OPA 启动时只监听localhost(127.0.0.1)。
  • K8s 的 Liveness Probe(探针)是通过 Pod IP 访问的,属于“外部”访问。
  • 因为监听地址限制,探针连接被拒绝,K8s 判定服务不健康,导致无限重启。

解决方案(临时暴力有效)
尝试通过 Helm--set传参失败(可能是 Chart 里的参数映射有问题),直接修改 Deployment 最快。

kubectl edit deployment gpu-cvat-opa -n gpu-cvat

找到args部分,手动添加--addr=0.0.0.0:8181,强制监听所有网络接口:

containers:-args:-run---server---addr=0.0.0.0:8181# 【关键修改】让它监听所有IP---bundle

修改保存后,Pod 重启,状态瞬间变为 Running。

其中,尝试过 upgrade 这些服务,但不生效:

helm upgrade... --set cvat.opa.extraArgs="{--addr=0.0.0.0:8181}"--reuse-values

可能某些版本的 CVAT Helm Chart 中,extraArgs 的传递方式或者 OPA 的默认启动命令(Entrypoint)优先级更高,导致修改根本没有生效。

永久解决方案(未验证)
手动编辑的配置会在下一次helm upgrade时丢失。为了让配置持久化,需要将参数写入values.override2.yaml

在配置文件中找到cvat.opa部分,加入extraArgs

cvat:opa:# 强制让 OPA 监听所有接口,解决健康检查不通的问题extraArgs:-"--addr=0.0.0.0:8181"

这样下次执行 Helm 更新时,这个参数就会自动带上,不用再手动改 Deployment 了。

坑二:浏览器白屏与 405 报错 (HTTP vs HTTPS)

现象
配置好 Nginx HTTP 转发后,访问页面出现白屏或报错(F12):

  1. API 请求报405 Not Allowed401 Unauthorized
  2. 控制台报错:The Cross-Origin-Opener-Policy header has been ignored...
  3. JS 报错:ReferenceError: structuredClone is not defined

原因分析
这是现代浏览器的安全机制。CVAT 是一个重型前端应用,使用了SharedArrayBuffer等特性来实现多线程处理。
浏览器规定:这些高级特性必须在“安全上下文” (Secure Context) 下才能运行。
所谓安全上下文,要么是localhost,要么必须是HTTPS。如果是 HTTP,这些 API 直接被禁用,导致代码崩盘。

解决方案(配置 Nginx SSL + 安全头)
我们必须配置 HTTPS,并且在 Nginx 中显式添加 COOP/COEP 响应头。

Nginx 配置参考:

server { listen 443 ssl; server_name gpu-cvat.aa.com; # 统一使用一个域名 ssl_certificate /etc/nginx/conf.d/sans_crt2/server.crt; ssl_certificate_key /etc/nginx/conf.d/sans_crt2/server.key; # 1. 后端 API 转发 location ~ ^/(api|auth|admin|django-static)/ { proxy_pass http://gpu-cvat-backend-service.gpu-cvat.svc.cluster.local:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 2. 前端页面转发 location / { proxy_pass http://gpu-cvat-frontend-service.gpu-cvat.svc.cluster.local:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 必须加上这两个 Header,否则 CVAT 内部 JS 会报错 add_header Cross-Origin-Opener-Policy 'same-origin'; add_header Cross-Origin-Embedder-Policy 'require-corp'; } }

关于Nginx 转发规则,虽然官方文档未明说后端路径,但通过 F12 开发者工具观察网络请求,并参考 Chart 源码中 templates/ingress.yaml 的分流定义,可以明确 /api、/auth、/admin 及 /django-static 这类涉及到数据交互和 Django 后台的请求必须精准转发至后端 Service,而其余流量则指向前端。


五、 创建管理员

部署成功且页面能打开后,发现——没有账号登录
CVAT 默认不创建任何账号,需要手动进入容器执行 Django 命令来创建超级管理员(教程下一步)。

一键创建命令

# 你部署 CVAT 的命名空间exportHELM_RELEASE_NAMESPACE="gpu-cvat"# 你给这个 Helm 实例起的名称exportHELM_RELEASE_NAME="gpu-cvat"BACKEND_POD_NAME=$(kubectl get pod --namespace $HELM_RELEASE_NAMESPACE -ltier=backend,app.kubernetes.io/instance=$HELM_RELEASE_NAME,component=server -ojsonpath='{.items[0].metadata.name}')kubectlexec-it --namespace$HELM_RELEASE_NAMESPACE$BACKEND_POD_NAME-c cvat-backend -- python manage.py createsuperuser

按照提示输入用户名、邮箱和密码即可。

创建好后,就可以使用这个账号登录系统。


六、 存储验证

前面在values.yaml中配置了storageClassName: rook-cephfs后,并且已经部署完成了,现在验证一下是不是用了 ceph 的存储。

1. 查看集群内 PVC 状态

通过kubectl get pv命令可以看到,CVAT 的后端数据(backend-data)和 kvrocks 已经成功绑定了我们预设的1000Gi大容量存储,且状态均为Bound

# 查看 CVAT 相关的持久化卷kubectl getpv|grepgpu-cvat

注意:可以看到gpu-cvat-backend-data的模式是RWX(ReadWriteMany),这对于多副本部署至关重要。

2. 追踪底层的 Ceph Subvolume

为了确认数据确实落在了 CephFS 上,我们可以随机挑选一个 PV 进行describe,查看它在 Ceph 内部的subvolumePath

kubectl describe pv/pvc-ec561f53-c54b-47d7-9ddb-6e01850046df|grepsubvolumePath# 输出结果:# subvolumePath=/volumes/csi/csi-vol-cee516.../de776093...

3. Ceph 后台验证

最后,登录Ceph Dashboard或直接在 Ceph 节点查看文件系统,可以看到该路径已经自动创建并开始记录数据。


总结

这次 Helm 部署过程暴露了 CVAT Chart 的几个痛点:

  1. 微服务拆分过细:虽然架构先进,但运维成本高。如果不是backend配置支持继承,单独配置每个 Pod 的调度策略会非常痛苦。
  2. 默认配置不合理:OPA 默认只监听localhost导致健康检查失败,这是一个非常低级的默认配置坑,迫使我们必须手动介入。
  3. 文档缺失:官方文档未强调 HTTPS 对于前端功能的强制性,导致很容易在 HTTP 环境下浪费时间排查 JS 报错。
  4. 内网友好度低:内网环境下,Grafana 插件下载、依赖包拉取都需要自己在values.yaml里注入 Proxy 环境变量。

感觉这个 Helm-Chart 做得不够完善,并且加上公司内网原因,导致没法一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/31 5:50:50

Qwen3-ForcedAligner应用案例:如何快速生成带时间戳的访谈记录

Qwen3-ForcedAligner应用案例:如何快速生成带时间戳的访谈记录 1. 场景切入:为什么访谈转录总在“卡点”? 你有没有过这样的经历:刚结束一场45分钟的深度访谈,录音文件躺在电脑里,却迟迟不敢点开——因为…

作者头像 李华
网站建设 2026/7/31 21:38:26

癌症药研发企业Eikon冲刺美股:9个月亏2.5亿美元 路演PPT曝光

雷递网 雷建平 2月5日癌症药研发医药企业Eikon Therapeutics(股票代码拟定为“EIKN”)日前递交招股书,准备2026年2月5日在美国纳斯达克上市。当前,贝恩资本支持的零售商Bobs Discount Furniture Inc.,Neos Partners支持…

作者头像 李华
网站建设 2026/7/31 3:27:51

Nano-Banana实战案例:用AI为3C产品说明书自动生成多角度分解图

Nano-Banana实战案例:用AI为3C产品说明书自动生成多角度分解图 1. 为什么3C说明书还在靠人工画图? 你有没有翻过一部新手机的纸质说明书?那些整齐排列的螺丝、主板、电池、摄像头模组,被一根根虚线连接,标注着编号和…

作者头像 李华
网站建设 2026/7/30 23:03:59

Qwen3-VL-8B Web系统教程:start_chat.sh与run_app.sh分工逻辑解析

Qwen3-VL-8B Web系统教程:start_chat.sh与run_app.sh分工逻辑解析 1. 理解这个AI聊天系统的本质 你拿到的不是一个“点开就能用”的黑盒应用,而是一套经过工程化拆解、职责清晰的本地AI服务组合。它不像手机App那样封装严密,而是像一辆可拆…

作者头像 李华
网站建设 2026/7/31 3:26:48

解锁你的艺术天赋:灵感画廊创意绘画指南

解锁你的艺术天赋:灵感画廊创意绘画指南 1. 这不是又一个AI绘图工具,而是一间会呼吸的画室 你有没有过这样的时刻:脑海里浮现出一幅画面——晨雾中泛着青灰调的江南石桥,桥下流水映着半片残月,一只白鹭掠过水面&…

作者头像 李华
网站建设 2026/8/1 15:03:44

Qwen3-VL-Reranker-8B详细步骤:Python 3.11+Torch 2.8环境兼容性验证

Qwen3-VL-Reranker-8B详细步骤:Python 3.11Torch 2.8环境兼容性验证 1. 这不是普通重排序模型,是真正能“看懂”图文视频的多模态理解引擎 你可能用过不少文本重排序模型,输入一段查询和一堆候选文本,返回一个打分列表——但Qwe…

作者头像 李华