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:
112
infra/backup/test-backup-mysql.sh
Normal file
112
infra/backup/test-backup-mysql.sh
Normal 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
|
||||
@@ -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/ # 平台级 chart(namespace/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)
|
||||
|
||||
@@ -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 Service(ClusterIP)
|
||||
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
|
||||
11
infra/k8s/helm/ai/Chart.yaml
Normal file
11
infra/k8s/helm/ai/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/ai/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/ai/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/ai/templates/deployment.yaml
Normal file
77
infra/k8s/helm/ai/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/ai/templates/service.yaml
Normal file
16
infra/k8s/helm/ai/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/ai/values.yaml
Normal file
85
infra/k8s/helm/ai/values.yaml
Normal 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
|
||||
12
infra/k8s/helm/api-gateway/Chart.yaml
Normal file
12
infra/k8s/helm/api-gateway/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/api-gateway/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/api-gateway/templates/_helpers.tpl
Normal 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 -}}
|
||||
13
infra/k8s/helm/api-gateway/templates/configmap.yaml
Normal file
13
infra/k8s/helm/api-gateway/templates/configmap.yaml
Normal 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 }}
|
||||
77
infra/k8s/helm/api-gateway/templates/deployment.yaml
Normal file
77
infra/k8s/helm/api-gateway/templates/deployment.yaml
Normal 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 }}
|
||||
29
infra/k8s/helm/api-gateway/templates/hpa.yaml
Normal file
29
infra/k8s/helm/api-gateway/templates/hpa.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/api-gateway/templates/service.yaml
Normal file
16
infra/k8s/helm/api-gateway/templates/service.yaml
Normal 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
|
||||
86
infra/k8s/helm/api-gateway/values.yaml
Normal file
86
infra/k8s/helm/api-gateway/values.yaml
Normal 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
|
||||
11
infra/k8s/helm/content/Chart.yaml
Normal file
11
infra/k8s/helm/content/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/content/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/content/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/content/templates/deployment.yaml
Normal file
77
infra/k8s/helm/content/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/content/templates/service.yaml
Normal file
16
infra/k8s/helm/content/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/content/values.yaml
Normal file
85
infra/k8s/helm/content/values.yaml
Normal 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
|
||||
11
infra/k8s/helm/core-edu/Chart.yaml
Normal file
11
infra/k8s/helm/core-edu/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/core-edu/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/core-edu/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/core-edu/templates/deployment.yaml
Normal file
77
infra/k8s/helm/core-edu/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/core-edu/templates/service.yaml
Normal file
16
infra/k8s/helm/core-edu/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/core-edu/values.yaml
Normal file
85
infra/k8s/helm/core-edu/values.yaml
Normal 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
|
||||
11
infra/k8s/helm/data-ana/Chart.yaml
Normal file
11
infra/k8s/helm/data-ana/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/data-ana/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/data-ana/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/data-ana/templates/deployment.yaml
Normal file
77
infra/k8s/helm/data-ana/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/data-ana/templates/service.yaml
Normal file
16
infra/k8s/helm/data-ana/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/data-ana/values.yaml
Normal file
85
infra/k8s/helm/data-ana/values.yaml
Normal 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
|
||||
12
infra/k8s/helm/edu-platform/Chart.yaml
Normal file
12
infra/k8s/helm/edu-platform/Chart.yaml
Normal 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
|
||||
42
infra/k8s/helm/edu-platform/templates/_helpers.tpl
Normal file
42
infra/k8s/helm/edu-platform/templates/_helpers.tpl
Normal 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 -}}
|
||||
13
infra/k8s/helm/edu-platform/templates/configmap.yaml
Normal file
13
infra/k8s/helm/edu-platform/templates/configmap.yaml
Normal 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 }}
|
||||
34
infra/k8s/helm/edu-platform/templates/hpa.yaml
Normal file
34
infra/k8s/helm/edu-platform/templates/hpa.yaml
Normal 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 }}
|
||||
35
infra/k8s/helm/edu-platform/templates/ingress.yaml
Normal file
35
infra/k8s/helm/edu-platform/templates/ingress.yaml
Normal 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 }}
|
||||
10
infra/k8s/helm/edu-platform/templates/namespace.yaml
Normal file
10
infra/k8s/helm/edu-platform/templates/namespace.yaml
Normal 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 }}
|
||||
26
infra/k8s/helm/edu-platform/templates/secret.yaml
Normal file
26
infra/k8s/helm/edu-platform/templates/secret.yaml
Normal 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 }}
|
||||
24
infra/k8s/helm/edu-platform/values-dev.yaml
Normal file
24
infra/k8s/helm/edu-platform/values-dev.yaml
Normal 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 # 开发环境单副本即可
|
||||
35
infra/k8s/helm/edu-platform/values-prod.yaml
Normal file
35
infra/k8s/helm/edu-platform/values-prod.yaml
Normal 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
|
||||
23
infra/k8s/helm/edu-platform/values-staging.yaml
Normal file
23
infra/k8s/helm/edu-platform/values-staging.yaml
Normal 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
|
||||
72
infra/k8s/helm/edu-platform/values.yaml
Normal file
72
infra/k8s/helm/edu-platform/values.yaml
Normal 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
|
||||
11
infra/k8s/helm/iam/Chart.yaml
Normal file
11
infra/k8s/helm/iam/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/iam/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/iam/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/iam/templates/deployment.yaml
Normal file
77
infra/k8s/helm/iam/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/iam/templates/service.yaml
Normal file
16
infra/k8s/helm/iam/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/iam/values.yaml
Normal file
85
infra/k8s/helm/iam/values.yaml
Normal 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
|
||||
11
infra/k8s/helm/msg/Chart.yaml
Normal file
11
infra/k8s/helm/msg/Chart.yaml
Normal 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
|
||||
29
infra/k8s/helm/msg/templates/_helpers.tpl
Normal file
29
infra/k8s/helm/msg/templates/_helpers.tpl
Normal 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 -}}
|
||||
77
infra/k8s/helm/msg/templates/deployment.yaml
Normal file
77
infra/k8s/helm/msg/templates/deployment.yaml
Normal 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 }}
|
||||
16
infra/k8s/helm/msg/templates/service.yaml
Normal file
16
infra/k8s/helm/msg/templates/service.yaml
Normal 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
|
||||
85
infra/k8s/helm/msg/values.yaml
Normal file
85
infra/k8s/helm/msg/values.yaml
Normal 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
|
||||
Reference in New Issue
Block a user