Skip to content

feat(chart): 添加 Helm Chart 部署方案#445

Open
jangrui wants to merge 4 commits into
iflytek:mainfrom
jangrui:feature/helm-chart
Open

feat(chart): 添加 Helm Chart 部署方案#445
jangrui wants to merge 4 commits into
iflytek:mainfrom
jangrui:feature/helm-chart

Conversation

@jangrui
Copy link
Copy Markdown

@jangrui jangrui commented May 16, 2026

概述

添加 Helm Chart 部署支持。

核心特性

  • PostgreSQL/Redis:内置 StatefulSet 部署或连接外部服务
  • 弹性伸缩:支持 HPA(CPU+内存)和 PDB 预算配置
  • 网络:ClusterIP / NodePort / LoadBalancer 三种服务类型
  • 存储:Local PVC / S3 兼容存储,PVC 卸载保护
  • 安全:cert-manager 自动 TLS 证书签发
  • 依赖检查:initContainer 等待数据库和 Redis 就绪

安装示例

helm install skillhub ./charts/skillhub \
  --set bootstrapAdmin.password=admin123 \
  --set service.type=NodePort

CI/CD

  • PR 校验:9 种场景矩阵验证
  • 发布:打 tag 后自动打包推送到 GHCR OCI

新增 Helm Chart 支持完整的 SkillHub 私有化部署,包括:

- PostgreSQL/Redis 内置 StatefulSet 及外部模式切换
- 零依赖设计,无需 Bitnami 子 Chart
- 支持 standalone/cluster 数据库架构
- NodePort/LoadBalancer/ClusterIP 多种服务类型
- HPA、PDB、ServiceMonitor 完整运维支持
- cert-manager 证书自动签发
- initContainer 等待数据库和 Redis 就绪
- PVC 卸载保护 (helm.sh/resource-policy: keep)
- GitHub Actions: PR 校验 + 发布到 GHCR OCI
@jangrui jangrui changed the title feat(chart): 添加 SkillHub Helm Chart 部署方案 feat(chart): 添加 Helm Chart 部署方案 May 16, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive Helm chart for the SkillHub application, covering backend, frontend, and scanner components along with internal PostgreSQL and Redis statefulsets. The review identified several critical security and stability issues: sensitive credentials for Redis and S3 are exposed as plain text environment variables, and the use of randAlphaNum for secrets without persistence checks will cause authentication failures during Helm upgrades. Furthermore, the PostgreSQL configuration for multiple replicas is invalid for the base image used and risks data corruption. Other feedback includes the need for configuration checksums to trigger rolling updates, fixing hardcoded usernames in health probes, and avoiding the latest image tag for production stability.

Comment thread charts/skillhub/templates/secret.yaml Outdated
Comment on lines +12 to +14
spring-datasource-password: {{ if eq .Values.database.mode "internal" }}{{ default (randAlphaNum 16) .Values.secrets.springDatasourcePassword }}{{ else }}{{ .Values.database.external.password }}{{ end }}

