FROM ZERO · 把名词一次讲明白

Kubernetes 管的不是容器,
是你「想要的状态」

学过 Docker 后再看 K8s 会卡在"组件太多、名词太抽象"。这份讲义换个思路:先讲透 K8s 唯一的核心思想——你只描述"我想要什么",它负责让现实一直保持成那样。理解了这条主线,后面 Pod、Service、Deployment 这些就都是为它服务的零件。遇到易考易混处会用橙色「考点」框点一下。

PodDeploymentServiceIngressConfigMapPV/PVCkubectl
01

K8s 是什么 + 集群长什么样

Docker 管一台机器上的几个容器;当容器有几十上百个、还要跨多台机器、自动重启、自动扩容时,就需要一个"总调度系统"——这就是 Kubernetes(K8s)。

核心思想:声明式 + 自愈(最重要,先记牢)

类比:恒温空调。你不会手动开关压缩机,你只设一个目标:"我要 26 度"(期望状态)。空调自己不停地测当前温度、和目标比、然后调整,直到达到并维持 26 度。K8s 一模一样:你用 YAML 声明"我要 3 个 nginx 副本一直在线"(期望状态),K8s 的各种控制器就不停地把现实拉回到这个目标——挂了一个就自动补一个。这叫控制循环 / 自愈
  • 声明式:你描述"想要的结果",而不是"一步步怎么做"。
  • 自愈:Pod 挂了、节点宕了,K8s 自动重建/迁移,维持期望副本数。
  • Helm 是 K8s 的包管理器(类比手机应用商店 / apt / npm),用 Chart 一键安装整套应用。

架构控制面(大脑)+ 工作节点(干活的)

一个 K8s 集群分两部分:控制面 Control Plane 负责决策与记账,工作节点 Node 负责真正跑你的容器。

控制面 Control Plane · 集群的大脑/指挥部
API Server唯一入口/前台,所有操作都经过它
etcd分布式键值数据库,存全部集群状态(账本)
Scheduler 调度器决定新 Pod 该放到哪个节点
Controller Manager跑各种控制器,保证副本数等"对账"
工作节点 Node ①
kubelet节点上的工头,按指令运行/汇报 Pod
kube-proxy负责 Service 的流量转发/负载均衡
容器运行时containerd 等,真正跑容器
Pod · Pod · …你的应用就跑在这里
工作节点 Node ②
kubelet同上
kube-proxy同上
容器运行时同上
Pod · Pod · …同上

CNI 插件(Calico、Flannel、Cilium 等)负责给 Pod 分配 IP、打通 Pod 间网络——它解决的是"网络",而存储是 CSI 的事。

考点
① 调度 Pod 的是 kube-scheduler(kubelet 只是按结果执行);② 存集群状态/配置的是 etcd;③ CNI 负责 Pod 网络(不是存储);④ Helm 是包管理工具(kubectl 是命令行、kubeadm 是装集群、kustomize 是配置定制)。
02

Pod:K8s 的最小运行单位

K8s 不直接管"容器",而是管 Pod。Pod 是调度和运行的最小单位,里面可以装一个或多个紧密协作的容器。

概念Pod 是什么

类比:豌豆荚。Pod 是荚,里面的容器是豌豆。一个荚通常一颗豆(一个容器),也可放几颗(如主容器 + 日志收集边车)。同一个荚里的豆共享同一个网络(用 localhost 互通、共用一个 IP)和存储卷
  • initContainer(初始化容器):在主容器之前先跑的"准备工序",按顺序串行执行,前一个成功才跑下一个,全部成功后才启动主容器(常用于等依赖、初始化数据)。
考点
initContainer 是顺序执行、前一个成功才执行后一个,不是和主容器同时启动。

