跳转到内容

Helm 部署

Helm 是 Kubernetes 多副本和平台化运维路径,不是第一次接触 SyncTV 的默认入口。开始前应明确 Secret、PVC、Ingress、ServiceMonitor/VMServiceScrape、滚动更新和数据库/Redis 运维边界。

如果你只是想在一台机器上长期运行 SyncTV,先使用 单机生产 Compose。如果还没决定路径,先读 部署路径选择

决策默认选择不要忽略的风险
PostgreSQL托管数据库、平台数据库 Operator,或 chart standard 模式必须持久化并可恢复
Redis生产配置,多副本必需多副本不能使用不同 Redis 或冲突 key prefix
Secret使用外部 Secret 或受控 Secret 管理OPAQUE 和 credential key 不能随发布随机变化
HTTP/gRPC IngressHTTP 和 gRPC 分开gRPC Ingress 需要独立 backend protocol
HLS 存储小规模用 publisher-node proxy,高流量用 RWX/OSS不要把 emptyDir 当共享 HLS 存储
metrics私网抓取并启用鉴权不要把 /metrics 直接暴露公网

最小生产 values 骨架:

config:
bootstrap:
createRootUser: true
cluster:
enabled: false
existingSecret: "synctv-production-secret"
ingress:
enabled: true
hosts:
- host: synctv.example.com

Helm chart 位于:

helm/synctv

默认会创建:

  • SyncTV Deployment。
  • HTTP/API Service。
  • gRPC Service。
  • PostgreSQL。
  • Redis。
  • ConfigMap。
  • Secret。
  • Ingress。
  • ServiceAccount、Role、RoleBinding。
  • 可选 metrics、ServiceMonitor、VMServiceScrape、PrometheusRule、NetworkPolicy、HPA、PDB。

通过 OCI registry 安装:

Terminal window
helm install synctv oci://ghcr.io/zijiren233/synctv/charts/synctv \
--version 0.1.0 \
--namespace synctv --create-namespace

默认父级 OCI repository 是 ghcr.io/zijiren233/synctv/charts。Helm 会追加 chart 名,因此安装引用最后仍是 /synctv。维护者可以通过 HELM_OCI_REPOSITORY 覆盖发布目标。

通过传统 Helm repository 安装:

Terminal window
helm repo add synctv https://zijiren233.github.io/synctv
helm repo update
helm install synctv synctv/synctv \
--version 0.1.0 \
--namespace synctv --create-namespace

发布版 Chart 由 release workflow 自动生成。源码仓库只维护 helm/synctv 下的 chart 源码;打包后的 .tgz 和 Helm repository 的 index.yaml 在发布时生成。公开安装要求 GHCR chart package 设为 public,并且 GitHub Pages 使用 helm-charts 分支提供内容。

Terminal window
helm install synctv ./helm/synctv \
--namespace synctv \
--create-namespace

生产环境使用自己的 values 文件:

Terminal window
helm install synctv ./helm/synctv \
--namespace synctv \
--create-namespace \
--values my-values.yaml

SyncTV 进程内部 HTTP REST 和 gRPC 使用同一个容器端口,但 Helm chart 会创建两个独立 Service:

Service用途端口名
synctvHTTP/REST API 入口api
synctv-rtmprtmpService.enabled=true 时的 RTMP 推流入口rtmp
synctv-stunstunService.enabled=trueconfig.webrtc.enableBuiltinStun=true 时的内置 UDP STUNstun
synctv-metricsmetrics.enabled=true 时的专用指标入口metrics
synctv-grpcgRPC 专用入口grpc

为什么拆开:

  • Ingress controller 通常需要对 gRPC backend 使用独立协议配置。
  • HTTP 和 gRPC 虽然同端口,但 Kubernetes Service/Ingress 层需要不同语义。
  • metrics selector 可以只匹配专用 metrics Service,避免误抓公网 API/RTMP 或 gRPC Service。

