feat(infra): k8s Helm Chart 演化与备份脚本测试

- 新增 edu-platform 平台级 chart(namespace/configmap/secret/ingress/hpa)
- 新增 api-gateway 服务级 chart(完整迁移自原 manifest)
- 新增 6 个业务服务 chart 桩(iam/core-edu/content/msg/data-ana/ai)
- 删除原 api-gateway-deployment.yaml(已迁移至 helm chart)
- 更新 infra/k8s/README.md 为 Helm Chart 管理说明
- 新增 backup-mysql.sh dry-run 测试脚本(17 断言)
This commit is contained in:
SpecialX
2026-07-08 12:50:56 +08:00
parent 9b33303195
commit d831915f06
51 changed files with 2111 additions and 165 deletions

View File

@@ -0,0 +1,112 @@
#!/bin/bash
# backup-mysql.sh 参数解析与校验的 dry-run 测试
# 不实际执行 mysqldump仅验证参数解析、必填校验、默认值、帮助信息等。
#
# 运行方式(需要 bash 环境,如 Git Bash / WSL
# bash infra/backup/test-backup-mysql.sh
#
# 退出码0 表示全部通过,非 0 表示有失败用例。
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="${SCRIPT_DIR}/backup-mysql.sh"
PASS=0
FAIL=0
# assertExit <expected_code> <description> <actual_code> <stderr>
assertExit() {
local expected="$1" desc="$2" actual="$3" stderr="${4:-}"
if [[ "$actual" == "$expected" ]]; then
echo "[PASS] $desc (exit=$actual)"
PASS=$((PASS + 1))
else
echo "[FAIL] $desc: 期望 exit=$expected, 实际 exit=$actual"
[[ -n "$stderr" ]] && echo " stderr: $stderr"
FAIL=$((FAIL + 1))
fi
}
# assertContains <needle> <description> <haystack>
assertContains() {
local needle="$1" desc="$2" haystack="${3:-}"
if [[ "$haystack" == *"$needle"* ]]; then
echo "[PASS] $desc"
PASS=$((PASS + 1))
else
echo "[FAIL] $desc: 输出应包含 '$needle'"
echo " 实际输出: $haystack"
FAIL=$((FAIL + 1))
fi
}
echo "=== backup-mysql.sh dry-run 测试 ==="
# ---------- 用例 1: 无参数应失败并提示 --service 必填 ----------
output="$("$SCRIPT" 2>&1)"
code=$?
assertExit 1 "无参数应退出 1" "$code" "$output"
assertContains "--service 参数必填" "无参数应提示 --service 必填" "$output"
# ---------- 用例 2: --help 应退出 0 并输出 Usage ----------
output="$("$SCRIPT" --help 2>&1)"
code=$?
assertExit 0 "--help 应退出 0" "$code" "$output"
assertContains "Usage:" "--help 应输出 Usage" "$output"
assertContains "--service" "--help 应说明 --service 参数" "$output"
assertContains "--keep" "--help 应说明 --keep 参数" "$output"
# ---------- 用例 3: --keep 默认值(未提供时)应在日志中体现 7 天 ----------
# 设置 MYSQL_PASSWORD 让脚本通过环境变量校验,进入主流程打印日志;
# 随后会在 mysqldump 阶段失败CI 环境无 mysqldump
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam 2>&1)"
code=$?
assertExit 1 "无 mysqldump 时应最终退出 1" "$code" "$output"
assertContains "保留 7 天" "未提供 --keep 时应使用默认值 7 天" "$output"
# ---------- 用例 4: --keep 非数字应失败 ----------
output="$("$SCRIPT" --service iam --keep abc 2>&1)"
code=$?
assertExit 1 "--keep 非数字应退出 1" "$code" "$output"
assertContains "--keep 必须为正整数" "非数字 --keep 应报错" "$output"
# ---------- 用例 5: --keep 小于 1 应失败 ----------
output="$("$SCRIPT" --service iam --keep 0 2>&1)"
code=$?
assertExit 1 "--keep=0 应退出 1" "$code" "$output"
assertContains "--keep 必须为正整数" "--keep=0 应报错" "$output"
# ---------- 用例 6: 未知参数应失败 ----------
output="$("$SCRIPT" --service iam --unknown-flag 2>&1)"
code=$?
assertExit 1 "未知参数应退出 1" "$code" "$output"
assertContains "未知参数" "未知参数应报错" "$output"
# ---------- 用例 7: --keep 自定义值应在日志中体现 ----------
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam --keep 30 2>&1)"
code=$?
assertExit 1 "无 mysqldump 时应最终退出 1用例 7 预置)" "$code" "$output"
assertContains "保留 30 天" "--keep=30 应在日志中体现" "$output"
# ---------- 用例 8: MYSQL_PASSWORD 已设置但 mysqldump 不可用时应优雅失败 ----------
# 此用例验证:参数校验通过后,脚本会尝试调用 mysqldump若 mysqldump 不存在则失败。
# 在无 MySQL 容器的 CI 环境中,这是最接近真实 dry-run 的验证。
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam 2>&1)"
code=$?
# mysqldump 不存在时pipefail + gzip 写入空文件 → 脚本检测到空文件后 exit 1
# 或 mysqldump 命令未找到 → set -e 触发 exit 1
# 任一路径都应是非 0 退出
if [[ "$code" -ne 0 ]]; then
echo "[PASS] mysqldump 不可用时应非 0 退出 (exit=$code)"
PASS=$((PASS + 1))
else
echo "[FAIL] mysqldump 不可用时不应返回 0"
FAIL=$((FAIL + 1))
fi
echo "=== 测试结果 ==="
echo "通过: $PASS 失败: $FAIL"
if [[ "$FAIL" -gt 0 ]]; then
exit 1
fi
exit 0

View File

@@ -1,55 +1,118 @@
# K8s 部署说明(骨架)
# K8s 部署说明
> **说明**本目录为 K8s 部署**骨架**,仅提供最小可用 manifest**生产环境请使用 Helm Chart**
> **状态**已迁移到 Helm Chart 管理。本目录保留 `namespace.yaml` 作为基础资源,其余资源通过 `helm/` 下的 chart 部署
## 适用范围
## 目录结构
- 开发 / Staging 环境快速拉起
- 验证服务在 K8s 上的基本可用性
- 作为后续 Helm 化的过渡参考
## Manifest 类别
| 文件 | 类别 | 用途 |
|------|------|------|
| `namespace.yaml` | namespace | 划分 4 个命名空间system / services / monitoring / ingress |
| `configmap-*.yaml` | configmap | 非敏感配置(服务端口、特性开关等) |
| `secret-*.yaml` | secret | 敏感配置(密钥、连接串),生产用 External Secrets |
| `*-deployment.yaml` | deployment | 服务无状态部署,含探针 / 资源 / 副本数 |
| `*-service.yaml` | service | ClusterIP 服务发现 |
| `ingress.yaml` | ingress | 对外入口TLS 终结 + 路由 |
| `*-hpa.yaml` | hpa | 水平自动扩缩容 |
```
infra/k8s/
├─ namespace.yaml # 基础命名空间4 个system/services/monitoring/ingress
└─ helm/ # Helm Chart 仓库
├─ edu-platform/ # 平台级 chartnamespace/configmap/secret/ingress/hpa
│ ├─ Chart.yaml
│ ├─ values.yaml # 全局默认值
│ ├─ values-dev.yaml # 开发环境覆盖
│ ├─ values-staging.yaml # 预发布环境覆盖
│ ├─ values-prod.yaml # 生产环境覆盖
│ └─ templates/
│ ├─ _helpers.tpl
│ ├─ namespace.yaml
│ ├─ configmap.yaml
│ ├─ secret.yaml # 骨架;生产请用 External Secrets Operator
│ ├─ ingress.yaml
│ └─ hpa.yaml # 全局 HPA 示例(默认不渲染)
├─ api-gateway/ # 服务级 chart完整迁移自原 manifest
│ ├─ Chart.yaml
│ ├─ values.yaml
│ └─ templates/
│ ├─ _helpers.tpl
│ ├─ deployment.yaml
│ ├─ service.yaml
│ ├─ configmap.yaml
│ └─ hpa.yaml
├─ iam/ # 业务服务 chart 桩P2
├─ core-edu/ # 业务服务 chart 桩P3
├─ content/ # 业务服务 chart 桩P4
├─ msg/ # 业务服务 chart 桩P5
├─ data-ana/ # 业务服务 chart 桩P4
└─ ai/ # 业务服务 chart 桩P5
```
## 命名空间规划
| Namespace | 用途 |
|-----------|------|
| `edu-system` | 系统组件(数据库代理、配置等) |
| `edu-services` | 业务微服务api-gateway / iam / core-edu / content / msg |
| `edu-monitoring` | 监控栈Prometheus / Grafana / Alertmanager |
| `edu-ingress` | 入口控制器NGINX Ingress / cert-manager |
| Namespace | 用途 |
| ---------------- | ---------------------------------------------------------- |
| `edu-system` | 系统组件(数据库代理、配置等) |
| `edu-services` | 业务微服务api-gateway / iam / core-edu / content / msg |
| `edu-monitoring` | 监控栈Prometheus / Grafana / Alertmanager |
| `edu-ingress` | 入口控制器NGINX Ingress / cert-manager |
## 部署顺序
## 部署方式
### 1. 安装平台级 chart命名空间 / 全局 ConfigMap / Secret / Ingress
```bash
# 开发环境
helm install edu-platform ./helm/edu-platform -f ./helm/edu-platform/values-dev.yaml
# 生产环境
helm install edu-platform ./helm/edu-platform -f ./helm/edu-platform/values-prod.yaml \
--set secret.data.MYSQL_PASSWORD=<base64> \
--set secret.data.JWT_SECRET=<base64> \
--set secret.data.REDIS_PASSWORD=<base64>
```
### 2. 安装服务级 chart
```bash
# api-gateway
helm install api-gateway ./helm/api-gateway
# 其他业务服务iam / core-edu / content / msg / data-ana / ai
helm install iam ./helm/iam
helm install core-edu ./helm/core-edu
# ...
```
### 3. 应用基础命名空间(如未通过 helm 安装 edu-platform
```bash
kubectl apply -f namespace.yaml
kubectl apply -f configmap-*.yaml
kubectl apply -f secret-*.yaml # 生产请改用 External Secrets
kubectl apply -f *-deployment.yaml
kubectl apply -f *-service.yaml
kubectl apply -f ingress.yaml
kubectl apply -f *-hpa.yaml
```
## Helm 化路线(后续)
## 验证
1. 将骨架迁移为 Helm Chart`charts/edu-platform/`
2. 每个微服务一个子 Chart统一通过 umbrella chart 编排
3. 环境差异通过 values-<env>.yaml 管理
4. 敏感配置接入 External Secrets Operator对接 Vault / KMS
5. CI/CD 通过 ArgoCD / Flux 做 GitOps 部署
```bash
# lint 所有 chart
helm lint helm/edu-platform helm/api-gateway helm/iam helm/core-edu helm/content helm/msg helm/data-ana helm/ai
## 当前文件
# 渲染模板(不实际部署)
helm template edu-platform ./helm/edu-platform
helm template api-gateway ./helm/api-gateway
```
- `namespace.yaml`4 个命名空间定义
- `api-gateway-deployment.yaml`api-gateway Deployment + Service 骨架
## 环境差异
| 环境 | values 文件 | 副本数 | HPA | TLS |
| ------- | ------------------- | ------ | ---- | ---- |
| dev | values-dev.yaml | 1 | 关闭 | 关闭 |
| staging | values-staging.yaml | 2 | 2-5 | 开启 |
| prod | values-prod.yaml | 3 | 3-20 | 开启 |
## 敏感配置
⚠️ **生产环境禁止在 values.yaml 中硬编码密钥**
推荐方案:
1. 使用 [External Secrets Operator](https://external-secrets.io/) 对接 Vault / KMS / 云 KMS
2. 通过 `--set secret.data.<KEY>=<base64>` 临时注入
3. 通过 ArgoCD / Flux GitOps + Sealed Secrets
## 后续路线
- [ ] 接入 External Secrets Operator
- [ ] ArgoCD / Flux GitOps 部署
- [ ] 各服务 chart 补充 configmap.yaml / hpa.yaml 模板(当前桩仅含 deployment/service
- [ ] 服务级 values-dev/staging/prod 覆盖文件
- [ ] CI/CD 集成helm chart 推送到 OCI registry

View File

@@ -1,125 +0,0 @@
# api-gateway Deployment + Service 骨架
# 生产环境请通过 Helm Chart 管理,此处仅作骨架参考
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: edu-services
labels:
app.kubernetes.io/name: api-gateway
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: gateway
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: api-gateway
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app.kubernetes.io/name: api-gateway
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: gateway
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
containers:
- name: api-gateway
image: edu/api-gateway:latest # 生产请固定 tag避免 latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
# 存活探针:失败触发重启
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
# 就绪探针:失败从 Service Endpoints 摘除
readinessProbe:
httpGet:
path: /readyz
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
env:
# 从 ConfigMap 引用非敏感配置
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: api-gateway-config
key: NODE_ENV
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: api-gateway-config
key: LOG_LEVEL
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: api-gateway-config
key: MYSQL_HOST
# 从 Secret 引用敏感配置
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: api-gateway-secret
key: MYSQL_PASSWORD
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: api-gateway-secret
key: JWT_SECRET
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: api-gateway-secret
key: REDIS_PASSWORD
# 生产建议挂载 /tmp 并设置 readOnlyRootFilesystem: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
---
# api-gateway ServiceClusterIP
apiVersion: v1
kind: Service
metadata:
name: api-gateway
namespace: edu-services
labels:
app.kubernetes.io/name: api-gateway
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: gateway
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: api-gateway
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: ai
description: ai 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- ai
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "ai.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "ai.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "ai.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "ai.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: ai-gateway
{{- end -}}
{{- define "ai.selectorLabels" -}}
app.kubernetes.io/name: {{ include "ai.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "ai.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "ai.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "ai.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "ai.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: ai-gateway
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "ai.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "ai.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "ai.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "ai.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "ai.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# ai 服务默认值AI 网关 - 业务领域 D6
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/ai
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3006
targetPort: 3006
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3006
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,12 @@
apiVersion: v2
name: api-gateway
description: api-gateway 服务级 Helm Chart从 infra/k8s/api-gateway-deployment.yaml 迁移)
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- gateway
- api
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "api-gateway.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "api-gateway.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "api-gateway.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "api-gateway.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: gateway
{{- end -}}
{{- define "api-gateway.selectorLabels" -}}
app.kubernetes.io/name: {{ include "api-gateway.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,13 @@
{{- if .Values.configMap.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "api-gateway.name" . }}-config
namespace: {{ .Values.namespace }}
labels:
{{- include "api-gateway.labels" . | nindent 4 }}
data:
{{- range $k, $v := .Values.configMap.data }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "api-gateway.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "api-gateway.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "api-gateway.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "api-gateway.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: gateway
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "api-gateway.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "api-gateway.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,29 @@
{{- if .Values.hpa.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "api-gateway.name" . }}-hpa
namespace: {{ .Values.namespace }}
labels:
{{- include "api-gateway.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "api-gateway.name" . }}
minReplicas: {{ .Values.hpa.minReplicas }}
maxReplicas: {{ .Values.hpa.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.hpa.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.hpa.targetMemoryUtilizationPercentage }}
{{- end }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "api-gateway.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "api-gateway.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "api-gateway.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,86 @@
# api-gateway 服务默认值
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/api-gateway
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 8080
targetPort: 8080
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 8080
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
MYSQL_HOST: mysql.edu-system.svc.cluster.local
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: content
description: content 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- content
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "content.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "content.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "content.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "content.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: content
{{- end -}}
{{- define "content.selectorLabels" -}}
app.kubernetes.io/name: {{ include "content.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "content.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "content.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "content.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "content.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: content
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "content.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "content.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "content.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "content.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "content.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# content 服务默认值(内容资源 - 业务领域 D4
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/content
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3003
targetPort: 3003
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3003
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: core-edu
description: core-edu 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- core-edu
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "core-edu.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "core-edu.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "core-edu.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "core-edu.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: teaching
{{- end -}}
{{- define "core-edu.selectorLabels" -}}
app.kubernetes.io/name: {{ include "core-edu.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "core-edu.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "core-edu.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "core-edu.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "core-edu.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: teaching
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "core-edu.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "core-edu.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "core-edu.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "core-edu.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "core-edu.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# core-edu 服务默认值(教学核心 - 业务领域 D2+D3
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/core-edu
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3002
targetPort: 3002
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3002
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: data-ana
description: data-ana 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- data-ana
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "data-ana.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "data-ana.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "data-ana.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "data-ana.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: analytics
{{- end -}}
{{- define "data-ana.selectorLabels" -}}
app.kubernetes.io/name: {{ include "data-ana.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "data-ana.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "data-ana.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "data-ana.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "data-ana.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: analytics
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "data-ana.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "data-ana.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "data-ana.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "data-ana.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "data-ana.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# data-ana 服务默认值(数据分析 - 业务领域 D6
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/data-ana
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3005
targetPort: 3005
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3005
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,12 @@
apiVersion: v2
name: edu-platform
description: Edu 平台级 Helm Chart命名空间 / 全局 ConfigMap / Secret / Ingress / HPA 模板)
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- platform
- infrastructure
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,42 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "edu-platform.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Fully qualified app name.
*/}}
{{- define "edu-platform.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{/*
Common labels.
*/}}
{{- define "edu-platform.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "edu-platform.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.global.labels }}
{{ toYaml . }}
{{- end -}}
{{- end -}}
{{/*
Selector labels.
*/}}
{{- define "edu-platform.selectorLabels" -}}
app.kubernetes.io/name: {{ include "edu-platform.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,13 @@
{{- if .Values.configMap.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.configMap.name }}
namespace: edu-system
labels:
{{- include "edu-platform.labels" . | nindent 4 }}
data:
{{- range $k, $v := .Values.configMap.data }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,34 @@
{{/*
全局 HPA 模板示例(参考用)。
实际 HPA 应在各服务自身的 chart 中定义,以便针对服务特性调参。
本模板在 edu-platform 中默认不渲染hpa.targetService 为空时跳过)。
*/}}
{{- if and .Values.hpa.enabled .Values.hpa.targetService }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ .Values.hpa.targetService }}-hpa
namespace: edu-services
labels:
{{- include "edu-platform.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Values.hpa.targetService }}
minReplicas: {{ .Values.hpa.minReplicas }}
maxReplicas: {{ .Values.hpa.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.hpa.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.hpa.targetMemoryUtilizationPercentage }}
{{- end }}

View File

@@ -0,0 +1,35 @@
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $.Release.Name }}-ingress
namespace: edu-ingress
labels:
{{- include "edu-platform.labels" $ | nindent 4 }}
{{- with $.Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ $.Values.ingress.className }}
{{- with $.Values.ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
- host: {{ .host }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ .service }}
port:
number: {{ .port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,10 @@
{{- range .Values.namespaces }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .name }}
labels:
{{- include "edu-platform.labels" $ | nindent 4 }}
app.kubernetes.io/component: {{ .component }}
{{- end }}

View File

@@ -0,0 +1,26 @@
{{- if .Values.secret.enabled }}
{{- /*
⚠️ 生产环境警告:不要在 values.yaml 中硬编码真实密钥!
推荐方案:使用 External Secrets Operator 对接 Vault / KMS / 云 KMS
本模板仅作骨架;空字符串字段不会被渲染(避免覆盖已存在的 Secret
*/ -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.secret.name }}
namespace: edu-system
labels:
{{- include "edu-platform.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": before-hook-creation
type: Opaque
data:
{{- range $k, $v := .Values.secret.data }}
{{- if $v }}
{{ $k }}: {{ $v }}
{{- else }}
{{ $k }}: "" # 占位:部署时通过 --set 或 ExternalSecrets 注入
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,24 @@
# 开发环境覆盖
global:
labels:
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/environment: dev
configMap:
data:
NODE_ENV: development
LOG_LEVEL: debug
ingress:
enabled: true
hosts:
- host: edu-dev.local
paths:
- path: /api
pathType: Prefix
service: api-gateway
port: 8080
tls: [] # 开发环境不强制 TLS
hpa:
enabled: false # 开发环境单副本即可

View File

@@ -0,0 +1,35 @@
# 生产环境覆盖
global:
labels:
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/environment: prod
imagePullSecrets:
- name: registry-credentials
configMap:
data:
NODE_ENV: production
LOG_LEVEL: warn
ingress:
hosts:
- host: edu.example.com
paths:
- path: /api
pathType: Prefix
service: api-gateway
port: 8080
- path: /auth
pathType: Prefix
service: api-gateway
port: 8080
tls:
- secretName: edu-tls
hosts:
- edu.example.com
hpa:
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 60
targetMemoryUtilizationPercentage: 70

View File

@@ -0,0 +1,23 @@
# 预发布环境覆盖
global:
labels:
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/environment: staging
configMap:
data:
NODE_ENV: staging
LOG_LEVEL: info
ingress:
hosts:
- host: edu-staging.example.com
paths:
- path: /api
pathType: Prefix
service: api-gateway
port: 8080
hpa:
minReplicas: 2
maxReplicas: 5

View File

@@ -0,0 +1,72 @@
# Edu 平台全局默认值
# 环境覆盖文件values-dev.yaml / values-staging.yaml / values-prod.yaml
# 全局标签(自动注入到所有资源)
global:
labels:
app.kubernetes.io/part-of: edu-platform
# 镜像拉取凭证(生产建议使用 Secret + serviceAccount
imagePullSecrets: []
# 命名空间规划
namespaces:
- name: edu-system
component: system
- name: edu-services
component: services
- name: edu-monitoring
component: monitoring
- name: edu-ingress
component: ingress
# 全局 ConfigMap非敏感配置
configMap:
enabled: true
name: edu-platform-config
data:
NODE_ENV: production
LOG_LEVEL: info
MYSQL_HOST: mysql.edu-system.svc.cluster.local
REDIS_HOST: redis.edu-system.svc.cluster.local
KAFKA_BROKERS: kafka.edu-system.svc.cluster.local:9092
# 全局 Secret仅骨架生产请使用 External Secrets Operator 对接 Vault/KMS
secret:
enabled: true
name: edu-platform-secret
# 真实部署时通过 --set secret.data.MYSQL_PASSWORD=<base64> 注入
# 或通过 externalSecrets 引用
data:
MYSQL_PASSWORD: ""
JWT_SECRET: ""
REDIS_PASSWORD: ""
# 全局 Ingress
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: edu.example.com
paths:
- path: /api
pathType: Prefix
service: api-gateway
port: 8080
- path: /auth
pathType: Prefix
service: api-gateway
port: 8080
tls:
- secretName: edu-tls
hosts:
- edu.example.com
# HPA 全局默认策略(各服务可在自身 chart 中覆盖)
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: iam
description: iam 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- iam
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "iam.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "iam.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "iam.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "iam.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: identity
{{- end -}}
{{- define "iam.selectorLabels" -}}
app.kubernetes.io/name: {{ include "iam.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "iam.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "iam.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "iam.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "iam.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: identity
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "iam.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "iam.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "iam.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "iam.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "iam.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# iam 服务默认值(身份认证 - 业务领域 D1
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/iam
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3001
targetPort: 3001
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3001
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD

View File

@@ -0,0 +1,11 @@
apiVersion: v2
name: msg
description: msg 服务级 Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
keywords:
- edu
- msg
maintainers:
- name: edu-arch

View File

@@ -0,0 +1,29 @@
{{- define "msg.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "msg.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .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 -}}
{{- define "msg.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "msg.selectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: messaging
{{- end -}}
{{- define "msg.selectorLabels" -}}
app.kubernetes.io/name: {{ include "msg.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "msg.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "msg.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "msg.selectorLabels" . | nindent 6 }}
strategy:
type: {{ .Values.strategy.type }}
rollingUpdate:
maxSurge: {{ .Values.strategy.maxSurge }}
maxUnavailable: {{ .Values.strategy.maxUnavailable }}
template:
metadata:
labels:
{{- include "msg.selectorLabels" . | nindent 8 }}
app.kubernetes.io/part-of: edu-platform
app.kubernetes.io/component: messaging
{{- if .Values.metrics.enabled }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
spec:
containers:
- name: {{ include "msg.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- if .Values.configMap.enabled }}
{{- range $k, $v := .Values.configMap.data }}
- name: {{ $k }}
valueFrom:
configMapKeyRef:
name: {{ include "msg.name" $ }}-config
key: {{ $k }}
{{- end }}
{{- end }}
{{- range $secret := .Values.secretRefs }}
{{- range $key := $secret.keys }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $secret.name }}
key: {{ $key }}
{{- end }}
{{- end }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "msg.name" . }}
namespace: {{ .Values.namespace }}
labels:
{{- include "msg.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "msg.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,85 @@
# msg 服务默认值(消息通知 - 业务领域 D5
# 副本数(生产建议 ≥ 2
replicaCount: 2
image:
repository: edu/msg
tag: latest # 生产请固定 tag避免 latest
pullPolicy: IfNotPresent
# 服务端口
service:
type: ClusterIP
port: 3004
targetPort: 3004
# 命名空间(默认 edu-services由 edu-platform chart 创建)
namespace: edu-services
# 探针配置
probes:
liveness:
path: /healthz
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readiness:
path: /readyz
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
# 资源配额
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 滚动更新策略
strategy:
type: RollingUpdate
maxSurge: 1
maxUnavailable: 0
# Prometheus 指标采集
metrics:
enabled: true
port: 3004
path: /metrics
# 安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
# 服务级 ConfigMap非敏感配置
configMap:
enabled: true
data:
NODE_ENV: production
LOG_LEVEL: info
# HPA
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 敏感配置(从 Secret 引用Secret 由 edu-platform chart 或 ExternalSecrets 管理)
secretRefs:
- name: edu-platform-secret
keys:
- MYSQL_PASSWORD
- JWT_SECRET
- REDIS_PASSWORD