系列专栏《深入剖析 Kubernetes》· 基于张磊极客时间专栏思想整理 · 适合 CSDN 发布14 · 集群实战Metrics Server 部署与 HPA / Ingress 实测前两篇我们分别在「监控日志与 HPA 弹性伸缩」「容器网络」中建立了理论认知。本篇把理论搬到真实 4 节点集群1 Master 3 WorkerKubernetes v1.28.2上跑通三件最常被问到的事kubectl top为什么一开始用不了—— 部署Metrics ServerHPA 到底能不能自动扩缩—— 用 CPU 压测把它从 2 副本打到 10 副本Ingress 七层路由怎么暴露业务—— 用ingress-nginx把真实 nginx 通过域名nginx.local暴露出来。所有输出均来自真实集群踩坑一并记录。┌──────────────────────────────────────────┐ │ K8s Cluster │ kubectl top ─────────▶ │ Metrics Server (Deployment, 1 replica) │ HPA 读取指标 ◀────────│ │ 请求 kubelet /stats/summary │ │ ▼ │ │ kubelet (每个节点, :10250) ◀── cAdvisor │ │ │ HPA 控制器 ── 监控 CPU% ─▶ Deployment/hpa-demo ── 扩/缩 ──▶ Pod×N │ │ │ 外部浏览器 ── Host:nginx.local ─▶ ingress-nginx(NodePort 30080) │ │ 七层路由 │ ▼ │ Service/nginx ──▶ Pod(nginx:1.25) │ └──────────────────────────────────────────┘一、部署 Metrics Server让kubectl top说话Kubernetes 自身不采集资源指标。kubectl top的数据来自Metrics Servermetrics.k8s.io API它周期性地从每个节点的 kubelet 拉取/stats/summary。1.1 镜像与参数改造国内环境必做官方components.yaml默认从registry.k8s.io拉镜像国内不可达。两处必改# 1) 镜像换成阿里云同步源sed-is#registry.k8s.io/metrics-server/metrics-server:v0.7.2#registry.aliyuncs.com/google_containers/metrics-server:v0.7.2#gcomponents.yaml# 2) 自签证书 跳过 kubelet TLS 校验演示环境最简方案# 在 args 段追加# - --kubelet-insecure-tls# - --kubelet-preferred-address-typesInternalIP,ExternalIP,Hostname踩坑 1必须加--kubelet-insecure-tls。否则 Metrics Server 用 kubelet 的 API 证书做校验而我们的 kubelet 证书 SAN 里只有内网 IP校验会失败日志报x509: certificate is valid for ... not ...。1.2 部署与验证真实输出kubectl apply-fcomponents.yaml等待约 1 分钟APIService 变为AVAILABLETrueNAME SERVICE AVAILABLE AGE v1beta1.metrics.k8s.io kube-system/metrics-server True 54s此时kubectl top正式可用$ kubectltopnodes NAME CPU(cores)CPU% MEMORY(bytes)MEMORY% ecs-eb8a-0001 76m0% 1139Mi7% ecs-eb8a-0002 18m0% 714Mi4% ecs-eb8a-0003 16m0% 777Mi5% ecs-eb8a-0004 17m0% 692Mi4% $ kubectltoppods --all-namespaces --sort-bycpu NAMESPACE NAME CPU(cores)MEMORY(bytes)kube-system kube-apiserver-ecs-eb8a-0001 32m 232Mi kube-system etcd-ecs-eb8a-0001 11m 36Mi kube-system kube-controller-manager-ecs-eb8a-0001 7m 45Mi kube-system metrics-server-5c5f7f897b-57wcz 5m 16Mi default nginx-6cbd46d475-5slfj 1m 7Mi踩坑 2刚apply完立刻kubectl top会报Metrics API not available。这是正常的——APIService 聚合注册 Metrics Server 首次拉取需要几十秒等它AVAILABLE即可。二、HPA 自动伸缩实测2 副本 → 10 副本HPAHorizontalPodAutoscaler水平Pod自动伸缩器是「声明式 API 控制器模式」最直观的落地你声明「CPU 平均利用率不超过 50%」控制器持续比对实际值并调谐副本数。2.1 工作负载 HPA 定义apiVersion:apps/v1kind:Deploymentmetadata:{name:hpa-demo}spec:replicas:2template:spec:containers:-name:hpa-demoimage:nginx:1.25# 已离线分发到所有节点resources:requests:{cpu:100m,memory:64Mi}# 不设 limit压测时可真实冲高---apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:{name:hpa-demo}spec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:hpa-demominReplicas:2maxReplicas:10metrics:-type:Resourceresource:name:cputarget:{type:Utilization,averageUtilization:50}# 目标每副本 CPU ≈ 50mbehavior:scaleDown:stabilizationWindowSeconds:60# 缩容稳定窗口避免抖动HPA 计算的分母是你声明的 requests.cpu。所以requests.cpu不写HPA 就无法算利用率——这是新手最常见的「HPA 不生效」原因。2.2 压测在两个 Pod 里制造 CPU 忙循环forpin$(kubectl get pods-lapphpa-demo-ojsonpath{.items[*].metadata.name});dokubectlexec$p--sh-cnohup sh -c while true; do : ; done /dev/null 21 done2.3 真实结果自动扩容到上限负载施加约 100 秒后NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpa-demo Deployment/hpa-demo 200%/50% 2 10 10 2m44s $ kubectl get pods -l apphpa-demo -o wide NAME READY STATUS NODE hpa-demo-dcd8589df-6dzrn 1/1 Running ecs-eb8a-0003 hpa-demo-dcd8589df-qgsq9 1/1 Running ecs-eb8a-0004 hpa-demo-dcd8589df-bp7tz 1/1 Running ecs-eb8a-0004 hpa-demo-dcd8589df-c9vt4 1/1 Running ecs-eb8a-0003 hpa-demo-dcd8589df-mcrdw 1/1 Running ecs-eb8a-0003 hpa-demo-dcd8589df-rh76r 1/1 Running ecs-eb8a-0002 hpa-demo-dcd8589df-rl97d 1/1 Running ecs-eb8a-0004 hpa-demo-dcd8589df-s2nmw 1/1 Running ecs-eb8a-0002 hpa-demo-dcd8589df-vjp4t 1/1 Running ecs-eb8a-0004 hpa-demo-dcd8589df-wjjjf 1/1 Running ecs-eb8a-0002TARGETS 从0%/50%升到200%/50%副本数从 2 自动扩到 10命中maxReplicas且均衡散落到 3 个 Worker 节点。这正是「控制器调谐循环」┌────────────┐ 读取 ┌──────────────────┐ 实际状态 ──▶│ HPA 控制器 │◀────────│ Metrics Server │ (CPU 200%) └─────┬──────┘ └──────────────────┘ │ 调谐(Reconcile) ▼ ┌────────────┐ 计算 desired current/target × replicas │ Deployment │──▶ 副本 2 → 10 └────────────┘停掉负载、等待缩容稳定窗口60s后副本自动回缩到minReplicas2。扩容快、缩容稳这就是 HPA 的设计哲学。三、Ingress 七层路由实测用域名暴露真实 nginxClusterIP / NodePort 只能做四层IP端口暴露。要在80 端口用不同域名/路径路由到不同服务必须靠Ingress七层。3.1 部署 ingress-nginx精简版规避 webhook 复杂度采用旧版 controllerv1.10.1阿里云镜像以 NodePort 30080/30443 暴露便于从节点公网 IP 直接验证apiVersion:apps/v1kind:Deploymentmetadata:{name:nginx-ingress-controller,namespace:ingress-nginx}spec:template:spec:containers:-name:nginx-ingress-controllerimage:registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.10.1args:-/nginx-ingress-controller---default-backend-servicedefault/nginx# 复用 default/nginx 作默认后端---ingress-classnginx后端应用与 Ingress 规则apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:nginxannotations:kubernetes.io/ingress.class:nginxnginx.ingress.kubernetes.io/rewrite-target:/spec:ingressClassName:nginxrules:-host:nginx.localhttp:paths:-path:/pathType:Prefixbackend:{service:{name:nginx,number:80}}3.2 验证外部访问真实输出# 经 ingress-nginx 的 NodePort30080 Host 头访问curl-HHost: nginx.localhttp://节点公网IP:30080/返回真实 nginx 默认页!DOCTYPEhtmlhtmlheadtitleWelcome to nginx!/title/headbodyh1Welcome to nginx!/h1/body/html3.3 踩坑合集本篇最值钱的部分踩坑 3404缺 IngressClass。只写ingressClassName: nginx但集群里没有对应的 IngressClass 资源controller 不接纳该 Ingress请求落到 controller 内部默认 404。解决补一个IngressClass见deploy/ingress-class.yamlcontroller: k8s.io/ingress-nginx。踩坑 4503RBAC 缺endpointslices。旧版 controller 通过EndpointSlicesdiscovery.k8s.io获取后端端点。若 ClusterRole 只授权了老endpoints日志会报Service default/nginx does not have any active Endpoint外部访问得到 503。必须补-apiGroups:[discovery.k8s.io]resources:[endpointslices]verbs:[list,watch]-apiGroups:[coordination.k8s.io]# 领导者选举需要resources:[leases]verbs:[get,list,watch,create,update,patch]踩坑 5镜像拉取演示镜像走离线分发。公共镜像在 Worker 上拉取不稳。本集群把nginx:1.25在 Master 用ctr images export导出为 tar经内网 HTTP 分发到 3 个 Worker 后ctr images import并打标准 tagdocker.io/library/nginx:1.25Pod 用标准名即可命中本地镜像彻底绕开公网拉取。四、小结 / 核心要点Metrics Server 是kubectl top与 HPA 的前置依赖国内部署务必改镜像源 加--kubelet-insecure-tls。HPA 玩的是「声明式期望 vs 实际状态」的调谐本实测把 2 副本在 CPU 压测下自动扩到 10停载后回缩到 2。HPA 生效前提是 Pod 声明了requests.cpu否则无法计算利用率。Ingress 提供七层路由但旧版 ingress-nginx 对IngressClass与endpointslicesRBAC 有硬性要求漏掉任何一个都会以 404/503 形式坑你。镜像分发是国内部署第一痛点离线export/import 打标准 tag 是最稳妥的兜底方案。配套部署脚本与 YAML 见仓库deploy/metrics-components.yaml、hpa-demo.yaml、ingress-nginx-legacy.yaml、ingress-class.yaml、nginx-app-ingress.yaml。