mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-09 03:17:52 +00:00
feat(chart): 添加 SkillHub Helm Chart 部署方案
新增 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 Signed-off-by: jangrui <admin@jangrui.com>
This commit is contained in:
parent
098616dcb6
commit
dd1e87f1f3
19 changed files with 1615 additions and 0 deletions
146
.github/workflows/pr-helm-chart.yml
vendored
Normal file
146
.github/workflows/pr-helm-chart.yml
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
name: PR Helm Chart
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- charts/skillhub/**
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: pr-helm-chart-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint Chart
|
||||
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }}
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: charts/skillhub
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Lint chart
|
||||
run: helm lint
|
||||
|
||||
- name: Validate chart metadata
|
||||
run: |
|
||||
CHART_VERSION=$(helm show chart . | grep '^version:' | awk '{print $2}')
|
||||
APP_VERSION=$(helm show chart . | grep '^appVersion:' | awk '{print $2}')
|
||||
echo "Chart version: $CHART_VERSION"
|
||||
echo "App version: $APP_VERSION"
|
||||
if [ -z "$CHART_VERSION" ]; then
|
||||
echo "ERROR: Chart version is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
template:
|
||||
name: Template Validation
|
||||
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }}
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: charts/skillhub
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
scenario:
|
||||
- name: internal-default
|
||||
description: 内置 PostgreSQL + Redis
|
||||
args: ""
|
||||
- name: external-db-redis
|
||||
description: 外置 PostgreSQL + Redis
|
||||
args: >
|
||||
--set database.mode=external
|
||||
--set redis.mode=external
|
||||
- name: external-sentinel
|
||||
description: 外置 DB + Redis 哨兵模式
|
||||
args: >
|
||||
--set database.mode=external
|
||||
--set redis.mode=external
|
||||
--set redis.external.sentinel.enabled=true
|
||||
--set redis.external.sentinel.nodes="{10.0.0.1:26379,10.0.0.2:26379}"
|
||||
- name: ingress-tls-certmanager
|
||||
description: Ingress + TLS + cert-manager
|
||||
args: >
|
||||
--set ingress.enabled=true
|
||||
--set ingress.tls.enabled=true
|
||||
--set ingress.certManager.enabled=true
|
||||
- name: s3-storage
|
||||
description: S3 存储
|
||||
args: >
|
||||
--set storage.provider=s3
|
||||
--set storage.s3.bucket=test-bucket
|
||||
--set storage.s3.endpoint=s3.amazonaws.com
|
||||
--set storage.s3.region=us-east-1
|
||||
- name: external-secret
|
||||
description: 引用已有 Secret
|
||||
args: --set existingSecret=my-custom-secret
|
||||
- name: scanner-disabled
|
||||
description: 禁用 Scanner
|
||||
args: --set scanner.enabled=false
|
||||
- name: db-cluster
|
||||
description: PostgreSQL cluster 模式
|
||||
args: --set database.architecture=cluster
|
||||
- name: hpa-pdb
|
||||
description: HPA + PDB 开启
|
||||
args: >
|
||||
--set server.autoscaling.enabled=true
|
||||
--set web.autoscaling.enabled=true
|
||||
--set scanner.autoscaling.enabled=true
|
||||
--set server.podDisruptionBudget.enabled=true
|
||||
--set web.podDisruptionBudget.enabled=true
|
||||
--set scanner.podDisruptionBudget.enabled=true
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Render template - ${{ matrix.scenario.name }}
|
||||
run: |
|
||||
echo "## ${{ matrix.scenario.description }}"
|
||||
helm template test-release . ${{ matrix.scenario.args }} > /dev/null
|
||||
echo "✅ Template rendered successfully"
|
||||
|
||||
- name: Validate no empty resources
|
||||
run: |
|
||||
RESOURCES=$(helm template test-release . ${{ matrix.scenario.args }} | grep -c '^kind:')
|
||||
echo "Rendered $RESOURCES resources for ${{ matrix.scenario.name }}"
|
||||
if [ "$RESOURCES" -eq 0 ]; then
|
||||
echo "ERROR: No resources rendered for ${{ matrix.scenario.name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Validate resource names are well-formed
|
||||
run: |
|
||||
helm template test-release . ${{ matrix.scenario.args }} | \
|
||||
grep -E '^ name:' | \
|
||||
while read -r line; do
|
||||
if echo "$line" | grep -qP '\{\{'; then
|
||||
echo "ERROR: Unrendered template in name: $line"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "✅ All resource names properly rendered"
|
||||
81
.github/workflows/publish-helm-chart.yml
vendored
Normal file
81
.github/workflows/publish-helm-chart.yml
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
name: Publish Helm Chart
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: publish-helm-chart-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
package:
|
||||
name: Package and Publish
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: charts/skillhub
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Extract chart version from tag
|
||||
id: chartver
|
||||
run: |
|
||||
REF="${{ github.ref_name }}"
|
||||
# Support helm-vX.Y.Z or just vX.Y.Z tags
|
||||
if [[ "$REF" =~ ^helm-v?([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
|
||||
VERSION="${BASH_REMATCH[1]}"
|
||||
elif [[ "$REF" =~ ^v?([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
|
||||
VERSION="${BASH_REMATCH[1]}"
|
||||
else
|
||||
# Fallback: use chart.yaml version
|
||||
VERSION=$(helm show chart . | grep '^version:' | awk '{print $2}')
|
||||
fi
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Packaging chart version: $VERSION"
|
||||
|
||||
- name: Lint chart
|
||||
run: helm lint
|
||||
|
||||
- name: Package chart
|
||||
run: |
|
||||
helm package . --version "${{ steps.chartver.outputs.version }}" \
|
||||
--destination /tmp/helm-charts
|
||||
echo "Packaged:"
|
||||
ls -la /tmp/helm-charts/
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push chart to GHCR OCI
|
||||
run: |
|
||||
helm push /tmp/helm-charts/skillhub-${{ steps.chartver.outputs.version }}.tgz \
|
||||
oci://ghcr.io/${{ github.repository_owner }}/charts
|
||||
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: /tmp/helm-charts/skillhub-${{ steps.chartver.outputs.version }}.tgz
|
||||
|
||||
- name: Upload chart artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: skillhub-${{ steps.chartver.outputs.version }}.tgz
|
||||
path: /tmp/helm-charts/skillhub-${{ steps.chartver.outputs.version }}.tgz
|
||||
retention-days: 90
|
||||
24
charts/skillhub/.helmignore
Normal file
24
charts/skillhub/.helmignore
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editors / IDEs
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Local tooling
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# CI
|
||||
.github/
|
||||
|
||||
# Template artifacts
|
||||
*.tgz
|
||||
13
charts/skillhub/Chart.yaml
Normal file
13
charts/skillhub/Chart.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v2
|
||||
name: skillhub
|
||||
description: Self-hosted, open-source agent skill registry for enterprises.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: 0.2.8
|
||||
keywords:
|
||||
- skillhub
|
||||
- ai
|
||||
- skills
|
||||
home: https://github.com/iflytek/skillhub
|
||||
sources:
|
||||
- https://github.com/iflytek/skillhub
|
||||
127
charts/skillhub/templates/_helpers.tpl
Normal file
127
charts/skillhub/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
{{- /*
|
||||
SkillHub Helm Chart 模板辅助函数
|
||||
*/}}
|
||||
|
||||
{{- /* 名称 */}}
|
||||
{{- define "skillhub.name" -}}
|
||||
{{- default "skillhub" .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* 完整名称 */}}
|
||||
{{- define "skillhub.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default "skillhub" .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Chart 标签 */}}
|
||||
{{- define "skillhub.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* 通用标签 */}}
|
||||
{{- define "skillhub.labels" -}}
|
||||
helm.sh/chart: {{ include "skillhub.chart" . }}
|
||||
{{ include "skillhub.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/part-of: skillhub
|
||||
{{- end }}
|
||||
|
||||
{{- /* 选择器标签 */}}
|
||||
{{- define "skillhub.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "skillhub.name" . }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* 组件标签 */}}
|
||||
{{- define "skillhub.server.labels" -}}
|
||||
{{ include "skillhub.labels" . }}
|
||||
app.kubernetes.io/component: server
|
||||
{{- end }}
|
||||
{{- define "skillhub.server.selectorLabels" -}}
|
||||
{{ include "skillhub.selectorLabels" . }}
|
||||
app.kubernetes.io/component: server
|
||||
{{- end }}
|
||||
|
||||
{{- define "skillhub.web.labels" -}}
|
||||
{{ include "skillhub.labels" . }}
|
||||
app.kubernetes.io/component: web
|
||||
{{- end }}
|
||||
{{- define "skillhub.web.selectorLabels" -}}
|
||||
{{ include "skillhub.selectorLabels" . }}
|
||||
app.kubernetes.io/component: web
|
||||
{{- end }}
|
||||
|
||||
{{- define "skillhub.scanner.labels" -}}
|
||||
{{ include "skillhub.labels" . }}
|
||||
app.kubernetes.io/component: scanner
|
||||
{{- end }}
|
||||
{{- define "skillhub.scanner.selectorLabels" -}}
|
||||
{{ include "skillhub.selectorLabels" . }}
|
||||
app.kubernetes.io/component: scanner
|
||||
{{- end }}
|
||||
|
||||
{{- /* 镜像地址 */}}
|
||||
{{- define "skillhub.image" -}}
|
||||
{{- $registry := .registry | default .global.registry }}
|
||||
{{- printf "%s/%s:%s" $registry .name .tag }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* JDBC Host */}}
|
||||
{{- define "skillhub.jdbcHost" -}}
|
||||
{{- if eq .Values.database.mode "internal" -}}
|
||||
{{ include "skillhub.fullname" . }}-postgres
|
||||
{{- else -}}
|
||||
{{ .Values.database.external.host }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- /* JDBC Port */}}
|
||||
{{- define "skillhub.jdbcPort" -}}
|
||||
{{- if eq .Values.database.mode "internal" -}}5432{{- else -}}
|
||||
{{ .Values.database.external.port | default "5432" }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Secret 名称 */}}
|
||||
{{- define "skillhub.secretName" -}}
|
||||
{{- .Values.existingSecret | default (printf "%s-secret" (include "skillhub.fullname" .)) }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Redis Host */}}
|
||||
{{- define "skillhub.redisHost" -}}
|
||||
{{- if eq .Values.redis.mode "internal" -}}
|
||||
{{ include "skillhub.fullname" . }}-redis
|
||||
{{- else -}}
|
||||
{{ .Values.redis.external.host }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Redis Port */}}
|
||||
{{- define "skillhub.redisPort" -}}
|
||||
{{- if eq .Values.redis.mode "internal" -}}6379{{- else -}}
|
||||
{{ .Values.redis.external.port | default "6379" }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- /* 数据库 JDBC URL */}}
|
||||
{{- define "skillhub.jdbcUrl" -}}
|
||||
{{- if eq .Values.database.mode "internal" -}}
|
||||
jdbc:postgresql://{{ include "skillhub.fullname" . }}-postgres:5432/skillhub
|
||||
{{- else -}}
|
||||
{{- if .Values.database.external.jdbcUrl -}}
|
||||
{{ .Values.database.external.jdbcUrl }}
|
||||
{{- else -}}
|
||||
jdbc:postgresql://{{ .Values.database.external.host }}:{{ .Values.database.external.port }}/{{ .Values.database.external.database }}{{ if .Values.database.external.parameters }}?{{ .Values.database.external.parameters }}{{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
236
charts/skillhub/templates/backend-deployment.yaml
Normal file
236
charts/skillhub/templates/backend-deployment.yaml
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "skillhub.server.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.server.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "skillhub.server.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.server.podAnnotations | nindent 8 }}
|
||||
spec:
|
||||
{{- $secrets := .Values.server.imagePullSecrets | default .Values.global.imagePullSecrets }}
|
||||
{{- if $secrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml $secrets | nindent 8 }}
|
||||
{{- end }}
|
||||
initContainers:
|
||||
- name: wait-for-dependencies
|
||||
image: busybox:latest
|
||||
env:
|
||||
- name: DB_HOST
|
||||
value: {{ include "skillhub.jdbcHost" . }}
|
||||
- name: DB_PORT
|
||||
value: {{ include "skillhub.jdbcPort" . | quote }}
|
||||
- name: REDIS_HOST
|
||||
value: {{ include "skillhub.redisHost" . }}
|
||||
- name: REDIS_PORT
|
||||
value: {{ include "skillhub.redisPort" . | quote }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
echo "Waiting for PostgreSQL at ${DB_HOST}:${DB_PORT}..."
|
||||
until nc -z -w 2 "${DB_HOST}" "${DB_PORT}"; do sleep 2; done
|
||||
echo "PostgreSQL is ready!"
|
||||
echo "Waiting for Redis at ${REDIS_HOST}:${REDIS_PORT}..."
|
||||
until nc -z -w 2 "${REDIS_HOST}" "${REDIS_PORT}"; do sleep 2; done
|
||||
echo "Redis is ready!"
|
||||
containers:
|
||||
- name: server
|
||||
image: {{ .Values.images.registry }}/skillhub-server:{{ .Values.images.tag }}
|
||||
imagePullPolicy: {{ .Values.images.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.service.serverPort }}
|
||||
name: http
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: {{ .Values.springProfilesActive }}
|
||||
|
||||
# Database
|
||||
- name: SPRING_DATASOURCE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: spring-datasource-url
|
||||
- name: SPRING_DATASOURCE_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: spring-datasource-username
|
||||
- name: SPRING_DATASOURCE_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: spring-datasource-password
|
||||
|
||||
# Redis
|
||||
- name: SPRING_DATA_REDIS_HOST
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: redis-host
|
||||
- name: SPRING_DATA_REDIS_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: redis-port
|
||||
|
||||
{{- if and (eq .Values.redis.mode "external") .Values.redis.external.password }}
|
||||
- name: SPRING_DATA_REDIS_PASSWORD
|
||||
value: {{ .Values.redis.external.password }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.redis.external.sentinel.enabled }}
|
||||
- name: SPRING_DATA_REDIS_SENTINEL_MASTER
|
||||
value: {{ .Values.redis.external.sentinel.masterSet }}
|
||||
- name: SPRING_DATA_REDIS_SENTINEL_NODES
|
||||
value: {{ join "," .Values.redis.external.sentinel.nodes }}
|
||||
{{- end }}
|
||||
|
||||
# Storage
|
||||
- name: STORAGE_BASE_PATH
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: storage-base-path
|
||||
- name: SKILLHUB_STORAGE_PROVIDER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: skillhub-storage-provider
|
||||
|
||||
{{- if eq .Values.storage.provider "s3" }}
|
||||
- name: SKILLHUB_S3_BUCKET
|
||||
value: {{ .Values.storage.s3.bucket }}
|
||||
- name: SKILLHUB_S3_ENDPOINT
|
||||
value: {{ .Values.storage.s3.endpoint }}
|
||||
- name: SKILLHUB_S3_REGION
|
||||
value: {{ .Values.storage.s3.region }}
|
||||
{{- if .Values.storage.s3.accessKey }}
|
||||
- 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 }}
|
||||
{{- end }}
|
||||
|
||||
# Scanner
|
||||
- name: SKILLHUB_SECURITY_SCANNER_ENABLED
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: skill-scanner-enabled
|
||||
- name: SKILLHUB_SECURITY_SCANNER_URL
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: skill-scanner-url
|
||||
- name: SKILLHUB_SECURITY_SCANNER_MODE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: skill-scanner-mode
|
||||
|
||||
# Session
|
||||
- name: SESSION_COOKIE_SECURE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: session-cookie-secure
|
||||
|
||||
# Bootstrap Admin
|
||||
- name: BOOTSTRAP_ADMIN_ENABLED
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: bootstrap-admin-enabled
|
||||
- name: BOOTSTRAP_ADMIN_USER_ID
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: bootstrap-admin-user-id
|
||||
- name: BOOTSTRAP_ADMIN_USERNAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: bootstrap-admin-username
|
||||
- name: BOOTSTRAP_ADMIN_DISPLAY_NAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: bootstrap-admin-display-name
|
||||
- name: BOOTSTRAP_ADMIN_EMAIL
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
key: bootstrap-admin-email
|
||||
- name: BOOTSTRAP_ADMIN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: bootstrap-admin-password
|
||||
optional: true
|
||||
|
||||
# OAuth2 GitHub (optional)
|
||||
- name: OAUTH2_GITHUB_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: oauth2-github-client-id
|
||||
optional: true
|
||||
- name: OAUTH2_GITHUB_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: oauth2-github-client-secret
|
||||
optional: true
|
||||
|
||||
{{- if .Values.server.javaOpts }}
|
||||
- name: JAVA_OPTS
|
||||
value: {{ .Values.server.javaOpts }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.server.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
|
||||
volumeMounts:
|
||||
- name: skillhub-storage
|
||||
mountPath: /var/lib/skillhub/storage
|
||||
|
||||
resources:
|
||||
{{- toYaml .Values.server.resources | nindent 12 }}
|
||||
|
||||
startupProbe:
|
||||
{{- toYaml .Values.server.probes.startup | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.server.probes.readiness | nindent 12 }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.server.probes.liveness | nindent 12 }}
|
||||
|
||||
volumes:
|
||||
- name: skillhub-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "skillhub.fullname" . }}-storage-pvc
|
||||
{{- with .Values.server.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.server.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.server.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
17
charts/skillhub/templates/certificate.yaml
Normal file
17
charts/skillhub/templates/certificate.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{{- if and .Values.ingress.enabled .Values.ingress.certManager.enabled }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-tls
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ include "skillhub.fullname" . }}-tls
|
||||
duration: 2160h
|
||||
renewBefore: 360h
|
||||
dnsNames:
|
||||
- {{ .Values.ingress.host }}
|
||||
issuerRef:
|
||||
name: {{ .Values.ingress.certManager.issuerName }}
|
||||
kind: {{ .Values.ingress.certManager.issuerKind }}
|
||||
{{- end }}
|
||||
34
charts/skillhub/templates/configmap.yaml
Normal file
34
charts/skillhub/templates/configmap.yaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-config
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
data:
|
||||
# Redis 配置
|
||||
redis-host: {{ include "skillhub.redisHost" . }}
|
||||
redis-port: {{ include "skillhub.redisPort" . | quote }}
|
||||
|
||||
# 存储路径
|
||||
storage-base-path: /var/lib/skillhub/storage
|
||||
|
||||
# 存储提供者: local | s3
|
||||
skillhub-storage-provider: {{ .Values.storage.provider }}
|
||||
|
||||
# 技能扫描器
|
||||
skill-scanner-enabled: {{ .Values.scanner.enabled | quote }}
|
||||
skill-scanner-url: http://{{ include "skillhub.fullname" . }}-scanner:8000
|
||||
skill-scanner-mode: upload
|
||||
|
||||
# Bootstrap 管理员
|
||||
bootstrap-admin-enabled: {{ .Values.bootstrapAdmin.enabled | quote }}
|
||||
bootstrap-admin-user-id: {{ .Values.bootstrapAdmin.userId }}
|
||||
bootstrap-admin-username: {{ .Values.bootstrapAdmin.username }}
|
||||
bootstrap-admin-display-name: {{ .Values.bootstrapAdmin.displayName }}
|
||||
bootstrap-admin-email: {{ .Values.bootstrapAdmin.email }}
|
||||
|
||||
# Session
|
||||
session-cookie-secure: {{ .Values.session.cookieSecure | quote }}
|
||||
|
||||
# Spring Profiles
|
||||
spring-profiles-active: {{ .Values.springProfilesActive }}
|
||||
54
charts/skillhub/templates/frontend-deployment.yaml
Normal file
54
charts/skillhub/templates/frontend-deployment.yaml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
labels:
|
||||
{{- include "skillhub.web.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.web.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "skillhub.web.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.web.podAnnotations | nindent 8 }}
|
||||
spec:
|
||||
{{- $secrets := .Values.web.imagePullSecrets | default .Values.global.imagePullSecrets }}
|
||||
{{- if $secrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml $secrets | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: web
|
||||
image: {{ .Values.images.registry }}/skillhub-web:{{ .Values.images.tag }}
|
||||
imagePullPolicy: {{ .Values.images.pullPolicy }}
|
||||
env:
|
||||
- name: SKILLHUB_API_UPSTREAM
|
||||
value: http://{{ include "skillhub.fullname" . }}-server:{{ .Values.service.serverPort }}
|
||||
{{- with .Values.web.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.service.webPort }}
|
||||
name: http
|
||||
resources:
|
||||
{{- toYaml .Values.web.resources | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.web.probes.readiness | nindent 12 }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.web.probes.liveness | nindent 12 }}
|
||||
{{- with .Values.web.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.web.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.web.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
101
charts/skillhub/templates/hpa.yaml
Normal file
101
charts/skillhub/templates/hpa.yaml
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
{{- if .Values.server.autoscaling.enabled }}
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "skillhub.server.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
minReplicas: {{ .Values.server.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.server.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.server.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.server.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.server.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.server.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.web.autoscaling.enabled }}
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
labels:
|
||||
{{- include "skillhub.web.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
minReplicas: {{ .Values.web.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.web.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.web.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.web.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.web.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.web.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.scanner.enabled .Values.scanner.autoscaling.enabled }}
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-scanner
|
||||
labels:
|
||||
{{- include "skillhub.scanner.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "skillhub.fullname" . }}-scanner
|
||||
minReplicas: {{ .Values.scanner.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.scanner.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.scanner.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.scanner.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.scanner.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.scanner.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
47
charts/skillhub/templates/ingress.yaml
Normal file
47
charts/skillhub/templates/ingress.yaml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{{- if .Values.ingress.enabled }}
|
||||
{{- $secretName := .Values.ingress.tls.secretName | default (printf "%s-tls" (include "skillhub.fullname" .)) }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- if .Values.ingress.annotations }}
|
||||
{{- toYaml .Values.ingress.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.certManager.enabled }}
|
||||
{{- if eq .Values.ingress.certManager.issuerKind "ClusterIssuer" }}
|
||||
cert-manager.io/cluster-issuer: {{ .Values.ingress.certManager.issuerName }}
|
||||
{{- else }}
|
||||
cert-manager.io/issuer: {{ .Values.ingress.certManager.issuerName }}
|
||||
{{- end }}
|
||||
cert-manager.io/issuer-kind: {{ .Values.ingress.certManager.issuerKind }}
|
||||
{{- end }}
|
||||
spec:
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- if or .Values.ingress.tls.enabled .Values.ingress.certManager.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.ingress.host }}
|
||||
secretName: {{ $secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host }}
|
||||
http:
|
||||
paths:
|
||||
- path: /api
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
port:
|
||||
number: {{ .Values.service.serverPort }}
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
port:
|
||||
number: {{ .Values.service.webPort }}
|
||||
{{- end }}
|
||||
44
charts/skillhub/templates/pdb.yaml
Normal file
44
charts/skillhub/templates/pdb.yaml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{{- if .Values.server.podDisruptionBudget.enabled }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "skillhub.server.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.server.selectorLabels" . | nindent 6 }}
|
||||
minAvailable: {{ .Values.server.podDisruptionBudget.minAvailable }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.web.podDisruptionBudget.enabled }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
labels:
|
||||
{{- include "skillhub.web.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.web.selectorLabels" . | nindent 6 }}
|
||||
minAvailable: {{ .Values.web.podDisruptionBudget.minAvailable }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.scanner.enabled .Values.scanner.podDisruptionBudget.enabled }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-scanner
|
||||
labels:
|
||||
{{- include "skillhub.scanner.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.scanner.selectorLabels" . | nindent 6 }}
|
||||
minAvailable: {{ .Values.scanner.podDisruptionBudget.minAvailable }}
|
||||
{{- end }}
|
||||
100
charts/skillhub/templates/postgres-statefulset.yaml
Normal file
100
charts/skillhub/templates/postgres-statefulset.yaml
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
{{- if eq .Values.database.mode "internal" }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-postgres
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
serviceName: {{ include "skillhub.fullname" . }}-postgres
|
||||
replicas: {{ if eq .Values.database.architecture "cluster" }}3{{ else }}1{{ end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: database
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: {{ .Values.database.internal.registry }}/{{ .Values.database.internal.image }}
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: skillhub
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: spring-datasource-username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: spring-datasource-password
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
resources:
|
||||
{{- toYaml .Values.database.internal.resources | nindent 12 }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- pg_isready
|
||||
- -U
|
||||
- skillhub
|
||||
- -h
|
||||
- localhost
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- pg_isready
|
||||
- -U
|
||||
- skillhub
|
||||
- -h
|
||||
- localhost
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 15
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 10 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.storage.local.accessMode }}
|
||||
{{- if .Values.database.internal.storageClassName }}
|
||||
storageClassName: {{ .Values.database.internal.storageClassName }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.database.internal.storage }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-postgres
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: postgres
|
||||
name: postgres
|
||||
selector:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
{{- end }}
|
||||
19
charts/skillhub/templates/pvc.yaml
Normal file
19
charts/skillhub/templates/pvc.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{{- if eq .Values.storage.provider "local" }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-storage-pvc
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.storage.local.accessMode }}
|
||||
{{- if .Values.storage.local.storageClassName }}
|
||||
storageClassName: {{ .Values.storage.local.storageClassName }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.storage.local.storage }}
|
||||
{{- end }}
|
||||
83
charts/skillhub/templates/redis-statefulset.yaml
Normal file
83
charts/skillhub/templates/redis-statefulset.yaml
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{{- if eq .Values.redis.mode "internal" }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-redis
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
serviceName: {{ include "skillhub.fullname" . }}-redis
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: cache
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: {{ .Values.redis.internal.registry }}/{{ .Values.redis.internal.image }}
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
command:
|
||||
- redis-server
|
||||
- --appendonly
|
||||
- "yes"
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
resources:
|
||||
{{- toYaml .Values.redis.internal.resources | nindent 12 }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: redis-data
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 10 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.storage.local.accessMode }}
|
||||
{{- if .Values.redis.internal.storageClassName }}
|
||||
storageClassName: {{ .Values.redis.internal.storageClassName }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.redis.internal.storage }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-redis
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: redis
|
||||
name: redis
|
||||
selector:
|
||||
{{- include "skillhub.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cache
|
||||
{{- end }}
|
||||
66
charts/skillhub/templates/scanner-deployment.yaml
Normal file
66
charts/skillhub/templates/scanner-deployment.yaml
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{{- if .Values.scanner.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-scanner
|
||||
labels:
|
||||
{{- include "skillhub.scanner.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "skillhub.scanner.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "skillhub.scanner.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.scanner.podAnnotations | nindent 8 }}
|
||||
spec:
|
||||
{{- $secrets := .Values.scanner.imagePullSecrets | default .Values.global.imagePullSecrets }}
|
||||
{{- if $secrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml $secrets | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: scanner
|
||||
image: {{ .Values.images.registry }}/skillhub-scanner:{{ .Values.images.tag }}
|
||||
imagePullPolicy: {{ .Values.images.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.service.scannerPort }}
|
||||
name: http
|
||||
env:
|
||||
- name: SKILL_SCANNER_LLM_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: skill-scanner-llm-api-key
|
||||
optional: true
|
||||
- name: SKILL_SCANNER_LLM_MODEL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "skillhub.secretName" . }}
|
||||
key: skill-scanner-llm-model
|
||||
optional: true
|
||||
{{- with .Values.scanner.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.scanner.resources | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.scanner.probes.readiness | nindent 12 }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.scanner.probes.liveness | nindent 12 }}
|
||||
{{- with .Values.scanner.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.scanner.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.scanner.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
28
charts/skillhub/templates/secret.yaml
Normal file
28
charts/skillhub/templates/secret.yaml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{{- if not .Values.existingSecret }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-secret
|
||||
labels:
|
||||
{{- include "skillhub.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
spring-datasource-url: {{ include "skillhub.jdbcUrl" . | quote }}
|
||||
spring-datasource-username: {{ if eq .Values.database.mode "internal" }}skillhub{{ else }}{{ .Values.database.external.username }}{{ end }}
|
||||
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) }}
|
||||
|
||||
{{- if .Values.secrets.oauth2GithubClientId }}
|
||||
oauth2-github-client-id: {{ .Values.secrets.oauth2GithubClientId }}
|
||||
{{- end }}
|
||||
{{- if .Values.secrets.oauth2GithubClientSecret }}
|
||||
oauth2-github-client-secret: {{ .Values.secrets.oauth2GithubClientSecret }}
|
||||
{{- end }}
|
||||
{{- if .Values.secrets.scannerLlmApiKey }}
|
||||
skill-scanner-llm-api-key: {{ .Values.secrets.scannerLlmApiKey }}
|
||||
{{- end }}
|
||||
{{- if .Values.secrets.scannerLlmModel }}
|
||||
skill-scanner-llm-model: {{ .Values.secrets.scannerLlmModel }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
83
charts/skillhub/templates/services.yaml
Normal file
83
charts/skillhub/templates/services.yaml
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "skillhub.server.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if eq .Values.service.type "LoadBalancer" }}
|
||||
{{- if .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .Values.service.serverPort }}
|
||||
targetPort: http
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.serverNodePort }}
|
||||
nodePort: {{ .Values.service.serverNodePort }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "skillhub.server.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-web
|
||||
labels:
|
||||
{{- include "skillhub.web.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if eq .Values.service.type "LoadBalancer" }}
|
||||
{{- if .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .Values.service.webPort }}
|
||||
targetPort: http
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.webNodePort }}
|
||||
nodePort: {{ .Values.service.webNodePort }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "skillhub.web.selectorLabels" . | nindent 4 }}
|
||||
{{- if .Values.scanner.enabled }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "skillhub.fullname" . }}-scanner
|
||||
labels:
|
||||
{{- include "skillhub.scanner.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if eq .Values.service.type "LoadBalancer" }}
|
||||
{{- if .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .Values.service.scannerPort }}
|
||||
targetPort: http
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.scannerNodePort }}
|
||||
nodePort: {{ .Values.service.scannerNodePort }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "skillhub.scanner.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
312
charts/skillhub/values.yaml
Normal file
312
charts/skillhub/values.yaml
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# ============================================================================
|
||||
# SkillHub Helm Chart 全局配置
|
||||
# ============================================================================
|
||||
|
||||
# ============================================================================
|
||||
# Global
|
||||
# ============================================================================
|
||||
global:
|
||||
imageRegistry: ""
|
||||
imagePullSecrets: []
|
||||
|
||||
# ============================================================================
|
||||
# 镜像配置
|
||||
# ============================================================================
|
||||
images:
|
||||
registry: ghcr.io/iflytek
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# ============================================================================
|
||||
# 副本数
|
||||
# ============================================================================
|
||||
replicaCount: 1
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
# ============================================================================
|
||||
# 服务配置
|
||||
# ============================================================================
|
||||
service:
|
||||
# ClusterIP | NodePort | LoadBalancer
|
||||
type: ClusterIP
|
||||
serverPort: 8080
|
||||
webPort: 80
|
||||
scannerPort: 8000
|
||||
# type: NodePort 时指定 nodePort(不指定则由集群分配)
|
||||
serverNodePort: ""
|
||||
webNodePort: ""
|
||||
scannerNodePort: ""
|
||||
# type: LoadBalancer 时可选固定 IP
|
||||
loadBalancerIP: ""
|
||||
loadBalancerSourceRanges: []
|
||||
|
||||
# ============================================================================
|
||||
# Ingress 配置
|
||||
# ============================================================================
|
||||
ingress:
|
||||
enabled: false
|
||||
className: nginx
|
||||
host: skills.example.com
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 100m
|
||||
tls:
|
||||
enabled: false
|
||||
secretName: ""
|
||||
certManager:
|
||||
enabled: false
|
||||
issuerName: letsencrypt-prod
|
||||
issuerKind: ClusterIssuer
|
||||
|
||||
# ============================================================================
|
||||
# 应用组件配置
|
||||
# ============================================================================
|
||||
server:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
javaOpts: ""
|
||||
extraEnv: []
|
||||
podAnnotations: {}
|
||||
imagePullSecrets: []
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
# HPA(自动扩缩容)
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
# PDB(自愿干扰预算,多副本时保证最少可用实例)
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
probes:
|
||||
startup:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
failureThreshold: 30
|
||||
readiness:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: http
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 10
|
||||
liveness:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 15
|
||||
|
||||
web:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
extraEnv: []
|
||||
podAnnotations: {}
|
||||
imagePullSecrets: []
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
# HPA(自动扩缩容)
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 5
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
# PDB(自愿干扰预算,多副本时保证最少可用实例)
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
probes:
|
||||
readiness:
|
||||
httpGet:
|
||||
path: /nginx-health
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
liveness:
|
||||
httpGet:
|
||||
path: /nginx-health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
|
||||
scanner:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
extraEnv: []
|
||||
podAnnotations: {}
|
||||
imagePullSecrets: []
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
# HPA(自动扩缩容)
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 5
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
# PDB(自愿干扰预算,多副本时保证最少可用实例)
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
probes:
|
||||
readiness:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
liveness:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
|
||||
# ============================================================================
|
||||
# 数据库配置(PostgreSQL)
|
||||
# ============================================================================
|
||||
# mode: internal(内置)| external(外置)
|
||||
# architecture: standalone(单实例)| cluster(高可用集群)
|
||||
# - standalone + internal: 部署单实例 PostgreSQL
|
||||
# - standalone + external: 连接外置单节点 PostgreSQL
|
||||
# - cluster 时建议使用 external 模式
|
||||
database:
|
||||
mode: internal
|
||||
architecture: standalone
|
||||
|
||||
internal:
|
||||
image: postgres:16-alpine
|
||||
registry: docker.io
|
||||
storage: 10Gi
|
||||
storageClassName: ""
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
external:
|
||||
host: postgres.example.com
|
||||
port: 5432
|
||||
database: skillhub
|
||||
username: skillhub
|
||||
password: ""
|
||||
parameters: ""
|
||||
# 自定义 JDBC URL(非空时覆盖 host/port/database/parameters 的拼接结果)
|
||||
# 用于连接外部 PostgreSQL 集群(如 Patroni、JDBC 多主机等)
|
||||
jdbcUrl: ""
|
||||
|
||||
# ============================================================================
|
||||
# Redis 配置
|
||||
# ============================================================================
|
||||
# mode: internal(内置单实例)| external(外置)
|
||||
# 注意: Redis Cluster 模式不支持
|
||||
redis:
|
||||
mode: internal
|
||||
|
||||
internal:
|
||||
image: redis:7-alpine
|
||||
registry: docker.io
|
||||
storage: 5Gi
|
||||
storageClassName: ""
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
external:
|
||||
host: redis.example.com
|
||||
port: 6379
|
||||
password: ""
|
||||
sentinel:
|
||||
enabled: false
|
||||
masterSet: mymaster
|
||||
nodes: []
|
||||
|
||||
# ============================================================================
|
||||
# 存储配置
|
||||
# ============================================================================
|
||||
storage:
|
||||
provider: local
|
||||
local:
|
||||
# 多副本 (replicaCount > 1) 时必须设为 ReadWriteMany,底层需支持 RWX(如 NFS/Longhorn)
|
||||
accessMode: ReadWriteOnce
|
||||
storage: 10Gi
|
||||
storageClassName: ""
|
||||
s3:
|
||||
bucket: skillhub-storage
|
||||
endpoint: ""
|
||||
region: ""
|
||||
accessKey: ""
|
||||
secretKey: ""
|
||||
|
||||
# ============================================================================
|
||||
# Bootstrap 管理员
|
||||
# ============================================================================
|
||||
bootstrapAdmin:
|
||||
enabled: true
|
||||
userId: docker-admin
|
||||
username: admin
|
||||
displayName: "Platform Admin"
|
||||
email: admin@example.com
|
||||
password: ""
|
||||
|
||||
# ============================================================================
|
||||
# Session 配置
|
||||
# ============================================================================
|
||||
session:
|
||||
cookieSecure: false
|
||||
|
||||
# ============================================================================
|
||||
# Spring Profiles
|
||||
# ============================================================================
|
||||
springProfilesActive: docker
|
||||
|
||||
# ============================================================================
|
||||
# Secret 配置
|
||||
# ============================================================================
|
||||
# 使用已有 Secret(优先级高于下方 secrets.* 字段)
|
||||
# 设置后 chart 不会创建 Secret,而是直接引用该名称
|
||||
existingSecret: ""
|
||||
|
||||
secrets:
|
||||
springDatasourceUrl: ""
|
||||
springDatasourceUsername: ""
|
||||
springDatasourcePassword: ""
|
||||
bootstrapAdminPassword: ""
|
||||
oauth2GithubClientId: ""
|
||||
oauth2GithubClientSecret: ""
|
||||
scannerLlmApiKey: ""
|
||||
scannerLlmModel: ""
|
||||
|
||||
Loading…
Add table
Reference in a new issue