当前位置: 首页 > news >正文

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  # 必须与 DeploymentPod 的标签一致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暴露外部访问入口

相关文章:

  • springboot框架常用配置
  • Microsoft Entra ID 详解:现代身份与访问管理的核心
  • 《PyTorch documentation》(PyTorch 文档)
  • 学习记录:DAY21
  • 深度解析:Vue.js 性能优化全景指南(从原理到实践)
  • 破局 AI 焦虑:企业如何抢占智能时代的制高点
  • DC-DC常见应用问题解疑
  • 2025年CC攻击防御全攻略:应对复杂化攻击的实战策略
  • DeepSeek基础-使用python请求deepseek
  • 2025华东杯A/B/C题解题思路+可运行代码参考
  • 从 “可办“ 到 “好办“:云蝠大模型如何重塑政务服务体验
  • ubuntu下一些环境配置
  • 插入到word里面的用origin画的图,怎么获取图片细节?
  • 【Spring AI】Java结合ollama实现大模型调用
  • 大数据治理自动化与智能化实践指南:架构、工具与实战方案(含代码)
  • 一种动态分配内存错误的解决办法
  • 蓝桥杯 序列计数
  • nginx 代理时怎么更改 Remote Address 请求头
  • 单片机-89C51部分:11、IIC 、传感器温湿度
  • 机器手电机驱动器小体积解决方案
  • 向左繁华都市,向右和美乡村,嘉兴如何打造城乡融合发展样本
  • “上博号”彩绘大飞机今日启航:万米高空传播中国古代文化
  • 深入贯彻中央八项规定精神学习教育中央指导组培训会议召开
  • 一季度全国城镇新增就业308万人
  • 中国黄金协会:一季度我国黄金产量同比增1.49%,黄金消费量同比降5.96%
  • 体坛联播|利物浦提前4轮夺冠,安切洛蒂已向皇马更衣室告别