K3s、Kubernets基础
核心概念
K3s 是什么?和标准 K8s 的区别?(轻量级、简化部署、适合边缘)
一句话原理 K3s 是由 Rancher Labs 开发的轻量级 Kubernetes 发行版,它删除了 K8s 中非必需的遗留代码、Alpha/Beta 特性和内置插件(如默认 Storage Driver),将所有组件打包进一个小于 100MB 的单一二进制文件中。
一句话源码
在 Linux 服务器上只需执行 curl -sfL https://get.k3s.io | sh - 即可完成 K8s 集群的安装,无需复杂的 kubeadm init 和证书配置。
一句话项目/场景 在“物联网边缘计算”项目中,将 K3s 部署在 ARM 架构的树莓派或工业网关上,用于管理运行在边缘侧的容器应用,实现离线数据处理和低延迟响应。
详细区别:K3s vs 标准 K8s
| 维度 | 标准 K8s (Upstream) | K3s |
|---|---|---|
| 二进制大小 | 约 1.5 GB(需多个组件二进制) | < 100 MB(单一二进制文件) |
| 内存占用 | 高(控制平面至少需要 2GB+) | 极低(最低 512MB 即可运行) |
| 安装复杂度 | 高。需安装 kubeadm, kubelet, etcd 等,配置证书、RBAC。 | 极低。一条命令自动安装,自带 SQLite/Traefik。 |
| 依赖项 | 依赖外部 etcd、CNI 插件、容器运行时。 | 去除外设依赖。内置 SQLite(可选 etcd)、Flannel、Traefik、CoreDNS。 |
| 数据库后端 | 强依赖 etcd(运维门槛高)。 | 支持 SQLite、MySQL、Postgres、etcd(灵活性极高)。 |
| 适用架构 | x86_64 服务器集群。 | x86_64 & ARM/ARM64(完美支持树莓派)。 |
| 适用场景 | 云数据中心、大规模生产集群。 | 边缘计算、IoT、CI/CD 流水线、嵌入式设备、开发测试环境。 |
为什么叫 K3s?
名字的由来是一个梗:K8s 是 10 个字母的缩写(K + 8 个字母 + s),K3s 意味着它是 K8s 的“一半”大小(5 个字母的概念),寓意更轻量、更精简。
K3s 做了哪些“减法”?
为了实现轻量级,K3s 剔除了以下内容,但完全保留了 K8s 的核心 API:
- 废弃功能:移除了所有 Alpha/Beta 阶段的 API。
- 内置插件:去掉了默认的云厂商存储插件(AWS EBS, GCE PD 等),改用 CSI。
- Legacy 功能:移除了 docker 作为容器运行时的支持(仅支持 containerd,这也是 K8s 的趋势)。
- 重命名:相关二进制文件从
kube-xxx改名为k3s-xxx。
K3s 的核心优势
简化运维: 原生 K8s 集群维护需要专业的 SRE 团队处理证书轮转、etcd 备份。K3s 大幅降低了运维门槛,甚至支持单节点运行完整的 K8s 功能。
边缘友好: 在网络不稳定或带宽受限的边缘环境,K3s 可以离线运行,并在网络恢复后自动同步数据。
适合开发: 开发者在本地笔记本电脑上运行 K3s,可以获得与生产环境一致的 K8s API 体验,比 Minikube 更省资源。
Kubernetes 的核心组件有哪些?(API Server、etcd、Scheduler、Controller Manager、Kubelet)
一句话原理 Kubernetes 采用控制平面与工作节点分离的架构。控制平面负责“决策与管理”(大脑),工作节点负责“执行与负载”(手脚)。
一句话源码
用户通过 kubectl 向 API Server 提交请求,数据存入 etcd;Scheduler 决定 Pod 去哪,Controller Manager 确保 Pod 数量正常,Kubelet 在节点上负责让容器跑起来。
一句话项目/场景 在“电商平台高可用部署”中,Scheduler 将订单服务 Pod 调度到空闲节点,Controller Manager 监控到订单服务 Pod 挂掉后立即重建,etcd 记录了整个集群的实时状态。
详细组件解析
一、 控制平面组件
这些组件负责管理集群状态,通常运行在 Master 节点上。
API Server(入口与网关)
- 角色:集群的统一入口,唯一的“前台接待员”。
- 作用:
- 提供RESTful API接口(如
kubectl的所有命令最终都打到这)。 - 负责认证、授权、准入控制(谁能进?能干什么?数据合不合法?)。
- 是唯一能直接连接 etcd 的组件,所有状态变更都要经过它。
- 提供RESTful API接口(如
etcd(数据库)
- 角色:集群的唯一记忆库。
- 作用:
- 高可用的键值对数据库,存储集群所有的配置信息和状态数据(如“现在应该有几个Pod”、“实际有几个Pod”)。
- 注意:etcd 的数据丢失等于集群彻底崩溃,必须做好备份。
Scheduler(调度器)
- 角色:集群的人力资源经理。
- 作用:
- 监听 API Server,发现“新来的 Pod 还没分配节点”。
- 根据预设策略(资源余量、亲和性、污点容忍等)进行打分,选择一个最优节点绑定给 Pod。
- 它只负责决策(把Pod安排到哪),不负责执行(真正去启动Pod)。
Controller Manager(控制器管理器)
- 角色:集群的大管家,负责维持状态。
- 作用:
- 包含多个控制器(如 Node Controller、Replication Controller)。
- 核心逻辑:死循环执行“调谐循环”。不断对比“期望状态”(YAML定义)和“实际状态”(etcd记录)。
- 例子:定义了
replicas: 3,如果实际只有 2 个 Pod 运行,它会通知 API Server 创建新的 Pod。
二、 工作节点组件
这些组件在每个工作节点上都必须运行,负责维护运行的 Pod。
Kubelet(节点代理)
- 角色:Master 派驻在节点上的厂长。
- 作用:
- 监听 API Server,发现有 Pod 被调度到自己的节点上。
- 调用底层的容器运行时(如 Containerd 或 Docker)来启动、停止容器。
- 定期向 Master 汇报节点健康状况(心跳)。
Kube-proxy(网络代理)
- 角色:网络交警。
- 作用:
- 维护节点上的网络规则(通常操作 iptables 或 IPVS)。
- 确保 Service(虚拟IP)的流量能正确转发到后端的 Pod 上。
组件协作流程图解
假设用户执行 kubectl run nginx --image=nginx --replicas=3:
- API Server:接收请求,验证权限,将请求写入 etcd。
- Controller Manager:发现“期望 3 个 Nginx,实际 0 个”,创建 3 个 Pod 对象写入 etcd。
- Scheduler:发现 3 个新 Pod 处于 Pending 状态,根据资源情况分配节点(如 Node A, Node B, Node C),并更新 Pod 信息到 etcd。
- Kubelet(在 Node A/B/C 上):监听到有新 Pod 分配给自己,调用容器运行时下载镜像并启动容器。
总结记忆口诀
- API Server:管入口,一切由此入。
- etcd:管数据,一切存于此。
- Scheduler:管调度,决定谁去哪。
- Controller:管状态,少了补多了删。
- Kubelet:管执行,负责干苦力。
什么是 Pod?和容器的关系?
一句话原理 Pod 是 Kubernetes 中最小的可部署单元,它是一组(一个或多个)紧密关联的容器的集合,这些容器共享网络命名空间(IP地址)和存储卷,始终“同生共死”。
一句话源码 Pod 的本质是一个逻辑概念,实际上是一组共享 Namespace 和 Cgroups 的容器进程。
一句话项目/场景 在“内容管理系统”中,一个 Pod 包含两个容器:Nginx 容器(提供前端访问)和 File Puller 容器(定期拉取更新内容),两者通过共享的 Volume 交换文件,构成一个完整的服务单元。
详细解析:Pod 与容器的关系
类比理解
- 容器:像是“独立运行的程序”。
- Pod:像是“虚拟机”或“进程组”。
- 在传统虚拟机中,几个程序跑在同一台机器上,共享 IP 和磁盘。
- 在 K8s 中,Pod 模拟了这种环境。Pod 内的所有容器共享同一个网络栈( localhost 互相通信)和存储。
核心特性:为什么需要 Pod?
A. 共享网络
- 机制:Pod 里的所有容器通过
Pause 容器(根容器)共享 Network Namespace。 - 结果:
- 所有容器共享同一个 IP 地址。
- 容器之间可以通过
localhost直接通信(例如:Nginx 容器可以通过 localhost:8080 访问同一 Pod 内的 Tomcat 容器)。 - 容器之间不存在端口冲突(不能同时监听同一端口)。
B. 共享存储
- 机制:Pod 可以挂载 Volume,Pod 内的所有容器都可以挂载这个 Volume。
- 结果:容器 A 写入文件,容器 B 可以直接读取,实现了数据共享。
C. 原子性管理
- Pod 是 K8s 调度的原子单位。
- K8s 不会调度“容器”,只会调度“Pod”。
- 同一个 Pod 内的容器绝对不会被拆分到不同的机器上,它们总是同生共死。
容器设计模式:Sidecar(边车模式)
这是 Pod 最经典的设计模式,体现了 Pod 存在的价值。
- 场景:一个主容器运行业务代码(如 Java 应用),但它需要日志收集功能。
- 解耦方案:不要把日志收集逻辑写进 Java 代码里。
- 容器 1(主容器):运行 Java 应用,把日志写到共享 Volume。
- 容器 2(Sidecar 容器):运行 Logstash 或 Filebeat,读取共享 Volume 并上传到日志中心。
- 优势:职责单一,容器独立,组合灵活。
总结对比
| 维度 | 容器 | Pod |
|---|---|---|
| 定义 | 镜像的运行实例 | K8s 最小调度单元 |
| 包含关系 | 包含在 Pod 中 | 包含一个或多个容器 |
| 网络 | 独立 IP | 内部容器共享 IP,对外统一 IP |
| 生命周期 | 独立运行 | 内部容器同时创建、同时销毁 |
| 调度单位 | 被 K8s 调度 | 被 K8s 调度 |
核心记忆点: Pod = 一组共享网络和存储的容器进程组。
什么是 Deployment、StatefulSet、DaemonSet?各自的应用场景?
一句话原理 这三者是 Kubernetes 的工作负载控制器,决定了 Pod 的创建方式、运行拓扑和生命周期。
- Deployment:管理无状态应用,像牧场主管理羊群(数量对就行,个体不重要)。
- StatefulSet:管理有状态应用,像管理运动员队伍(每个人都有固定号码和角色)。
- DaemonSet:管理守护进程,像每个房间的巡逻保安(每个节点必须有一个)。
一句话源码
Deployment 通过 replicas 控制副本数量;StatefulSet 通过 headless service 维持固定网络标识;DaemonSet 通过 nodeSelector 确保节点覆盖。
一句话项目/场景
- Deployment:部署 Nginx 前端、Spring Boot API 服务。
- StatefulSet:部署 MySQL 主从集群、Redis 集群、ZooKeeper。
- DaemonSet:部署日志采集 Agent(Fluentd)、监控 Agent(Prometheus Node Exporter)。
详细解析与对比
Deployment(无状态应用)
这是最常用的控制器。
- 核心特性:
- 无序:Pod 名称包含随机哈希(如
nginx-6d4cf5644-x7v2a),IP 也是动态的。 - 弹缩:随意扩容缩容,新的 Pod 随时可以替代旧的 Pod,对业务无感知。
- 滚动更新:支持自动滚动更新和回滚。
- 无序:Pod 名称包含随机哈希(如
- 应用场景:
- Web 服务器、API 微服务。
- 任何不需要保存本地数据、不依赖固定网络身份的应用。
StatefulSet(有状态应用)
专为数据库和中间件设计。
- 核心特性:
- 有序标识:Pod 名称固定且有序(如
mysql-0,mysql-1)。 - 稳定存储:每个 Pod 绑定独立的持久化存储(PVC),Pod 重建后数据不丢失,且挂载回原来的存储。
- 稳定网络:Pod 拥有固定的主机名,可以通过 DNS 解析(如
mysql-0.service.ns)。 - 有序部署/缩容:必须按顺序启动(0->1->2),缩容时逆序(2->1->0)。
- 有序标识:Pod 名称固定且有序(如
- 应用场景:
- 关系型数据库。
- 分布式存储。
- 需要集群选举的应用。
DaemonSet(守护进程)
确保每个节点都跑一份副本。
- 核心特性:
- 节点全覆盖:当新节点加入集群时,自动在该节点上创建 Pod;节点移除时,Pod 自动回收。
- 无需指定副本数:副本数等于集群节点数。
- 应用场景:
- 日志采集。
- 监控代理。
- 网络插件(Calico, Weave)。
总结对比表
| 维度 | Deployment | StatefulSet | DaemonSet |
|---|---|---|---|
| Pod 名称 | 随机哈希 | 固定序号 (0, 1, 2…) | 随机哈希 + 节点名约束 |
| 存储 (PVC) | 共享存储 (通常) | 独立专属存储 (每个 Pod 一块盘) | 通常为 HostPath (读取宿主机信息) |
| 网络标识 | 随机 IP,Service 负载均衡 | 固定 DNS 主机名,Headless Service | 每个 Node 一个 IP |
| 启动顺序 | 并行启动 | 严格有序 (必须等前一个 Ready) | 并行启动 |
| 副本数控制 | 手动/Auto Scaling | 手动 Scaling | 自动等于 Node 数量 |
| 典型代表 | Nginx, Tomcat | MySQL, Redis, Kafka | Fluentd, CNI 插件 |
记忆口诀
- Deployment:大家一起上,谁上都行。
- StatefulSet:排好队,一人一个号,谁也别抢谁的盘。
- DaemonSet:每个房间放一个保安,寸步不离。
网络与存储
Kubernetes 的服务发现方式有哪些?(ClusterIP、NodePort、LoadBalancer、Ingress)
一句话原理 Kubernetes 服务发现通过 Service 和 Ingress 两种资源,将抽象的 Pod 网络端点暴露给内部或外部调用者,实现了从“内部互通”到“外网访问”的四级流量暴露体系。
一句话源码
Service 通过 spec.type 字段定义暴露方式(ClusterIP/NodePort/LoadBalancer),Ingress 通过定义路由规则将外部 HTTP/HTTPS 流量分发到 Service。
一句话项目/场景
- ClusterIP:前端服务调用后端 API(内部通信)。
- NodePort:开发测试环境快速通过节点端口访问服务。
- LoadBalancer:公网暴露 API 网关(对接云厂商负载均衡)。
- Ingress:生产环境基于域名(如
api.example.com)将流量路由到不同微服务。
详细解析:四种服务发现方式
ClusterIP(默认方式)
- 定义:分配一个集群内部的虚拟 IP (VIP),仅能在集群内部访问。
- 原理:kube-proxy 在节点上配置 iptables/IPVS 规则,将访问 VIP 的流量转发到后端 Pod。
- 应用场景:
- 微服务之间的内部调用(如 Order Service 调用 User Service)。
- 不需要对外暴露的数据库、缓存服务。
- 缺点:外部用户无法直接访问。
NodePort(节点端口)
- 定义:在 ClusterIP 基础上,在每个 Node 节点上开放一个静态端口(默认范围 30000-32767)。
- 原理:外部用户通过
NodeIP:NodePort访问,流量被转发到 Service,再分发到 Pod。 - 应用场景:
- 测试环境、演示环境。
- 需要快速暴露非 HTTP 服务(如游戏服务器、自定义 TCP 服务)。
- 缺点:
- 端口号难记且不美观。
- 每个节点都会占用端口,存在安全风险。
- 无法基于域名路由。
LoadBalancer(负载均衡器)
- 定义:在 NodePort 基础上,自动调用云厂商(AWS/阿里云/腾讯云)的 API,创建一个外部的负载均衡器(如 ELB/SLB)。
- 原理:云 LB -> NodePort -> ClusterIP -> Pod。
- 应用场景:
- 生产环境中需要对外暴露 TCP/UDP 服务。
- 通常用于暴露 API 网关或需要公网 IP 的服务。
- 缺点:
- 成本高:每创建一个 LoadBalancer Service,云厂商都会分配一个独立的公网 IP 和 LB 实例,费用昂贵。
- 资源浪费。
Ingress(智能路由)
- 定义:这不是 Service 的一种类型,而是一个独立的资源对象。它作为一个智能网关,统一管理集群的入口流量。
- 原理:
- 部署一个 Ingress Controller(如 Nginx Ingress),它本身通常是一个 LoadBalancer 或 HostNetwork 类型的 Pod。
- Ingress 规则定义:
host: a.com -> Service A;host: b.com -> Service B。 - 外部流量 -> Ingress Controller -> 根据 HTTP Header/路径 -> 对应 Service。
- 应用场景:
- 生产环境 HTTP/HTTPS 服务暴露。
- 一个 IP 地址服务多个域名(虚拟主机)。
- 需要统一处理 SSL 证书、限流、鉴权的场景。
- 优点:成本最低(只需一个公网 IP),配置灵活。
总结对比表
| 方式 | 访问范围 | 访问地址示例 | 成本 | 适用场景 |
|---|---|---|---|---|
| ClusterIP | 集群内部 | 10.96.0.1:80 | 无 | 内部微服务通信 |
| NodePort | 集群外部 | NodeIP:30080 | 低 | 测试、非 HTTP 服务 |
| LoadBalancer | 集群外部 | 42.10.1.1:80 (公网IP) | 高 (每服务一个IP) | 生产环境 TCP/UDP 暴露 |
| Ingress | 集群外部 | api.example.com | 低 (多服务共享IP) | 生产环境 Web 服务暴露 |
最佳实践架构
在真实的生产环境中,通常遵循以下链路: 外部用户 -> 云厂商 LB (LoadBalancer) -> Ingress Controller -> Service (ClusterIP) -> Pod
这样既利用了云厂商 LB 的稳定性,又利用了 Ingress 的灵活性,还能节省公网 IP 资源。
什么是 ConfigMap 和 Secret?如何使用?
一句话原理 ConfigMap 和 Secret 是 Kubernetes 解耦配置数据与容器镜像的两种资源对象。ConfigMap 用于存储非敏感的配置信息,Secret 用于存储敏感信息( Base64 编码)。
一句话源码
ConfigMap 存储明文键值对(key: value),Secret 存储编码后的键值对。Pod 通过环境变量或挂载卷的方式引用它们。
一句话项目/场景 在“多环境部署”中,镜像代码不变,通过挂载不同的 ConfigMap 切换开发/生产环境的数据库地址;通过 Secret 安全注入数据库密码,避免密码明文写在代码或 YAML 中。
详细解析与对比
| 维度 | ConfigMap | Secret |
|---|---|---|
| 存储内容 | 明文配置(配置文件、命令行参数、环境变量)。 | 敏感数据(密码、证书、Token、SSH Key)。 |
| 编码方式 | 直接存储(明文)。 | Base64 编码(注意:仅编码非加密,ETCD 需加密配置才安全)。 |
| 大小限制 | 最大 1MB。 | 最大 1MB。 |
| 安全性 | 权限控制较宽松。 | 权限控制更严格,且节点上通常存储在内存文件系统。 |
如何使用?(三种方式)
创建资源(准备数据)
ConfigMap 创建示例:
Secret 创建示例:
在 Pod 中使用(注入方式)
方式一:环境变量 适合传递少量参数或启动参数。
| |
方式二:挂载为文件 适合配置文件场景,如 Nginx.conf 或 application.properties。
| |
注:挂载后,ConfigMap 的 Key 会变成文件名,Value 会变成文件内容。Secret 的内容会被自动解码还原为明文存入文件。
最佳实践
- 不可变配置:对于不需要频繁修改的配置,建议设置
immutable: true,可以防止意外更新,也能降低 kube-apiserver 的负载。 - 不要滥用 Secret 存大文件:Secret 存储在 etcd 中,大小限制 1MB,不适合存放大文件(如视频、大型图片)。
- 安全加密:默认 Secret 只是 Base64 编码,建议在 etcd 层面开启静态数据加密,或使用第三方保险库(如 HashiCorp Vault)。
- 配置更新:
- 环境变量方式:Pod 启动后注入,ConfigMap 更新不会自动更新环境变量,必须重启 Pod。
- 挂载卷方式:ConfigMap 更新后,Kubelet 会自动更新节点上的文件,应用需支持热加载配置。
如何在 K8s 中实现持久化存储?(PV、PVC、StorageClass)
一句话原理 Kubernetes 通过 PV(存储资源)、PVC(存储需求) 和 StorageClass(存储模板) 三层抽象,将存储基础设施与业务应用解耦,实现数据的持久化保存。
一句话源码 用户在 YAML 中声明 PVC(我要多大的盘),StorageClass 自动调用云厂商 API 创建 PV(实际的存储卷),Pod 挂载 PVC 使用存储。
一句话项目/场景 在“MySQL 数据库迁移”场景中,即使 MySQL Pod 被删除重建,只要挂载了同一个 PVC,数据依然存在,因为数据实际保存在云厂商的硬盘(PV)中,而非容器内部。
核心概念解析
PV (Persistent Volume) - 存储资源
- 定义:持久卷。它是集群中的一块存储资源(如 NFS、Ceph、AWS EBS 硬盘)。
- 角色:类似于 Node(节点资源),属于集群级资源,由运维人员管理。
- 生命周期:独立于 Pod,Pod 删除后 PV 依然存在。
PVC (Persistent Volume Claim) - 存储需求
- 定义:持久卷声明。它是用户对存储资源的“申请书”(例如:“我要 10G 的读写盘”)。
- 角色:类似于 Pod(消耗资源),属于命名空间级资源,由开发人员管理。
- 绑定机制:K8s 会根据 PVC 的需求(大小、访问模式)自动匹配并绑定最合适的 PV。
StorageClass (SC) - 存储模板
- 定义:存储类。它是一个动态创建 PV 的模板。
- 作用:解决了运维手动创建 PV 的痛苦。当用户申请 PVC 时,SC 自动调用 Provisioner(存储供应商)创建对应的底层存储并生成 PV。
- 参数:定义了存储类型(如 SSD、HDD)、回收策略等。
存储使用流程
阶段一:静态供给- 传统模式
运维手动创建 PV,用户手动申请 PVC。
- 运维:手动在云厂商买一块盘,创建 PV 对象。
- 用户:创建 PVC,请求 10G 空间。
- K8s:寻找匹配的 PV 并绑定。
阶段二:动态供给- 推荐模式
用户申请 PVC,系统自动创建 PV。
- 运维:创建 StorageClass(定义了存储供应商和参数)。
- 用户:创建 PVC,并在 YAML 中指定
storageClassName。 - K8s:PVC 触发 SC,SC 调用底层 API 自动创建硬盘并生成 PV,最后绑定给 PVC。
实战 YAML 示例
StorageClass (定义模板)
PVC (用户申请)
Pod (挂载使用)
关键概念补充
访问模式:
ReadWriteOnce (RWO):读写,只能被单个节点挂载(常用块存储)。ReadOnlyMany (ROX):只读,可被多个节点挂载。ReadWriteMany (RWX):读写,可被多个节点挂载(常用 NFS/CephFS)。
回收策略:
Retain:Pod 删了,数据保留(需手动清理)。Delete:PVC 删除,PV 和底层存储自动删除(动态供给默认行为)。
总结记忆口诀
- PV:仓库里的货(硬盘)。
- PVC:提货单(申请书)。
- StorageClass:自动售货机(自动造货)。
调度与扩缩容
什么是水平自动伸缩(HPA)?基于哪些指标?
一句话原理 HPA (Horizontal Pod Autoscaler) 是 Kubernetes 的一种控制器,它根据 Pod 的实时负载情况,自动增加或减少 Pod 的副本数量,实现业务的“弹性伸缩”。
一句话源码
HPA 控制器通过轮询 Metrics Server 获取指标数据,计算当前指标与目标值的比率,动态调整 Deployment 的 replicas 字段。
一句话项目/场景 在“双11大促”期间,随着请求量激增,CPU 使用率飙升至 80%,HPA 自动将 Pod 数量从 3 个扩展到 50 个以分担流量;流量低谷期自动缩容回 3 个以节省成本。
详细解析
核心工作流程
HPA 的工作是一个闭环控制过程:
- 获取指标:HPA 控制器定期向 Kubernetes API Server 发起请求,API Server 从 Metrics Server(必须安装的插件)获取资源使用数据。
- 计算期望副本数:
- 公式:
期望副本数 = ceil(当前副本数 * (当前指标值 / 目标指标值)) - 例如:目标 CPU 是 50%,当前 CPU 是 100%,则
当前副本数 * (100/50) = 2倍,需要扩容一倍。
- 公式:
- 执行伸缩:更新 Deployment 的 replicas 数量,触发新的 Pod 创建或删除。
基于哪些指标?
HPA 支持三类指标来源:
A. 资源指标 —— 最常用
由 Metrics Server 提供,K8s 原生支持。
- CPU 利用率:最常用的指标。例如设置目标为 60%。
- 内存利用率:适用于内存密集型应用(如 Redis、Java 应用)。
- 注意:CPU 支持弹性伸缩较好,内存通常不支持频繁释放,扩容效果不如 CPU 直观。
B. Pods 指标
与 Pod 直接相关的自定义指标。
- QPS (每秒查询数):例如 Nginx Ingress 的每秒请求数。
- 并发连接数:Web 服务器的当前活跃连接数。
C. Object / 外部指标
由第三方监控系统(如 Prometheus + Prometheus Adapter)提供。
- 消息队列深度:例如 RabbitMQ 或 Kafka 队列中堆积的消息数量。如果堆积超过 1000 条,就扩容消费者 Pod。
- HTTP 请求延迟:基于响应时间进行扩容。
实战 YAML 示例
以下示例定义了一个 HPA:目标 CPU 使用率 50%,最少 2 个 Pod,最多 10 个 Pod。
| |
关键机制与避坑
冷却时间
为了防止指标抖动导致 Pod 频繁创建删除(“颤抖”),K8s 默认设置:
- 扩容:即时进行(无需等待)。
- 缩容:默认需要等待 5 分钟 稳定期,确认负载持续降低才会缩容。
就绪延迟
对于刚启动的 Pod,HPA 默认会给予一段缓冲期,等待 Pod 准备就绪并收集到足够的数据后,再将其纳入指标计算范围,避免启动瞬间的 CPU 峰值误触发扩容。
依赖条件
使用 HPA 必须确保集群中安装了 Metrics Server:
| |
如何实现滚动更新?如何控制更新策略?
一句话原理 Kubernetes 的滚动更新通过逐个替换旧 Pod 的方式升级服务,通过 maxSurge(最大激增)和 maxUnavailable(最大不可用)两个参数精确控制更新速度与可用性之间的平衡。
一句话源码
在 Deployment 的 YAML 文件中设置 spec.strategy.type: RollingUpdate 并配置相关参数,执行 kubectl set image 命令触发更新。
一句话项目/场景 在“电商平台发版”时,确保始终有足够的 Pod 在线处理订单,用户无感知地从 v1 版本平滑过渡到 v2 版本;一旦发现 v2 报错,立即回滚到 v1。
详细解析
滚动更新的工作机制
假设当前有 3 个 v1 Pod,我们要更新到 v2。
更新流程:
- 创建:创建 1 个 v2 Pod。
- 就绪:等待 v2 Pod 通过 ReadinessProbe(就绪探针)检查,变为 Ready 状态。
- 销毁:删除 1 个 v1 Pod。
- 循环:重复上述步骤,直到所有 v1 Pod 被替换为 v2 Pod。
关键点:在整个过程中,服务是不中断的,Service 始终有后端 Pod 可用。
如何控制更新策略?
通过 Deployment 的 spec.strategy.rollingUpdate 字段控制。
A. maxSurge(最大激增)
- 定义:更新过程中,允许同时存在的总 Pod 数量上限(旧+新)。
- 作用:控制更新速度。
- 示例(Replicas=10, maxSurge=2):
- 更新时,集群最多会有 10+2=12 个 Pod。
- 如果设为 0,则必须先删掉一个旧 Pod,才能创建一个新 Pod(速度慢)。
B. maxUnavailable(最大不可用)
- 定义:更新过程中,允许不可用 Pod 数量上限。
- 作用:控制服务稳定性。
- 示例(Replicas=10, maxUnavailable=0):
- 更新时,必须保证 10 个 Pod 全部在线。
- 这意味着必须先启动新 Pod 并就绪,才能删除旧 Pod(最平滑,但资源消耗大)。
典型组合场景:
| 场景 | 配置策略 | 特点 |
|---|---|---|
| 平稳过渡(推荐) | maxSurge: 25%, maxUnavailable: 0 | 先增后减,保证总容量不下降,资源占用短暂增加。适合生产环境。 |
| 快速更新 | maxSurge: 50%, maxUnavailable: 25% | 大批量并行更新,速度快,但更新期间服务容量可能下降,风险高。 |
| 资源紧张 | maxSurge: 0, maxUnavailable: 1 | 先减后增,不需要额外资源,但更新期间服务能力会短暂下降(少一个Pod)。 |
触发更新与回滚命令
触发更新:
注意:--record 参数(旧版 K8s)会将命令记录到 revision 中,方便回滚。新版建议使用注解管理。
查看更新状态:
| |
暂停与恢复(金丝雀发布利器):
回滚操作: 如果新版本有问题,一键回到上一个版本。
什么是亲和性(Affinity)和反亲和性(Anti-Affinity)?
一句话原理 亲和性与反亲和性是 Kubernetes 中更高级的调度规则,用于精确控制 Pod 更愿意调度到哪些节点,或者坚决不调度到哪些节点,解决了简单的 NodeSelector 无法表达的复杂逻辑。
一句话源码
通过在 Pod Spec 中定义 affinity 字段,配置 requiredDuringScheduling(硬性要求)或 preferredDuringScheduling(软性偏好)。
一句话项目/场景
- 亲和性:将“前端 Web 服务”调度到部署了“高性能 SSD 磁盘”的节点上,或者让同一业务的 Pod 尽量聚拢。
- 反亲和性:将“数据库主节点”和“从节点”坚决隔离在不同的物理机上,防止单机故障导致双挂;或者将“高 CPU 消耗”的服务分散开。
详细解析
为什么需要它?(对比 NodeSelector)
- NodeSelector:只能根据节点的标签进行简单的“相等”匹配,功能太弱。
- Affinity:
- 支持软策略(Preferred):优先满足,实在不行也能跑。
- 支持硬策略(Required):必须满足,否则 Pod 一直 Pending。
- 支持运算符:In, NotIn, Exists, DoesNotExist, Gt, Lt。
- 支持拓扑域:可以基于节点、机架、可用区等维度调度。
两种类型的亲和性
A. 节点亲和性
关注 Pod 与 Node 的关系。
- 硬亲和性:Pod 必须运行在满足条件的节点上。如果不存在,Pod 处于 Pending。
- 场景:数据库 Pod 必须运行在标签为
disk=ssd的节点上。
- 场景:数据库 Pod 必须运行在标签为
- 软亲和性:Pod 倾向运行在满足条件的节点上,如果没有,也能调度到其他节点。
- 场景:Web 服务优先调度到
zone=east,但如果该区域满了,也可以去zone=west。
- 场景:Web 服务优先调度到
B. Pod 亲和性/反亲和性
关注 Pod 与 Pod 之间的关系(通过 Node 标签作为中介)。
- Pod 亲和性:让某些 Pod 靠近运行。
- 场景:前端服务应该和缓存服务在同一个节点/机架上,降低网络延迟。
- Pod 反亲和性:让某些 Pod 分散运行。
- 场景:为了保证高可用,同一个服务的 3 个副本必须分散在不同的节点或可用区。
实战 YAML 示例
场景一:节点亲和性(必须用 SSD 盘)
场景二:Pod 反亲和性(多副本必须分散)
这是生产环境保证高可用的经典配置:
| |
- 解读:必须调度到不包含
app=web-app标签 Pod 的节点上(topologyKey: kubernetes.io/hostname)。这意味着每个节点最多只能跑一个该服务的 Pod。
核心概念补充
硬策略 vs 软策略
| 策略类型 | 字段名 | 行为 | 适用场景 |
|---|---|---|---|
| 硬策略 | requiredDuringScheduling... | 必须满足。找不到节点则 Pending。 | 强制性约束(如 GPU、SSD、高可用打散)。 |
| 软策略 | preferredDuringScheduling... | 尽力满足。找不到则选次优节点。 | 性能优化(如同机架低延迟、偏好某可用区)。 |
拓扑域
这是 Pod 亲和性/反亲和性的核心。它定义了“靠近”或“分散”的范围。
kubernetes.io/hostname:范围是单个节点(分散在不同机器)。topology.kubernetes.io/zone:范围是可用区(分散在不同机房/可用区)。topology.kubernetes.io/region:范围是区域。
总结记忆口诀
- 节点亲和:找好房子(Node),比如带泳池的(SSD)。
- Pod 亲和:找好邻居,比如跟缓存住一块(低延迟)。
- Pod 反亲和:躲着邻居,比如分居两地(高可用)。
- 硬策略:非你不可,宁死不屈。
- 软策略:有则最好,无也凑合。