news 2026/7/15 0:46:54

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/3 12:31:12

Whisper-large-v3在车载系统的应用:智能语音交互方案

Whisper-large-v3在车载系统的应用:智能语音交互方案 1. 车载语音交互的现实困境 开车时伸手去点屏幕,或者低头看导航,哪怕只是一秒,都可能带来安全隐患。这是很多司机都经历过的真实场景。我们团队在和几家车企合作过程中发现&…

作者头像 李华
网站建设 2026/6/29 5:20:01

ERNIE-4.5-0.3B-PT在教育培训中的个性化应用

ERNIE-4.5-0.3B-PT在教育培训中的个性化应用效果展示 1. 教育场景中的真实能力呈现 当学生在数学题上卡壳时,传统教学往往只能提供标准答案和固定解析。而ERNIE-4.5-0.3B-PT带来的变化是:它能根据学生刚刚答错的那道题,立刻生成一段专属于这…

作者头像 李华
网站建设 2026/7/1 17:02:25

亚洲美女-造相Z-Turbo案例分享:如何生成不同风格的AI模特

亚洲美女-造相Z-Turbo案例分享:如何生成不同风格的AI模特 你是否试过用AI生成亚洲模特图,却总感觉“像又不太像”——五官不够协调、肤色偏灰、神态缺乏灵性,或者风格千篇一律?不是模型不行,而是没摸清它的表达逻辑。…

作者头像 李华
网站建设 2026/7/2 1:20:42

VibeVoice多语言语音合成:基于迁移学习的跨语言适配

VibeVoice多语言语音合成:基于迁移学习的跨语言适配效果展示 1. 当语音合成开始“说多种语言” 你有没有试过让AI助手用法语读一段新闻,再切换成日语讲解同一个内容?或者为面向全球用户的播客准备不同语言版本,却苦于每个语种都…

作者头像 李华
网站建设 2026/7/2 14:31:20

DeerFlow案例展示:72小时全球科技动态追踪报告

DeerFlow案例展示:72小时全球科技动态追踪报告 1. 什么是DeerFlow?一个能“自己查资料、写报告、做播客”的研究助手 你有没有过这样的经历:想快速了解某项新技术的最新进展,却要在十几个网站间反复切换、复制粘贴、整理时间线&…

作者头像 李华