config.server.grpcCompressionEnabled 默认是 true,会让 gRPC 客户端和服务端协商 gzip 压缩。跨节点调用、Ingress 转发、批量响应较多时通常保持开启;如果你的 gRPC 调用都在本地低延迟网络且 CPU 比带宽更紧张,可以显式关闭。

config.fileStorage.backends.<name>.database.compression 控制数据库文件存储后端写入 PostgreSQL file_blob_parts 永久分段的压缩算法,默认 zstdcompressionMinSizeBytes 默认 4096compressionMinSavingsPercent 默认 10,压缩收益低于阈值时写入原始 bytes。Database 文件存储使用永久分段并从分段服务 HTTP Range;S3 文件存储使用原生 multipart 直传支持 GB 级断点续传。

S3 文件存储凭证建议挂载 Kubernetes Secret,并在 Helm values 中设置 camelCase 的 accessKeyIdFile / secretAccessKeyFile。生成的 SyncTV YAML 会使用 snake_case 的 access_key_id_file / secret_access_key_file 路径,并在启动时读取 Secret 文件。

config:
fileStorage:
defaultBackend: s3_public
backends:
s3_public:
type: s3
s3:
endpoint: https://s3.example.com
bucket: synctv-files
region: auto
basePath: files/
publicBaseUrl: https://cdn.example.com/files
accessKeyIdFile: /run/secrets/file-storage-s3/access_key_id
secretAccessKeyFile: /run/secrets/file-storage-s3/secret_access_key
extraVolumes:
- name: file-storage-s3
secret:
secretName: synctv-file-storage-s3
extraVolumeMounts:
- name: file-storage-s3
mountPath: /run/secrets/file-storage-s3
readOnly: true

默认 HTTP Ingress 使用:

ingress:
enabled: true
hosts:
- host: synctv.example.com

gRPC Ingress 独立配置:

ingress:
grpc:
enabled: true
hosts:
- host: grpc.synctv.example.com
paths:
- path: /
pathType: Prefix
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"

注意:gRPC annotations 是独立的 ingress.grpc.annotations,不会复用 HTTP Ingress annotations。

Chart 默认会生成并保存 Secret。生产环境显式配置:

secrets:
jwt:
secret: "replace-with-strong-secret"
cluster:
grpcSecret: "replace-with-cluster-secret"
security:
credentialEncryptionKey: "64-hex-character-key"
opaqueServerSetupSecret: "stable-random-secret"
bootstrap:
rootPassword: "StrongRootPass12345"

如果使用外部 Secret:

existingSecret: "my-external-synctv-secret"

需要提供这些 key:

  • SYNCTV_DATABASE_PASSWORD,用于 PostgreSQL standard 模式、external 模式和 KubeBlocks 应用账号。
  • SYNCTV_REDIS_PASSWORD,Redis 使用 standard 模式时必需;external 模式只在外部 Redis 需要密码时提供;KubeBlocks 模式不需要提供。
  • SYNCTV_JWT_SECRET
  • SYNCTV_CLUSTER_SECRET
  • SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY
  • SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET
  • SYNCTV_BOOTSTRAP_ROOT_PASSWORD,如果 config.bootstrap.createRootUser=true
  • SYNCTV_MANAGEMENT_AUTH_TOKEN,如果 management 使用 TCP。
  • SYNCTV_EMAIL_SMTP_USERNAMESYNCTV_EMAIL_SMTP_PASSWORD,如果配置了 config.email.smtpHost 且 SMTP 需要认证。
  • SYNCTV_METRICS_AUTH_BEARER_TOKEN,如果 metrics.enabled=truemetrics.auth.mode=bearer_token
  • SYNCTV_METRICS_AUTH_BASIC_USERNAMESYNCTV_METRICS_AUTH_BASIC_PASSWORD,如果 metrics.enabled=truemetrics.auth.mode=basic
  • SYNCTV_LIVESTREAM_HLS_OSS_ACCESS_KEY_IDSYNCTV_LIVESTREAM_HLS_OSS_SECRET_ACCESS_KEY,如果 config.livestream.hlsStorageBackend=oss

