Skip to content

K8s 基础概念

Docker 解决单个容器怎么运行。Compose 解决单机多容器怎么组织。当服务要跑在多台机器上、副本数要动态调整、某台机器挂了服务要自动迁走时,这两样就不够了。

Kubernetes 处理的是多节点、多副本、多服务长期运行时的调度、网络、存储、配置、发布和故障恢复。

编排的本质——声明期望状态

Kubernetes 的工作方式是:提交期望状态("我要 3 个 web 副本"),控制器持续把集群实际状态调整到期望状态。副本少了就补,多了就缩,节点坏了就在别处重建。

不用 K8s 时,这些动作通常是运维脚本在做——检查进程、手动重启、改 Nginx upstream、更新 DNS。用 K8s 之后,这些"检查→纠正"的循环由控制器接管。

K8s 覆盖的主要场景和对应核心对象如下。Pod、Service、ConfigMap 这些对象先按职责区分,具体字段和排查方式会落到对应资源里。

场景Kubernetes 负责的部分
多副本 Web/API调度 Pod(最小调度单元,一组容器)、维护副本数、滚动发布
服务发现Service 提供稳定访问入口,Pod IP 变化不影响调用方
节点故障节点异常后,控制器在其他节点重建副本
配置分发ConfigMap(明文配置)、Secret(敏感配置)挂载或注入到容器
资源约束requests(申请量)、limits(上限)、QoS、驱逐策略
发布治理滚动更新、回滚、蓝绿、金丝雀
可观测性事件、日志、指标、审计

K8s 把调度、服务发现、配置挂载、滚动更新这些动作标准化了。但应用自身的启动逻辑、健康检查、数据一致性、数据库迁移、连接池配置仍然是应用和运维一起处理的——平台提供能力,不替代应用设计。

集群结构——控制平面和工作节点

一个集群分成两部分:控制平面负责决策和记录状态,工作节点负责运行容器。

所有组件都通过 kube-apiserver 读写资源对象——kubectl、scheduler、controller-manager、kubelet 没有例外。etcd 只在 API Server 后面做持久化存储,没有组件直接操作 etcd。这意味着:想查集群里有什么对象、想改对象的状态、想监听变化——全部走 API Server。这个设计让认证、授权、审计和准入控制在同一个入口完成,不需要在每个组件上分别做一遍。

核心组件

每个组件解决一类问题:

组件所在位置解决的问题常见故障
kube-apiserver控制平面提供统一的 API 入口证书过期、认证失败、请求延迟高
etcd控制平面持久化保存所有集群对象状态磁盘慢、快照丢失、quorum 丢失
kube-scheduler控制平面新 Pod 应该放在哪个节点资源不足、污点、亲和性、PVC 未绑定
kube-controller-manager控制平面持续调和期望状态和实际状态副本不补、节点状态更新异常
kubelet每个节点管理本节点的 Pod 和容器生命周期镜像拉取失败、挂载失败、探针失败
containerd / CRI-O每个节点容器运行时——真正创建和运行容器镜像损坏、容器创建失败
kube-proxy每个节点把 Service 规则变成节点上的转发规则iptables/IPVS 规则异常、Service 不通
CNI 插件每个节点给 Pod 分配 IP、实现 Pod 间通信Pod 无 IP、跨节点不通、策略异常

etcd 是整个集群状态的唯一持久化存储。控制平面节点故障后可以重建,Pod 可以重建——etcd 数据丢了等于集群所有对象(Deployment、Service、ConfigMap、Secret、RBAC)全部丢失。生产集群里 etcd 快照、证书有效期、磁盘延迟是固定巡检项。

声明式 API 和控制循环

K8s 的基本动作不是"执行一次命令",而是"提交期望状态,控制器持续调和":

把 Deployment 副本数从 2 改到 5 时,实际发生的不是"启动三个新容器"一条指令,而是每个组件接力完成自己那一段。变更后的状态传递过程:

