Kubernetes 从入门到精通:云原生容器编排

文章目录

  • [Kubernetes 从入门到精通:云原生容器编排](#Kubernetes 从入门到精通:云原生容器编排)
    • [一、引言:当 200 个容器同时挂掉,手动恢复还来得及吗?](#一、引言:当 200 个容器同时挂掉,手动恢复还来得及吗?)
    • 二、核心架构:谁在替你盯着集群
    • [三、核心对象:Pod、Deployment、Service 三驾马车](#三、核心对象:Pod、Deployment、Service 三驾马车)
      • [3.1 Pod:最小的调度单元](#3.1 Pod:最小的调度单元)
      • [3.2 Deployment:声明式管理 Pod 副本](#3.2 Deployment:声明式管理 Pod 副本)
      • [3.3 Service:给 Pod 一个固定的"门牌号"](#3.3 Service:给 Pod 一个固定的“门牌号”)
    • [四、实战:从零部署一个 Web + Redis 应用](#四、实战:从零部署一个 Web + Redis 应用)
      • [4.1 环境准备与 Deployment 部署](#4.1 环境准备与 Deployment 部署)
      • [4.2 配置管理:ConfigMap 与 Secret](#4.2 配置管理:ConfigMap 与 Secret)
      • [4.3 存储:PV/PVC 解耦存储供应](#4.3 存储:PV/PVC 解耦存储供应)
    • 五、高级特性:自动扩缩与零停机发布
      • [5.1 HPA:按 CPU/内存自动扩缩副本](#5.1 HPA:按 CPU/内存自动扩缩副本)
      • [5.2 滚动更新与回滚](#5.2 滚动更新与回滚)
    • 六、网络与安全:从互通到可控
      • [6.1 网络模型与 CNI](#6.1 网络模型与 CNI)
      • [6.2 NetworkPolicy:控制 Pod 间流量](#6.2 NetworkPolicy:控制 Pod 间流量)
      • [6.3 RBAC:谁能动什么资源](#6.3 RBAC:谁能动什么资源)
    • 七、监控与日志:别等用户报警才知道故障
      • [7.1 监控:Prometheus + Grafana](#7.1 监控:Prometheus + Grafana)
      • [7.2 日志:EFK/EFK 栈](#7.2 日志:EFK/EFK 栈)
    • 八、生产最佳实践清单
    • 九、总结
    • 参考资料

Kubernetes 从入门到精通:云原生容器编排

一、引言:当 200 个容器同时挂掉,手动恢复还来得及吗?

Docker 解决了"在我机器上能跑"的问题,但当你把应用拆成几十个微服务、每个服务扩到 3 个副本,再加上测试环境和灰度发布,容器数量轻轻松松破百。这时候,谁去重启挂掉的容器?谁把流量切到健康的实例上?谁在新节点上自动补足缺失的副本?

这些问题不是靠写几个运维脚本就能解决的。你需要的是一个能持续观测集群状态、自动将实际状态修正为期望状态的控制系统------这就是 Kubernetes 被设计出来的目的。

Kubernetes(K8s)由 Google 基于内部 Borg 系统设计,现由 CNCF 维护。它不只是容器编排工具,更是一套分布式系统运行的通用底座:无论你在跑微服务、大数据任务还是机器学习训练,K8s 都能提供一致的调度、网络、存储和安全接口。

本文将沿着"核心架构→基础对象→实战部署→高级特性→生产运维"这条主线展开,每部分都会给出可直接应用的配置,以及我们在生产环境里真实踩过的坑。

二、核心架构:谁在替你盯着集群

Kubernetes 采用主从(Master-Worker)架构,所有组件协同工作,构成一个自愈的控制闭环。下面这张图帮助你从整体上把握各组件的角色和通信关系:
#mermaid-svg-aZX3au8Ah2pVebvW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aZX3au8Ah2pVebvW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aZX3au8Ah2pVebvW .error-icon{fill:#552222;}#mermaid-svg-aZX3au8Ah2pVebvW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aZX3au8Ah2pVebvW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aZX3au8Ah2pVebvW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aZX3au8Ah2pVebvW .marker.cross{stroke:#333333;}#mermaid-svg-aZX3au8Ah2pVebvW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aZX3au8Ah2pVebvW p{margin:0;}#mermaid-svg-aZX3au8Ah2pVebvW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aZX3au8Ah2pVebvW .cluster-label text{fill:#333;}#mermaid-svg-aZX3au8Ah2pVebvW .cluster-label span{color:#333;}#mermaid-svg-aZX3au8Ah2pVebvW .cluster-label span p{background-color:transparent;}#mermaid-svg-aZX3au8Ah2pVebvW .label text,#mermaid-svg-aZX3au8Ah2pVebvW span{fill:#333;color:#333;}#mermaid-svg-aZX3au8Ah2pVebvW .node rect,#mermaid-svg-aZX3au8Ah2pVebvW .node circle,#mermaid-svg-aZX3au8Ah2pVebvW .node ellipse,#mermaid-svg-aZX3au8Ah2pVebvW .node polygon,#mermaid-svg-aZX3au8Ah2pVebvW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aZX3au8Ah2pVebvW .rough-node .label text,#mermaid-svg-aZX3au8Ah2pVebvW .node .label text,#mermaid-svg-aZX3au8Ah2pVebvW .image-shape .label,#mermaid-svg-aZX3au8Ah2pVebvW .icon-shape .label{text-anchor:middle;}#mermaid-svg-aZX3au8Ah2pVebvW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aZX3au8Ah2pVebvW .rough-node .label,#mermaid-svg-aZX3au8Ah2pVebvW .node .label,#mermaid-svg-aZX3au8Ah2pVebvW .image-shape .label,#mermaid-svg-aZX3au8Ah2pVebvW .icon-shape .label{text-align:center;}#mermaid-svg-aZX3au8Ah2pVebvW .node.clickable{cursor:pointer;}#mermaid-svg-aZX3au8Ah2pVebvW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aZX3au8Ah2pVebvW .arrowheadPath{fill:#333333;}#mermaid-svg-aZX3au8Ah2pVebvW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aZX3au8Ah2pVebvW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aZX3au8Ah2pVebvW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aZX3au8Ah2pVebvW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aZX3au8Ah2pVebvW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aZX3au8Ah2pVebvW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aZX3au8Ah2pVebvW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aZX3au8Ah2pVebvW .cluster text{fill:#333;}#mermaid-svg-aZX3au8Ah2pVebvW .cluster span{color:#333;}#mermaid-svg-aZX3au8Ah2pVebvW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aZX3au8Ah2pVebvW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aZX3au8Ah2pVebvW rect.text{fill:none;stroke-width:0;}#mermaid-svg-aZX3au8Ah2pVebvW .icon-shape,#mermaid-svg-aZX3au8Ah2pVebvW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aZX3au8Ah2pVebvW .icon-shape p,#mermaid-svg-aZX3au8Ah2pVebvW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aZX3au8Ah2pVebvW .icon-shape .label rect,#mermaid-svg-aZX3au8Ah2pVebvW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aZX3au8Ah2pVebvW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aZX3au8Ah2pVebvW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aZX3au8Ah2pVebvW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Worker节点2
Worker节点1
Master节点
API Server
etcd
Scheduler
Controller Manager
Kubelet
Container Runtime
Kube-proxy
iptables/ipvs
Kubelet
Container Runtime
Kube-proxy
iptables/ipvs
kubectl/Client

各组件职责一句话总结:

组件 角色 你什么时候会跟它打交道
API Server 集群唯一入口,所有操作都走 REST API kubectl 命令的接收端
etcd 分布式 KV 存储,保存集群全部状态 备份恢复、性能调优时关注
Scheduler 把待调度的 Pod 绑定到合适的 Node Pod 长时间 Pending 时排查
Controller Manager 运行各种控制器,持续修正状态 Deployment、ReplicaSet 行为异常时关注
Kubelet 每个节点上的代理,管理 Pod 生命周期 节点 NotReady 时重点排查
Kube-proxy 维护网络规则,实现 Service 负载均衡 Service 访问不通时检查

踩坑记录 :刚接触 K8s 时,我曾经直接重启了 etcd 节点,导致整个集群状态丢失。etcd 是关键中的关键,任何对它的大动作都必须先做快照备份:ETCDCTL_API=3 etcdctl snapshot save snapshot.db

三、核心对象:Pod、Deployment、Service 三驾马车

3.1 Pod:最小的调度单元

Pod 是 Kubernetes 最基本的调度和运行单元。一个 Pod 可以包含一个或多个容器,这些容器共享网络命名空间(同一个 IP 和端口空间)和存储卷。绝大多数场景下,一个 Pod 只跑一个主容器,Sidecar 模式是主要例外。
#mermaid-svg-JwEtAmQTynYLpKqg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JwEtAmQTynYLpKqg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JwEtAmQTynYLpKqg .error-icon{fill:#552222;}#mermaid-svg-JwEtAmQTynYLpKqg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JwEtAmQTynYLpKqg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JwEtAmQTynYLpKqg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg .marker.cross{stroke:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JwEtAmQTynYLpKqg p{margin:0;}#mermaid-svg-JwEtAmQTynYLpKqg defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-JwEtAmQTynYLpKqg g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-JwEtAmQTynYLpKqg g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-JwEtAmQTynYLpKqg g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-JwEtAmQTynYLpKqg g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-JwEtAmQTynYLpKqg .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-JwEtAmQTynYLpKqg .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-JwEtAmQTynYLpKqg .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-JwEtAmQTynYLpKqg .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-JwEtAmQTynYLpKqg .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-JwEtAmQTynYLpKqg .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-JwEtAmQTynYLpKqg .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-JwEtAmQTynYLpKqg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JwEtAmQTynYLpKqg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JwEtAmQTynYLpKqg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JwEtAmQTynYLpKqg .edgeLabel .label text{fill:#333;}#mermaid-svg-JwEtAmQTynYLpKqg .label div .edgeLabel{color:#333;}#mermaid-svg-JwEtAmQTynYLpKqg .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-JwEtAmQTynYLpKqg .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-JwEtAmQTynYLpKqg .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-JwEtAmQTynYLpKqg .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JwEtAmQTynYLpKqg .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JwEtAmQTynYLpKqg #statediagram-barbEnd{fill:#333333;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JwEtAmQTynYLpKqg .cluster-label,#mermaid-svg-JwEtAmQTynYLpKqg .nodeLabel{color:#131300;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-JwEtAmQTynYLpKqg .note-edge{stroke-dasharray:5;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-note text{fill:black;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram-note .nodeLabel{color:black;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagram .edgeLabel{color:red;}#mermaid-svg-JwEtAmQTynYLpKqg #dependencyStart,#mermaid-svg-JwEtAmQTynYLpKqg #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-JwEtAmQTynYLpKqg .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JwEtAmQTynYLpKqg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pod 被创建,等待调度
调度成功,容器启动
所有容器正常退出
至少一个容器异常退出
节点失联,状态不可知
调度失败或镜像拉取失败
Pending
Running
Succeeded
Failed
Unknown

Pod 的状态流转是排查问题的第一切入点。Pending 卡太久?看调度器和镜像拉取。Running 但服务不通?看健康检查和端口映射。

3.2 Deployment:声明式管理 Pod 副本

不要直接在集群里 kubectl run 一个裸 Pod。使用 Deployment 来管理 Pod 的副本数、滚动更新和回滚。你只需要在 YAML 里声明"我想要 3 个副本",Deployment Controller 会驱动 ReplicaSet 去保证这个数量始终成立。
#mermaid-svg-mBpzp0L4TmpxaglY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mBpzp0L4TmpxaglY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mBpzp0L4TmpxaglY .error-icon{fill:#552222;}#mermaid-svg-mBpzp0L4TmpxaglY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mBpzp0L4TmpxaglY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mBpzp0L4TmpxaglY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mBpzp0L4TmpxaglY .marker.cross{stroke:#333333;}#mermaid-svg-mBpzp0L4TmpxaglY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mBpzp0L4TmpxaglY p{margin:0;}#mermaid-svg-mBpzp0L4TmpxaglY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mBpzp0L4TmpxaglY .cluster-label text{fill:#333;}#mermaid-svg-mBpzp0L4TmpxaglY .cluster-label span{color:#333;}#mermaid-svg-mBpzp0L4TmpxaglY .cluster-label span p{background-color:transparent;}#mermaid-svg-mBpzp0L4TmpxaglY .label text,#mermaid-svg-mBpzp0L4TmpxaglY span{fill:#333;color:#333;}#mermaid-svg-mBpzp0L4TmpxaglY .node rect,#mermaid-svg-mBpzp0L4TmpxaglY .node circle,#mermaid-svg-mBpzp0L4TmpxaglY .node ellipse,#mermaid-svg-mBpzp0L4TmpxaglY .node polygon,#mermaid-svg-mBpzp0L4TmpxaglY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mBpzp0L4TmpxaglY .rough-node .label text,#mermaid-svg-mBpzp0L4TmpxaglY .node .label text,#mermaid-svg-mBpzp0L4TmpxaglY .image-shape .label,#mermaid-svg-mBpzp0L4TmpxaglY .icon-shape .label{text-anchor:middle;}#mermaid-svg-mBpzp0L4TmpxaglY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mBpzp0L4TmpxaglY .rough-node .label,#mermaid-svg-mBpzp0L4TmpxaglY .node .label,#mermaid-svg-mBpzp0L4TmpxaglY .image-shape .label,#mermaid-svg-mBpzp0L4TmpxaglY .icon-shape .label{text-align:center;}#mermaid-svg-mBpzp0L4TmpxaglY .node.clickable{cursor:pointer;}#mermaid-svg-mBpzp0L4TmpxaglY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mBpzp0L4TmpxaglY .arrowheadPath{fill:#333333;}#mermaid-svg-mBpzp0L4TmpxaglY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mBpzp0L4TmpxaglY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mBpzp0L4TmpxaglY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mBpzp0L4TmpxaglY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mBpzp0L4TmpxaglY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mBpzp0L4TmpxaglY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mBpzp0L4TmpxaglY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mBpzp0L4TmpxaglY .cluster text{fill:#333;}#mermaid-svg-mBpzp0L4TmpxaglY .cluster span{color:#333;}#mermaid-svg-mBpzp0L4TmpxaglY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mBpzp0L4TmpxaglY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mBpzp0L4TmpxaglY rect.text{fill:none;stroke-width:0;}#mermaid-svg-mBpzp0L4TmpxaglY .icon-shape,#mermaid-svg-mBpzp0L4TmpxaglY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mBpzp0L4TmpxaglY .icon-shape p,#mermaid-svg-mBpzp0L4TmpxaglY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mBpzp0L4TmpxaglY .icon-shape .label rect,#mermaid-svg-mBpzp0L4TmpxaglY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mBpzp0L4TmpxaglY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mBpzp0L4TmpxaglY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mBpzp0L4TmpxaglY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} kubectl apply
创建并管理
维持副本数
维持副本数
维持副本数
滚动更新时
用户
Deployment
ReplicaSet
Pod 1
Pod 2
Pod 3
新 ReplicaSet
新 Pod
新 Pod

3.3 Service:给 Pod 一个固定的"门牌号"

Pod 的 IP 是临时的,Pod 重建后 IP 就变了。Service 通过标签选择器找到一组 Pod,并提供一个固定的 ClusterIP 和 DNS 名称,让调用方永远不需要关心后端 Pod 换了几个。
#mermaid-svg-33lnaFXas2lMtMM5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-33lnaFXas2lMtMM5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-33lnaFXas2lMtMM5 .error-icon{fill:#552222;}#mermaid-svg-33lnaFXas2lMtMM5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-33lnaFXas2lMtMM5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-33lnaFXas2lMtMM5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-33lnaFXas2lMtMM5 .marker.cross{stroke:#333333;}#mermaid-svg-33lnaFXas2lMtMM5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-33lnaFXas2lMtMM5 p{margin:0;}#mermaid-svg-33lnaFXas2lMtMM5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-33lnaFXas2lMtMM5 .cluster-label text{fill:#333;}#mermaid-svg-33lnaFXas2lMtMM5 .cluster-label span{color:#333;}#mermaid-svg-33lnaFXas2lMtMM5 .cluster-label span p{background-color:transparent;}#mermaid-svg-33lnaFXas2lMtMM5 .label text,#mermaid-svg-33lnaFXas2lMtMM5 span{fill:#333;color:#333;}#mermaid-svg-33lnaFXas2lMtMM5 .node rect,#mermaid-svg-33lnaFXas2lMtMM5 .node circle,#mermaid-svg-33lnaFXas2lMtMM5 .node ellipse,#mermaid-svg-33lnaFXas2lMtMM5 .node polygon,#mermaid-svg-33lnaFXas2lMtMM5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-33lnaFXas2lMtMM5 .rough-node .label text,#mermaid-svg-33lnaFXas2lMtMM5 .node .label text,#mermaid-svg-33lnaFXas2lMtMM5 .image-shape .label,#mermaid-svg-33lnaFXas2lMtMM5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-33lnaFXas2lMtMM5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-33lnaFXas2lMtMM5 .rough-node .label,#mermaid-svg-33lnaFXas2lMtMM5 .node .label,#mermaid-svg-33lnaFXas2lMtMM5 .image-shape .label,#mermaid-svg-33lnaFXas2lMtMM5 .icon-shape .label{text-align:center;}#mermaid-svg-33lnaFXas2lMtMM5 .node.clickable{cursor:pointer;}#mermaid-svg-33lnaFXas2lMtMM5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-33lnaFXas2lMtMM5 .arrowheadPath{fill:#333333;}#mermaid-svg-33lnaFXas2lMtMM5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-33lnaFXas2lMtMM5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-33lnaFXas2lMtMM5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-33lnaFXas2lMtMM5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-33lnaFXas2lMtMM5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-33lnaFXas2lMtMM5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-33lnaFXas2lMtMM5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-33lnaFXas2lMtMM5 .cluster text{fill:#333;}#mermaid-svg-33lnaFXas2lMtMM5 .cluster span{color:#333;}#mermaid-svg-33lnaFXas2lMtMM5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-33lnaFXas2lMtMM5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-33lnaFXas2lMtMM5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-33lnaFXas2lMtMM5 .icon-shape,#mermaid-svg-33lnaFXas2lMtMM5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-33lnaFXas2lMtMM5 .icon-shape p,#mermaid-svg-33lnaFXas2lMtMM5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-33lnaFXas2lMtMM5 .icon-shape .label rect,#mermaid-svg-33lnaFXas2lMtMM5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-33lnaFXas2lMtMM5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-33lnaFXas2lMtMM5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-33lnaFXas2lMtMM5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 访问 service-name
解析为 ClusterIP
负载均衡
负载均衡
负载均衡
集群内客户端
CoreDNS
Service: 10.96.0.1
Pod: app=my-app

IP: 10.244.1.2
Pod: app=my-app

IP: 10.244.2.3
Pod: app=my-app

IP: 10.244.3.4

Service 类型选择建议:

  • ClusterIP:集群内部通信,默认选择
  • NodePort:开发调试时暴露服务,不建议直接用于生产
  • LoadBalancer:对接云厂商 LB,生产环境入口

四、实战:从零部署一个 Web + Redis 应用

4.1 环境准备与 Deployment 部署

bash 复制代码
# 本地搭建集群(任选一种)
minikube start --cpus=2 --memory=4096
# 或
kind create cluster

创建 Web 应用的 Deployment:

yaml 复制代码
# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "500m"
            memory: "128Mi"

创建 Service 暴露服务:

yaml 复制代码
# web-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

部署 Redis:

yaml 复制代码
# redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        ports:
        - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: 6379

执行部署并验证:

bash 复制代码
kubectl apply -f web-deployment.yaml
kubectl apply -f web-service.yaml
kubectl apply -f redis-deployment.yaml

# 查看部署状态
kubectl get pods,svc
# 输出:web-app-xxx 三个 Pod Running,web-service 和 redis-service 已创建

4.2 配置管理:ConfigMap 与 Secret

ConfigMap 存储非敏感配置:

yaml 复制代码
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  REDIS_HOST: "redis-service"
  REDIS_PORT: "6379"

Secret 存储敏感信息(密码等):

yaml 复制代码
# app-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  REDIS_PASSWORD: cmVkaXNwYXNz  # base64 of "redispass"

在 Pod 中引用:

yaml 复制代码
# 在 Deployment 的 spec.template.spec.containers 下添加
envFrom:
- configMapRef:
    name: app-config
- secretRef:
    name: app-secret

4.3 存储:PV/PVC 解耦存储供应

对于 Redis 这种有状态服务,Pod 重建后数据必须保留。Kubernetes 通过 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)将存储的供应使用解耦。
#mermaid-svg-1JD4h5PkQxK9vkPk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1JD4h5PkQxK9vkPk .error-icon{fill:#552222;}#mermaid-svg-1JD4h5PkQxK9vkPk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1JD4h5PkQxK9vkPk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1JD4h5PkQxK9vkPk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1JD4h5PkQxK9vkPk .marker.cross{stroke:#333333;}#mermaid-svg-1JD4h5PkQxK9vkPk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1JD4h5PkQxK9vkPk p{margin:0;}#mermaid-svg-1JD4h5PkQxK9vkPk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster-label text{fill:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster-label span{color:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster-label span p{background-color:transparent;}#mermaid-svg-1JD4h5PkQxK9vkPk .label text,#mermaid-svg-1JD4h5PkQxK9vkPk span{fill:#333;color:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk .node rect,#mermaid-svg-1JD4h5PkQxK9vkPk .node circle,#mermaid-svg-1JD4h5PkQxK9vkPk .node ellipse,#mermaid-svg-1JD4h5PkQxK9vkPk .node polygon,#mermaid-svg-1JD4h5PkQxK9vkPk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1JD4h5PkQxK9vkPk .rough-node .label text,#mermaid-svg-1JD4h5PkQxK9vkPk .node .label text,#mermaid-svg-1JD4h5PkQxK9vkPk .image-shape .label,#mermaid-svg-1JD4h5PkQxK9vkPk .icon-shape .label{text-anchor:middle;}#mermaid-svg-1JD4h5PkQxK9vkPk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1JD4h5PkQxK9vkPk .rough-node .label,#mermaid-svg-1JD4h5PkQxK9vkPk .node .label,#mermaid-svg-1JD4h5PkQxK9vkPk .image-shape .label,#mermaid-svg-1JD4h5PkQxK9vkPk .icon-shape .label{text-align:center;}#mermaid-svg-1JD4h5PkQxK9vkPk .node.clickable{cursor:pointer;}#mermaid-svg-1JD4h5PkQxK9vkPk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1JD4h5PkQxK9vkPk .arrowheadPath{fill:#333333;}#mermaid-svg-1JD4h5PkQxK9vkPk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1JD4h5PkQxK9vkPk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1JD4h5PkQxK9vkPk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1JD4h5PkQxK9vkPk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1JD4h5PkQxK9vkPk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1JD4h5PkQxK9vkPk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster text{fill:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk .cluster span{color:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1JD4h5PkQxK9vkPk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1JD4h5PkQxK9vkPk rect.text{fill:none;stroke-width:0;}#mermaid-svg-1JD4h5PkQxK9vkPk .icon-shape,#mermaid-svg-1JD4h5PkQxK9vkPk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1JD4h5PkQxK9vkPk .icon-shape p,#mermaid-svg-1JD4h5PkQxK9vkPk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1JD4h5PkQxK9vkPk .icon-shape .label rect,#mermaid-svg-1JD4h5PkQxK9vkPk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1JD4h5PkQxK9vkPk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1JD4h5PkQxK9vkPk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1JD4h5PkQxK9vkPk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建 PV
创建 PVC
绑定
挂载
管理员
PersistentVolume

10Gi NFS
开发者
PersistentVolumeClaim

请求 1Gi
Redis Pod

创建 PVC:

yaml 复制代码
# redis-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

修改 Redis Deployment 挂载 PVC:

yaml 复制代码
# 在 redis Deployment 的 spec.template.spec 下添加
volumes:
- name: redis-data
  persistentVolumeClaim:
    claimName: redis-pvc
# 在 containers 下添加
volumeMounts:
- name: redis-data
  mountPath: /data

五、高级特性:自动扩缩与零停机发布

5.1 HPA:按 CPU/内存自动扩缩副本

手动调节副本数跟不上流量波动,HPA(Horizontal Pod Autoscaler)可以根据 CPU 或内存使用率自动增减 Pod。
#mermaid-svg-m8JBRHUhGSURBP8m{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-m8JBRHUhGSURBP8m .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m8JBRHUhGSURBP8m .error-icon{fill:#552222;}#mermaid-svg-m8JBRHUhGSURBP8m .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m8JBRHUhGSURBP8m .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m8JBRHUhGSURBP8m .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m8JBRHUhGSURBP8m .marker.cross{stroke:#333333;}#mermaid-svg-m8JBRHUhGSURBP8m svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m8JBRHUhGSURBP8m p{margin:0;}#mermaid-svg-m8JBRHUhGSURBP8m .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-m8JBRHUhGSURBP8m .cluster-label text{fill:#333;}#mermaid-svg-m8JBRHUhGSURBP8m .cluster-label span{color:#333;}#mermaid-svg-m8JBRHUhGSURBP8m .cluster-label span p{background-color:transparent;}#mermaid-svg-m8JBRHUhGSURBP8m .label text,#mermaid-svg-m8JBRHUhGSURBP8m span{fill:#333;color:#333;}#mermaid-svg-m8JBRHUhGSURBP8m .node rect,#mermaid-svg-m8JBRHUhGSURBP8m .node circle,#mermaid-svg-m8JBRHUhGSURBP8m .node ellipse,#mermaid-svg-m8JBRHUhGSURBP8m .node polygon,#mermaid-svg-m8JBRHUhGSURBP8m .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m8JBRHUhGSURBP8m .rough-node .label text,#mermaid-svg-m8JBRHUhGSURBP8m .node .label text,#mermaid-svg-m8JBRHUhGSURBP8m .image-shape .label,#mermaid-svg-m8JBRHUhGSURBP8m .icon-shape .label{text-anchor:middle;}#mermaid-svg-m8JBRHUhGSURBP8m .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m8JBRHUhGSURBP8m .rough-node .label,#mermaid-svg-m8JBRHUhGSURBP8m .node .label,#mermaid-svg-m8JBRHUhGSURBP8m .image-shape .label,#mermaid-svg-m8JBRHUhGSURBP8m .icon-shape .label{text-align:center;}#mermaid-svg-m8JBRHUhGSURBP8m .node.clickable{cursor:pointer;}#mermaid-svg-m8JBRHUhGSURBP8m .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m8JBRHUhGSURBP8m .arrowheadPath{fill:#333333;}#mermaid-svg-m8JBRHUhGSURBP8m .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m8JBRHUhGSURBP8m .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m8JBRHUhGSURBP8m .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8JBRHUhGSURBP8m .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m8JBRHUhGSURBP8m .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8JBRHUhGSURBP8m .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m8JBRHUhGSURBP8m .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m8JBRHUhGSURBP8m .cluster text{fill:#333;}#mermaid-svg-m8JBRHUhGSURBP8m .cluster span{color:#333;}#mermaid-svg-m8JBRHUhGSURBP8m div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-m8JBRHUhGSURBP8m .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m8JBRHUhGSURBP8m rect.text{fill:none;stroke-width:0;}#mermaid-svg-m8JBRHUhGSURBP8m .icon-shape,#mermaid-svg-m8JBRHUhGSURBP8m .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8JBRHUhGSURBP8m .icon-shape p,#mermaid-svg-m8JBRHUhGSURBP8m .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m8JBRHUhGSURBP8m .icon-shape .label rect,#mermaid-svg-m8JBRHUhGSURBP8m .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8JBRHUhGSURBP8m .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m8JBRHUhGSURBP8m .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m8JBRHUhGSURBP8m :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 采集 CPU/内存
target: CPU 50%
调整 replicas
Metrics Server
HPA Controller
Deployment
Pod 集合

配置示例:

yaml 复制代码
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

踩坑记录 :HPA 依赖 Metrics Server 提供指标数据。如果在集群里装完 HPA 发现一直 unknown,十有八九是 Metrics Server 没部署。执行 kubectl top nodes 验证,如果没有输出,先部署 Metrics Server。

5.2 滚动更新与回滚

Deployment 默认使用滚动更新,逐步替换旧 Pod,保证服务不中断。

更新策略控制:

yaml 复制代码
# 在 Deployment spec 下
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1   # 更新过程中最多允许不可用的 Pod 数
    maxSurge: 1         # 更新过程中最多允许超出期望的 Pod 数

回滚操作:

bash 复制代码
# 查看历史版本
kubectl rollout history deployment/web-app

# 回滚到上一个版本
kubectl rollout undo deployment/web-app

# 回滚到指定版本
kubectl rollout undo deployment/web-app --to-revision=2

六、网络与安全:从互通到可控

6.1 网络模型与 CNI

Kubernetes 网络模型有三个基本要求:

  • 所有 Pod 可以直接通信(无需 NAT)
  • 所有节点可以与所有 Pod 通信
  • Pod 看到的自己 IP 与其他 Pod 看到的一致

具体实现依赖 CNI 插件。常见选择:

插件 特点 适用场景
Flannel 简单易用,overlay 网络 小型集群、学习环境
Calico 高性能,支持 NetworkPolicy 生产环境,需要网络策略
Cilium 基于 eBPF,可观测性强 大规模集群,需要细粒度网络管控

6.2 NetworkPolicy:控制 Pod 间流量

Kubernetes 默认允许所有 Pod 之间通信。生产环境必须通过 NetworkPolicy 限制访问范围:

yaml 复制代码
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 80

踩坑记录:写了 NetworkPolicy 后发现不生效,排查很久才发现是 CNI 插件不支持。Flannel 默认不开启 NetworkPolicy,必须配合 Calico 或切换到 Canal 模式。

6.3 RBAC:谁能动什么资源

yaml 复制代码
# rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

七、监控与日志:别等用户报警才知道故障

7.1 监控:Prometheus + Grafana

Prometheus 是 Kubernetes 监控的事实标准。通过 ServiceMonitor 自动发现需要采集指标的目标:

yaml 复制代码
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: web-monitor
spec:
  selector:
    matchLabels:
      app: web
  endpoints:
  - port: metrics
    interval: 15s

7.2 日志:EFK/EFK 栈

Fluentd 以 DaemonSet 方式运行在每个节点上,收集容器标准输出并转发到 Elasticsearch,Kibana 提供可视化查询界面。关键配置:务必限制日志文件大小和轮转数量,避免磁盘写满。

bash 复制代码
# kubelet 日志轮转配置(在 /var/lib/kubelet/config.yaml)
containerLogMaxSize: "10Mi"
containerLogMaxFiles: 5

八、生产最佳实践清单

实践 为什么重要 怎么做
始终设置 resources 防止单个 Pod 吃光节点资源 requests + limits 必填
配置健康检查 流量只路由到健康实例 livenessProbe + readinessProbe
使用 PodDisruptionBudget 保证驱逐时有足够副本可用 minAvailable: 1
节点亲和性/反亲和性 控制 Pod 分布,提高容灾 podAntiAffinity 分散副本
定期备份 etcd 集群状态可恢复的最后防线 etcdctl snapshot save

九、总结

Kubernetes 的核心设计思想可以浓缩为一句话:声明期望状态,让控制器持续修正实际状态,直到两者一致。理解了这个闭环,再看 Pod、Deployment、Service、HPA 这些概念,它们就不再是一堆需要死记硬背的 YAML,而是这套思想在不同场景下的具体实现。

建议的学习路径:

  1. 入门:在 Minikube/Kind 上部署简单的 Deployment + Service,理解 Pod 的生命周期
  2. 进阶:配置 ConfigMap/Secret、PVC、HPA,完成滚动更新和回滚操作
  3. 精通:深入 NetworkPolicy、RBAC、自定义 CRD 和 Operator,学习服务网格(Istio)

Kubernetes 不是终点,而是你在云原生世界里的一块通用底板。掌握了它,你构建的分布式应用就天然具备了弹性、自愈和可移植的能力。

参考资料

相关推荐
zhangfeng11333 小时前
国家超算中心K8s 容器服务,新版容器和老版本的一些坑
云原生·容器·kubernetes
开发者联盟league15 小时前
使用k8s安装Sonarqube
云原生·容器·kubernetes
松岩19 小时前
网络问题导致 Pod Pending
kubernetes·aiops
运维老郭1 天前
Kubernetes 二进制部署完全指南:从零搭建生产级HA集群
运维·云原生·kubernetes
阿洛学长1 天前
Kubernetes超详细教程,从零开始学习k8s,从入门到实战
k8s·ks
成为你的宁宁1 天前
【K8S黑盒监控实践:Probe配置、Prometheus验证与Grafana可视化】
kubernetes·grafana·prometheus
成为你的宁宁1 天前
【Prometheus Operator监控K8S Nginx】
nginx·kubernetes·prometheus
宇明一不急1 天前
k8s headless svc
云原生·容器·kubernetes
成为你的宁宁1 天前
【K8S使用Helm部署MySQL一主多从并集成Prometheus监控】
mysql·kubernetes·prometheus