首次提交:初始化项目

This commit is contained in:
fei
2026-02-05 00:11:05 +08:00
commit 26eaf8110b
171 changed files with 17105 additions and 0 deletions

View File

@@ -0,0 +1,380 @@
# KEDA HTTP Add-on 自动缩容到 0 配置指南
本指南说明如何使用 KEDA HTTP Add-on 实现应用在无流量时自动缩容到 0有访问时自动启动。
## 前提条件
1. K3s 集群已安装
2. KEDA 已安装
3. KEDA HTTP Add-on 已安装
4. Traefik 作为 Ingress Controller
### 检查 KEDA HTTP Add-on 是否已安装
```bash
kubectl get pods -n keda | grep http
```
应该看到类似输出:
```
keda-add-ons-http-controller-manager-xxx 1/1 Running
keda-add-ons-http-external-scaler-xxx 1/1 Running
keda-add-ons-http-interceptor-xxx 1/1 Running
```
### 如果未安装,执行以下命令安装
```bash
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install http-add-on kedacore/keda-add-ons-http --namespace keda
```
## 配置步骤
### 1. 准备应用的基础资源
确保你的应用已经有以下资源:
- Deployment
- Service
- Namespace
示例:
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: myapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: your-image:tag
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: myapp
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 80
```
### 2. 创建 HTTPScaledObject
这是实现自动缩容到 0 的核心配置。
```yaml
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
name: myapp-http-scaler
namespace: myapp # 必须与应用在同一个 namespace
spec:
hosts:
- myapp.example.com # 你的域名
pathPrefixes:
- / # 匹配的路径前缀
scaleTargetRef:
name: myapp # Deployment 名称
kind: Deployment
apiVersion: apps/v1
service: myapp # Service 名称
port: 80 # Service 端口
replicas:
min: 0 # 空闲时缩容到 0
max: 10 # 最多扩容到 10 个副本
scalingMetric:
requestRate:
granularity: 1s
targetValue: 100 # 每秒 100 个请求时扩容
window: 1m
scaledownPeriod: 300 # 5 分钟300秒无流量后缩容到 0
```
**重要参数说明:**
- `hosts`: 你的应用域名
- `scaleTargetRef.name`: 你的 Deployment 名称
- `scaleTargetRef.service`: 你的 Service 名称
- `scaleTargetRef.port`: 你的 Service 端口
- `replicas.min: 0`: 允许缩容到 0
- `scaledownPeriod`: 无流量后多久缩容(秒)
### 3. 创建 Traefik IngressRoute
**重要IngressRoute 必须在 keda namespace 中创建**,因为它需要引用 keda namespace 的拦截器服务。
```yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: myapp-ingress
namespace: keda # 注意:必须在 keda namespace
spec:
entryPoints:
- web # HTTP 入口
# - websecure # 如果需要 HTTPS添加这个
routes:
- match: Host(`myapp.example.com`) # 你的域名
kind: Rule
services:
- name: keda-add-ons-http-interceptor-proxy
port: 8080
```
**如果需要 HTTPS添加 TLS 配置:**
```yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: myapp-ingress
namespace: keda
spec:
entryPoints:
- websecure
routes:
- match: Host(`myapp.example.com`)
kind: Rule
services:
- name: keda-add-ons-http-interceptor-proxy
port: 8080
tls:
certResolver: letsencrypt # 你的证书解析器
```
### 4. 完整配置文件模板
将以下内容保存为 `myapp-keda-scaler.yaml`,并根据你的应用修改相应的值:
```yaml
---
# HTTPScaledObject - 实现自动缩容到 0
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
name: myapp-http-scaler
namespace: myapp # 改为你的 namespace
spec:
hosts:
- myapp.example.com # 改为你的域名
pathPrefixes:
- /
scaleTargetRef:
name: myapp # 改为你的 Deployment 名称
kind: Deployment
apiVersion: apps/v1
service: myapp # 改为你的 Service 名称
port: 80 # 改为你的 Service 端口
replicas:
min: 0
max: 10
scalingMetric:
requestRate:
granularity: 1s
targetValue: 100
window: 1m
scaledownPeriod: 300 # 5 分钟无流量后缩容
---
# Traefik IngressRoute - 路由流量到 KEDA 拦截器
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: myapp-ingress
namespace: keda # 必须在 keda namespace
spec:
entryPoints:
- web
routes:
- match: Host(`myapp.example.com`) # 改为你的域名
kind: Rule
services:
- name: keda-add-ons-http-interceptor-proxy
port: 8080
```
### 5. 应用配置
```bash
kubectl apply -f myapp-keda-scaler.yaml
```
### 6. 验证配置
```bash
# 查看 HTTPScaledObject 状态
kubectl get httpscaledobject -n myapp
# 应该看到 READY = True
# NAME TARGETWORKLOAD TARGETSERVICE MINREPLICAS MAXREPLICAS AGE READY
# myapp-http-scaler apps/v1/Deployment/myapp myapp:80 0 10 10s True
# 查看 IngressRoute
kubectl get ingressroute -n keda
# 查看当前 Pod 数量
kubectl get pods -n myapp
```
## 工作原理
1. **有流量时**
- 用户访问 `myapp.example.com`
- Traefik 将流量路由到 KEDA HTTP 拦截器
- 拦截器检测到请求,通知 KEDA 启动 Pod
- Pod 启动后5-10秒拦截器将流量转发到应用
- 用户看到正常响应(首次访问可能有延迟)
2. **无流量时**
- 5 分钟scaledownPeriod无请求后
- KEDA 自动将 Deployment 缩容到 0
- 不消耗任何计算资源
## 常见问题排查
### 1. 访问返回 404
**检查 IngressRoute 是否在 keda namespace**
```bash
kubectl get ingressroute -n keda | grep myapp
```
如果不在,删除并重新创建:
```bash
kubectl delete ingressroute myapp-ingress -n myapp # 删除错误的
kubectl apply -f myapp-keda-scaler.yaml # 重新创建
```
### 2. HTTPScaledObject READY = False
**查看详细错误信息:**
```bash
kubectl describe httpscaledobject myapp-http-scaler -n myapp
```
**常见错误:**
- `workload already managed by ScaledObject`: 删除旧的 ScaledObject
```bash
kubectl delete scaledobject myapp-scaler -n myapp
```
### 3. Pod 没有自动缩容到 0
**检查是否有旧的 ScaledObject 阻止缩容:**
```bash
kubectl get scaledobject -n myapp
```
如果有,删除它:
```bash
kubectl delete scaledobject <name> -n myapp
```
### 4. 查看 KEDA 拦截器日志
```bash
kubectl logs -n keda -l app.kubernetes.io/name=keda-add-ons-http-interceptor --tail=50
```
### 5. 测试拦截器是否工作
```bash
# 获取拦截器服务 IP
kubectl get svc keda-add-ons-http-interceptor-proxy -n keda
# 直接测试拦截器
curl -H "Host: myapp.example.com" http://<CLUSTER-IP>:8080
```
## 调优建议
### 调整缩容时间
根据你的应用特点调整 `scaledownPeriod`
- **频繁访问的应用**:设置较长时间(如 600 秒 = 10 分钟)
- **偶尔访问的应用**:设置较短时间(如 180 秒 = 3 分钟)
- **演示/测试环境**:可以设置很短(如 60 秒 = 1 分钟)
```yaml
scaledownPeriod: 600 # 10 分钟
```
### 调整扩容阈值
根据应用负载调整 `targetValue`
```yaml
scalingMetric:
requestRate:
targetValue: 50 # 每秒 50 个请求时扩容(更敏感)
```
### 调整最大副本数
```yaml
replicas:
min: 0
max: 20 # 根据你的资源和需求调整
```
## 监控和观察
### 实时监控 Pod 变化
```bash
watch -n 2 'kubectl get pods -n myapp'
```
### 查看 HTTPScaledObject 事件
```bash
kubectl describe httpscaledobject myapp-http-scaler -n myapp
```
### 查看 Deployment 副本数变化
```bash
kubectl get deployment myapp -n myapp -w
```
## 完整示例navigation 应用
参考 `navigation-complete.yaml` 文件,这是一个完整的工作示例。
## 注意事项
1. **首次访问延迟**Pod 从 0 启动需要 5-10 秒,用户首次访问会有延迟
2. **数据库连接**:确保应用能够快速重新建立数据库连接
3. **会话状态**:不要在 Pod 中存储会话状态,使用 Redis 等外部存储
4. **健康检查**:配置合理的 readinessProbe确保 Pod 就绪后才接收流量
5. **资源限制**:设置合理的 resources limits避免启动过慢
## 参考资源
- KEDA 官方文档: https://keda.sh/
- KEDA HTTP Add-on: https://github.com/kedacore/http-add-on
- Traefik IngressRoute: https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/

View File

@@ -0,0 +1,45 @@
---
# HTTPScaledObject - 用于实现缩容到 0 的核心配置
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
name: navigation-http-scaler
namespace: navigation
spec:
hosts:
- dh.u6.net3w.com
pathPrefixes:
- /
scaleTargetRef:
name: navigation
kind: Deployment
apiVersion: apps/v1
service: navigation
port: 80
replicas:
min: 0 # 空闲时缩容到 0
max: 10 # 最多 10 个副本
scalingMetric:
requestRate:
granularity: 1s
targetValue: 100 # 每秒 100 个请求时扩容
window: 1m
scaledownPeriod: 300 # 5 分钟无流量后缩容到 0
---
# Traefik IngressRoute - 将流量路由到 KEDA HTTP Add-on 的拦截器
# 注意:必须在 keda namespace 中才能引用该 namespace 的服务
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: navigation-ingress
namespace: keda
spec:
entryPoints:
- web
routes:
- match: Host(`dh.u6.net3w.com`)
kind: Rule
services:
- name: keda-add-ons-http-interceptor-proxy
port: 8080

View File

@@ -0,0 +1,24 @@
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
name: navigation-http-scaler
namespace: navigation
spec:
hosts:
- dh.u6.net3w.com
pathPrefixes:
- /
scaleTargetRef:
name: navigation
kind: Deployment
apiVersion: apps/v1
service: navigation
port: 80
replicas:
min: 0 # 空闲时缩容到 0
max: 10 # 最多 10 个副本
scalingMetric:
requestRate:
granularity: 1s
targetValue: 100 # 每秒 100 个请求时扩容
window: 1m

View File

@@ -0,0 +1,19 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: navigation-ingress
namespace: navigation
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: dh.u6.net3w.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: keda-add-ons-http-interceptor-proxy
port:
number: 8080

View File

@@ -0,0 +1,23 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: navigation-scaler
namespace: navigation
spec:
scaleTargetRef:
name: navigation
minReplicaCount: 1 # 至少保持 1 个副本HPA 限制)
maxReplicaCount: 10 # 最多 10 个副本
pollingInterval: 15 # 每 15 秒检查一次
cooldownPeriod: 180 # 缩容冷却期 3 分钟
triggers:
- type: prometheus
metadata:
serverAddress: http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090
metricName: nginx_http_requests_total
query: sum(rate(nginx_http_requests_total{namespace="navigation"}[1m]))
threshold: "10" # 每分钟超过 10 个请求时启动
- type: cpu
metricType: Utilization
metadata:
value: "60" # CPU 使用率超过 60% 时扩容

View File

@@ -0,0 +1,261 @@
# ⚠️ PostgreSQL 不适合使用 KEDA 自动扩缩容
## 问题说明
对于传统的 PostgreSQL 架构,直接通过 KEDA 增加副本数会导致:
### 1. 存储冲突
- 多个 Pod 尝试挂载同一个 PVC
- ReadWriteOnce 存储只能被一个 Pod 使用
- 会导致 Pod 启动失败
### 2. 数据损坏风险
- 如果使用 ReadWriteMany 存储,多个实例同时写入会导致数据损坏
- PostgreSQL 不支持多主写入
- 没有锁机制保护数据一致性
### 3. 缺少主从复制
- 需要配置 PostgreSQL 流复制Streaming Replication
- 需要配置主从切换机制
- 需要使用专门的 PostgreSQL Operator
## 正确的 PostgreSQL 扩展方案
### 方案 1: 使用 PostgreSQL Operator
推荐使用专业的 PostgreSQL Operator
#### Zalando PostgreSQL Operator
```bash
# 添加 Helm 仓库
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
# 安装 Operator
helm install postgres-operator postgres-operator-charts/postgres-operator
# 创建 PostgreSQL 集群
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: acid-minimal-cluster
spec:
teamId: "acid"
volume:
size: 10Gi
storageClass: longhorn
numberOfInstances: 3 # 1 主 + 2 从
users:
zalando:
- superuser
- createdb
databases:
foo: zalando
postgresql:
version: "16"
```
#### CloudNativePG Operator
```bash
# 安装 CloudNativePG
kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.22/releases/cnpg-1.22.0.yaml
# 创建集群
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
storage:
storageClass: longhorn
size: 10Gi
```
### 方案 2: 读写分离 + KEDA
如果需要使用 KEDA正确的架构是
```
┌─────────────────┐
│ 主库 (Master) │ ← 固定 1 个副本,处理写入
│ StatefulSet │
└─────────────────┘
│ 流复制
┌─────────────────┐
│ 从库 (Replica) │ ← KEDA 管理,处理只读查询
│ Deployment │ 可以 0-N 个副本
└─────────────────┘
```
**配置示例:**
```yaml
# 主库 - 固定副本
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql-master
spec:
replicas: 1 # 固定 1 个
# ... 配置主库
---
# 从库 - KEDA 管理
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql-replica
spec:
# replicas 由 KEDA 管理
# ... 配置从库(只读)
---
# KEDA ScaledObject - 只扩展从库
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: postgresql-replica-scaler
spec:
scaleTargetRef:
name: postgresql-replica # 只针对从库
minReplicaCount: 0
maxReplicaCount: 5
triggers:
- type: postgresql
metadata:
connectionString: postgresql://user:pass@postgresql-master:5432/db
query: "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%'"
targetQueryValue: "10"
```
### 方案 3: 垂直扩展(推荐用于单实例)
对于单实例 PostgreSQL使用 VPA (Vertical Pod Autoscaler) 更合适:
```yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: postgresql-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: StatefulSet
name: postgresql
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: postgresql
minAllowed:
cpu: 250m
memory: 512Mi
maxAllowed:
cpu: 2000m
memory: 4Gi
```
## 当前部署建议
对于您当前的 PostgreSQL 部署(`/home/fei/k3s/010-中间件/002-postgresql/`
### ❌ 不要使用 KEDA 水平扩展
- 当前是单实例 StatefulSet
- 没有配置主从复制
- 直接扩展会导致数据问题
### ✅ 推荐的优化方案
1. **保持单实例运行**
```yaml
replicas: 1 # 固定不变
```
2. **优化资源配置**
```yaml
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
```
3. **配置连接池**
- 使用 PgBouncer 作为连接池
- PgBouncer 可以使用 KEDA 扩展
4. **定期备份**
- 使用 Longhorn 快照
- 备份到 S3
## PgBouncer + KEDA 方案
这是最实用的方案PostgreSQL 保持单实例PgBouncer 使用 KEDA 扩展。
```yaml
# PostgreSQL - 固定单实例
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
spec:
replicas: 1 # 固定
# ...
---
# PgBouncer - 连接池
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgbouncer
spec:
# replicas 由 KEDA 管理
template:
spec:
containers:
- name: pgbouncer
image: pgbouncer/pgbouncer:latest
# ...
---
# KEDA ScaledObject - 扩展 PgBouncer
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: pgbouncer-scaler
spec:
scaleTargetRef:
name: pgbouncer
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: postgresql
metadata:
connectionString: postgresql://postgres:postgres123@postgresql:5432/postgres
query: "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'"
targetQueryValue: "20"
```
## 总结
| 方案 | 适用场景 | 复杂度 | 推荐度 |
|------|---------|--------|--------|
| PostgreSQL Operator | 生产环境,需要高可用 | 高 | ⭐⭐⭐⭐⭐ |
| 读写分离 + KEDA | 读多写少场景 | 中 | ⭐⭐⭐⭐ |
| PgBouncer + KEDA | 连接数波动大 | 低 | ⭐⭐⭐⭐⭐ |
| VPA 垂直扩展 | 单实例,资源需求变化 | 低 | ⭐⭐⭐ |
| 直接 KEDA 扩展 | ❌ 不适用 | - | ❌ |
**对于当前部署,建议保持 PostgreSQL 单实例运行,不使用 KEDA 扩展。**
如果需要扩展能力,优先考虑:
1. 部署 PgBouncer 连接池 + KEDA
2. 或者迁移到 PostgreSQL Operator
---
**重要提醒:有状态服务的扩展需要特殊处理,不能简单地增加副本数!** ⚠️

View File

@@ -0,0 +1,23 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: redis-scaler
namespace: redis
spec:
scaleTargetRef:
name: redis
minReplicaCount: 0 # 空闲时缩容到 0
maxReplicaCount: 5 # 最多 5 个副本
pollingInterval: 30 # 每 30 秒检查一次
cooldownPeriod: 300 # 缩容冷却期 5 分钟
triggers:
- type: prometheus
metadata:
serverAddress: http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090
metricName: redis_connected_clients
query: sum(redis_connected_clients{namespace="redis"})
threshold: "1" # 有连接时启动
- type: cpu
metricType: Utilization
metadata:
value: "70" # CPU 使用率超过 70% 时扩容