文章目录
- [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,而是这套思想在不同场景下的具体实现。
建议的学习路径:
- 入门:在 Minikube/Kind 上部署简单的 Deployment + Service,理解 Pod 的生命周期
- 进阶:配置 ConfigMap/Secret、PVC、HPA,完成滚动更新和回滚操作
- 精通:深入 NetworkPolicy、RBAC、自定义 CRD 和 Operator,学习服务网格(Istio)
Kubernetes 不是终点,而是你在云原生世界里的一块通用底板。掌握了它,你构建的分布式应用就天然具备了弹性、自愈和可移植的能力。