news 2026/6/11 4:47:54

Service、扩容与滚动更新——从单点到高可用的实战之路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Service、扩容与滚动更新——从单点到高可用的实战之路

🚀阅读提示:本文假设你已经掌握 kubectl 基础命令。建议按顺序阅读本系列文章。

前言

那是一个让我永生难忘的凌晨2点

公司搞促销活动,流量突然暴涨。我正在家睡觉,突然电话被打爆了——服务崩了

手忙脚乱地爬起来开电脑,登录 K8s 集群一看:

  • 只有一个 Pod 在运行
  • CPU 使用率飙到 100%
  • 大量请求超时
  • Pod 不断重启

那时候我才意识到:上了 K8s 不代表就高可用了!

如果你只有一个 Pod,没有负载均衡,没有自动扩容,那和传统单点部署没什么区别。K8s 只是提供了能力,怎么配置还得靠自己

那晚上折腾了3个小时,我学会了:

  • Service做负载均衡
  • scale手动扩容
  • Rolling Update零停机发布

今天这篇文章,把我那晚的血泪教训和实战经验分享出来,帮你提前避开这些坑


一、Service:Pod 的代言人

1.1 为什么需要 Service?

在 K8s 中,Pod 是临时的、动态的

  • Pod 的 IP 地址是不固定的(重启后会变)
  • Pod 可能被调度到不同的节点
  • Pod 可能因为故障被重建

那其他应用怎么访问这个 Pod 呢?总不能每次都改 IP 吧?

这就是Service存在的意义——为 Pod 提供一个稳定的访问入口

1.2 Service 的工作原理

用户/其他应用 ↓ Service(固定IP/域名) ↓ Label Selector(标签选择) ↓ Pod 1, Pod 2, Pod 3... ↓ 负载均衡分发请求

Service 的核心能力

  1. 服务发现:为 Pod 提供固定的访问地址(ClusterIP 或域名)
  2. 负载均衡:自动将请求分发到后端的多个 Pod
  3. 解耦:调用方不需要知道 Pod 的具体位置

1.3 Service 的三种类型

K8s 提供了三种 Service 类型,适应不同的访问场景:

类型访问方式适用场景生产环境推荐度
ClusterIP集群内部 IP集群内部服务间通信⭐⭐⭐⭐⭐
NodePort<NodeIP>:<NodePort>开发测试、简单暴露⭐⭐
LoadBalancer云厂商负载均衡器 IP生产环境对外服务⭐⭐⭐⭐
ClusterIP(默认)
apiVersion:v1kind:Servicemetadata:name:nginx-servicespec:type:ClusterIP# 默认就是 ClusterIP,可以省略selector:app:nginxports:-port:80targetPort:80

特点

  • 只在集群内部可访问
  • 分配一个内部虚拟 IP(ClusterIP)
  • 适用于微服务间的内部通信

访问方式

# 集群内通过 Service 名访问curlhttp://nginx-service:80# 或者通过 ClusterIPcurlhttp://10.96.10.90:80
NodePort
apiVersion:v1kind:Servicemetadata:name:nginx-servicespec:type:NodePortselector:app:nginxports:-port:80targetPort:80nodePort:32600# 范围:30000-32767

特点

  • 在每个节点上开放一个端口(NodePort)
  • 通过<NodeIP>:<NodePort>访问
  • 会自动创建 ClusterIP

访问方式

# 任意节点的 IP + NodePortcurlhttp://192.168.0.112:32600curlhttp://192.168.0.113:32600

⚠️注意:NodePort 的端口范围是 30000-32767,如果不指定,K8s 会随机分配。

LoadBalancer
apiVersion:v1kind:Servicemetadata:name:nginx-servicespec:type:LoadBalancerselector:app:nginxports:-port:80targetPort:80

特点

  • 在云环境(AWS、阿里云、腾讯云等)中,会自动创建云负载均衡器
  • 分配一个外部可访问的 IP(EXTERNAL-IP)
  • 会自动创建 NodePort 和 ClusterIP

访问方式

# 查看分配的公网 IPkubectl get svc nginx-service# 输出示例# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)# nginx-service LoadBalancer 10.96.10.90 47.102.34.56 80:32600/TCP# 通过公网 IP 访问curlhttp://47.102.34.56

