K8S - HPA + 探针实战 - 实现弹性扩缩与自愈
引言
在分布式系统中,弹性扩缩容与 服务自愈是保障业务高可用的核心能力。Kubernetes 通过自动化机制实现两大关键功能:
• 动态扩缩容:基于 CPU/内存负载自动调整 Pod 副本数量,应对流量波动。
• 故障自愈:通过健康探针自动重启异常容器,并剔除未就绪实例,确保服务零中断。
一、Kubernetes 弹性扩缩容原理
1. 水平自动扩缩容(HPA)
• 监控指标:实时采集 Pod 的 CPU/内存使用率。
• 动态调整:指标超阈值时自动扩展,负载下降后自动收缩。
2. 服务自愈机制
• 存活探针(Liveness Probe):定期检测容器健康状态,失败时自动重启容器。
• 就绪探针(Readiness Probe):检查容器是否就绪,未就绪时从 Service 移除流量,避免请求分发至异常实例。
二、K8S 自愈与扩缩容实战
2.1 环境准备
1. 安装必要工具
确保已安装并配置好以下环境:
Kubernetes 集群(可使用 Minikube 或 Kind 进行本地测试)
kubectl命令行工具
Docker(用于构建镜像)
2. 创建本地集群(Kind)
kind-cluster.yamlkind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-planekubeadmConfigPatches:- |kind: InitConfigurationnodeRegistration:kubeletExtraArgs:node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80hostPort: 80protocol: TCP- containerPort: 443hostPort: 443protocol: TCP
创建并验证集群
# 创建集群(名称 local-k8s)
kind create cluster --name local-k8s --config kind-cluster.yaml
# 验证节点状态
kubectl get nodes
# 预期输出:显示一个 control-plane 节点为 Ready 状态
2.2 业务代码
1. 项目结构
k8s-scaling-selfheal/
├── app/
│ ├── myapp.py # Flask 应用代码
│ └── Dockerfile # Docker 镜像构建文件
├── k8s/
│ ├── deployment.yaml # Deployment 配置
│ ├── hpa.yaml # HPA(Horizontal Pod Autoscaler)
│ ├── service.yaml # Service 资源
│ └── ingress.yaml # Ingress 路由配置
└── README.md
2. 业务代码(Python 示例)
app/myapp.py
from flask import Flask
import osapp = Flask(__name__)@app.route("/")
def hello():return "Hello, Kubernetes!"@app.route("/healthz")
def health():# 假设这里你可以增加一些更复杂的健康检查逻辑return "OK", 200if __name__ == "__main__":app.run(host="0.0.0.0", port=int(os.getenv("PORT", 5000)))
app/requirements.txt
Flask==2.2.2
Dockerfile
FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "myapp.py"]
2.3 构建镜像并加载到集群
# 1. 构建镜像
docker build -t baixin005/hello-k8s-flask:latest .# 2. 加载镜像到集群(名称一致!)
kind load docker-image baixin005/hello-k8s-flask:latest --name local-k8s# 3. 验证镜像已加载
kubectl describe node local-k8s-control-plane | grep "hello-k8s-flask"
# 输出示例:docker.io/baixin005/hello-k8s-flask:latest
Kind 集群特性:
• 镜像加载后直接存储在集群节点中,无需推送至远程仓库。
• 若修改代码并重新构建镜像,需要重新执行 kind load命令。
• Kind Load 仅用于本地测试,生产环境需推送镜像到远程仓库(如Docker hub)。
2.4 Kubernetes 资源配置
1. 创建 Deployment并应用到集群
步骤1: 生成 Deployment
kubectl create deployment hello-k8s-flask \--image=baixin005/hello-k8s-flask:latest \--replicas=2 \--dry-run=client -o yaml > k8s/deployment.yaml
补充后的 Deployment.yaml
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: hello-k8s-flasklabels:app: hello-k8s-flask # Deployment 标签(用于分类管理)
spec:replicas: 2 # 初始副本数selector:matchLabels:app: hello-k8s-flask # 必须与 Pod 模板标签一致template:metadata:labels:app: hello-k8s-flask # Pod 标签(用于 Service/Ingress 流量路由)spec:containers:- name: hello-k8s-flask image: baixin005/hello-k8s-flask:latest # 镜像地址ports:- containerPort: 5000 # 容器监听端口(与 Flask 应用的 port=5000 一致)resources:requests:cpu: "100m" # 初始 CPU 请求(0.1 核,HPA 依赖此值计算利用率)memory: "100Mi" # 初始内存请求(HPA 也可监控内存)limits:cpu: "200m" # CPU 上限(防止单个 Pod 过度消耗资源)memory: "200Mi" # 内存上限(防止内存泄漏导致节点故障)livenessProbe: # 存活探针httpGet:path: /healthz # 健康检查接口port: 5000initialDelaySeconds: 15 # 容器启动后等待 15 秒开始探测periodSeconds: 10 # 每 10 秒探测一次readinessProbe: # 就绪探针httpGet:path: / # 就绪检查接口port: 5000initialDelaySeconds: 5periodSeconds: 5
关键配置说明:
步骤2:部署及验证
# 1. 应用 Deployment
kubectl apply -f k8s/deployment.yaml
# 2. 验证 Pod 状态
kubectl get pods -l app=hello-k8s-flask
# 预期输出:
# NAME READY STATUS RESTARTS AGE
# hello-k8s-flask-56457fc57c-jkh4k 1/1 Running 0 10s
# hello-k8s-flask-56457fc57c-r246t 1/1 Running 0 10s
# 3. 查看资源分配详情
kubectl describe pod <pod-name> | grep -A 5 "Requests"
# 预期输出:
# Requests:
# cpu: 100m
# memory: 100Mi
# Limits:
# cpu: 200m
# memory: 200Mi
2.负载均衡环境搭建
步骤1:创建service
service资源类似VM框架下的弹性伸缩组的负载均衡器,它能以加权轮询的方式将流量转发到多个pod 副本上。
kubectl create service clusterip hello-k8s-flask --tcp=5000:5000 --dry-run=client -o yaml > k8s/service.yaml
service.yaml
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:name: hello-k8s-flask
spec:ports:- name: "5000"port: 5000protocol: TCPtargetPort: 5000selector:app: hello-k8s-flask # 必须与 Deployment 中 Pod 的标签一致type: ClusterIP
关键配置说明
端口映射:
• port: 5000
Service 对外暴露的端口(集群内访问用)。
• targetPort: 5000
容器内部监听的端口(需与 Flask 应用 app.run(port=5000)一致)。
步骤2:部署并验证Service
kubectl apply -f k8s/service.yaml
查看 Service 状态
kubectl get svc hello-k8s-flask
# NAME TYPE CLUSTER-IP PORT(S) AGE
# hello-k8s-flask ClusterIP 10.96.123.45 5000/TCP 10s
检查 Endpoints
kubectl describe svc hello-k8s-flask | grep Endpoints
# Endpoints: 10.244.0.10:5000,10.244.0.11:5000
步骤3:部署 Ingress-Nginx
# 1. 部署 Ingress-Nginx(官方源)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/kind/deploy.yaml
# 2. 验证状态
kubectl get pods -n ingress-nginx
# NAME READY STATUS RESTARTS AGE
# ingress-nginx-controller-5d88495688-s4p7g 1/1 Running 0 2m
# 3. 查看镜像地址(确认无第三方仓库)
kubectl describe pod -n ingress-nginx ingress-nginx-controller-xxxx | grep Image
# Image: registry.k8s.io/ingress-nginx/controller:v1.8.2
部署4:创建集群的外网访问入口 ingress
kubectl create ingress hello-k8s-flask --rule="/=hello-k8s-flask:5000"
ingress.yaml
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: hello-k8s-flask
spec:ingressClassName: nginx # 与 Ingress-Nginx 控制器匹配rules:- http:paths:- path: /pathType: Prefixbackend:service:name: hello-k8s-flask # 指向 Service 名称port:number: 5000 # 指向 Service 端口
步骤5:应用 ingress 到集群
kubectl apply -f k8s/ingress.yaml
步骤6:验证部署与应用
1. 验证pod 正常启动。
注意: 通过 deployment 建立的pod副本名字后具有随机后缀,与工作负载是pod 的建立不同。
kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-k8s-flask-56457fc57c-jkh4k 1/1 Running 0 32m
hello-k8s-flask-56457fc57c-r246t 1/1 Running 1 (106s ago) 32m
预期结果:所有 Pod 处于 Running状态,且 READY为 1/1。
失败排查:查看 Pod 详情 kubectl describe pod ,或查看日志 kubectl logs 。
2. 验证 Service 流量转发
# 集群内部访问测试
kubectl run test --rm -it --image=busybox --restart=Never -- wget -qO- http://hello-k8s-flask:5000
# 预期输出:Hello, Kubernetes! from Pod: <pod-name>
失败排查:
•确保 Service 正确映射端口 kubectl describe svc hello-k8s-flask。•检查 Pod 端口是否正确 kubectl get pods -o wide。
3. 验证 Ingress 外部访问
# 获取 Ingress 外部地址(Kind 集群为 localhost)
kubectl get ingress
# 预期输出:
# NAME CLASS HOSTS ADDRESS PORTS AGE
# hello-k8s-flask nginx * localhost 80 5m# 通过 Ingress 访问应用
curl http://localhost
# 预期输出:Hello, Kubernetes! from Pod: <pod-name>
到此已完成镜像到集群的部署,可以进行 K8S 自愈和扩缩容演示了。
2.4 K8S 自愈能力演示
步骤 1:模拟持续访问
# 持续发送请求,观察流量分配
while true; do sleep 1; echo -e "\n$(date)"; curl http://127.0.0.1; done# 预期输出(交替显示两个 Pod 名称):
# Hello, Kubernetes! from Pod: hello-k8s-flask-56457fc57c-jkh4k
# Hello, Kubernetes! from Pod: hello-k8s-flask-56457fc57c-r246t
步骤 2:模拟 Pod 宕机
# 选择一个 Pod 名称(例如 hello-k8s-flask-56457fc57c-r246t)
POD_NAME=$(kubectl get pods -l app=hello-k8s-flask -o jsonpath='{.items[0].metadata.name}')# 手动杀死容器进程(模拟宕机)
kubectl exec -it $POD_NAME -- bash -c "killall python3"
步骤 3:观察自愈过程
# 监控 Pod 状态变化
kubectl get pods -w
# 预期现象:
# 1. 宕机 Pod 状态变为 `Error`,随后自动重启(RESTARTS+1)
# 2. 请求流量全部转移到健康 Pod
# 3. 约 30 秒后,宕机 Pod 恢复为 `Running`
步骤 4:验证最终状态
# 查看所有 Pod 状态
kubectl get pods -l app=hello-k8s-flask
# 预期输出:
# NAME READY STATUS RESTARTS AGE
# hello-k8s-flask-56457fc57c-jkh4k 1/1 Running 0 35m
# hello-k8s-flask-56457fc57c-r246t 1/1 Running 1 35m
2.5 K8S自动扩缩容能力演示
步骤 1:安装 Metrics Server
# 部署 Metrics Server(监控 CPU/内存)
kubectl apply -f https://ghproxy.com/https://raw.githubusercontent.com/kubernetes-sigs/metrics-server/v0.7.0/deploy/extra/missing.yaml# 等待 metrics 就绪
kubectl wait deployment -n kube-system metrics-server --for condition=Available=True --timeout=90s
步骤 2:配置 HPA 策略
# 创建自动扩容策略(CPU 阈值 50%,副本数 2-10)
kubectl autoscale deployment hello-k8s-flask --cpu-percent=50 --min=2 --max=10# 验证 HPA 状态
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# myapp Deployment/myapp 0%/50% 2 10 2 10s
hpa.yaml
# k8s/hpa.yamlapiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:name: hello-k8s-flask # HPA 的名称,需与 Deployment 名称匹配
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: hello-k8s-flask # 目标 Deployment,HPA 监控该 Deployment 进行扩缩容minReplicas: 2 # 最少副本数,保证服务的基础可用性maxReplicas: 10 # 最大副本数,避免资源消耗过大metrics:- type: Resourceresource:name: cpu # 监控 CPU 资源target:type: Utilization # 使用 CPU 利用率作为扩缩容指标averageUtilization: 50 # 目标 CPU 使用率(%),超过该值则扩容,低于该值则缩容
部署hpa 到集群
kubectl apply -f k8s/hpa.yaml
步骤 3:触发扩容
# 进入 Pod 执行压测
POD_NAME=$(kubectl get pods -l app=hello-k8s-flask -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD_NAME -- bash
apt update && apt install -y apache2-utils
ab -c 50 -n 10000 http://hello-k8s-flask:5000/
步骤 4:监控扩容过程
# 新终端窗口执行(观察 Pod 数量变化)
watch kubectl get pods,hpa# 预期现象:
# 1. 1-2 分钟后,Pod 数量逐步增加(最多 10 个)
# 2. HPA 的 `TARGETS` 列显示 CPU 使用率超过 50%
步骤 5:验证缩容
# 停止压测后等待 5 分钟,观察 Pod 数量逐步恢复至 2 个
kubectl get pods -w# 预期输出:
# NAME READY STATUS RESTARTS AGE
# hello-k8s-flask-8f57b8494-brqz7 1/1 Running 0 11m
# hello-k8s-flask-8f57b8494-d26tg 1/1 Running 0 11m
三、总结
3.1 核心总结
自愈能力:通过探针机制自动恢复故障容器,保障服务连续性。
弹性扩缩容:基于资源指标动态调整副本数,优化资源利用率。
核心资源协作
• Deployment管理 Pod 生命周期
• Service提供负载均衡
• HPA实现弹性伸缩,
• Ingress暴露外部访问入口