服务端出站请求使用 config.security.ssrf 中的全局 SSRF 策略。默认关闭 SSRF 防护,方便自托管环境使用内网媒体源。公网部署建议启用 SSRF 防护,并为可信内网媒体端点配置显式 allowlist:

config:
security:
ssrf:
enabled: true
allowPrivateNetworkTargets: false
allowedHosts:
- nas.example.internal
allowedIpRanges:
- 10.0.8.0/24

只有在所有用户和 provider endpoint 都可信的私有部署里,才应设置 allowPrivateNetworkTargets=true

默认模式。Chart 自己创建 StatefulSet/Service。

postgresql:
mode: standard
redis:
mode: standard

如果集群安装了 KubeBlocks,可以让 chart 创建 KubeBlocks Cluster。

postgresql:
mode: kubeblocks
redis:
mode: kubeblocks

KubeBlocks 模式下,数据库账号密码来自 KubeBlocks 生成的 Secret。

PostgreSQL 场景中,SyncTV 只在 init container 启动阶段使用 KubeBlocks 的 postgres 系统账号,用它创建或修正 postgresql.kubeblocks.appUsernamepostgresql.kubeblocks.database;主容器随后使用这个应用账号连接数据库。应用账号密码保存在 Chart Secret 的 SYNCTV_DATABASE_PASSWORD 中;如果配置了 existingSecret,需要自行提供这个 key。

注意:KubeBlocks Redis Sentinel 组件属于数据库 Operator 的内部拓扑,不等同于把 SyncTV 配置成 redis.deployment_mode=sentinel。Helm 默认仍向 SyncTV 注入稳定 Redis Service endpoint;SyncTV 集群模式不能与 SyncTV Sentinel mode 同时使用。

如果 PostgreSQL 或 Redis 由云厂商、平台团队或其他 Operator 管理,使用 external 模式。Chart 不会创建对应的 StatefulSet、Service 或 KubeBlocks Cluster,只会把连接参数注入 SyncTV。

postgresql:
mode: external
external:
host: "postgres.example.internal"
port: 5432
username: "synctv"
database: "synctv"
redis:
mode: external
external:
host: "redis.example.internal"
port: 6379
username: ""
database: 0

external PostgreSQL 必须通过 existingSecretSYNCTV_DATABASE_PASSWORDsecrets.database.password 提供密码。external Redis 的 SYNCTV_REDIS_PASSWORD 是可选的:只有外部 Redis 启用了密码认证时才需要提供。

如果同时启用 networkPolicy.enabled=true,external PostgreSQL/Redis 以及对外 HTTP/HTTPS egress 会使用 ipBlock CIDR,而不是匹配 Chart 内部 Pod label;这些规则默认 fail-closed:external PostgreSQL 或 Redis 模式要求设置 networkPolicy.externalPostgresqlCIDRs / networkPolicy.externalRedisCIDRs,或者显式设置 networkPolicy.allowAnyExternalDatabaseEgress=true;对外 OAuth、媒体源 HTTP、HLS OSS 和 S3-compatible 对象存储 endpoint 要求设置 networkPolicy.externalHttpCIDRs,或者显式设置 networkPolicy.allowAnyExternalHttpEgress=true

应用 Service、PDB 和应用 NetworkPolicy 只选择带有 app.kubernetes.io/component=app 的 Pod。Chart 管理的 PostgreSQL 和 Redis 使用各自的 component label;启用 NetworkPolicy ingress 隔离时,Chart 会为它们渲染依赖专用 ingress policy,只允许 SyncTV 应用 Pod 访问对应端口。因此启用 NetworkPolicy 不会把 API 流量路由到依赖 Pod,也不会把依赖和 SyncTV 自身隔离开。

Redis 连接管理相关的 Helm 值:

