前端也要懂点k8s-上篇
点击关注公众号,“技术干货” 及时达!
前言
最近在采用Jenkins实现前端项目自动化部署功能,其中有一个步骤用到了k8s, 这一块知识令我感到比较陌生,看不懂配置文件里的语句含义,以及如何被外部的bash指令串联起来,刚好假期有时间,决定学习一下k8s。学完目标是学完之后要了解k8s常用的操作。现在我们进入今天的主题:
一、Kubernetes 简介
Kubernetes(简称 K8s)是一个用于「自动部署、扩展和管理容器化应用程序」的开源系统。下图展示了Kubernetes集群的架构及其与外部系统的交互方式:
1.1 外部系统(External Systems)
kubectl: 这是Kubernetes的命令行工具,用户可以通过它与Kubernetes API服务器进行交互,执行各种操作如创建、删除和更新资源。 CI/CD Systems: 持续集成/持续部署系统可以使用Kubernetes API来自动化应用的部署和管理。 Apps Use SDK to connect to API server: 应用程序可以使用SDK连接到Kubernetes API服务器,以实现更复杂的集成和自动化。
1.2 Kubernetes 集群(Kubernetes Cluster)
Kubernetes集群采用的是「主从架构(Master-Slave Architecture)」 ,主要由两个角色组成:
「控制平面(Control Plane)」 :负责集群的整体管理和调度。 「工作节点(Worker Node)」 :负责实际运行应用容器。
1.2.1 控制平面(Control Plane)
控制平面是 Kubernetes 的“大脑”,主要负责接收用户指令、调度任务、监控运行状态。它包含以下组件:
| 「kube-apiserver」 | |
| 「etcd」 | |
| 「kube-scheduler」 | |
| 「kube-controller-manager」 | |
| 「cloud-controller-manager」 |
所有这些组件通常运行在 Master 节点上。在生产环境中,控制平面可以做高可用部署(即多个 Master 节点):
保证 apiserver 的可用性(通过负载均衡) 保证 etcd 的数据冗余与高一致性(通常部署 3 个及以上节点) 避免单点故障,增强容灾能力
1.2.2 工作节点(Worker Node)
每个 Node 是实际运行容器的机器(虚拟机或物理机),其核心组件包括:
| 「kubelet」 | |
| 「kube-proxy」 | |
| 「Container Runtime」 |
1.2.3 云提供商APIs
Kubernetes可以通过云提供商APIs与云服务进行集成,例如负载均衡器、存储卷和身份认证等。这使得Kubernetes能够利用云平台提供的各种服务来增强其功能。
1.3 k8s和docker的关系?
k8s和docker的用途都含有容器管理,初学者一般都搞不清楚两者之间的关系。可以理解为:「Docker 负责造车,Kubernetes 负责调度车队跑起来并保持秩序」。
| 「Docker」 | |
| 「Kubernetes」 |
「Docker 管理单个容器,Kubernetes 管理容器的集群」;它们各司其职,共同构成了现代云原生应用的基石。
1.4 工作流程
开发者通过 kubectl 提交 YAML 清单到 apiserver。 apiserver 验证请求,并将信息存储到 etcd。 scheduler 监听到新 Pod 创建请求,并根据调度算法分配到合适的 Node。 对应 Node 上的 kubelet 接收到任务,调用 Container Runtime 启动容器。 kube-proxy 设置好服务发现和访问规则,确保内部通信正常。
二、搭建 Kubernetes 环境
根据使用场景不同,k8s有三种搭建方式。三种搭建方式的优缺点如下:
由于篇幅所限,本文只演示一下第一种搭建k8s环境的方式(以 macOS / Linux 为例):
2.1 安装 kubectl(Kubernetes 命令行工具)
curl -LO "https://dl.k8s.io/release/$(curl -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client
2.2 安装 Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
2.3 启动 Minikube 集群
minikube start
2.4 查看集群节点状态
kubectl get nodes
三、常用资源对象介绍
Kubernetes 中资源种类很多,常见的有:
3.1 Pod:最小部署单元
3.1.1 什么是Pod?
Pod 是 K8s 中最小的可调度单元。一个 Pod 包含一个或多个 「容器(通常是 Docker 容器)」 ,这些容器共享:
网络(IP 和端口空间) 存储(Volume 卷) 生命周期(被视为一个整体)
Pod 的典型用途是运行一个应用或服务的一个实例。一个 Pod 运行一个容器(最常见场景):
apiVersion:v1
kind:Pod
metadata:
name:nginx-pod
spec:
containers:
-name:nginx
image:nginx:1.24
ports:
-containerPort:80
这个 Pod 会启动一个 Nginx 容器,并暴露 80 端口。
3.1.2 Pod 生命周期
Pod 的状态包括:
Pending: 等待调度资源Running: 正在运行Succeeded: 运行成功后退出Failed: 运行失败Unknown: 状态无法获取
3.1.3 Pod的创建,查看与删除
# 创建
kubectl apply -f nginx-pod.yaml
# 查看所有pod
kubectl get pods
# 查看某个pod
kubectl describe pod nginx-pod
# 删除
kubectl delete pod nginx-pod
上面给出的都是独立的pod的创建与管理方式,虽然你可以手动管理 Pod,但 「更推荐使用 Deployment 控制器」 ,创建Pod,自动管理 Pod 的副本数量、自愈能力和升级策略。
3.2 Deployment:无状态应用的部署控制器
Deployment 是 Kubernetes 中最常用的控制器之一,专门用于管理 「无状态应用的生命周期」。它确保你的 Pod 副本在集群中始终按预期运行,并具备以下功能:
保证指定数量的 Pod 始终处于运行状态(副本控制) 支持应用的滚动升级和回滚 支持 declarative 式的配置和更新 自动重建失败的 Pod(具备自愈能力)
3.2.1 典型 Deployment 示例
说明:
replicas: 设置运行的 Pod 数量为 3selector: 用于匹配管理哪些 Podtemplate: 定义 Pod 的内容(镜像、端口等)
apiVersion:apps/v1
kind:Deployment
metadata:
name:my-nginx
spec:
replicas:3
selector:
matchLabels:
app:nginx
template:
metadata:
labels:
app:nginx
spec:
containers:
-name:nginx
image:nginx:1.24
ports:
-containerPort:80
3.2.2 Deployment 的工作逻辑
寻找所有标签匹配 selector.matchLabels的 Pod
如果数量不足 replicas,则新建 Pod如果数量过多,则删除多余的 Pod 如果标签相同但镜像等配置不同,则更新 Pod Deployment 不直接控制 Pod,而是通过创建一个 ReplicaSet,再由 ReplicaSet 具体去创建 Pod,维护副本数量,做滚动更新。
3.2.3 Deployment操作命令
# 创建 Deployment
kubectl apply -f nginx-deploy.yaml
# 查看状态
kubectl get deployments
kubectl describe deployment nginx-deploy
# 查看管理的 Pod
kubectl get pods -l app=nginx
修改镜像并滚动升级,将nginx从1.24升级到1.25
spec:
containers:
-name:nginx
image:nginx:1.25
# 升级
kubectl apply -f nginx-deploy.yaml
# 查看历史记录
kubectl rollout history deployment nginx-deploy
# 回滚
kubectl rollout undo deployment nginx-deploy
3.3 Service:服务发现与负载均衡
在 Kubernetes 中,「Pod 是会变化的」 —— 当 Deployment 滚动更新、Pod 重启时,Pod 的 IP 会变。所以不能依赖 Pod 的 IP 地址来通信。
这就是 Service 出场的原因,它为一组 Pod 提供了一个 「稳定的网络访问入口」,实现了:
「服务发现」(Pod 动态变动也能找到) 「负载均衡」(多个 Pod 间自动分流请求)
3.3.1 Service实例
实例:为 nginx Pod 暴露一个 Service
apiVersion:v1
kind:Service
metadata:
name:nginx-service
spec:
selector:
app:nginx# 匹配被管理的 Pod(Deployment 创建的)
ports:
-protocol:TCP
port:80# Service 对外暴露的端口
targetPort:80# Pod 内部容器监听的端口
type:ClusterIP# 集群内访问(默认)
常见 Service 类型:
3.3.2 Service 如何做服务发现?
Kubernetes 内置 「DNS 服务」,会为每个 Service 分配一个 DNS 名称: 例如
http://nginx-service.default.svc.cluster.local
容器中的其他 Pod 只需用这个 DNS 名称就能访问 nginx 服务,完全不需要关心 Pod IP。
3.3.3 创建并访问 Service 示例
# 创建 Deployment
kubectl apply -f nginx-deployment.yaml
# 创建 Service
kubectl apply -f nginx-service.yaml
# 查看 Service IP 和端口:
kubectl get svc
# 在集群中访问 Service:
curl http://nginx-service
3.4 Ingress
在 Kubernetes 中,Ingress是一种 API 对象,用于管理外部用户如何通过 HTTP 或 HTTPS 访问集群内的服务(Service) 。简而言之,Ingress 提供了一种统一的方式,将域名或路径映射到集群中的服务上,并支持负载均衡、SSL 终端和基于路径/主机的路由。
3.4.1 为什么需要 Ingress?
在没有 Ingress 的情况下,集群外部访问服务只能通过:
「NodePort」:每个 Service 暴露一个端口,访问地址为 NodeIP:Port,难管理。「LoadBalancer」:为每个服务申请一个云负载均衡器,成本高。 「Port-forward / kubectl proxy」:临时调试用,不适合生产。
而 Ingress 通过一个统一的入口,根据域名或路径来转发请求,成本低、配置灵活、可维护性强。Ingress 功能点如下:
3.4.2 组成结构
Ingress 本身不直接处理请求,它依赖 「Ingress Controller」 来工作。常见 Ingress Controller:
下面这张图展示了 Ingress 在 Kubernetes 中进行流量转发的完整架构流程
用户访问
example.com/web;Ingress 中定义了
/web路径指向my-webService;Ingress Controller(如 nginx-ingress)读取 Ingress 规则;
Ingress Controller 接收到请求后,将其转发给
my-webService;Service 查找符合条件的 Pod(例如标签为
app=web);请求最终到达 Pod,得到业务响应。
+--------------+
| Internet |
+------+-------+
|
+-------v--------+
| Ingress | ← 配置路由规则的资源
| (定义规则) |
+-------+--------+
|
+--------v---------+
| Ingress Controller| ← 实际负责转发流量
| (如 Nginx, Traefik)|
+--------+---------+
|
+-----v------+
| Kubernetes |
| Services |
+-----+------+
|
+--v--+
| Pod |
+-----+
3.4.3 配置一个简单的 Ingress
Ingress 如何连接 Service? 假设你有一个名为 my-web 的 Service,监听端口为 80:
service.yaml
apiVersion:v1
kind:Service
metadata:
name:my-web
spec:
selector:
app:web
ports:
-port:80
targetPort:8080
service.yaml对应的my-web-deployment.yaml配置如下:
apiVersion:apps/v1
kind:Deployment
metadata:
name:my-web
spec:
replicas:2
selector:
matchLabels:
app:web
template:
metadata:
labels:
app:web
spec:
containers:
-name:web
image:nginx:1.24
ports:
-containerPort:8080
这个 Service 将流量从端口 80 转发到选中 Pod 的 8080 端口。Ingress 配置如下:
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:web-ingress
spec:
rules:
-host:example.com
http:
paths:
-path:/web
pathType:Prefix
backend:
service:
name:my-web# 指向 Service 的名字
port:
number:80# 指向 Service 的 port 字段
❝当用户访问
http://example.com/web时:❞
请求被 Ingress Controller 捕获; 根据 /web路径匹配到规则;将请求转发到 my-webService;Service 根据 selector 找到对应的 Pod(如 app=web);将请求转发给这些 Pod 的 targetPort: 8080。
3.4.4 配置 HTTPS Ingress
通过如下命令创建了一个包含 TLS 证书的 Secret:这个 Secret 包含公钥证书(CRT)和私钥(KEY),名称为 tls-secret,位于 default 命名空间中.
kubectl create secret tls tls-secret \
--cert=example.com.crt \
--key=example.com.key \
-n default
在Ingress 配置启用 HTTPS
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target:/
spec:
tls:
-hosts:
-example.com
secretName:tls-secret# 指向我们预先创建的 TLS Secret
rules:
-host:example.com
http:
paths:
-path:/
pathType:Prefix
backend:
service:
name:my-web
port:
number:80
效果验证:
本地配置 DNS:
echo"INGRESS_IP example.com" | sudo tee -a /etc/hostsINGRESS_IP是你的 Ingress Controller 的外网 IP 地址。浏览器访问:
https://example.com/
若配置无误,将自动跳转并看到你部署的 nginx 页面。
3.5 ConfigMap 与 Secret
在 Kubernetes 中,「ConfigMap 和 Secret」 是用于「配置管理」的两种核心资源类型,它们用于将配置和敏感数据(如密码、API 密钥)与容器解耦,让你的应用部署更加灵活、安全。
3.5.1 ConfigMap:存储非敏感配置
创建 ConfigMap 的方式
方法 1:使用 kubectl 命令行创建
kubectl create configmap my-config --from-literal=color=blue --from-literal=lang=zh
方法 2:使用 YAML 创建
apiVersion:v1
kind:ConfigMap
metadata:
name:my-config
data:
color:blue
lang:zh
使用 ConfigMap 的方式
方法 1:作为环境变量注入容器
env:
-name:COLOR
valueFrom:
configMapKeyRef:
name:my-config
key:color
方法 2:挂载为文件
volumeMounts:
-name:config-volume
mountPath:/etc/config
volumes:
-name:config-volume
configMap:
name:my-config
3.5.2 Secret:存储敏感配置
Secret 的数据会以 Base64 编码存储(可以结合加密存储后端实现更高安全性)。
创建 Secret 的方式
方法 1:命令行直接创建
kubectl create secret generic my-secret --from-literal=password=123456
方法 2:YAML 文件创建(注意 Base64 编码)
apiVersion:v1
kind:Secret
metadata:
name:my-secret
type:Opaque
data:
password:MTIzNDU2# Base64 编码后的 "123456"
可以用如下命令手动编码:
echo -n "123456" | base64
使用 Secret 的方式
方法 1:作为环境变量注入
env:
-name:DB_PASSWORD
valueFrom:
secretKeyRef:
name:my-secret
key:password
方法 2:挂载为文件
volumeMounts:
-name:secret-volume
mountPath:/etc/secret
volumes:
-name:secret-volume
secret:
secretName:my-secret
3.6 PersistentVolumeClaim
PersistentVolumeClaim(PVC) 是一种资源对象,用于申请持久化存储空间(PersistentVolume,PV) 。简单来说,它是 Pod 与底层存储之间的桥梁,用户通过 PVC 来请求磁盘,而不是直接绑定硬盘资源。
3.6.1 什么是 PersistentVolume 与 PersistentVolumeClaim?
「PersistentVolume(PV)」 :由管理员创建或自动创建的「存储资源」,类似“硬盘”。 「PersistentVolumeClaim(PVC)」 :用户申请使用 PV 的方式,类似“租用硬盘”。
❝🧩 类比理解:
❞
「PV = 房东提供的房子」 「PVC = 租客发出的租房申请」 Kubernetes 匹配 PVC 与 PV,实现租房动作
为什么需要 PVC?在容器运行时,容器内的数据是「临时的(临时存储)」 ,容器重启或迁移后会丢失。如果需要保存数据库、文件上传等数据,就必须使用 PVC 来绑定到稳定的硬盘。
3.6.2 PVC 使用流程
管理员配置 StorageClass 或 PV 开发者在 Pod 中声明 PVC 系统自动匹配合适的 PV 给 PVC Pod 使用 PVC 提供的存储挂载路径
3.6.3 PVC 使用示例
Step1:定义 PVC
申请一个 1Gi 的存储空间
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:my-pvc
spec:
accessModes:
-ReadWriteOnce# 只允许一个 Pod 挂载读写
resources:
requests:
storage:1Gi# 请求 1Gi 存储空间
访问模式说明:
Step 2:Pod 中使用 PVC
apiVersion:v1
kind:Pod
metadata:
name:nginx-with-pvc
spec:
containers:
-name:nginx
image:nginx
volumeMounts:
-mountPath:"/usr/share/nginx/html"
name:web-data
volumes:
-name:web-data
persistentVolumeClaim:
claimName:my-pvc
这样,Pod 就能把 /usr/share/nginx/html 目录的数据存储到持久化卷中。也可以用 PVC 搭配 StorageClass,让 K8s 自动向云厂商(如 AWS、GCP)动态创建磁盘资源,无需管理员手动创建 PV。
3.7 Namespace
「Namespace(命名空间)」 是一种用于对集群中的资源进行「逻辑隔离和分组管理」的机制。可以把它理解为集群中的「虚拟子集群」,用于将资源划分为多个相互独立的空间。并非所有的资源都可以用命名空间进行隔离。
顺便说一下Node和Pod的区别:
| 「Node(节点)」 | 「Pod」 | |
|---|---|---|
| 「定义」 | ||
| 「层级关系」 | ||
| 「数量」 | ||
| 「作用」 | ||
| 「组成部分」 |
通俗理解「Node 是宿舍楼」,里面住着多个 「Pod(宿舍间)」 一个 Node 可以运行多个 Pod,但 Pod 不能脱离 Node 独立存在。
3.7.1 Namespace 有什么用?
1. 「资源隔离」
每个 Namespace 里的资源彼此隔离,互不干扰。 比如你在 dev和prod中分别部署了两个nginx,它们不会冲突,因为在各自的命名空间中是唯一的。
2. 「权限控制(RBAC)」
可以基于 Namespace 分配不同的权限,比如:
张三只能管理dev命名空间;李四只能查看prod命名
便于企业多团队协作时的权限边界管理。
3. 「资源配额限制(ResourceQuota)」
可以为不同 Namespace 设置资源配额限制,比如:
devNamespace 最多使用 4 个 CPU、8G 内存;prodNamespace 可以使用更多资源;
这样可以避免某个项目“吃光”整个集群资源。
4. 「便于环境分离」
常见实践:按环境划分 Namespace:
dev:开发环境test:测试环境prod:生产环境
在一个集群中部署多套系统而互不干扰。此外Kubernetes 默认提供了几个内置命名空间:
default | |
kube-system | |
kube-public | |
kube-node-lease |
3.7.2 创建命名空间并部署资源示例
# 创建命名空间
kubectl create namespace dev
# 在 dev 命名空间部署 nginx
kubectl run nginx --image=nginx -n dev
# 查看 dev 命名空间下的 Pod
kubectl get pods -n dev
命名空间的逻辑隔离:
+------------------------+
| Kubernetes 集群 |
| |
| +--------+ +--------+ |
| | dev | | prod | |
| | | | | |
| | nginx | | nginx | |
| | redis | | mysql | |
| +--------+ +--------+ |
+------------------------+
3.8 RBAC
「RBAC(基于角色的访问控制,Role-Based Access Control)」 是一种权限管理机制,用来控制「谁可以对哪些资源执行哪些操作」。RBAC 就像公司中的权限系统:不同的岗位(角色)有不同的权限,不同的员工(用户)只能做他们被授权的事情。
3.8.1 RBAC 的核心组件
RBAC 一共由 4 个关键对象组成:
| 「Role」 | |
| 「ClusterRole」 | |
| 「RoleBinding」 | |
| 「ClusterRoleBinding」 |
常见的操作:
get | |
list | |
watch | |
create | |
update | |
delete |
3.8.2 创建一个只读角色
创建 Role:只能查看 Pod 和 Service
apiVersion:rbac.authorization.k8s.io/v1
kind:Role
metadata:
name:pod-reader
namespace:dev
rules:
-apiGroups:[""]
resources:["pods","services"]
verbs:["get","list","watch"]
创建 RoleBinding:把这个权限绑定给某个用户
apiVersion:rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
name:read-pods-binding
namespace:dev
subjects:
-kind:User
name:alice
apiGroup:rbac.authorization.k8s.io
roleRef:
kind:Role
name:pod-reader
apiGroup:rbac.authorization.k8s.io
表示:用户 alice 在 dev 命名空间内,可以读取 Pod 和 Service,但不能创建、删除、修改。
常用命令:
# 查看所有 ClusterRole
kubectl get clusterroles
# 查看绑定关系
kubectl get rolebindings -n dev
# 授予某用户集群管理员权限(示例)
kubectl create clusterrolebinding admin-binding \
--clusterrole=cluster-admin \
[email protected]
3.9 CronJob
「CronJob」 是用来按计划周期性运行任务的资源类型,类似于 Linux 中的 crontab。它适用于那些需要定时执行的任务,例如数据库备份、定期数据清理、定时邮件发送等。
配置字段说明:
CronJob | |
Job | |
Pod | |
restartPolicy | OnFailure,失败时重试 |
suspend | true 暂停 CronJob 执行 |
示例:每天午夜运行一次任务
apiVersion:batch/v1
kind:CronJob
metadata:
name:hello-cronjob
spec:
schedule:"0 0 * * *"# crontab 格式:每天0点
jobTemplate:
spec:
template:
spec:
containers:
-name:hello
image:busybox
args:
-/bin/sh
--c
-echo"Hello from CronJob at $(date)"
restartPolicy:OnFailure
schedule 使用的是类 Unix 的 cron 表达式,格式如下:
分 时 日 月 星期
*/5 * * * * | |
0 0 * * * | |
0 9 * * 1 |
CronJob 的执行过程:
时间触发器 (schedule)
↓
+-----------+
| CronJob | ← 负责按照 schedule 触发 Job
+-----------+
↓
+-----------+
| Job | ← 一次性任务(控制器)
+-----------+
↓
+-----------+
| Pod | ← 实际执行任务的容器
+-----------+
常用命令:
# 获取集群中所有CronJob资源的列表
kubectl get cronjob
# 查看名为 hello-cronjob 的 CronJob 资源的详细信息
kubectl describe cronjob hello-cronjob
# 列出所有的 Job 资源
kubectl get jobs
# 查看与指定 Job 相关的 Pod 的日志
kubectl logs <job-created-pod-name>
四、自动伸缩(HPA)
「HPA(Horizontal Pod Autoscaler,水平 Pod 自动扩缩容)」 是一个控制器,它会根据CPU、内存或自定义指标,自动调整 Pod 的副本数量,确保应用在不同负载情况下都能平稳运行。
4.1 HPA 的工作原理
HPA 监测目标 Pod 资源使用情况(默认监测 CPU)。 如果 CPU 或其他指标高于设定阈值,就自动「增加」 Pod 副本数。 如果 CPU 或其他指标低于设定阈值,就自动「减少」 Pod 副本数。
4.2 如何使用 HPA?
4.2.1 确保 Metrics Server 已安装
HPA 需要 metrics-server 提供 Pod 资源使用数据。可以使用以下命令检查:
kubectl get apiservices | grep metrics
如果 metrics.k8s.io 没有运行,需要安装:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
4.2.2 创建一个 Deployment
apiVersion:apps/v1
kind:Deployment
metadata:
name:php-apache
spec:
replicas:1
selector:
matchLabels:
app:php-apache
template:
metadata:
labels:
app:php-apache
spec:
containers:
-name:php-apache
image:k8s.gcr.io/hpa-example
ports:
-containerPort:80
resources:
requests:
cpu:200m
limits:
cpu:500m
注意:HPA 需要 resources.requests.cpu 进行判断,因此 Pod 必须指定 cpu requests 值,否则 HPA 不会生效。
4.2.3 创建 HPA 规则(基于 CPU 自动扩缩)
apiVersion:autoscaling/v2
kind:HorizontalPodAutoscaler
metadata:
name:php-apache-hpa
spec:
scaleTargetRef:
apiVersion:apps/v1
kind:Deployment
name:php-apache# 关联的 Deployment
minReplicas:1# 最少 1 个副本
maxReplicas:10# 最多 10 个副本
metrics:
-type:Resource
resource:
name:cpu
target:
type:Utilization
averageUtilization:50# CPU 使用率超过 50% 时扩容
4.2.4 应用与查看 HPA 规则
kubectl apply -f hpa.yaml
kubectl get hpa
示例输出:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 60%/50% 1 10 3 5m
TARGETS 60%/50%:当前 CPU 使用率 60%,HPA 目标是 50%。REPLICAS 3:HPA 自动扩展了 3 个 Pod。
4.2.5 模拟高负载(测试 HPA)
可以使用 busybox 持续压测 Pod 的 CPU:
kubectl run -i --tty busybox --image=busybox -- sh
# 在 BusyBox 终端里执行
whiletrue; do wget -q -O- http://php-apache; done
观察 HPA 变化:
kubectl get hpa -w
4.2.6 进阶-基于自定义指标扩缩容
HPA 也可以基于「内存使用量」或「Prometheus 自定义指标」进行扩缩容,例如:
metrics:
-type:Resource
resource:
name:memory
target:
type:Utilization
averageUtilization:70# 当内存使用率超过 70% 时扩容
或者基于 「Prometheus 监控指标」 进行扩容:
metrics:
-type:External
external:
metric:
name:requests_per_second
target:
type:AverageValue
averageValue:1000# 每秒请求超过1000次扩容
4.3 怎么解决资源不足问题?
HPA 扩展的 Pod 所需的硬件资源,来自集群中已有的 Node(节点)资源池。如果 Node上没有足够资源容纳新的 Pod,Pod 会「处于 Pending 状态」,直到有资源调度。举例说明:
集群中有 3 个 Node,每个 Node 有 2 核 CPU 和 4G 内存。 每个 Pod 要求 cpu: 500m。初始状态运行了 6 个 Pod,正好占满资源(理论上最多能运行 「12 个 Pod」,但我们说「6 个 Pod 就占满资源」,是因为现实中不能这么理想化计算,系统组件也占资源,再预留一些 buffer 来应对波动、调度策略等,6~8 个 Pod 就可能接近极限了)。 负载升高,HPA 触发扩容为 8 个 Pod。
结果:新创建的 2 个 Pod 会 「Pending(等待)」 ,因为没有 Node 有足够资源运行它们。
怎么解决资源不足问题?有两种方式:
4.3.1 手动添加节点(扩容集群)
如果你使用的是物理机或虚拟机搭建的集群,可以手动加入更多 Node。
# 添加新节点后,kubelet 会将其注册进集群
kubectl get nodes
4.3.2 使用 Cluster Autoscaler(集群自动扩容)
❝Cluster Autoscaler 是 Kubernetes 官方提供的「自动添加/移除 Node 的组件」。
❞
当 Pod 无法调度时,Cluster Autoscaler 会自动向云服务申请添加 Node。 当某些 Node 上没有运行任何 Pod 并维持一段时间,自动释放这些 Node。
支持的云平台:
GKE(Google) EKS(AWS) AKS(Azure) 阿里云、腾讯云等也有类似组件
4.3.3 最佳方案
最佳实践:HPA + Cluster Autoscaler 联用 是生产环境最常见做法:
HPA 根据 CPU/内存/自定义指标自动调整 Pod 数量。 如果资源不足,Cluster Autoscaler 自动申请节点,保障 Pod 正常运行。
结语
肚子有点饿,今天先写到这里,下篇明天再续写。
关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding