skillhub/charts/skillhub
philsun 34f244e7a4 feat(web): support configurable base-path deployment
Signed-off-by: philsun <xinyi.sun@daocloud.io>
2026-08-05 12:50:26 +08:00
..
templates feat(web): support configurable base-path deployment 2026-08-05 12:50:26 +08:00
tests feat(web): support configurable base-path deployment 2026-08-05 12:50:26 +08:00
.helmignore fix(helm): 修正组件启停与依赖配置并增加 values 校验 2026-07-15 17:19:24 +08:00
Chart.lock feat(chart): 集成 Bitnami 组件并重构高可用配置 2026-06-01 20:59:58 +08:00
Chart.yaml fix(helm): resolve deployment review blockers 2026-07-29 14:04:26 +08:00
README.md feat(redis): complete cluster connection support 2026-07-29 17:36:06 +08:00
values.schema.json feat(web): support configurable base-path deployment 2026-08-05 12:50:26 +08:00
values.yaml feat(web): support configurable base-path deployment 2026-08-05 12:50:26 +08:00

SkillHub Helm Chart

企业级 AI 技能中心私有化部署方案,基于 Kubernetes 和 Helm。

特性

  • 微服务架构ServerSpring Boot、WebNginx、Scanner 分离部署
  • 高可用:支持 HPA 自动扩缩容、PDB Pod 中断预算
  • 数据层:使用 Bitnami PostgreSQL/Redis支持主从复制、哨兵模式
  • 安全TLS 证书管理、Secret 密码保护Bitnami 数据组件默认提供 NetworkPolicy
  • 可观测性:内置 Prometheus metrics exporter

快速开始

前置要求

  • Kubernetes 1.24+
  • Helm 3.8+
  • kubectl configured

安装

先创建受保护的 values-production.yaml。以下值必须替换为实际随机强密码:

secrets:
  allowAutoGenerated: false
  bootstrapAdminPassword: "<固定管理员密码>"
  downloadAnonCookieSecret: "<至少32字符的固定随机值>"

postgresql:
  auth:
    postgresPassword: "<固定PostgreSQL管理员密码>"
    password: "<固定skillhub用户密码>"

redis:
  auth:
    password: "<固定Redis密码>"
helm dependency build ./charts/skillhub
kubectl create namespace skillhub

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set publicBaseUrl=https://skills.example.com

未显式设置 deviceAuthVerificationUriChart 使用 <publicBaseUrl>/cli/auth。所有 values 会先经过 values.schema.json 和跨字段校验, 无效的组件、Ingress、HPA 与存储组合会在安装前失败。

Ingress values 迁移: 当前版本只支持结构化的 ingress.hosts[]ingress.tls[]。旧的 ingress.hostingress.tls.enabledingress.tls.secretName 不再接受,升级前必须改成本文 Ingress 示例中的数组结构。

合并或发布前,可在一个空的测试 Kubernetes 集群中运行可重复的安装/升级 smoke

for scenario in default sentinel s3 ingress-tls; do
  HELM_SMOKE_SCENARIO="$scenario" \
    bash charts/skillhub/tests/install-upgrade-smoke.sh
done

脚本验证 install -> Ready -> HTTP health -> upgrade -> Ready,并确认 Secret 数据、 PVC UID 与绑定 PV 在升级前后保持不变。四个场景分别覆盖默认依赖、Redis Sentinel、实际 MinIO S3 连接,以及由 Kubernetes API 接受的 TLS Ingress 路由。 默认清理自己创建的 namespace设置 KEEP_HELM_SMOKE=true 可保留现场用于排查。

高可用模式

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set postgresql.architecture=replication \
  --set postgresql.auth.replicationPassword=your-replication-password \
  --set redis.architecture=replication

外部数据库模式

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set postgresql.enabled=false \
  --set redis.enabled=false \
  --set externalDatabase.host=postgres.example.com \
  --set externalDatabase.port=5432 \
  --set externalDatabase.database=skillhub \
  --set externalDatabase.username=skillhub \
  --set externalDatabase.password=your-db-password \
  --set externalRedis.host=redis.example.com \
  --set externalRedis.port=6379 \
  --set externalRedis.password=your-redis-password

使用 existingSecret

通过 existingSecret 引用已存在的 Secret 对象,避免在 values 中明文写入密码。 内置 PostgreSQL/Redis 使用各自的 Bitnami Secret不需要复制到该 Secret。

