第 1 章 背景与演进:为什么需要 Kubernetes
1.1 容器化带来的"幸福的烦恼"
Docker 让"构建一次,到处运行"成为现实,应用被封装成镜像后,开发、测试、生产环境的差异被大幅抹平。但当一个团队需要管理几十、几百甚至上千个容器时,单机 Docker 的局限立刻暴露:
| 痛点 | 具体表现 |
|---|---|
| 调度问题 | 容器该放在哪台机器上?如何根据 CPU / 内存合理分配? |
| 故障恢复 | 容器崩溃、节点宕机后谁来自动拉起?人工重启不可扩展 |
| 扩缩容 | 流量高峰时如何快速扩容?低谷时如何缩容省资源? |
| 服务发现 | 容器 IP 频繁变化,前端如何找到后端? |
| 滚动发布 | 如何做到不停机发布、失败自动回滚? |
| 配置管理 | 不同环境(dev / prod)的配置如何统一管理与注入? |
这些问题的本质是:容器的生命周期管理不能靠人肉完成,需要一套自动化系统------这就是容器编排器(Container Orchestrator)的使命。
1.2 编排器的核心职责
一个合格的编排器至少要回答三个问题:
- 放哪里跑(调度):把容器放到资源充足、负载合理的节点上;
- 跑得好不好(自愈):持续对比"期望状态"与"实际状态",出现偏差就纠正(容器挂了重启、节点挂了迁移);
- 怎么被找到(服务发现与负载均衡):给一组容器提供稳定的访问入口。
1.3 为什么是 Kubernetes 胜出
2014-2016 年间出现过 Docker Swarm、Apache Mesos、HashiCorp Nomad、Kubernetes 等多个编排方案。最终 Kubernetes 胜出,核心原因有四:
- Google Borg / Omega 的经验背书:K8s 脱胎于 Google 内部运行了十余年的 Borg 系统,设计上继承了大规模集群管理的实战沉淀,而非从零摸索;
- 声明式 API 而非命令式:用户只需描述"最终要达到什么状态"(如"我要 3 个副本"),系统自行完成达成路径;相比命令式指令,声明式天然支持自愈、审计与 GitOps;
- 开放生态与中立性:K8s 由 CNCF 托管,社区驱动,从容器运行时(CRI)、网络(CNI)、存储(CSI)到设备(Device Plugin)全部插件化,不绑定任何厂商;
- 扩展机制:CRD(CustomResourceDefinition)+ Operator 模式让用户能把任意业务系统"变成"一等公民资源,生态爆炸式增长。
如今 Kubernetes 已是云原生(Cloud Native)的技术底座,几乎所有公有云都提供托管 K8s(EKS / AKS / GKE / TKE 等),大量中间件(数据库、消息队列、AI 训练)都以"跑在 K8s 上"为默认交付形态。
1.4 一句话理解 Kubernetes
Kubernetes 是一个"声明式 + 自愈"的分布式系统控制平面:你告诉它世界应该长什么样(Desired State),它负责让世界变成那样,并一直保持那样。
它是操作系统级抽象------如果把数据中心比作一台巨型计算机,K8s 就是它的"操作系统内核",负责进程(Pod)调度、内存(Node 资源)分配、网络(Service)与存储(PV)管理。
第 2 章 架构与核心组件
Kubernetes 集群分为**控制面(Control Plane)与工作节点(Node / Worker)**两部分。控制面负责"决策",节点负责"干活",两者通过 HTTPS 通信。
2.1 控制面(Control Plane)
| 组件 | 职责 | 一句话理解 |
|---|---|---|
| kube-apiserver | 集群唯一入口,提供 REST API,处理所有读写请求并做认证、授权、准入控制(Admission Control) | 集群的"前台 + 总闸" |
| etcd | 分布式键值数据库,存储集群全部状态(资源对象、配置、期望状态) | 集群的"记忆"与唯一事实来源 |
| kube-scheduler | 为新创建的 Pod 挑选最合适的节点(综合资源、亲和性、污点、拓扑约束) | 集群的"房产中介" |
| kube-controller-manager | 运行各类控制器(ReplicationController、Deployment、Endpoint 等),执行"期望状态 → 实际状态"的控制回路 | 集群的"监工" |
| cloud-controller-manager(可选) | 对接云厂商 API,管理负载均衡器、节点、路由等云资源 | 云上的"接线员" |
2.2 工作节点(Node)
| 组件 | 职责 | 说明 |
|---|---|---|
| kubelet | 节点上的"管家",接收 API Server 指令,负责 Pod 的创建、启停、健康检查与状态上报 | 唯一直接操作容器的控制面代理 |
| kube-proxy | 维护节点上的网络规则(iptables / IPVS),实现 Service 的负载均衡与流量转发 | 只做数据面转发,不负责服务发现决策 |
| 容器运行时 | 实际运行容器的软件,如 containerd、CRI-O、Docker(已废弃) | 通过 CRI(Container Runtime Interface)接入 |
2.3 一次部署请求的完整流转
以 kubectl apply -f deployment.yaml 为例,从提交到运行经过 6 个环节:
kubectl ──①──▶ kube-apiserver ──②──▶ etcd
│ ③
▼
kube-scheduler(为 Pod 选节点)
│ ④ 写回 Pod 的 nodeName 字段
▼
kube-apiserver
│ ⑤ Watch 到调度结果
▼
kubelet(调用容器运行时创建容器)
│ ⑥ 上报 Pod 状态
▼
kube-apiserver ──▶ etcd(状态收敛到期望值)
关键点:所有组件都不直接互相调用,只与 API Server 通信 ;kubelet 等组件通过 Watch(长连接监听) 感知资源变化,而不是轮询。
2.4 自愈能力的根源:控制回路(Reconcile Loop)
Kubernetes 的核心设计思想是期望状态(Desired State)与现实状态(Current State)的循环比对:
期望状态(etcd 中的 YAML 描述)
│ 控制器 Watch
▼
控制器比对 ── 有偏差?── 否 ──▶ 保持不动(什么都不做)
│ 是
▼
执行纠正动作(创建 / 删除 / 重启 / 扩缩容)
│
▼
现实状态上报(kubelet 等)──▶ 回到比对
这就是为什么"删掉一个 Pod,它会被自动重建"------不是某个组件盯着 Pod,而是 ReplicaSet 控制器发现"实际副本数 2 < 期望副本数 3",于是主动补建。理解了这个循环,就理解了 K8s 80% 的"魔法"。
第 3 章 核心概念与工作负载资源
3.1 Namespace:集群内的"逻辑分区"
Namespace 用于在同一个集群内做资源隔离与权限划分(如 dev / test / prod),资源名在 Namespace 内唯一。注意:Namespace 是逻辑隔离而非硬性安全隔离,跨 Namespace 的网络默认也互通。
# 创建 Namespace
apiVersion: v1
kind: Namespace
metadata:
name: dev
常用命令:kubectl create ns dev、kubectl get ns、kubectl -n dev get pods。
3.2 Pod:调度与运行的最小单元
Pod 是 K8s 中可以创建和管理的最小计算单元,一个 Pod 可包含一个或多个容器。同 Pod 内容器:
- 共享同一个网络命名空间(共享 IP、端口空间),通过 localhost 互通;
- 共享同一个存储卷(Volume);
- 由一个"暂停容器(pause / sandbox)"先占位拉起网络,业务容器随后加入。
为什么用 Pod 而不是直接调度容器? 因为"调度单位"需要比"进程"更大一些:关系紧密的一组进程(如主进程 + sidecar 日志采集 + 本地代理)必须同生共死、同节点运行,Pod 就是这层抽象。日常场景几乎不直接创建 Pod,而是通过 Deployment 等工作负载管理。
3.3 工作负载(Workload)资源选型
| 工作负载 | 有无状态 | 运行方式 | 典型场景 | 关键特性 |
|---|---|---|---|---|
| Deployment | 无状态 | 常驻 | Web / API / 微服务 | 管理 ReplicaSet,支持滚动更新、回滚、水平扩缩容 |
| StatefulSet | 有状态 | 常驻 | 数据库、消息队列、分布式存储 | 稳定网络标识(Pod 名 + 序号)、稳定存储(PVC 按序绑定)、顺序部署/删除 |
| DaemonSet | 无状态 | 每节点一个 | 日志采集(Fluentd)、监控(node-exporter)、网络插件 | 新节点加入自动部署,节点删除自动清理 |
| Job / CronJob | 无状态 | 一次性 / 定时 | 数据迁移、批处理、定期备份 | 运行完成即结束,CronJob 按 cron 表达式定时触发 |
选型口诀:常驻 + 无状态 → Deployment;常驻 + 有状态 → StatefulSet;每节点必须有一个 → DaemonSet;跑完就走 / 定时 → Job / CronJob。
3.4 配置解耦:ConfigMap 与 Secret
- ConfigMap:存放非敏感配置(环境变量、配置文件内容、命令行参数)。
- Secret:存放敏感信息(密码、Token、证书),以 base64 形式存储(注意:base64 只是编码不是加密,详见第 7 章坑位)。
两者都可以通过环境变量 或挂载为文件 的方式注入 Pod。挂载方式支持热更新(Volume 方式更新的文件,K8s 会周期性同步),环境变量方式不支持运行时更新(重建 Pod 才生效)。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: production
config.yaml: |
server:
port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
image: nginx:1.27
envFrom:
- configMapRef:
name: app-config
volumeMounts:
- name: cfg
mountPath: /etc/app
volumes:
- name: cfg
configMap:
name: app-config
3.5 Service 与 Ingress:访问入口
- Service:为一组 Pod 提供稳定的虚拟 IP(ClusterIP)与 DNS 名,内置负载均衡,是 K8s 内部流量的"路由器";
- Ingress:集群入口层的"反向代理规则",负责把外部 HTTP(S) 流量按域名 / 路径路由到不同 Service(需配合 Ingress Controller 实现,如 Nginx Ingress、Traefik)。
两者职责不同:Service 解决"Pod 之间怎么找到对方",Ingress 解决"外部怎么进到集群"。详见第 6 章。
第 4 章 Kubernetes API 体系详解
Kubernetes 的一切操作最终都是对 API Server 的 REST 请求。kubectl 只是 API 的客户端封装,理解 API 模型才能真正理解 K8s。
4.1 API 三级模型:Group / Version / Resource
每个资源类型都归属于某个 API Group ,并且有自己的 Version:
/api/v1/namespaces/{ns}/pods/{name} → 核心组(core,无 group 名)
/apis/apps/v1/deployments → apps 组
/apis/batch/v1/jobs → batch 组
/apis/networking.k8s.io/v1/ingresses → networking.k8s.io 组
为什么分组? 不同领域(工作负载 / 调度 / 网络 / 存储)独立演进,各有自己的版本节奏,互不阻塞。
| 版本等级 | 含义 | 稳定性 |
|---|---|---|
| alpha(v1alpha1) | 试验特性,可能有破坏性变更,默认关闭 | 不稳定,仅评估用 |
| beta(v1beta1) | 已基本可用,默认开启 | 较稳定,可能有小变更 |
| stable(v1) | 正式 GA,长期兼容 | 稳定,可放心用于生产 |
生产环境必须优先使用 stable(v1) API。K8s 对废弃 API 的移除有明确的节奏(N-3 规则,即某 API 在版本 N 废弃后,至少要到版本 N+3 才移除),升级集群前务必检查待删除的 API。
4.2 资源对象的元结构:metadata / spec / status
任意 K8s 资源对象都遵守同一三元结构:
| 字段 | 谁负责写 | 作用 |
|---|---|---|
| metadata | 用户 | 名称、命名空间、标签(labels)、注解(annotations)、UID、资源版本(resourceVersion) |
| spec | 用户 | 期望状态:用户声明的"世界应该长什么样" |
| status | 控制器 / kubelet | 实际状态:系统观测到的"世界现在长什么样",只读 |
kubectl apply 的核心机制:用户提交完整的 spec,API Server 用 Server-Side Apply / 三方合并 计算差异后更新,而不是简单整体覆盖。这是 GitOps 能够落地的底层保证。
4.3 kubectl 与 API 的对应关系
| kubectl 命令 | HTTP 方法 | 对应 API 操作 | 说明 |
|---|---|---|---|
| kubectl create -f x.yaml | POST | /apis/apps/v1/namespaces/{ns}/deployments | 创建新资源 |
| kubectl get deployments | GET | 同上的 LIST | 列出资源 |
| kubectl get deployment myapp -o yaml | GET | /apis/apps/v1/.../deployments/myapp | 读取单个资源 |
| kubectl apply -f x.yaml | PATCH(Server-Side Apply) | 同上 | 声明式更新,推荐 |
| kubectl delete deployment myapp | DELETE | 同上 | 删除资源 |
| kubectl exec -it pod -- bash | 升级为 SPDY/WebSocket | 子资源 exec | 进入容器执行命令 |
所有请求都经过认证(Authentication)→ 授权(Authorization,RBAC)→ 准入控制(Admission)三道关卡才写入 etcd。
4.4 认证与授权:RBAC 三要素
RBAC(Role-Based Access Control)由三类对象组成:
-
Role / ClusterRole:定义"能做什么"(对哪些资源有哪些操作权限,如 get/list/watch pods);
-
ServiceAccount:定义"是谁"(Pod 内部的身份,区别于人类用户);
-
RoleBinding / ClusterRoleBinding:把"身份"与"权限"绑定。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-bind
namespace: dev
subjects:- kind: ServiceAccount
name: ci-bot
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
- apiGroups: [""]
4.5 资源发现与调试 API
bash
# 查看集群支持的 API 组与版本
kubectl api-versions
# 查看某类资源的可用版本(含 alpha/beta/stable 全部)
kubectl api-resources | grep deployment
# 查看某资源对象的详细 YAML 定义(含可写字段)
kubectl explain deployment.spec.template.spec.containers.resources
kubectl explain 是学习 K8s API 的最佳助手:任何字段的合法取值、必填与否、含义都能在线查到,比死记文档高效得多。
4.6 扩展机制:CRD 与 Aggregated API
- CRD(CustomResourceDefinition):用户自定义资源类型(如 CronTab、MySQLCluster),创建后即可用 kubectl 管理;
- Operator 模式:CRD + 自定义控制器,把运维专家经验固化为代码,让 K8s 自动运维复杂应用(如 etcd-operator、prometheus-operator)。
这正是 K8s"平台化"能力的关键:API 是可扩展的,而不仅是固定的资源清单。
第 5 章 详细使用说明:从部署到运行的完整链路
5.1 环境搭建:三种方式怎么选
| 方式 | 适用场景 | 说明 |
|---|---|---|
| minikube / kind | 本地学习、快速验证 | 单节点,分钟级起集群,推荐入门 |
| kubeadm | 自建生产集群 | 官方引导工具,需自行运维 etcd 高可用、证书、网络插件 |
| 托管云 K8s(EKS / AKS / GKE / TKE) | 生产主力 | 控制面免运维,按节点付费,推荐企业使用 |
5.2 最小 YAML:把一个镜像跑起来
以部署 nginx 为例,最小集合是 Deployment + Service 两个对象:
# ① Deployment:声明期望状态
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-demo
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
---
# ② Service:暴露给其他 Pod / 外部
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
bash
kubectl apply -f nginx.yaml
kubectl get deployment,rs,pods,svc -l app=nginx
重要:spec.selector.matchLabels 必须与 Pod 模板的 metadata.labels 一致,这是控制器"认领"Pod 的依据,写错会导致 Deployment 无法管理 Pod。
5.3 暴露服务:外部流量怎么进集群
| 方式 | 原理 | 适用场景 | 局限 |
|---|---|---|---|
| ClusterIP(默认) | 集群内虚拟 IP + DNS,仅集群内可访问 | 内部服务调用 | 外部无法访问 |
| NodePort | 在每个节点上开一个端口(30000-32767),转发到 Service | 测试、临时暴露 | 端口范围有限、需自行管理入口 |
| LoadBalancer | 云厂商创建负载均衡器(ELB / SLB)指向 NodePort | 生产直接暴露 | 每个 Service 一个 LB,成本高 |
| Ingress | Ingress Controller(Nginx 等)按域名 / 路径路由 | 生产 HTTP(S) 入口 | 只支持 HTTP/HTTPS,需安装 Controller |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
5.4 配置与密钥注入
推荐用 ConfigMap / Secret 挂载文件(支持热更新)或 envFrom 注入环境变量。注意:
- Secret 的 value 必须是 base64 编码(echo -n 'xxx' | base64);
- 敏感信息建议用 ExternalSecret / SOPS 等外部方案管理,避免明文入库;
- 配置变更后 Pod 不会自动重启,需要 kubectl rollout restart deployment/myapp。
5.5 存储挂载
无状态应用推荐用 emptyDir (临时)或 PVC(持久);有状态应用必须用 PVC + StorageClass 动态供给。最小 PVC 挂载示例:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
# Deployment 中使用
spec:
template:
spec:
containers:
- name: app
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
5.6 滚动更新、回滚与扩缩容
# 更新镜像并滚动发布(默认 maxUnavailable=25%, maxSurge=25%)
kubectl set image deployment/myapp app=nginx:1.28
# 查看发布状态
kubectl rollout status deployment/myapp
# 暂停 / 恢复(金丝雀发布常用)
kubectl rollout pause deployment/myapp
kubectl rollout resume deployment/myapp
# 回滚到上一个版本(或指定版本)
kubectl rollout undo deployment/myapp
kubectl rollout history deployment/myapp
# 手工扩缩容
kubectl scale deployment/myapp --replicas=5
# 自动扩缩容(HPA:按 CPU 利用率 70% 自动伸缩)
kubectl autoscale deployment/myapp --min=2 --max=10 --cpu-percent=70
HPA 生效前提:Pod 必须声明 resources.requests(HPA 依赖其计算利用率),且集群已安装 Metrics Server。
5.7 kubectl 常用命令速查矩阵
| 场景 | 命令 |
|---|---|
| 查看所有资源 | kubectl get all |
| 查看 Pod 详情与事件 | kubectl describe pod <name> |
| 查看实时日志 | kubectl logs -f <pod> -c 容器名 |
| 进入容器 | kubectl exec -it <pod> -- /bin/sh |
| 端口转发(本地调试) | kubectl port-forward svc/nginx-svc 8080:80 |
| 切换上下文 | kubectl config use-context <name> |
| 查看当前上下文 | kubectl config current-context |
| 查看集群事件 | kubectl get events --sort-by='.lastTimestamp' |
| 命令自动补全 | source <(kubectl completion bash)(bash) |
第 6 章 网络与存储机制
6.1 Pod 网络模型与 CNI
K8s 网络模型有 3 条铁律(无论使用什么插件都必须满足):
- 每个 Pod 拥有独立的 IP(同节点 Pod 也要能通过 IP 互通);
- 所有节点上的 Pod 之间无 NAT 直连(集群内任何 Pod 到任何 Pod 都可直达);
- Pod 看到的网络与节点网络不同,由 CNI(Container Network Interface) 插件负责打通。
主流 CNI 插件对比:
| 插件 | 模式 | 特点 | 适用 |
|---|---|---|---|
| Flannel | Overlay(VXLAN) | 简单易用、性能一般 | 小型集群、入门 |
| Calico | BGP / 路由 | 性能好、支持 NetworkPolicy | 中大型集群首选之一 |
| Cilium | eBPF | 性能极佳、可观测性强、支持 NetworkPolicy | 高性能 / 安全敏感场景 |
注意:Service 的 ClusterIP 是虚拟 IP,由 kube-proxy 用 iptables / IPVS 规则转发到真实 Pod,不参与 CNI 路由。
6.2 Service 三种类型的工作原理
以最常见的 ClusterIP 为例,访问链路为:
客户端 → ClusterIP:Port → kube-proxy 规则(iptables/IPVS)→ 随机选择一个后端 Pod
↑
通过 EndpointSlice(Pod IP 列表)实时更新
- ClusterIP:虚拟 IP,仅集群内可达,负载均衡到后端 Pod;
- NodePort:在 ClusterIP 基础上,每个节点额外开放一个端口(默认 30000-32767),外部 → NodeIP:NodePort → ClusterIP → Pod;
- LoadBalancer:在 NodePort 基础上,云厂商再创建一个外部负载均衡器,流量 外部 → LB → NodePort → Pod。
关键认知:三种类型是"叠加"关系,不是三选一的独立方案;externalTrafficPolicy: Local 可保留客户端源 IP,但会失去跨节点负载均衡。
6.3 Ingress 与 Ingress Controller
Ingress 本身只是一组规则声明 (哪个域名、哪个路径 → 哪个 Service),真正干活的是 Ingress Controller(如 Nginx Ingress Controller、Traefik、ALB Ingress):
外部请求 → LoadBalancer(或 NodePort) → Ingress Controller(Pod) → 按规则路由 → Service → Pod
从 K8s 1.19 起 Ingress 的 apiVersion 为 networking.k8s.io/v1(旧版 extensions/v1beta1 已废弃移除);1.21 起建议显式指定 ingressClassName。
6.4 集群 DNS:CoreDNS
K8s 内置 CoreDNS,为 Service 提供域名解析。命名规则:
<service-name>.<namespace>.svc.cluster.local
因此同 Namespace 内可直接用 service-name 访问,跨 Namespace 用 service-name.namespace。注意:/etc/hosts 不生效,Pod 内 DNS 由 CoreDNS 统一管理。
6.5 存储:PV / PVC / StorageClass 三层模型
| 对象 | 角色 | 谁创建 |
|---|---|---|
| PV(PersistentVolume) | 集群级存储资源(一块"硬盘") | 管理员静态创建,或 StorageClass 动态创建 |
| PVC(PersistentVolumeClaim) | 用户对存储的"申请单"(我要 10Gi 读写一块) | 用户 / 工作负载 |
| StorageClass | 存储"模板"(对接云盘 / NFS / 本地盘) | 管理员,用于动态供给 |
动态供给流程:
用户创建 PVC → 控制器看到 StorageClass → 调用云厂商 CSI 驱动创建云盘 → 生成 PV 并绑定 PVC → Pod 挂载
**回收策略(reclaimPolicy)**三选一:
| 策略 | 含义 | 适用 |
|---|---|---|
| Delete(默认,动态供给) | 删除 PVC 时连带删除底层存储(数据丢失!) | 无状态数据、可重建 |
| Retain | 删除 PVC 后 PV 保留,需管理员手动处理 | 生产数据、数据库备份 |
| Recycle(已废弃) | 旧版清理后复用 | 不推荐 |
高频事故:误删 PVC 后"云盘没了、数据没了"------因为默认是 Delete 策略。生产库务必确认回收策略为 Retain,并做好备份。
6.6 有状态应用与 StatefulSet 的存储约定
StatefulSet 的每个副本(Pod-0、Pod-1...)按序号绑定独立 PVC (volumeClaimTemplates),删除 Pod 后重新创建仍绑定原 PVC,数据不丢。这也是它适合跑数据库的原因:每个实例有专属、稳定的存储身份。
第 7 章 常错点与坑:高频踩坑指南
排障方法论:先 kubectl describe 看事件 → 再 kubectl logs 看日志 → 最后看 kubectl get events 全局事件。多数问题 5 分钟内可定位。
7.1 启动失败类:ImagePullBackOff / ErrImagePull
| 现象 | 根因 | 排查 / 解法 |
|---|---|---|
| ImagePullBackOff、ErrImagePull | 镜像名写错、Tag 不存在、私有仓库认证失败、镜像拉取被限流 | kubectl describe pod 看 Events 的拉取错误原文;docker pull 本地验证;私有仓库配置 imagePullSecrets;确认镜像名含正确 Tag 而非 latest 裸用 |
| InvalidImageName | 镜像名格式非法(如多写分隔符) | 检查 YAML 镜像字段 |
| 一直 ContainerCreating | 拉取超大镜像 / 存储驱动问题 | 事件定位,必要时优化镜像大小或预热 |
7.2 CrashLoopBackOff:容器反复崩溃
| 根因 | 特征 | 解法 |
|---|---|---|
| 应用启动即报错(依赖的 DB / 配置缺失) | 日志有明显报错 | 看 kubectl logs 修复应用配置 |
| 启动命令写错(command / args 覆盖了镜像默认入口) | 日志提示 command not found | 检查容器的 command / args |
| 探针误配:livenessProbe 太严格导致健康检查失败被杀 | 日志正常但 Pod 反复重启 | 调大 initialDelaySeconds / periodSeconds / failureThreshold;区分 liveness(活不活,杀)与 readiness(能不能接流量,摘流量不杀) |
| 资源限制太小(OOMKilled) | Events 显示 OOMKilled | 调大 resources.limits.memory,见 7.4 |
| 启动后立即退出(一次性任务误用常驻工作负载) | 日志显示正常结束 | Job 场景改用 Job / CronJob |
7.3 探针三连问(最高频的"玄学"坑)
-
livenessProbe 挂了 → K8s 杀容器重启:适合"进程活着但死锁"的场景;不适合启动慢的应用(会反复被杀);
-
readinessProbe 失败 → 只是从 Service 摘流量,不杀容器:用于"还没准备好"的优雅处理;
-
startupProbe 存在时,liveness 在其成功前不生效:慢启动应用用 startupProbe 兜底。
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
常见翻车:探针路径写错(404)、依赖外部组件导致探针误报、探针超时(timeoutSeconds 默认 1s 太短)。
7.4 资源请求 / 限制的坑
- 只配 limit 不配 request:调度时按 request 分配资源,limit 只做运行期上限;Pod 可能因 limit 过高被调度到资源不足的节点然后 OOM;反之只配 request 不配 limit,突发流量可能把节点打爆;
- CPU 是压缩资源:超过 limit 会被限流(throttling),表现为响应变慢而不是崩溃,性能排查时 container_cpu_cfs_throttled 指标暴涨即为此因;
- memory 是非压缩资源:超过 limit 直接 OOMKilled;
- request == limit 才是"Guaranteed" QoS:生产建议所有关键服务都配齐,避免被系统驱逐(Eviction)。
7.5 配置与 Secret 的坑
- ConfigMap / Secret 改了不生效 :Volume 挂载方式约 1 分钟同步,但环境变量注入不热更新 ,需要 kubectl rollout restart;且更新 ConfigMap 时引用它的 Deployment 不会自动重建 Pod------不要以为改了配置就会自动生效;
- Secret 是 base64 而非加密:kubectl get secret -o yaml 可直接解码明文,绝不要把 Secret 提交到公开仓库;
- Secret 无法直接更新被大量 Deployment 引用的场景:考虑 ExternalSecret / SOPS 等外部密钥方案;
- 镜像 Tag 用 latest :更新镜像后 kubectl rollout restart 可能拉不到新版本(节点缓存),生产必须用不可变 Tag(如 v1.2.3 或 commit SHA)。
7.6 存储的坑
- PVC 删除即数据丢失:动态供给默认 reclaimPolicy: Delete,删 PVC 云盘随之删除(见 6.5);
- PVC 扩容限制:accessModes 与存储类决定了能否在线扩容(ReadWriteOnce 可扩容,但部分存储类不支持缩小);
- StatefulSet 删 Pod 不删 PVC:需要手动清理 PVC,否则重建同名 Pod 会用旧数据(可能正是你想要的,也可能导致"数据残留"事故);
- emptyDir 在 Pod 删除后消失:跨 Pod 生命周期持久化数据必须用 PVC。
7.7 网络与入口的坑
- NodePort 端口冲突:默认范围 30000-32767,多个 Service 抢同一端口报错;
- Service selector 写错:后端 Pod 列表为空 → 访问 Connection Refused,用 kubectl get endpoints 检查是否有 Endpoint;
- 跨 Namespace 访问忘加域名后缀:svc.namespace 才是全名;
- Ingress 不生效:忘记安装 Ingress Controller、ingressClassName 未指定、TLS 证书格式错误(必须 PEM 格式含证书链);
- externalTrafficPolicy: Cluster(默认)丢失客户端源 IP:日志里全是节点 IP,需要改 Local。
7.8 版本与升级的坑
- API 版本被移除:升级集群前用 kubectl convert 或查阅 Release Notes 迁移废弃 API(如 extensions/v1beta1 Ingress、apps/v1beta1 Deployment);
- kubectl 与集群版本不匹配:建议 kubectl version 校验,差异过大报 client/server version mismatch;
- kubeadm 集群证书过期:默认一年有效期,kubeadm certs renew 续期,配合 kubeadm alpha certs renew(旧版命令)注意版本差异;
- 集群升级跳过多个版本:kubeadm 不支持跨多个 minor 版本直跳,必须逐版本升级。
7.9 HPA / 自动伸缩不生效
| 现象 | 原因 |
|---|---|
| HPA 一直显示 <unknown> 利用率 | 未安装 Metrics Server |
| HPA 不伸缩 | Pod 未声明 resources.requests.cpu(HPA 计算利用率的依据) |
| HPA 频繁抖动 | --horizontal-pod-autoscaler-sync-period 与冷却窗口、单 Pod 指标波动大;建议用 behavior 字段配置扩缩容策略 |
| 扩容到上限后仍有热点 | 需要结合 scaleUp 策略 / 自定义指标(KEDA) |
7.10 集群管理与排障速查
# 看 Pod 事件(90% 问题的第一现场)
kubectl describe pod <pod>
# 看容器日志(前 200 行 / 全部)
kubectl logs <pod> --tail=200
kubectl logs <pod> --previous # 崩溃前容器日志
# 全局事件(按时间排序)
kubectl get events --sort-by='.lastTimestamp' | tail -30
# 节点资源与污点
kubectl describe node <node>
kubectl get nodes -o wide
# 检查 kubelet(节点上执行)
journalctl -u kubelet -f # systemd 环境
终极兜底:事件与日志都正常但行为诡异时,检查 kubectl get all -A 全局资源、kubectl top nodes / pods 资源水位、以及 ConfigMap / Secret 引用是否被错误覆盖。
第 8 章 生产级最佳实践
8.1 资源治理:配额、限制与优先级
| 机制 | 作用 | 落地示例 |
|---|---|---|
| ResourceQuota | 限制 Namespace 级总资源(CPU / 内存 / 对象数量) | 每个环境 Namespace 设置配额,防止"一个团队吃光集群" |
| LimitRange | 限定 Pod / 容器级别的资源上下限,强制 request 与 limit 必填 | default-request-cpu: 100m、default-limit-memory: 1Gi |
| PriorityClass | 区分优先级,资源紧张时先驱逐低优先级 | 在线服务 > 批处理任务 |
| PodDisruptionBudget(PDB) | 保证主动驱逐(节点维护)时最少存活副本数 | 关键服务 minAvailable: 2 |
生产硬要求:所有 Deployment 显式声明 resources.requests 与 resources.limits;关键服务 QoS 为 Guaranteed(request == limit)。
8.2 多环境隔离与命名规范
- 每个环境独立 Namespace(dev / staging / prod),配合 RBAC 做到"谁只能看自己的环境";
- 统一标签规范(app / env / version / team),labels 是 K8s 的"索引系统",后续监控、网络策略、成本分摊都依赖它;
- 环境差异用 ConfigMap / Secret 区分,不要在镜像里烧环境配置。
8.3 安全基线(必做清单)
- RBAC 最小权限:ServiceAccount 只授予所需资源的最小 verbs;禁止把 cluster-admin 绑定给应用 Pod;
- 镜像安全:使用可复现构建、镜像扫描(Trivy / Grype)、私有仓库 + 签名验证、禁止 latest 进生产;
- 准入控制 :启用 Pod Security Admission(取代已废弃的 PSP),强制 restricted / baseline 策略(禁止特权容器、禁止 hostPath 等);
- NetworkPolicy:默认拒绝 + 白名单放行(Calico / Cilium 支持),防止横向渗透;
- Secret 管理:使用 External Secrets Operator / SOPS 管理密钥,杜绝明文入库;
- 节点加固:关闭不必要端口、kubelet 只监听内网、etcd 加密与 TLS。
8.4 可观测性:Metrics / Logs / Tracing 三支柱
| 支柱 | 方案 | 关键点 |
|---|---|---|
| 指标 | Prometheus + Grafana | 必配:Pod 资源、HPA 指标、kube-state-metrics;告警规则覆盖 CPU / 内存 / 重启 / PDB |
| 日志 | Loki / ELK(EFK) | 结构化日志(JSON)、kubectl logs 只查单 Pod,集群级检索必须集中式 |
| 链路 | OpenTelemetry + Jaeger / Tempo | 微服务排障必备,与 K8s 标签关联 |
最小闭环:先有 kubectl top 能看到资源,再有 Prometheus 历史曲线(容量规划),最后有告警(故障感知)------三者缺一不可。
8.5 声明式与 GitOps
- 所有资源用 Git 管理,kubectl apply -f 只用于 CI/CD,禁止手工 kubectl create 或 kubectl edit 直接改线上;
- Argo CD / Flux 作为 GitOps 引擎:Git 是唯一事实来源,集群自动同步,天然支持审计、回滚、多集群管理;
- 配置漂移检测:GitOps 工具会自动发现并修复"有人手动改过集群"的漂移。
8.6 高可用集群设计
| 维度 | 建议 |
|---|---|
| 控制面 | 3 个 master 节点 + 奇数 etcd,etcd 与 API Server 分离部署 |
| 工作节点 | 跨可用区(AZ)分布,配 PDB 容忍节点维护 |
| 网络 | 双栈 / 多 CNI 高可用方案,Ingress Controller 多副本 + PDB |
| 备份 | etcd 定期快照(etcdctl snapshot save),配置与资源清单 Git 备份 |
| 升级 | 小版本持续升级(不要跳大版本),先 staging 验证再 prod,配合 kubectl drain 优雅排空节点 |
8.7 上线前自检清单
- 所有工作负载有 request / limit,关键服务 Guaranteed QoS
- liveness / readiness 探针路径经过测试(不是 404)
- 存储回收策略确认(生产数据 Retain),有备份与恢复演练
- Service selector 与 labels 一致,kubectl get endpoints 非空
- 镜像使用不可变 Tag,来源受控(私有仓库)
- RBAC 最小权限,Pod Security 策略 applied
- 有监控与告警(CPU / 内存 / OOM / CrashLoop / 证书过期)
- 配置通过 ConfigMap / Secret 管理,Git 化,非手工维护
第 9 章 总结与进阶路线
9.1 全文核心结论
| 主题 | 一句话结论 |
|---|---|
| 为什么需要 K8s | 大规模容器生命周期管理无法人肉完成,需要声明式、自愈的编排系统 |
| 架构 | 控制面"决策"(API Server / etcd / scheduler / controller-manager),节点"执行"(kubelet / kube-proxy / 运行时),全部通过 API Server 通信 |
| 核心机制 | 期望状态 vs 实际状态的控制回路(Reconcile Loop)是自愈与自动化的根源 |
| 工作负载 | 按"有无状态 / 是否常驻 / 是否批量"三问选型:Deployment / StatefulSet / DaemonSet / Job |
| API | Group / Version / Resource 三级模型 + spec/status 分离 + RBAC 三道关卡;kubectl 只是 API 客户端 |
| 使用链路 | 部署 → 暴露 → 配置 → 存储 → 更新 → 扩容,六步覆盖日常 80% 操作 |
| 网络存储 | 网络走 CNI + Service 虚拟 IP + Ingress 入口;存储走 PV / PVC / StorageClass 动态供给 |
| 高频坑 | 集中在镜像 / 资源 / 配置 / 版本四类根因,用 describe / logs / events 三板斧系统性排障 |
| 生产化 | 资源治理 + 安全基线 + 可观测性 + GitOps 是四件必做的系统工程 |
9.2 进阶学习路线(建议按阶段推进)
阶段一:会操作(1-2 周)
- minikube 本地起集群,把第 5 章链路完整跑一遍;
- 熟练 kubectl describe / logs / get events 排障三板斧;
- 手写 Deployment / Service / ConfigMap / Secret / PVC 的 YAML,不依赖模板。
阶段二:懂原理(3-4 周)
- 阅读第 4 章 API 模型,用 kubectl explain 查字段;
- 弄懂控制回路:删掉 Pod 看它如何被重建,改 replicas 看控制器动作;
- 动手搭一次 kubeadm 集群(哪怕 1 master + 1 node),理解证书、etcd、网络插件。
阶段三:深入生态(1-2 个月)
| 方向 | 学习内容 | 适合人群 |
|---|---|---|
| Operator 开发 | CRD + controller-runtime / Operator SDK | 想平台化、做中间件运维的开发 |
| 交付与发布 | Helm(打包)、Argo CD / Flux(GitOps)、Kustomize | 平台 / 运维工程师 |
| 可观测性 | Prometheus、OpenTelemetry、Loki、Grafana | 运维 / SRE |
| 服务网格 | Istio / Linkerd(流量治理、安全、可观测) | 微服务团队 |
| 云原生存储 / 网络 | CSI / CNI 插件机制、Cilium eBPF | 资深基础设施工程师 |
建议 :不要一开始就扎进 Istio 或复杂 Operator。先把"资源模型 + 控制回路"这两个思维底座打牢,后续所有生态组件(Helm 只是模板引擎、Operator 只是控制器、Argo CD 只是持续 reconcile)都能在同一个心智模型里找到位置。
9.3 最后的话
Kubernetes 学习的真正难点不是命令,而是思维模式的转换:从"我手动执行每一步"转变为"我声明目标状态,系统负责达成并维持"。一旦完成这个转换,你会发现 K8s 的每一块拼图(调度、网络、存储、Operator、GitOps)都遵循同一个模式。祝你在云原生的路上少踩坑、多沉淀。