💡类型关系:LoadBalancer ⊃ NodePort ⊃ ClusterIP。选择高级类型时,低级类型的能力也具备。

1.4 三种类型的对比选择

决策流程图

需要外部访问? ├─ 否 → ClusterIP(内部服务间通信) └─ 是 → 在哪个环境? ├─ 开发/测试 → NodePort(简单快速) └─ 生产环境 → LoadBalancer(配合 Ingress 使用)

生产环境最佳实践

  • 内部服务:使用 ClusterIP + DNS
  • 外部服务:使用 LoadBalancer + Ingress
  • NodePort 慎用:端口冲突、安全性差,仅用于临时测试

二、实战:为 Nginx 添加 Service

2.1 创建 Service YAML

创建一个文件nginx-service.yaml

apiVersion:v1kind:Servicemetadata:name:nginx-servicelabels:app:nginxspec:type:NodePort# 使用 NodePort 类型,方便测试访问selector:app:nginx# 选择带有 app=nginx 标签的 Podports:-name:nginx-portprotocol:TCPport:80# Service 的端口(集群内部访问)nodePort:32600# NodePort(外部访问)targetPort:80# 转发到 Pod 的 80 端口

字段解释

字段说明
selector关键字段,决定哪些 Pod 属于这个 Service
portService 自身的端口(ClusterIP 使用)
targetPortPod 容器的端口(流量最终转发到这里)
nodePort节点上开放的端口(NodePort 类型特有)

🔥坑点警示selector必须和 Deployment 中 Pod 的labels匹配!如果不匹配,Service 找不到 Pod,请求就会失败。

2.2 部署 Service

# 应用配置kubectl apply-fnginx-service.yaml# 预期输出# service/nginx-service created

2.3 验证 Service

# 查看 Service 详情kubectl get svc nginx-service-owide

预期输出

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR nginx-service NodePort 10.96.10.90 <none> 80:32600/TCP 77s app=nginx

字段说明

  • CLUSTER-IP:Service 的内部虚拟 IP
  • PORT(S):80 是 Service 端口,32600 是 NodePort
  • SELECTOR:标签选择器(app=nginx)

2.4 测试访问

# 通过 NodePort 访问(任意节点的 IP)curlhttp://192.168.0.112:32600# 或者本地测试curlhttp://localhost:32600

如果看到 Nginx 的欢迎页面,说明 Service 工作正常!


三、Scaling(扩容):应对流量增长

还记得文章开头的那个凌晨吗?如果当时我配置了多个 Pod,服务就不会崩了。

3.1 为什么要扩容?

单个 Pod 的问题:

  • 性能瓶颈:无法处理大量并发请求
  • 单点故障:Pod 挂了服务就不可用
  • 没有冗余:无法应对突发流量

扩容的价值

  • 提高吞吐量
  • 实现高可用
  • 负载均衡分散压力

3.2 手动扩容

方式一:修改 YAML

编辑nginx-deployment.yaml,修改replicas

spec:replicas:4# 从 1 改为 4

然后应用:

kubectl apply-fnginx-deployment.yaml
方式二:命令行快速扩容(推荐)
# 将 nginx-deployment 扩容到 4 个副本kubectl scale deployment nginx-deployment--replicas=4

优势:不需要修改 YAML 文件,快速响应。

3.3 验证扩容结果

# 查看 Deploymentkubectl get deployment nginx-deployment

预期输出

NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 4/4 4 4 47m

4/4表示:期望 4 个,实际可用 4 个。

# 查看 Podkubectl get pods-lapp=nginx

预期输出

NAME READY STATUS RESTARTS AGE nginx-deployment-746fbb99df-tdmb7 1/1 Running 0 48m nginx-deployment-746fbb99df-v6l9c 1/1 Running 0 2m nginx-deployment-746fbb99df-v8cm5 1/1 Running 0 2m nginx-deployment-746fbb99df-w4qqx 1/1 Running 0 2m

现在有4 个 Pod在运行,Service 会自动将请求负载均衡到这 4 个 Pod!

3.4 验证负载均衡

# 多次访问,观察请求被分发到不同 Podforiin{1..10};docurl-shttp://localhost:32600|grep"Welcome";done

虽然输出内容相同,但请求实际上被分发到了不同的 Pod。

3.5 自动扩容(HPA)

手动扩容还是不够灵活,生产环境通常使用HPA(Horizontal Pod Autoscaler)自动扩容。

# 创建 HPA,当 CPU 超过 50% 时自动扩容,最多 10 个 Podkubectl autoscale deployment nginx-deployment\--cpu-percent=50\--min=2\--max=10# 查看 HPAkubectl get hpa

HPA 工作原理

  1. 监控 Pod 的 CPU/内存使用率
  2. 超过阈值时自动增加 Pod 数量
  3. 低于阈值时自动减少 Pod 数量
  4. 保持在minmax之间

💡前置条件:HPA 需要 metrics-server 支持。如果没安装,参考前文部署章节。


四、滚动更新:零停机发布

4.1 为什么需要滚动更新?

传统的发布方式:

  1. 停止旧版本服务
  2. 部署新版本
  3. 启动新版本

问题:发布过程中服务不可用(停机时间)。

滚动更新的价值

  • 零停机:整个更新过程服务持续可用
  • 风险可控:逐步替换,有问题可以及时回滚
  • 用户体验好:用户无感知

4.2 滚动更新的原理

初始状态: Pod A (v1) Pod B (v1) Pod C (v1) Pod D (v1) ← 4个旧版本 更新过程: 1. 创建新 Pod E (v2),替换 Pod A (v1) Pod E (v2) Pod B (v1) Pod C (v1) Pod D (v1) 2. 创建新 Pod F (v2),替换 Pod B (v1) Pod E (v2) Pod F (v2) Pod C (v1) Pod D (v1) 3. 继续替换... 最终状态: Pod E (v2) Pod F (v2) Pod G (v2) Pod H (v2) ← 全部新版本

核心机制

  • 始终保证有一定数量的 Pod 可用
  • 新 Pod Ready 后才删除旧 Pod
  • Service 自动将流量切换到新 Pod

4.3 执行滚动更新

修改镜像版本

编辑nginx-deployment.yaml,修改镜像标签:

spec:template:spec:containers:-name:nginximage:nginx:1.8# 从 1.7.9 升级到 1.8ports:-containerPort:80
应用更新
kubectl apply-fnginx-deployment.yaml

4.4 观察更新过程

# 实时查看 Pod 变化watchkubectl get pods-lapp=nginx

你会看到这样的变化

# 初始状态 - 全是旧版本 nginx-deployment-746fbb99df-tdmb7 1/1 Running 0 52m nginx-deployment-746fbb99df-v6l9c 1/1 Running 0 6m nginx-deployment-746fbb99df-v8cm5 1/1 Running 0 6m nginx-deployment-746fbb99df-w4qqx 1/1 Running 0 6m # 更新中 - 新旧版本共存 nginx-deployment-746fbb99df-tdmb7 1/1 Terminating 0 52m # 旧版本被终止 nginx-deployment-7cd7fc4dbf-ckdtk 1/1 Running 0 5s # 新版本启动 nginx-deployment-746fbb99df-v6l9c 1/1 Running 0 6m ... # 最终状态 - 全是新版本 nginx-deployment-7cd7fc4dbf-ckdtk 1/1 Running 0 2m nginx-deployment-7cd7fc4dbf-m4ppb 1/1 Running 0 2m nginx-deployment-7cd7fc4dbf-pq27j 1/1 Running 0 2m nginx-deployment-7cd7fc4dbf-xjndw 1/1 Running 0 2m

注意:Pod 名称中间的哈希值变了(746fbb99df7cd7fc4dbf),说明 ReplicaSet 已更新。

4.5 查看更新状态

# 查看滚动更新状态kubectl rollout status deployment nginx-deployment# 预期输出# Waiting for deployment "nginx-deployment" rollout to finish: 2 of 4 updated replicas are available...# deployment "nginx-deployment" successfully rolled out

4.6 查看更新历史

# 查看 Deployment 的修订历史kubectl rollouthistorydeployment nginx-deployment# 预期输出# deployment.apps/nginx-deployment# REVISION CHANGE-CAUSE# 1 <none># 2 <none>

4.7 回滚到上一个版本

如果更新后发现问题,可以快速回滚:

# 回滚到上一个版本kubectl rollout undo deployment nginx-deployment# 回滚到指定版本kubectl rollout undo deployment nginx-deployment --to-revision=1# 验证回滚kubectl get pods-lapp=nginx

💡回滚原理:K8s 会保留旧的 ReplicaSet,回滚时只需切换回旧 ReplicaSet 即可,速度很快。

4.8 自定义滚动更新策略

可以精细控制滚动更新的行为:

apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-deploymentspec:replicas:4strategy:type:RollingUpdaterollingUpdate:maxSurge:1# 更新时最多可以超出的 Pod 数(绝对值或百分比)maxUnavailable:1# 更新时最多不可用的 Pod 数selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:-name:nginximage:nginx:1.8

参数说明

参数说明示例
maxSurge更新时可超出的 Pod 数量1表示最多比期望多 1 个 Pod
maxUnavailable更新时允许不可用的 Pod 数量1表示允许 1 个 Pod 不可用

不同场景的配置建议

场景maxSurgemaxUnavailable说明
快速更新100%0先创建全部新 Pod,再删除旧 Pod(需要双倍资源)
保守更新025%先删除旧 Pod,再创建新 Pod(资源占用少,但有不可用时间)
平衡方案25%25%默认值,平衡速度和可用性

五、完整实战:从单点到高可用

5.1 一键部署完整示例

创建一个完整的 YAML 文件nginx-ha.yaml

---# Deployment:部署应用apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-deploymentlabels:app:nginxspec:replicas:3# 3 个副本,实现高可用strategy:type:RollingUpdaterollingUpdate:maxSurge:1maxUnavailable:1selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:-name:nginximage:nginx:1.8ports:-containerPort:80resources:requests:cpu:100mmemory:128Milimits:cpu:200mmemory:256Mi---# Service:暴露服务apiVersion:v1kind:Servicemetadata:name:nginx-servicelabels:app:nginxspec:type:NodePortselector:app:nginxports:-port:80targetPort:80nodePort:32600---# HPA:自动扩容apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:nginx-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:nginx-deploymentminReplicas:3maxReplicas:10metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:50

部署:

kubectl apply-fnginx-ha.yaml

5.2 验证高可用配置

# 1. 查看 Deploymentkubectl get deployment nginx-deployment# 2. 查看 Pod(应该有 3 个)kubectl get pods-lapp=nginx# 3. 查看 Servicekubectl get svc nginx-service# 4. 查看 HPAkubectl get hpa nginx-hpa# 5. 测试访问curlhttp://localhost:32600

5.3 故障演练:验证高可用

# 1. 手动删除一个 Pod,模拟故障kubectl delete pod-lapp=nginx --grace-period=0--force# 2. 立即查看 Pod 状态kubectl get pods-lapp=nginx-w# 你会发现:# - 被删除的 Pod 变成 Terminating# - Deployment 立即创建新 Pod 补充# - 服务一直可用(因为还有 2 个 Pod 在运行)

这就是高可用的力量!


六、我踩过的坑

坑 1:Service 的 selector 写错

现象:Service 创建成功,但访问时连接超时。

原因selector和 Pod 的labels不匹配。

解决

# 检查 Service 的 selectorkubectl get svc nginx-service-oyaml|grepselector-A2# 检查 Pod 的 labelskubectl get pods-lapp=nginx --show-labels# 确保两者匹配

坑 2:NodePort 端口冲突

现象:Service 创建失败,提示端口已占用。

原因:指定的nodePort已被其他 Service 使用。

解决

# 查看所有 NodePortkubectl get svc --all-namespaces|grepNodePort# 不指定 nodePort,让 K8s 自动分配# 或者换一个未被使用的端口

坑 3:滚动更新时服务中断

现象:更新过程中,部分请求失败。

原因maxUnavailable设置过大,导致可用 Pod 太少。

解决

strategy:rollingUpdate:maxUnavailable:0# 不允许不可用 PodmaxSurge:1# 最多超出 1 个

坑 4:HPA 不生效

现象:CPU 飙高,但 Pod 没有自动扩容。

原因

  1. metrics-server 未安装
  2. 没有设置 resources.requests

解决

# 检查 metrics-serverkubectl get apiservices|grepmetrics# 确保 Pod 设置了 resourcesresources: requests: cpu: 100m# 必须设置,HPA 依赖这个值计算使用率