Key 必填 说明
spring-datasource-password 使用外部 PostgreSQL 时 数据库密码
redis-password 使用外部 Redis 时 Redis 密码
redis-sentinel-password 使用外部 Sentinel 时 Redis Sentinel 密码
bootstrap-admin-password 初始管理员密码
skillhub-download-anon-cookie-secret 至少 32 字符的匿名下载 Cookie 签名密钥
oauth2-github-client-id GitHub OAuth2 Client ID
oauth2-github-client-secret GitHub OAuth2 Client Secret
skill-scanner-llm-api-key Scanner LLM API Key
skill-scanner-llm-base-url Scanner 自定义 LLM API 地址
skill-scanner-llm-model Scanner LLM 模型名称
skillhub-storage-s3-access-key S3 Access Key
skillhub-storage-s3-secret-key S3 Secret Key
helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set existingSecret=my-custom-secret

GitOps 稳定 Secret

Argo CD 等 GitOps 工具使用离线 helm template,无法通过 Helm lookup 读取集群 中已有的 Secret。Bitnami 子 Chart 和父 Chart 的空密码会在每次渲染时重新随机 生成。Chart 默认禁止自动生成并要求提供固定值:

secrets:
  allowAutoGenerated: false
  bootstrapAdminPassword: "<固定管理员密码>"
  downloadAnonCookieSecret: "<至少32字符的固定随机值>"

postgresql:
  auth:
    postgresPassword: "<固定PostgreSQL管理员密码>"
    password: "<固定skillhub用户密码>"
    # replication 架构还必须配置 replicationPassword

redis:
  auth:
    password: "<固定Redis密码>"

也可以为三个组件分别配置 existingSecretallowAutoGenerated=false 不会生成 可预测密码,而是在任何随机密码缺失时终止渲染并指出具体配置项。敏感值应放在 受保护的 values、External Secrets、Sealed Secrets 或密钥注入插件中。

内置 PostgreSQL、Redis、Sentinel 及 metrics exporter 镜像默认使用不可变的 多架构 manifest digest避免 Bitnami 子 Chart 的 latest 默认值造成不可复现的 安装和回滚,同时保留 amd64/arm64 支持。覆盖私有镜像仓库或 tag 时,必须同时把 对应的 image.digest 设为空,或改成私有仓库中该镜像的真实 digestdigest 非空时会优先于 tag。

配置参考

副本数配置

参数 描述 默认值
server.replicaCount Server 副本数 1
web.replicaCount Web 副本数 1
scanner.replicaCount Scanner 副本数 1
# 差异化副本配置
helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set server.replicaCount=3 \
  --set server.storage.accessMode=ReadWriteMany \
  --set web.replicaCount=2 \
  --set scanner.replicaCount=1

本地存储运行多个 Server 副本时,必须显式设置 ReadWriteMany,并使用支持 RWX 的 StorageClass。无法提供 RWX 时应改用 S3。

服务配置

参数 描述 默认值
server.service.type Server Service 类型 ClusterIP
server.service.port Server 端口 8080
web.service.type Web Service 类型 ClusterIP
web.service.port Web 端口 80
scanner.service.port Scanner 端口 8000

私有镜像仓库

使用私有仓库时,需要分别覆盖 SkillHub 镜像、依赖等待镜像和 Bitnami 子 Chart 镜像。以下示例中的数据库镜像标签均为明确版本,不使用 latest

global:
  imagePullSecrets:
    - private-registry
  security:
    allowInsecureImages: true

images:
  registry: registry.example.com/library
  tag: v0.2.14
  pullPolicy: IfNotPresent

server:
  dependencyWait:
    image:
      registry: registry.example.com
      repository: library/busybox
      tag: "1.37"
      pullPolicy: IfNotPresent
  imagePullSecrets:
    - name: private-registry

web:
  imagePullSecrets:
    - name: private-registry

scanner:
  imagePullSecrets:
    - name: private-registry

postgresql:
  image:
    registry: registry.example.com
    repository: library/postgresql
    tag: 18.4.0
    digest: ""
  metrics:
    image:
      registry: registry.example.com
      repository: library/postgres-exporter
      tag: 0.20.1
      digest: ""

redis:
  image:
    registry: registry.example.com
    repository: library/redis
    tag: 8.8.0
    digest: ""
  sentinel:
    image:
      registry: registry.example.com
      repository: library/redis-sentinel
      tag: 8.8.0
      digest: ""
  metrics:
    image:
      registry: registry.example.com
      repository: library/redis-exporter
      tag: 1.86.0
      digest: ""

global.security.allowInsecureImages 是 Bitnami 对自定义镜像仓库和镜像名称的校验 开关,并不表示使用不安全的 HTTP 仓库。先在目标 namespace 创建拉取凭据:

kubectl create secret docker-registry private-registry \
  -n skillhub \
  --docker-server=registry.example.com \
  --docker-username='<用户名>' \
  --docker-password='<密码>'

数据库配置

参数 描述 默认值
postgresql.enabled 启用内置 PostgreSQL true
postgresql.architecture 架构模式 standalone
redis.enabled 启用内置 Redis true
redis.architecture 架构模式 standalone

数据库架构支持边界

以下内置数据库目标架构已完成独立 namespace 的全新安装和运行时验证:

数据组件 已验证架构 运行时验证
PostgreSQL standalone Server 连接、Flyway 和应用启动
PostgreSQL replication 1 Primary + 2 Read Replicas两个副本均处于 recovery流复制状态为 streaming
Redis standalone Server 读写和应用启动
Redis replication 1 Master + 2 Replicas角色和数据复制正常
Redis replication + Sentinel 3 个 Sentinel 节点 master 视图一致Server 可通过 Sentinel 读写

上述支持表示 Chart 能够全新部署目标架构,并为 SkillHub 配置正确的写节点或 Sentinel 地址。Chart 不负责数据库架构切换时的数据迁移,也不承诺仅修改 architecturesentinel.enabled 就能保留已有数据。已有数据的 PostgreSQL standalone → replication、Redis standalone/replication → Sentinel 等切换,必须由 运维人员在 Chart 之外完成备份、恢复、PVC 复用或其他迁移方案。

外部 Redis Cluster 由云服务或运维系统提供Chart 只负责注入连接配置,不创建 Cluster也不将其计入上述内置架构运行时验证范围。应用侧应另行验证 Spring Data、Spring Session 与 Redisson Stream 链路。

Redis Sentinel

内置 Sentinel 使用 Bitnami Redis 的同一份密码同时保护 Redis 数据节点和 Sentinel。节点地址由副本数自动生成不需要手动配置。由于 Bitnami Sentinel 上报的 Pod 地址可能与客户端连接的 Headless Service FQDN 不同Chart 仅在该 内置模式下关闭 Redisson 的 Sentinel 地址一致性检查:

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set redis.architecture=replication \
  --set redis.sentinel.enabled=true

外部 Sentinel 必须提供至少一个 host:port 节点。Redis 数据密码和 Sentinel 密码可以不同;使用 existingSecret 时分别对应 redis-passwordredis-sentinel-password。外部 Sentinel 默认保留 Redisson 地址一致性检查; 只有已确认服务发现会改写节点地址时,才通过 server.extraEnv 显式设置 SKILLHUB_REDIS_SENTINEL_CHECK_SENTINELS_LIST=false

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set redis.enabled=false \
  --set externalRedis.password=redis-password \
  --set externalRedis.sentinel.enabled=true \
  --set externalRedis.sentinel.password=sentinel-password \
  --set-json 'externalRedis.sentinel.nodes=["sentinel-0.example.com:26379","sentinel-1.example.com:26379"]'

确需关闭检查时,在 values 文件中显式记录该兼容例外:

server:
  extraEnv:
    - name: SKILLHUB_REDIS_SENTINEL_CHECK_SENTINELS_LIST
      value: "false"

外部 Redis Cluster

Chart 不创建内置 Redis Cluster。生产环境的 Cluster 由云 Redis 或独立运维系统 提供SkillHub 通过标准 Spring Boot 配置连接。至少配置一个 seed 节点,且 Cluster 通告的所有节点地址都必须能从 Server Pod 访问:

redis:
  enabled: false

externalRedis:
  username: skillhub
  tls:
    enabled: true
  connectTimeout: 5s
  timeout: 3s
  clientName: skillhub-server
  cluster:
    enabled: true
    nodes:
      - redis-0.example.com:6379
      - redis-1.example.com:6379
      - redis-2.example.com:6379
    maxRedirects: 5

Redis Cluster 只支持数据库 0maxRedirects 交给 Spring Data/Lettuce 处理; Redisson 使用同一节点、ACL、TLS 与超时配置并自行处理 Cluster 路由。密码建议 通过 existingSecretredis-password 提供:

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set redis.enabled=false \
  --set existingSecret=skillhub-production-secret \
  --set externalRedis.cluster.enabled=true \
  --set-json 'externalRedis.cluster.nodes=["redis-0.example.com:6379","redis-1.example.com:6379","redis-2.example.com:6379"]'

externalRedis.sentinel.enabledexternalRedis.cluster.enabled 互斥;内置 redis.enabled=true 时也不能启用外部 Cluster。

存储配置

参数 描述 默认值
server.storage.accessMode 留空时单副本使用 ReadWriteOnce多副本必须显式使用 ReadWriteMany ""
server.storage.size PVC 大小 10Gi
server.storage.storageClassName StorageClass ""
server.podSecurityContext.fsGroup Server 本地存储的可写组 ID应与镜像内 app 用户组一致 101
server.podSecurityContext.fsGroupChangePolicy kubelet 调整 PVC 组权限的策略 OnRootMismatch

本地 PVC 会覆盖镜像内预先设置的目录所有者。Chart 默认通过 Pod fsGroup=101 使 Server 的非 root app 用户可以创建和更新技能文件。使用自定义 Server 镜像且其 运行组 ID 不同时,必须同步覆盖 server.podSecurityContext.fsGroup

使用本地 ReadWriteOnce PVC 时Server Deployment 自动采用 Recreate,避免 滚动升级期间新旧 Pod 同时挂载非共享卷而触发 Multi-Attach。单副本升级会有短暂 停机;使用支持 RWX 的 ReadWriteMany 存储或启用 S3 时Chart 保留 RollingUpdate

# 默认使用本地 PVC
helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml

S3 对象存储

s3.enabled=true 时,不创建 PVC应用使用 S3 作为存储后端。

参数 描述 默认值
s3.enabled 启用 S3 false
s3.bucket Bucket 名称 skillhub-storage
s3.endpoint S3 端点,非空时必须是绝对 HTTP(S) URL ""
s3.publicEndpoint S3 公网访问端点,非空时必须是绝对 HTTP(S) URL ""
s3.region 区域 us-east-1
s3.forcePathStyle 强制 path-style 访问 true
s3.disableChunkedEncoding 禁用 aws-chunked 编码 false
s3.autoCreateBucket 自动创建 Bucket false
s3.accessKey Access Key ""
s3.secretKey Secret Key ""
helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set s3.enabled=true \
  --set s3.bucket=your-bucket \
  --set s3.endpoint=https://s3.amazonaws.com \
  --set s3.region=us-east-1 \
  --set s3.accessKey=your-access-key \
  --set s3.secretKey=your-secret-key

Ingress + TLS

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set ingress.enabled=true \
  --set-json 'ingress.hosts=[{"host":"skills.example.com","paths":[{"path":"/","pathType":"Prefix"}]}]' \
  --set-json 'ingress.tls=[{"hosts":["skills.example.com"],"secretName":"skills-tls"}]' \
  --set publicBaseUrl=https://skills.example.com \
  --set ingress.certManager.enabled=true

配置非空 ingress.tls 或启用 ingress.certManagerChart 会自动将 Session Cookie 标记为 Secure。Ingress 要求 Server 和 Web Service 均保持启用。

ingress.className 和旧式 kubernetes.io/ingress.class annotation 均受支持, 可以任选其一,也可以同时输出。仅使用旧式 annotation 时将 className 留空:

ingress:
  enabled: true
  className: ""
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":6443}]'

hosts 是至少包含一个条目的对象数组。Chart 自动将 /api/oauth2/login/oauth2/.well-known 直接转发给 Server确保 TLS 终止后的 OAuth 回调协议保持正确;hosts[].paths 中的其他路径转发给 Web因此上述四个前缀 均为保留路径。tls 同样是数组可为不同证书分别配置域名TLS 域名会写入 cert-manager Certificate SAN

ingress:
  hosts:
    - host: skills.example.com
      paths:
        - path: /
          pathType: Prefix
    - host: skills.internal.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - hosts:
        - skills.example.com
        - skills.internal.example.com
      secretName: skills-tls

自动扩缩容

helm -n skillhub upgrade -i skillhub ./charts/skillhub \
  -f values-production.yaml \
  --set server.autoscaling.enabled=true \
  --set server.autoscaling.minReplicas=2 \
  --set server.autoscaling.maxReplicas=10 \
  --set server.storage.accessMode=ReadWriteMany

每个 HPA 至少需要一个非零 CPU 或内存利用率目标。本地存储的 Server HPA 同样 要求 RWX也可以启用 S3 来避免共享 PVC。

发布

.github/workflows/publish-chart.yml 在 GitHub Release 发布后或手动 workflow_dispatch 时运行。Release tag 必须使用 vX.Y.Zchart-vX.Y.Zhelm-vX.Y.Z;手动运行时显式输入 X.Y.Z。工作流按该版本打包 Chart并推送到 oci://ghcr.io/iflytek/charts,同时保留构建 artifact。

卸载

helm -n skillhub uninstall skillhub

Server 数据 PVC 带有 helm.sh/resource-policy: keep,卸载 release 后仍会保留, 需要确认数据不再使用后手动删除。

依赖

依赖 版本
postgresql 18.6.10
redis 25.5.3