config:
redis:
connectTimeoutSeconds: 5
responseTimeoutSeconds: 5
pipelineBufferSize: 512

responseTimeoutSeconds 限制 Redis 命令等待响应的时间;pipelineBufferSize 控制 connection manager 内部 pipeline buffer。高并发短命令场景可以适度调大,普通部署保持默认即可。

Helm 默认:

config:
dataDir: "/data"

Deployment 会挂载 /data。默认是 emptyDir,适合运行时临时文件。如果需要持久化运行时文件,可以设置 persistence.data.existingClaim

Helm 默认不启用集群模式。多副本 HLS 可以先使用 publisher-node HLS proxy;生产高流量场景使用 shared_file 或 OSS。shared_file 的 TS 分片由当前节点从共享路径读取。

本地 backend 示例:

config:
cluster:
enabled: true
livestream:
hlsStorageBackend: "memory"

这种配置不需要 HLS PVC,但非 publisher Pod 的 playlist/segment 请求会通过 gRPC 回源到 publisher Pod。

共享文件系统示例:

config:
cluster:
enabled: true
livestream:
hlsStorageBackend: "shared_file"
hlsStoragePath: "/var/lib/synctv/hls"
persistence:
hls:
existingClaim: "synctv-hls-rwx"

Helm 会提前拒绝以下组合:

  • hlsStorageBackend 不是 memoryfileshared_fileoss
  • hlsStorageBackend=file/shared_filehlsStoragePath 为空。
  • Kubernetes 中 hlsStorageBackend=file/shared_filehlsStoragePath 不是绝对路径。
  • hlsStorageBackend=shared_file 但没有配置 persistence.hls.existingClaim,避免把 emptyDir 误当成共享存储。

OSS 示例:

config:
cluster:
enabled: true
livestream:
hlsStorageBackend: "oss"
hlsOss:
endpoint: "https://s3.example.com"
bucket: "synctv-hls"
basePath: "synctv/hls/"
secrets:
livestream:
hlsOss:
accessKeyId: "..."
secretAccessKey: "..."

只要开启 config.cluster.enabled=true,应用启动校验还要求 Redis 可用、SYNCTV_CLUSTER_SECRET 稳定且所有副本一致,并且每个 Pod 具备可用于节点互联的 SYNCTV_SERVER_ADVERTISE_HOST。Helm 默认会注入 Redis 连接、自动生成 cluster secret,并用 Pod IP 作为 advertise host;如果你裁剪 values 或使用外部 Secret,需要保留这些条件。直播 HLS 选择本地 backend 时,还要确保 Pod 间 gRPC 路径可达,因为远端分片读取依赖 publisher-node proxy。

如果 config.cluster.discoveryMode=k8s_dns,Chart 会自动渲染 headless Service,并注入 HEADLESS_SERVICE_NAMEPOD_NAMESPACE。如果 config.cluster.leaderElectionMode=k8s_lease,Chart 会注入 POD_NAMEPOD_NAMESPACE。这两种模式都要求镜像构建包含 k8s feature。

开启 metrics:

metrics:
enabled: true
auth:
mode: bearer_token

ServiceMonitor:

metrics:
serviceMonitor:
enabled: true

VMServiceScrape:

metrics:
vmServiceScrape:
enabled: true

metrics Service selector 会匹配独立的 metrics Service,避免抓到公网 API/RTMP Service 或 gRPC Service。

如果使用 metrics.auth.mode=kubernetes,镜像内的 SyncTV 二进制必须启用 k8s feature。Helm 只负责 RBAC、ServiceAccount token 和抓取资源,不能改变镜像编译特性。

临时检查:

Terminal window
helm lint ./helm/synctv
helm template synctv ./helm/synctv
helm template synctv ./helm/synctv --set ingress.grpc.enabled=true

如果模板能渲染,不代表业务配置一定安全。还要在实际容器中运行配置校验或检查启动日志。