生命周期Pod 的状态、重启策略、优雅终止

  • 阶段(phase):Pending(待调度)、RunningSucceededFailedUnknown
  • restartPolicy(重启策略):只有 Always / OnFailure / Never 三种。
  • 优雅终止:删 Pod 时不会立刻杀,先发 SIGTERM 让程序收尾,等 terminationGracePeriodSeconds(默认 30 秒),仍不退出才发 SIGKILL 强杀。
  • QoS 等级:Guaranteed / Burstable / BestEffort 三档,资源紧张时优先牺牲 BestEffort。
考点
① "Waiting" 不是 Pod 阶段(它是容器状态);② restartPolicy 没有 UnlessStopped(那是 Docker 的);③ 优雅终止是"先 SIGTERM 再 SIGKILL",不是立即杀死;④ QoS 没有 "LowPriority" 这一档。
03

控制器:谁来保证 Pod 一直按期望跑

你几乎从不直接创建 Pod,而是创建"控制器",由它替你维持 Pod。不同场景用不同控制器。

家族常见控制器一览

控制器干什么 / 何时用
ReplicaSet保证指定数量的 Pod 副本一直在跑(Deployment 底层就靠它)
Deployment管理无状态应用,声明式 + 支持滚动更新/回滚(最常用)
StatefulSet管理有状态应用(数据库等):稳定名字 + 有序启停 + 独立存储
DaemonSet保证每个节点跑一个 Pod(日志/监控 agent、网络插件)
Job / CronJob一次性任务 / 定时任务
对比DeploymentStatefulSet
Pod 名称随机哈希有序号(mysql-0、mysql-1)
网络标识不稳定稳定
存储共享或不持久每个 Pod 独立 PVC
启停顺序并行顺序(0→N,删除逆序)
适用无状态应用有状态应用(数据库)
考点
① 保证副本数的是 ReplicaSet;② StatefulSet 的专有特点是稳定标识/有序,"自动扩缩容"不算它相对 Deployment 的特点(两者都能被 HPA 扩缩);③ DaemonSet = 每节点一个;④ Job 不是"失败后无限重试到成功",受 backoffLimit 限制(默认 6 次)。

滚动更新怎么做到"换版本不停服"

类比:换轮胎不停车。滚动更新一次只替换一部分 Pod:起一个新版的、确认就绪、再撤一个旧版的,逐个替换,服务全程在线。

两个旋钮控制节奏:maxUnavailable(最多允许几个不可用)、maxSurge(最多额外多起几个)。以 maxUnavailable=0, maxSurge=1 为例推一遍:

  • maxUnavailable=0 → 任何时刻可用数不能低于期望数,即不能先删旧的。
  • maxSurge=1 → 总数最多到"期望+1",即允许临时多起一个。
  • 结论:只能先起 1 个新 Pod、就绪后再删 1 个旧 Pod,如此逐个替换 → 零中断、较慢。
kubectl scale deploy/web --replicas=3 # 扩缩容到 3 副本
kubectl rollout undo deploy/web # 回滚到上一个版本
考点
maxUnavailable=0, maxSurge=1 = 先创建新 Pod、再删旧 Pod;② 回滚用 kubectl rollout undo
04

Service & Ingress:怎么找到 Pod、怎么对外暴露

Pod 会被随时重建,IP 一直变。想稳定地访问它们,就要在前面加一层固定入口——这就是 Service;想按域名/路径把外部 HTTP 流量分发出去,再加一层 Ingress。

Service一组 Pod 的"固定门牌 + 负载均衡"

类比:公司总机号码。员工(Pod)会换工位、换分机(IP 变),但对外的总机号(Service)永远不变,打进来自动转给某个在岗的人。Service 通过标签选择器(selector)匹配后端 Pod,并在它们之间做负载均衡。
  • 用 Service 名称(DNS)访问:集群内 CoreDNS 把 Service 名解析成稳定的 ClusterIP,所以代码里写服务名而不是写死 IP。
  • Headless Service(clusterIP: None):不分配 ClusterIP、不做负载均衡,DNS 直接返回各 Pod 的 IP 列表(常配合 StatefulSet 直连某个 Pod)。
  • ExternalName:不代理流量,只返回一条 CNAME,把集群内的服务名映射到一个外部域名(让内部用统一名字访问外部服务)。
  • 查后端:kubectl get endpointsdescribe svc 都能看 Service 关联了哪些 Pod。
考点
① 集群内访问 Service 推荐用 Service 名称(DNS);② Headless Service = 无 ClusterIP + 不负载均衡 + 直接返回 Pod IP(三点都对);③ ExternalName = 映射到外部域名;④ kube-proxy 模式有 userspace/iptables/ipvs,没有 bridge;⑤ Service 层会话保持只支持 ClientIP(Cookie 是 Ingress 层的能力)。

Ingress七层"大堂经理",按域名/路径分流

Service 偏 4 层;Ingress 在更上层,按 HTTP 的域名和路径(如 /api 进后端、/ 进前端)把外部请求分发到不同 Service,还能统一管 HTTPS 证书。

考点
Ingress 资源只是"规则",真正监听端口、执行规则、转发流量的是 Ingress Controller(如 nginx-ingress)。没有 Controller,Ingress 不生效。
05

探针:Liveness vs Readiness

K8s 怎么知道你的容器"是不是还活着""能不能接客"?靠两种探针。它俩名字像,效果完全不同,是高频考点。

两种探针一个管重启,一个管流量

Liveness 存活探针Readiness 就绪探针
它问什么"你还活着吗?""你准备好接客了吗?"
失败后果重启容器从 Service 的 Endpoints 摘除(不再转发流量,但不重启)
用途程序死锁/卡死时自动救活启动慢/临时繁忙时,先别给它发请求
记忆:Live(活着)失败 → 把它重启;Ready(就绪)失败 → 暂时别给它派活(摘流量),等它缓过来再加回。
考点
Liveness 失败 → 重启容器;Readiness 失败 → 从 Endpoints 移除(停转流量)。这两个结果千万别记反。
06

配置与存储:ConfigMap / Secret / PV / PVC

代码不该把配置和密码写死。配置外置用 ConfigMap/Secret;数据要持久化、活得比 Pod 久,就用 PV/PVC。

配置ConfigMap vs Secret

ConfigMapSecret
用途非敏感配置(参数、配置文件)敏感信息(密码、token、证书)
数据形式明文base64 编码(注意:只是编码,不是加密)
考点
① 存非敏感配置用 ConfigMap;② Secret 的值是 base64 编码——不等于加密(要真加密得开 etcd 静态加密)。

存储PV 与 PVC

类比:PV(PersistentVolume)是机房里"已经接好的一块硬盘";PVC(PersistentVolumeClaim)是你的"领用申请单"(我要 10G、可读写)。两者绑定后,Pod 就用这块存储。Pod 删了,数据还在 PV 上。
  • 绑定主要看容量、访问模式、StorageClass是否匹配(也可用标签选择器辅助筛选);PVC 不必指定具体 PV 名(动态供给会自动建 PV)。
  • 访问模式:ReadWriteOnce(RWO)ReadOnlyMany(ROX)ReadWriteMany(RWX)
  • 回收策略(Retain/Delete/Recycle)决定删 PVC 后 PV 上的数据怎么处理。
考点
① PV/PVC 可通过标签选择器匹配(且 PV 与 PVC 是一对一独占绑定);② 访问模式只有 RWO/ROX/RWX,"WriteOnceReadMany" 不存在。
07

调度与资源:Pod 该去哪、能用多少

两个问题:① 怎么控制 Pod 调度到哪些节点(Taint/Toleration、nodeSelector);② 怎么声明 Pod 的资源用量(requests/limits),以及自动扩缩(HPA)和命名空间配额(ResourceQuota)。

调度Taint(污点)与 Toleration(容忍)

类比:Taint 是给节点贴的"闲人免进"标签;Toleration 是 Pod 持有的"通行证"。节点有污点,只有带对应容忍的 Pod 才允许调度上去。
考点
Taint 定义在 Node 上,Toleration 定义在 Pod 上——归属别记反。