bootstrap-admin-password: {{ .Values.secrets.bootstrapAdminPassword | default .Values.bootstrapAdmin.password | default (randAlphaNum 16) }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

使用 randAlphaNum 生成随机密码时,如果没有配合 lookup 函数检查集群中是否已存在该 Secret,会导致每次执行 helm upgrade 时密码都被重新生成。这会导致应用在升级后无法连接数据库(因为数据库容器内的密码未变,但应用尝试使用新密码)或管理员账户失效。建议参考 Helm 官方最佳实践,先尝试读取现有 Secret 中的值,如果不存在再生成。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。使用 lookup 函数检查集群中是否已存在该 Secret,若存在则保留原值,仅在首次安装时生成随机密码。避免了 helm upgrade 因密码重新生成导致的数据库连接中断问题。

Comment on lines +87 to +89
- name: SPRING_DATA_REDIS_PASSWORD
value: {{ .Values.redis.external.password }}
{{- end }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

将 Redis 密码直接以明文形式写入环境变量的 value 是不安全的。这会导致敏感信息暴露在 Kubernetes API 和控制台中。建议将此密码放入 Secret 对象中,并使用 valueFrom.secretKeyRef 进行引用。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。Redis 密码已从明文环境变量移除,改为通过 secretKeyRef 从 Secret 中引用。对应的 redis-password 字段已添加至 Secret 模板。

Comment on lines +118 to +124
- name: SKILLHUB_S3_ACCESS_KEY
value: {{ .Values.storage.s3.accessKey }}
{{- end }}
{{- if .Values.storage.s3.secretKey }}
- name: SKILLHUB_S3_SECRET_KEY
value: {{ .Values.storage.s3.secretKey }}
{{- end }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

S3 的 AccessKey 和 SecretKey 属于敏感凭据,不应直接在 Deployment 中明文配置。建议将这些值移至 Secret 并通过 secretKeyRef 引用,以符合安全合规要求。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。S3 的 AccessKey 和 SecretKey 已从 Deployment 明文配置移除,改为通过 secretKeyRef 从 Secret 中引用。对应的 s3-access-keys3-secret-key 字段已在 Secret 模板中定义。

labels:
{{- include "skillhub.server.selectorLabels" . | nindent 8 }}
annotations:
{{- toYaml .Values.server.podAnnotations | nindent 8 }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

建议在 Pod 模板的注解中添加 ConfigMap 和 Secret 的校验和(checksum)。这样当配置发生变化时,Deployment 会自动触发 Pod 的滚动更新。如果没有这些注解,用户修改配置后必须手动重启 Pod 才能生效。

        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
        {{- toYaml .Values.server.podAnnotations | nindent 8 }}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。已在 server/web/scanner 三个 Deployment 的 Pod 注解中添加 checksum/configchecksum/secret,基于 ConfigMap 和 Secret 相关的 values 子集计算 SHA256。配置变更后 Deployment 将自动触发滚动更新。

echo "Redis is ready!"
containers:
- name: server
image: {{ .Values.images.registry }}/skillhub-server:{{ .Values.images.tag }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

镜像地址直接引用了 .Values.images.registry,未考虑 values.yaml 中定义的 global.imageRegistry。这会导致全局镜像仓库覆盖配置失效。建议使用 _helpers.tpl 中的模板或增加逻辑判断。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。server/web/scanner 三个 Deployment 的镜像地址均已改为 {{ .Values.global.imageRegistry | default .Values.images.registry }},优先使用全局 registry 覆盖。

app.kubernetes.io/component: database
spec:
serviceName: {{ include "skillhub.fullname" . }}-postgres
replicas: {{ if eq .Values.database.architecture "cluster" }}3{{ else }}1{{ end }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

当前使用的 postgres:16-alpine 镜像不支持自动集群化。将 replicas 设置为 3 会启动三个完全独立且互不同步的数据库实例,而 Service 会在它们之间进行负载均衡,这会导致严重的数据不一致和丢失问题。建议在 internal 模式下仅支持单实例,或者集成专门的 HA 方案(如 Bitnami PostgreSQL HA)。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。internal 模式下 PostgreSQL StatefulSet 的 replicas 强制为 1,移除了 architecture: cluster 时设为 3 的逻辑。内置 postgres:16-alpine 镜像不支持自动集群化,如需高可用请使用 external 模式连接外部 PostgreSQL 集群(如 Patroni)。

Comment on lines +54 to +64
- skillhub
- -h
- localhost
initialDelaySeconds: 10
periodSeconds: 10
livenessProbe:
exec:
command:
- pg_isready
- -U
- skillhub
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

探针命令中的用户名 -U skillhub 是硬编码的。如果用户在 values.yaml 或 Secret 中更改了数据库用户名,存活探针和就绪探针将会失败导致容器不断重启。建议使用环境变量 POSTGRES_USER 代替硬编码字符串。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。探针命令已改用 sh -c "pg_isready -U \"${POSTGRES_USER}\" -h localhost",通过环境变量动态获取数据库用户名,不再硬编码。

Comment thread charts/skillhub/values.yaml Outdated
# ============================================================================
images:
registry: ghcr.io/iflytek
tag: latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

默认镜像标签设为 latest 会导致部署结果不可预测,且在生产环境中难以进行版本回滚。建议始终指定具体的版本号(如 0.2.8)。

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。默认镜像标签已从 latest 改为 v0.2.8,支持可追溯的版本回滚。

jangrui added 3 commits May 16, 2026 08:40
- secret.yaml: lookup 检查现有 Secret 避免 upgrade 重新生成密码
- secret.yaml: Redis/S3 凭据通过 Secret 引用,移除明文环境变量
- backend/frontend/scanner: 新增 checksum 注解,配置变更自动触发滚动更新
- backend/frontend/scanner: 镜像地址支持 global.imageRegistry 覆盖
- postgres: internal 模式仅支持单副本,移除伪集群配置
- postgres: 探针用户名改用 POSTGRES_USER 环境变量
- values.yaml: accessMode 默认 ReadWriteMany,tag 指定 v0.2.8
values.yaml 中 images.tag 留空时自动取 Chart.yaml 的 appVersion,
格式为 v{appVersion}(如 0.2.8 → v0.2.8)。
用户仍可通过 --set images.tag=xxx 显式覆盖。
@jangrui
Copy link
Copy Markdown
Author

jangrui commented May 16, 2026

@dongmucat

您好!这个 PR 添加了 Helm Chart 部署方案与 CI/CD 工作流,包括:

  • Helm Chart 完整模板(Deployment、StatefulSet、Service、Ingress 等)
  • 9 场景 PR 验证工作流(helm lint + 模板渲染)
  • 自动发版工作流(tag push 触发,自动更新 appVersion 并推送 GHCR OCI)

当前有 workflows 需要您的批准才能运行,烦请批准,谢谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant