自建Kubernetes集群部署Novu:Helm Chart查询与部署方案咨询
Novu 自建K8s集群部署指南(适配v1.26裸金属环境)
官方Helm Chart状态
目前Novu官方尚未发布正式维护的Helm Chart,社区存在部分第三方贡献的Chart,但稳定性和适配性无法保障,建议基于官方docker-compose.yml手动拆解编写K8s资源清单,或自行封装专属Helm Chart。
手动编写清单的组件拆分结构
Novu组件按状态特性分为两类,拆分逻辑如下:
有状态组件(采用StatefulSet + PVC)
- MongoDB:存储核心通知数据,需持久化,UAT用
local-path存储类,生产切换为NFS存储类 - Redis:处理异步任务队列与缓存,需持久化避免任务丢失
- PostgreSQL(可选):启用事件归档等功能时部署
- InfluxDB(可选):用于监控指标存储
无状态组件(采用Deployment)
- Novu API:核心业务接口服务
- Novu Web UI:前端管理界面
- Novu Worker:异步任务处理(通知发送、重试等)
- Novu Notification Center:用户端通知展示服务
- Novu Subscriber:事件订阅服务
Novu环境变量安全处理
- 敏感变量(如数据库密码、JWT_SECRET、第三方服务API密钥等):存入K8s
Secret,通过envFrom或valueFrom注入Pod - 非敏感配置(如服务地址、端口、环境标识、日志级别等):存入K8s
ConfigMap,同样通过envFrom注入 - 严禁在Deployment/StatefulSet中硬编码敏感信息,所有敏感变量必须通过Secret管理
组件独立扩缩容最佳实践
- API/Web UI:基于CPU/内存使用率配置HPA(Horizontal Pod Autoscaler),根据请求量自动扩缩;生产环境建议设置最小2副本、最大10副本
- Worker组件:基于Redis队列长度配置自定义HPA指标(需部署Prometheus+Redis Exporter采集队列 metrics),队列积压时自动扩容,空闲时缩容至最小2副本
- 有状态组件:
- MongoDB:单实例场景直接调整StatefulSet的
replicas数扩副本;生产环境建议部署3副本StatefulSet集群,通过MongoDB自身副本机制保障高可用 - Redis:单实例扩副本需配置哨兵或集群模式避免单点故障;生产用Redis Cluster时按节点数扩容
- MongoDB:单实例场景直接调整StatefulSet的
- 资源配额约束:为Novu所在Namespace配置
ResourceQuota,限制总CPU/内存使用量;同时为每个Pod设置resources.requests和resources.limits,防止资源抢占
基础K8s资源清单示例
1. Namespace创建
apiVersion: v1 kind: Namespace metadata: name: novu
2. Secret(敏感配置)
apiVersion: v1 kind: Secret metadata: name: novu-secrets namespace: novu type: Opaque stringData: MONGO_PASSWORD: "your-mongo-password" REDIS_PASSWORD: "your-redis-password" JWT_SECRET: "your-jwt-secret-32chars-min" SMTP_PASSWORD: "your-smtp-password"
3. ConfigMap(非敏感配置)
apiVersion: v1 kind: ConfigMap metadata: name: novu-config namespace: novu data: NODE_ENV: "production" MONGO_URI: "mongodb://novu-mongo-0.novu-mongo.novu.svc.cluster.local:27017/novu?authSource=admin" REDIS_HOST: "novu-redis-0.novu-redis.novu.svc.cluster.local" REDIS_PORT: "6379" API_PORT: "3000" WEB_PORT: "4200"
4. PVC(MongoDB示例,生产用NFS存储类)
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: novu-mongo-pvc namespace: novu spec: accessModes: - ReadWriteOnce storageClassName: "nfs-storage" # UAT替换为local-path resources: requests: storage: 10Gi
5. StatefulSet(MongoDB)
apiVersion: apps/v1 kind: StatefulSet metadata: name: novu-mongo namespace: novu spec: serviceName: "novu-mongo" replicas: 1 selector: matchLabels: app: novu-mongo template: metadata: labels: app: novu-mongo spec: containers: - name: mongo image: mongo:6.0 ports: - containerPort: 27017 env: - name: MONGO_INITDB_ROOT_USERNAME value: "novu" - name: MONGO_INITDB_ROOT_PASSWORD valueFrom: secretKeyRef: name: novu-secrets key: MONGO_PASSWORD volumeMounts: - name: mongo-data mountPath: /data/db volumeClaimTemplates: - metadata: name: mongo-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "nfs-storage" # UAT替换为local-path resources: requests: storage: 10Gi
6. Deployment(Novu API)
apiVersion: apps/v1 kind: Deployment metadata: name: novu-api namespace: novu spec: replicas: 2 selector: matchLabels: app: novu-api template: metadata: labels: app: novu-api spec: containers: - name: novu-api image: novuhq/api:0.22.0 ports: - containerPort: 3000 envFrom: - secretRef: name: novu-secrets - configMapRef: name: novu-config resources: requests: cpu: "100m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi"
7. Service(API示例)
apiVersion: v1 kind: Service metadata: name: novu-api namespace: novu spec: selector: app: novu-api ports: - port: 3000 targetPort: 3000 type: ClusterIP
8. Ingress(Web UI + API)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: novu-ingress namespace: novu annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: tls: - hosts: - novu.your-domain.com secretName: novu-tls-secret rules: - host: novu.your-domain.com http: paths: - path: /api/(.*) pathType: Prefix backend: service: name: novu-api port: number: 3000 - path: /(.*) pathType: Prefix backend: service: name: novu-web port: number: 4200
9. ResourceQuota
apiVersion: v1 kind: ResourceQuota metadata: name: novu-quota namespace: novu spec: hard: requests.cpu: "2" requests.memory: "4Gi" limits.cpu: "4" limits.memory: "8Gi" pods: "20"
内容的提问来源于stack exchange,提问作者Darun Omar
相关产品推荐
相关产品推荐