资源requests / limits / HPA / ResourceQuota

类比:订餐厅。requests 像订位时说"我至少要一张能坐 4 人的桌"——调度器据此预留资源、选节点;limits 是"上限",真用超了会被限流(CPU)或杀掉(内存 OOM)。
  • requests:调度依据(预留下限);limits:运行上限。两者作用不同。
  • HPA(水平自动扩缩):按 CPU/内存(或自定义指标)使用率,自动增减 Pod 副本数(需 metrics-server)。
  • ResourceQuota:限制单个 Namespace 内的资源总量与对象数量。
考点
requests 用于调度、limits 用于限制;② HPA 按 CPU/内存使用率扩缩;③ ResourceQuota 限制的是 Namespace 级资源(不是单 Pod、不是整集群)。
08

网络与安全:谁能通、谁能做什么

先记住 K8s 网络的"默认全通"原则,再看怎么用 NetworkPolicy 收紧、用 RBAC 管权限、用 SecurityContext 收紧 Pod。

网络模型三条硬性原则

  • 每个 Pod 有独立 IP;同一 Pod 内的容器共享这个 IP。
  • 所有 Pod 之间可以不经 NAT 直接用 IP 互通(默认扁平、全通)。
  • Service 只是可选的稳定入口,Pod 并非"必须经 Service"才能通信。
NetworkPolicy 像给 Pod 加防火墙规则(控制入站/出站),但它需要支持它的 CNI 插件(Calico、Cilium)才生效——光写策略、底层不支持等于白写。
考点
① 网络模型不要求"Pod 必须通过 Service 访问"(可直接 IP 通);② 不同 Namespace 的 Pod 默认可以互通("不能通信"是错的);③ NetworkPolicy 需要 CNI 插件支持

权限RBAC 与 SecurityContext

  • RBAC:控制"谁(用户/ServiceAccount)能对什么资源做什么操作"。Role 只在某个 Namespace 内有效;ClusterRole 作用于整个集群
  • SecurityContext:收紧 Pod/容器的权限,可设运行用户、Linux Capabilities、SELinux 标签,也能用 runAsNonRoot: true 禁止以 root 运行。
考点
Role 限单 Namespace、ClusterRole 全集群;② SecurityContext 可以runAsNonRoot 限制 root——"不能限制 root 权限"是错误说法。
09

kubectl 命令地图 & 排错速查

最后把高频命令按"做什么"归类。记住每条命令的用途,选择题里的命令辨析就稳了。

命令地图看 / 改 / 调试

命令用途
kubectl get pods -o wide列资源;-o wide 显示 Pod 在哪个节点
kubectl get pods -w-w(watch)持续监听资源变化
kubectl describe pod详细信息 + 事件(排错首选)
kubectl logs --tail=100 -f看日志末尾 100 行并持续跟踪
kubectl exec -it … -- sh进容器开交互终端(-i 输入、-t 伪终端)
kubectl explain pod.spec查 API 资源字段文档
kubectl top pod/node看 CPU/内存用量(需 metrics-server)
kubectl version看客户端/服务端版本
kubectl get events --sort-by=.metadata.creationTimestamp看事件并按时间排序
kubectl run test --image=busybox -it --rm跑一个临时测试容器,退出即删

两组易混apply/create 与 安全删节点

  • apply vs create:create 是命令式、只能创建(对象已存在会报错);apply 是声明式,能创建也能更新(反复对账)。
  • 安全删节点:先 kubectl drain <node> 驱逐 Pod(并标记不可调度),等工作负载迁走后再 kubectl delete node。直接删或关机会中断业务。
考点
① 看详情/事件用 describe、看字段文档用 explain、持续监听用 -w、节点定位用 -o wide;② apply 可建可改、create 只能建;③ 安全删节点 = 先 drain 再 delete;④ 临时容器用 kubectl run ... --rm