七、生产环境配置建议

7.1 Service 选择建议

场景推荐类型配置
内部服务间通信ClusterIP配合 CoreDNS
开发测试环境NodePort限制端口范围
生产环境对外LoadBalancer + Ingress使用云厂商 LB

7.2 副本数建议

环境建议副本数说明
开发环境1-2节省资源
测试环境2验证高可用
生产环境≥3跨节点分布,避免单点

7.3 滚动更新策略建议

strategy:type:RollingUpdaterollingUpdate:maxSurge:25%# 最多超出 25%maxUnavailable:25%# 最多不可用 25%

7.4 HPA 配置建议

spec:minReplicas:3# 最少 3 个,保证高可用maxReplicas:20# 最多 20 个,防止无限制扩容metrics:-type:Resourceresource:name:cputarget:averageUtilization:60# CPU 60% 时扩容

八、命令速查表

命令说明
kubectl get svc查看所有 Service
kubectl get svc -o wide查看 Service 详情
kubectl describe svc <name>查看 Service 详细信息
kubectl scale deployment <name> --replicas=4手动扩容
kubectl autoscale deployment <name> --cpu-percent=50 --min=2 --max=10创建 HPA
kubectl get hpa查看 HPA 状态
kubectl rollout status deployment <name>查看滚动更新状态
kubectl rollout history deployment <name>查看更新历史
kubectl rollout undo deployment <name>回滚到上一个版本
kubectl rollout undo deployment <name> --to-revision=2回滚到指定版本

总结

这篇文章,我们学习了 K8s 高可用的三大支柱:

1. Service:稳定的访问入口

  • ClusterIP:内部通信
  • NodePort:外部访问(开发测试)
  • LoadBalancer:生产环境配合云厂商

2. Scaling:应对流量增长

  • 手动扩容kubectl scale,快速响应
  • 自动扩容(HPA):根据 CPU/内存自动扩缩容

3. Rolling Update:零停机发布

  • 原理:逐步替换,保证可用性
  • 配置maxSurgemaxUnavailable
  • 回滚:一键回滚到上一个版本

从单点到高可用的转变

特性单点部署高可用部署
Pod 数量1≥3
故障影响服务中断自动恢复
发布方式停机更新零停机滚动更新
应对流量手动扩容自动扩容

建议收藏关注,持续更新 K8s 系列教程!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 4:47:54

计算机毕业设计之django基于计算机专业的考研志愿填报模拟系统

随着信息化时代的到来&#xff0c;网络系统都趋向于智能化、系统化&#xff0c;考研志愿填报模拟系统也不例外&#xff0c;但目前国内的考研志愿填报仍都使用人工管理&#xff0c;考研人数越来越多&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的…

作者头像 李华
网站建设 2026/6/11 4:43:51

Outfit字体:为你的品牌穿上最合适的“文字外衣“

Outfit字体&#xff1a;为你的品牌穿上最合适的"文字外衣" 【免费下载链接】Outfit-Fonts The most on-brand typeface 项目地址: https://gitcode.com/gh_mirrors/ou/Outfit-Fonts 你是否曾为寻找一款既专业又个性的字体而烦恼&#xff1f;&#x1f914; 在品…

作者头像 李华
网站建设 2026/6/11 4:38:21

111、【Agent】【OpenCode】todowrite 工具提示词(完结)

【声明】本博客所有内容均为个人业余时间创作&#xff0c;所述技术案例均来自公开开源项目&#xff08;如Github&#xff0c;Apache基金会&#xff09;&#xff0c;不涉及任何企业机密或未公开技术&#xff0c;如有侵权请联系删除 背景 上篇 blog 【Agent】【OpenCode】todowr…

作者头像 李华
网站建设 2026/6/11 4:31:52

手把手教你用STM32CubeMX配置MAX30102心率血氧模块(附OLED波形显示代码)

基于STM32CubeMX的MAX30102心率血氧监测系统开发实战在可穿戴设备和健康监测领域&#xff0c;光学心率血氧传感器已经成为标配硬件。MAX30102作为一款高度集成的生物传感器&#xff0c;配合STM32微控制器&#xff0c;能够快速搭建专业级的生理参数监测系统。本文将彻底摆脱传统…

作者头像 李华