步骤哪个组件具体动作
修改 spec.replicas 为 5API Server接收新期望状态,写入 etcd
Deployment 控制器发现差异controller-manager当前 2 个副本 < 期望 5 个副本
创建 3 个新 Podcontroller-manager新 Pod 字段写入 etcd
给 Pod 选节点scheduler写入 Pod 的 spec.nodeName
拉起容器kubelet节点上拉镜像、挂载卷、启动进程

这个接力模型直接决定了排错方式。API 是否接收对象、控制器是否创建对象、调度是否成功、kubelet 是否创建容器、应用是否健康——五个不同阶段,排查入口和日志来源完全不同。

spec 和 status

Kubernetes 不直接操作进程,而是操作资源对象。所有资源对象共享一个结构:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: demo
  labels:
    app: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.26
status:   # 由控制器维护,用户不写

spec 是期望状态——用户写的内容。status 是当前状态——控制器写的内容。Pod IP、Ready 状态、重启次数、Deployment 可用副本数都在 status 里。

注意 YAML 里 selector.matchLabelstemplate.metadata.labels 写了同样的 app: web——这不是重复。selector 告诉 Deployment"哪些 Pod 归我管",template labels 是 Pod 出生时被打上的标记。两边的值必须匹配,否则 Deployment 创建出来的 Pod 不会被它自己识别,会导致副本数失控。

常见资源对象:

对象解决的问题
Namespace资源按项目/环境分组,权限作用范围
Pod最小调度单元——一组共享网络和存储的容器
Deployment管理无状态副本,滚动更新和回滚
StatefulSet管理有状态副本,提供稳定网络身份和持久存储
DaemonSet每个节点跑一个 Pod(日志采集、监控 Agent、CNI)
Service提供不随 Pod IP 变化的稳定访问入口
ConfigMap注入非敏感的明文配置
Secret注入敏感配置(密码、Token、证书)
Ingress / Gateway七层入口规则(域名路由、TLS、灰度)
PV / PVC / StorageClass把存储从 Pod 生命周期里独立出来

label 和 selector——资源关联的核心

K8s 里资源之间不靠固定 IP,靠 label 和 selector 建立关联:

关系关联方式
Deployment → Podspec.selector.matchLabels 匹配 Pod labels
Service → Podspec.selector 匹配 Pod labels
NetworkPolicy → PodpodSelector 匹配 Pod labels
ServiceMonitor → Serviceselector 匹配 Service labels
Pod → PVCclaimName 引用 PVC 名称
Ingress/Gateway → Servicebackend 引用 Service 名称和端口

标签写错或没对上时不会报错——Service 安安静静地没有后端 Pod,Deployment 接管不到新 Pod,监控采集不到目标。排查 Service "怎么不通"时,先确认 selector 和 Pod labels 是否一致。

K8s 的边界——什么能处理,什么处理不了

K8s 能处理说明
副本数维护Pod 少了补,多了缩
调度按资源、污点、亲和性选择节点
服务发现Service 和 DNS 提供稳定访问入口
配置挂载ConfigMap、Secret 注入容器
滚动发布分批替换 Pod
基础自愈容器退出后重启,节点故障后重调度
K8s 处理不了现场表现
应用启动逻辑错误CrashLoopBackOff——容器反复退出重启
数据库一致性Pod 重启不等于数据恢复——StatefulSet 提供稳定身份,不提供高可用方案
镜像 tag 混乱同名 tag 在不同节点可能指向不同镜像内容
连接池过大扩副本后数据库连接数打满——HPA 不会帮你调连接池
外部依赖故障Pod Running,但接口超时——探针定义在 K8s 里,根因在外部
存储后端故障PVC Bound,但挂载或 IO 异常——K8s 只看绑定状态,不看磁盘 IO

Kubernetes 适合无状态服务、批处理任务、节点级采集组件和可水平扩展的应用。有状态服务也能跑,但存储、备份、升级顺序和故障切换需要单独设计。