Skip to main content

19 posts tagged with "Architecture"

Architecture articles and guides

View all tags

从提示词到上下文工程:Claude、Codex 与多 Agent 协作的完整心智模型

· 26 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

很多人第一次使用 Claude Code 或 Codex 时,会把效果差异归结为“提示词写得好不好”。这当然重要,但只解释了很小一部分。

一个真正能持续工作的 AI Agent,不只是在读取一句 Prompt。它还会接收系统规则、项目规范、历史消息、代码与文档、Skill、MCP 工具描述、工具执行结果、长期记忆、子 Agent 汇总以及运行环境状态。随着任务推进,这些信息还会被检索、缓存、裁剪、压缩、持久化和重新装配。

因此,今天更准确的问题已经不是:

“我应该怎样写一句更神奇的提示词?”

而是:

“在 Agent 每一次决策前,应该让模型看到哪些信息,允许它调用哪些能力,怎样保留状态,又怎样证明任务真的完成?”

这就是从 **Prompt Engineering(提示词工程)**走向 **Context Engineering(上下文工程)**的关键变化。

本文基于截至 2026 年 9 月 4 日的 Claude 与 Codex 官方资料,建立一套不依赖具体产品界面的通用模型,并重点回答五个问题:

  1. Prompt、Context、Cache、Memory、Skill、MCP 到底有什么区别?
  2. Claude Code 与 Codex 如何组织项目上下文?
  3. 一个 AI Agent 从接收任务到完成验证,内部经历了什么流程?
  4. 多 Agent 为什么有时更强,又为什么经常更贵、更乱?
  5. 怎样写一份真正适合 Agent 执行的任务提示?

AI 原生 SDLC 全链路:从 Claude、Spotify 到真正可落地的团队工程系统

· 41 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

人类负责目标与判断,AI Agent 在受控环境中并行执行、验证并把生产证据反馈到下一轮规划

AI 进入软件研发以后,最容易犯的错误,是在原有 SDLC 的“编码”节点旁边放一个聊天机器人,然后宣布团队已经完成 AI 转型。

真正的变化更深:代码生成不再是主要稀缺资源,问题选择、上下文、验证、风险判断、发布反馈和人类注意力才是。团队如果只提高生成速度,结果通常不是更快交付,而是更多 PR、更长评审队列、更高变更风险和更快积累的技术债。

因此,AI 原生 SDLC 不是“AI 帮人写代码”,而是一套新的工程操作系统:

人类定义结果、边界和风险;Agent 在隔离环境中执行;确定性系统与独立评审生成证据;发布系统控制影响面;生产反馈再写回任务、规则、测试和组织知识。

本文基于截至 2026 年 8 月 30 日可获得的一手资料,重点参考:

  • Claude Code 团队的 JIT 规划、Dogfood、专家评审和扁平 Pod;
  • Anthropic Security 对 Plan、Code、Test、Deploy、Monitor、Governance 的 AI 原生安全改造;
  • Spotify 的 Backstage、Golden State、Fleet Management、Honk、Verifier 与 LLM Judge;
  • OpenAI 的 Harness Engineering、仓库内知识、隔离环境、Agent 可观测性与任务编排;
  • DORA 2025 对平台工程、交付吞吐、稳定性和信任的研究。

文章会给出完整链路、最细阶段流程、可复制模板、风险路由、工具地图、指标体系与 90 天建设计划。

WebMCP 深度解析:从概念、浏览器原理到 Agent 原生 Web 实战

· 30 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

WebMCP:人类与 AI Agent 在同一个实时网页中协作

过去的浏览器 Agent 想在网站上完成任务,通常需要截图、识别按钮、滚动页面、填写输入框,再猜测下一步该点哪里。它能工作,却像让一个只拿到监控画面的机器人操作控制台:页面布局一改、按钮被遮挡、文案稍有歧义,整条任务链就可能失败。

WebMCP 提出了另一种思路:网站主动把自身能力声明为结构化工具,由浏览器在页面和 Agent 之间完成发现、权限检查、调用与结果传递。

Agent 不再只看到“一个蓝色按钮”,而是能看到一份接近函数契约的描述:

{
"name": "book_appointment",
"description": "预约一个仍有空位的咨询时段。",
"inputSchema": {
"type": "object",
"properties": {
"date": { "type": "string", "format": "date" },
"slot": { "type": "string" }
},
"required": ["date", "slot"]
}
}

这不是要消灭图形界面,而是让同一个 Web 应用同时拥有两种可用界面:

  • 人类使用视觉 UI;
  • Agent 使用工具名、自然语言描述和 JSON Schema;
  • 两者共享同一标签页、登录状态、应用状态和可见结果。

这也是 OpenAI 发起 WebMCP Challenge 的核心命题:构建一个在人与 Agent 共同使用时会变得明显更好的 Web 应用。

先明确 WebMCP 当前的状态

截至 2026-08-27,WebMCP 是实验性、仍在演进的开放 Web 提案。当前文档是 Web Machine Learning Community Group 发布的 Draft Community Group Report,明确说明它还不是 W3C Standard,也不在 W3C Standards Track 上。

Chrome 从 149 提供 Origin Trial,本地开发也可通过 chrome://flags/#enable-webmcp-testing 启用。API、事件、权限和用户确认机制仍可能改变,生产项目应做能力检测、渐进增强并锁定测试环境。

Codex Harness 开源解读:如何读懂 Agent Loop,并以 SDK 与 App Server 构建自己的应用

· 17 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

开源 Codex Harness:应用、Harness 与执行环境的三层结构

2026 年 8 月 19 日,OpenAI 将 Codex 更清晰地定义为一个可供开发者构建产品的 开放 Agent Harness。这句话容易被误读成“Codex 模型开源了”,实际开放的是模型周围的运行时与集成面:会话、Agent Loop、工具执行、沙箱、审批、事件流、CLI、SDK 与 App Server。

用一句话概括:

模型决定下一步做什么,Harness 决定它能看到什么、可以怎样做、需要谁批准,以及整个过程如何被恢复和观察。

这篇文章会回答三个问题:

  1. openai/codex 到底开放了什么,没开放什么;
  2. 面对庞大的 Rust 工作区,应当怎样学习 Agent Harness 的原理;
  3. 如何选择 codex exec、Codex SDK 或 App Server,构建自己的应用。

DeepSeek Harness 深度解析:从一切皆插件到用基座构建自己的 Agent 应用

· 15 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

DeepSeek Harness:Cordis 内核、能力插件与追加式会话日志

2026 年 8 月,DeepSeek 开放了 DeepSeek Harness 的开发者预览与源代码。它不是“又一个 DeepSeek 模型”,也不是只把聊天框套在模型 API 外面;它是一套让模型能够读取环境、调用工具、维持会话、接受审批并持续完成任务的 Agent 运行时

官方给出的公式很直接:

Agent = Model + Harness

模型负责推理与决策,Harness 负责把推理接到真实世界:上下文从哪里来、工具如何注册、命令在哪里执行、状态怎样恢复、危险动作由谁批准、失败以后能否重放。本文会从“能跑起来”一直讲到“如何基于它开发自己的应用”。

开发者预览意味着什么

DeepSeek Harness 当前仍处于 Developer Preview,官方明确提示核心插件与 API 会快速演进并可能产生不兼容变更。本文基于 2026-08-24 的官方文档与主分支;生产项目应固定版本、保留迁移测试,不要直接追随 master

MCP 2.0 深度解析:2026-07-28 无状态协议、完整差异与实战指南

· 25 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

MCP 2026-07-28 技术架构:Host 内多个 Client 分别连接提供 Tools、Resources 与 Prompts 的 Server

2026 年 7 月 28 日发布的 Model Context Protocol 最新规范 不是一次普通增量更新。它移除了协议级会话和初始化握手,把版本与能力协商移到每一个请求,用 MRTR 重构服务器向客户端索取信息的方式,并将长任务移出核心协议。

如果把早期 MCP 看成“为桌面 AI 应用连接本地工具的会话协议”,那么这次修订更像是“可穿过网关、负载均衡器和无状态计算平台的 Agent 基础设施协议”。

先澄清版本名称

MCP 官方使用日期作为协议版本,例如 2025-11-252026-07-28官方没有发布名为 MCP 1.0MCP 2.0 的语义化版本

为方便理解,本文将官方称为 Legacy2025-11-25 及更早版本简称为“MCP 1.0”,将官方称为 Modern2026-07-28 版本简称为“MCP 2.0”。这是社区化表达,不是官方版本名。生产代码必须使用日期版本。

OKF 与 LLM Wiki 深度解析:从知识库到可编译知识操作系统

· 29 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

LLM Wiki 不是“给大模型看的百科页面”,而是把组织知识编译成一种人能读、机器能检索、Agent 能遍历、系统能验证的长期知识结构。

先澄清一个容易混淆的点:OKF 在开放知识领域通常指 Open Knowledge Foundation;而本文讨论的 OKF 是面向 LLM Wiki 的 Open Knowledge Format,可以理解为一种工程规范提案,用来约束 AI 原生知识库的目录、页面、元数据、引用、链接、校验和演进方式。

截至 2026-06-19,LLM Wiki 更像一个快速成型的系统范式,而不是已经被 W3C、ISO 或某个基金会正式标准化的协议。腾讯研究者在 2026 年 5 月的 LLM-Wiki 论文中,把它描述为一种“Retrieval as Reasoning”的检索范式:把原始文档编译成结构化 Wiki 页面,提供搜索、阅读和链接跟随工具,并用 Error Book 记录和修复知识构建错误。本文的 OKF 则是在这个方向上给出一套更可落地的格式规范。

WebRTC 全景实战 (0):架构全景与协议栈地图

· 18 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

"WebRTC 不是某一个 API,而是一整套让浏览器能够安全、低延迟地交换实时媒体的开放标准。"

如果你曾经尝试在网页里做视频通话,大概率遇到过这样的困惑:RTCPeerConnection 的文档能看懂,但 ICE 一直 failed;SDP 里一堆 a=rtpmap 不知道在协商什么;明明本地预览正常,对方却听不到声音。

这些问题的根源,通常不是某个 API 调用错了,而是缺少一张 WebRTC 协议栈的全景地图

本系列 WebRTC 全景实战 共 16 篇,将从架构认知出发,逐层深入到信令、SDP、ICE、DTLS/SRTP、RTP/RTCP、编解码、拥塞控制、SFU 架构与生产部署,每篇均配套 examples/webrtc-lab 实战代码。本文作为第零章,回答最根本的问题:WebRTC 是什么?它从哪来?它由哪些层组成?

Kubernetes 全景解析 (5):安全体系与可观测性全景

· 20 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

前言

当你的 Kubernetes 集群从开发环境走向生产环境,有两个话题再也无法回避——安全可观测性。安全是底线,确保只有正确的主体才能访问正确的资源;可观测性是生命线,让你在问题发生时能快速定位、快速恢复。

本文将从 K8s 安全的 4C 模型出发,深入 RBAC 权限控制、Pod 安全标准与服务账户管理;随后转向可观测性的三大支柱——指标、日志与链路追踪,构建一套完整的监控与诊断体系。


一、K8s 安全架构概览

1.1 4C 安全模型

Kubernetes 社区提出了经典的 4C 安全模型,将安全分为四个层次,从外到内逐层收紧:

层次名称关注点示例
第 1 层Cloud(云)云平台自身的安全配置IAM 策略、VPC、防火墙规则
第 2 层Cluster(集群)集群组件的访问控制RBAC、网络策略、审计日志
第 3 层Container(容器)容器运行时安全镜像签名、只读根文件系统、非 root 运行
第 4 层Code(代码)应用代码自身的安全输入校验、依赖漏洞、密钥管理
核心原则

4C 模型的关键思想是纵深防御(Defense in Depth)——任何单一层次的安全措施都不足以应对所有威胁,只有层层设防,才能构建真正可靠的安全体系。内层的安全措施不应依赖外层,每一层都应独立提供保护。

1.2 安全最佳实践总览

领域最佳实践
认证启用 TLS 双向认证,禁用匿名访问
授权最小权限原则,使用 RBAC 精细控制
Pod 安全强制非 root 运行,只读根文件系统
网络默认拒绝,按需开放 NetworkPolicy
镜像使用可信仓库,启用镜像签名验证
密钥使用外部密钥管理(Vault/AWS KMS),避免明文存储
审计启用 API Server 审计日志,记录所有变更

二、RBAC:基于角色的访问控制

2.1 核心概念

RBAC(Role-Based Access Control)是 K8s 授权机制中最常用、最推荐的方式。它通过四个核心对象实现权限管理:

对象作用范围说明
Role命名空间级别定义在某个命名空间内的权限规则
ClusterRole集群级别定义集群范围的权限规则
RoleBinding命名空间级别将 Role 绑定到用户/组/服务账户
ClusterRoleBinding集群级别将 ClusterRole 绑定到用户/组/服务账户
Role vs ClusterRole 的关键区别
  • Role 只能管理同一个命名空间内的资源
  • ClusterRole 可以管理所有命名空间以及非命名空间资源(如 Node、PersistentVolume、Namespace)

2.2 RBAC 权限模型

2.3 完整 YAML 示例

Role —— 命名空间管理员

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: namespace-admin
namespace: production
rules:
- apiGroups: ["", "apps", "batch"]
resources:
- pods
- pods/log
- deployments
- services
- configmaps
- secrets
- jobs
- cronjobs
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

ClusterRole —— 只读查看者

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-readonly
rules:
- apiGroups: ["", "apps", "batch", "extensions"]
resources: ["*"]
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/healthz", "/version", "/metrics"]
verbs: ["get"]

RoleBinding —— 将角色绑定到用户

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: bind-namespace-admin
namespace: production
subjects:
- kind: User
name: alice@example.com
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: dev-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: namespace-admin
apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding —— 将只读角色绑定到服务账户

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: bind-readonly-to-monitor
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
roleRef:
kind: ClusterRole
name: cluster-readonly
apiGroup: rbac.authorization.k8s.io

2.4 常见 RBAC 模式

模式适用场景实现方式
命名空间管理员团队负责人管理自己的命名空间Role + RoleBinding
只读查看者开发/测试人员查看集群状态ClusterRole + ClusterRoleBinding
开发人员开发者在指定命名空间部署应用Role(限制 verbs) + RoleBinding
运维人员运维管理节点、PV 等集群级资源ClusterRole(节点/PV 权限) + ClusterRoleBinding
聚合角色将多个 ClusterRole 合并为一个统一角色ClusterRole + aggregationRule
ClusterRole 聚合(Aggregated ClusterRoles)

Kubernetes 支持通过 aggregationRule 将多个 ClusterRole 聚合为一个组合角色。控制平面会自动监视匹配标签选择器的 ClusterRole,并将其规则合并到聚合角色的 rules 字段中。默认的用户角色(如 admineditview)就是通过聚合机制实现的,允许集群管理员通过添加匹配标签的 ClusterRole 来扩展默认角色的权限。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # 控制平面自动填充规则
注意事项
  • roleRef 一旦创建不可修改,如需变更必须删除重建 Binding
  • 避免使用 verbs: ["*"]resources: ["*"] 的通配符,遵循最小权限原则
  • 定期审计集群中的 RoleBinding 和 ClusterRoleBinding,清理不再需要的权限

三、Pod 安全标准

3.1 从 PSP 到 PSS

Kubernetes 在 v1.21 中废弃了 PodSecurityPolicy(PSP),并在 v1.25 中完全移除。取而代之的是 Pod Security Standards(PSS) + Pod Security Admission(PSA) 机制。

特性PSP(已废弃)PSS + PSA(推荐)
实现方式准入控制器(Admission Controller)内置准入插件
配置粒度每个 Pod 可绑定不同策略按命名空间统一标签
策略继承支持不支持(需借助第三方 Gatekeeper)
状态v1.25 已移除v1.23+ 内置可用

3.2 三种策略级别

级别说明典型控制
Privileged无限制,完全开放无任何控制
Baseline最低限度的安全防护禁止特权容器、禁止挂载宿主机路径、限制 hostNetwork、限制 SELinux 类型、禁止探针/生命周期钩子中的 host 字段(v1.34+)、限制 AppArmor 配置文件、限制安全 sysctl
Restricted高度安全,生产推荐强制非 root、只读根文件系统、限制 Capabilities(仅允许 NET_BIND_SERVICE)、禁止 seccomp profile=unconfined、要求显式设置 seccomp
Baseline 策略的完整控制列表(基于 v1.34 官方文档)

根据 Pod Security Standards 官方文档,Baseline 策略包含以下控制:

控制项说明
HostProcess禁止 Windows HostProcess 容器
Host Namespaces禁止共享 hostNetwork/hostPID/hostIPC
Privileged Containers禁止特权容器
Capabilities限制可添加的 Capabilities(如 AUDIT_WRITE、CHOWN、NET_BIND_SERVICE 等)
HostPath Volumes禁止 hostPath 卷
Host Ports禁止或限制 hostPort
Host Probes / Lifecycle Hooks(v1.34+)禁止探针和生命周期钩子中的 host 字段
AppArmor限制 AppArmor 配置文件类型(RuntimeDefault/Localhost)
SELinux限制 SELinux 类型(container_t/container_init_t/container_kvm_t/container_engine_t),禁止自定义 user/role
/proc Mount Type要求使用默认 /proc 掩码
Seccomp禁止显式设置为 Unconfined
Sysctls仅允许安全 sysctl 子集

3.3 Pod Security Admission 配置

PSA 通过在命名空间上打标签来生效,支持三种执行模式:

# 在命名空间上配置 PSA 标签
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# enforce: 违反策略的 Pod 将被拒绝
pod-security.kubernetes.io/enforce: restricted
# audit: 违反策略的 Pod 会记录审计日志
pod-security.kubernetes.io/audit: restricted
# warn: 违反策略的 Pod 会触发用户警告
pod-security.kubernetes.io/warn: restricted
# 指定策略版本
pod-security.kubernetes.io/enforce-version: latest

3.4 v1.34 新增安全控制详解

Kubernetes v1.34 在 Pod Security Standards 中引入了多项重要安全控制更新:

3.4.1 Host Probes / Lifecycle Hooks(v1.34+)

这是 v1.34 中 Baseline 策略新增的控制项,禁止在探针和生命周期钩子中使用 host 字段,防止容器通过 HTTP/TCP 探针访问宿主机网络。

受限字段包括:

  • livenessProbe.httpGet.host / readinessProbe.httpGet.host / startupProbe.httpGet.host
  • livenessProbe.tcpSocket.host / readinessProbe.tcpSocket.host / startupProbe.tcpSocket.host
  • lifecycle.postStart.httpGet.host / lifecycle.preStop.httpGet.host
  • lifecycle.postStart.tcpSocket.host / lifecycle.preStop.tcpSocket.host

允许值Undefined/nil 或空字符串 ""

这意味着在 Baseline 策略下,探针和生命周期钩子不能再指向宿主机的 IP 地址或主机名,有效防止了通过探针机制进行的 SSRF(服务端请求伪造)攻击。

3.4.2 SELinux 类型扩展

SELinux 控制在 Baseline 策略中进一步收紧:

  • 允许的 SELinux 类型container_tcontainer_init_tcontainer_kvm_tcontainer_engine_t(自 Kubernetes 1.31起新增)
  • 禁止:自定义 SELinux userrole 选项(允许值仅为 Undefined/""

container_engine_t 类型适用于需要与容器引擎交互的特殊工作负载场景。

3.4.3 安全 Sysctls 扩展

自 Kubernetes 1.29 起,Baseline 策略允许的安全 sysctl 列表新增了以下 TCP keepalive 相关参数:

Sysctl 名称说明新增版本
net.ipv4.tcp_keepalive_timeTCP keepalive 探测间隔since 1.29
net.ipv4.tcp_fin_timeoutTCP FIN 超时时间since 1.29
net.ipv4.tcp_keepalive_intvlTCP keepalive 探测间隔since 1.29
net.ipv4.tcp_keepalive_probesTCP keepalive 探测次数since 1.29

完整的安全 sysctl 列表还包括:kernel.shm_rmid_forcednet.ipv4.ip_local_port_rangenet.ipv4.ip_unprivileged_port_startnet.ipv4.tcp_syncookiesnet.ipv4.ping_group_rangenet.ipv4.ip_local_reserved_ports(since 1.27)。

3.4.4 AppArmor 控制

Baseline 策略对 AppArmor 配置文件的控制:

  • 允许的类型RuntimeDefaultLocalhost,或通过注解 container.apparmor.security.beta.kubernetes.io/* 设置 runtime/defaultlocalhost/*
  • 目的:防止禁用或绕过默认的 AppArmor 安全配置文件

3.5 SecurityContext 配置

SecurityContext 是 Pod 安全的核心配置点,可以在 Pod 级别和容器级别分别设置:

apiVersion: v1
kind: Pod
metadata:
name: secure-pod
namespace: production
spec:
securityContext:
# Pod 级别:所有容器共享
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.25
securityContext:
# 容器级别:仅对当前容器生效
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
为什么需要 emptyDir 挂载?

当设置 readOnlyRootFilesystem: true 时,Nginx 等应用需要写入 /tmp 和缓存目录。通过 emptyDir 提供临时可写目录,既满足了应用需求,又保持了根文件系统的只读安全。


四、服务账户与 Token 管理

4.1 ServiceAccount 概念

Kubernetes 中每个 Pod 都关联一个服务账户(ServiceAccount),用于标识 Pod 的身份。当 Pod 需要访问 API Server 时,使用的就是 ServiceAccount 的凭证。

# 创建专用服务账户
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
automountServiceAccountToken: false

4.2 自动挂载 Token 的风险

默认情况下,K8s 会将 ServiceAccount Token 自动挂载到每个 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ 目录。这意味着:

  • 任何能进入容器的人都能获取 Token
  • 如果容器被攻破,攻击者可以利用 Token 访问 API Server
  • 对于不需要访问 API Server 的 Pod,这是不必要的安全暴露
# 方式一:在 Pod 规范中禁用自动挂载
apiVersion: v1
kind: Pod
metadata:
name: app-no-token
spec:
serviceAccountName: app-service-account
automountServiceAccountToken: false
containers:
- name: app
image: myapp:latest
# 方式二:在 ServiceAccount 上全局禁用
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
automountServiceAccountToken: false

4.3 外部 Token 供应

对于需要更精细控制 Token 生命周期(如短时效 Token、Token 轮换)的场景,可以使用 TokenRequest API 获取面向 Pod 的绑定 Token:

# 使用 projected volume 注入短时效 Token
apiVersion: v1
kind: Pod
metadata:
name: app-with-projected-token
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: token
mountPath: /var/run/secrets/tokens
volumes:
- name: token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600 # Token 有效期 1 小时
audience: api
最佳实践
  1. 不需要访问 API Server 的 Pod:设置 automountServiceAccountToken: false
  2. 需要访问 API Server 的 Pod:创建专用的 ServiceAccount,配合最小权限的 RBAC
  3. 高安全要求场景:使用 projected volume + 短时效 Token,实现自动轮换

五、可观测性体系概览

5.1 三大支柱

可观测性(Observability)的三大支柱构成了完整的系统诊断能力:

支柱回答的问题典型工具数据特征
Metrics(指标)系统现在是什么状态?Prometheus、Thanos结构化数值,适合聚合与告警
Logs(日志)系统发生了什么?Fluent Bit、Loki、ELK非结构化文本,适合问题排查
Traces(链路追踪)请求经过了哪些路径?Jaeger、Zipkin、Tempo结构化事件流,适合性能分析与故障定位
为什么需要三大支柱?

单一支柱无法回答所有问题。指标告诉你"CPU 使用率 90%",但不能告诉你"是哪个请求导致的";日志告诉你"请求超时了",但不能告诉你"请求在哪个服务卡住了"。只有三者结合,才能快速、准确地定位问题。


六、Prometheus + Grafana:指标监控

6.1 Prometheus 在 K8s 中的部署

在生产环境中,推荐使用 kube-prometheus-stack(基于 Prometheus Operator)一键部署完整的监控栈:

# 通过 Helm 安装 kube-prometheus-stack
# helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# helm install prometheus prometheus-community/kube-prometheus-stack \
# --namespace monitoring --create-namespace

Prometheus Operator 引入了四个自定义资源(CRD)来声明式管理监控配置:

CRD作用
Prometheus管理 Prometheus 实例的生命周期
ServiceMonitor基于 Service 选择器自动发现监控目标
PodMonitor基于 Pod 标签直接发现监控目标
PrometheusRule声明式定义告警规则和录制规则

6.2 核心监控指标

级别关键指标说明
容器级container_cpu_usage_seconds_total容器 CPU 使用量
container_memory_working_set_bytes容器实际内存使用(含 Page Cache)
container_fs_usage_bytes容器文件系统使用量
Pod 级kube_pod_status_phasePod 当前阶段(Pending/Running/Succeeded/Failed)
kube_pod_container_status_restarts_totalPod 重启次数
kube_pod_container_status_waiting_reason容器等待原因(ImagePullBackOff 等)
Node 级node_cpu_seconds_total节点 CPU 使用量
node_memory_MemAvailable_bytes节点可用内存
kube_node_status_condition节点状态(Ready/NotReady)

6.3 ServiceMonitor 示例

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: app-service-monitor
namespace: monitoring
labels:
release: prometheus # 匹配 Prometheus 实例的选择器
spec:
selector:
matchLabels:
app: my-application # 匹配目标 Service 的标签
namespaceSelector:
names:
- production # 监控 production 命名空间中的 Service
endpoints:
- port: http # Service 中的端口名
path: /metrics # 指标暴露路径
interval: 30s # 采集间隔
scrapeTimeout: 10s # 采集超时

6.4 告警规则示例

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: app-alerting-rules
namespace: monitoring
labels:
release: prometheus
spec:
groups:
- name: app-alerts
rules:
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0
for: 15m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 处于 CrashLoopBackOff"
description: "容器 {{ $labels.container }} 在过去 15 分钟内重启超过 5 次"

- alert: HighMemoryUsage
expr: |
(container_memory_working_set_bytes / container_spec_memory_limit_bytes) > 0.9
and container_spec_memory_limit_bytes > 0
for: 5m
labels:
severity: warning
annotations:
summary: "容器 {{ $labels.container }} 内存使用率超过 90%"
description: "当前使用 {{ $value | humanizePercentage }},限制 {{ $labels.container }}"

- alert: NodeNotReady
expr: kube_node_status_condition{condition="Ready",status="true"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.node }} 处于 NotReady 状态"
告警设计原则
  • Critical 告警:需要立即响应(如节点宕机、Pod CrashLoop)
  • Warning 告警:需要关注但不必立即处理(如磁盘使用率 > 80%)
  • 设置合理的 for 持续时间,避免瞬时抖动触发误报
  • 告警信息要包含足够的上下文,让值班人员无需额外查询即可判断影响范围

七、日志收集体系

7.1 日志收集模式对比

模式原理优点缺点
Sidecar每个 Pod 注入一个日志采集容器隔离性好,可按应用定制资源开销大,管理复杂
DaemonSet每个 Node 运行一个采集 Agent资源开销低,管理简单需要共享日志卷
直连应用直接推送日志到后端无需额外组件与后端强耦合,侵入应用

7.2 常见方案对比

方案组合特点适用场景
PLG StackPromtail + Loki + Grafana轻量,与 Grafana 深度集成已有 Grafana 的团队
EFK StackFluentd/Fluent Bit + Elasticsearch + Kibana功能强大,全文搜索大规模日志分析
Fluent Bit + LokiFluent Bit + Loki + Grafana极低资源消耗资源敏感的环境

7.3 Fluent Bit DaemonSet 配置

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
labels:
app: fluent-bit
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
serviceAccountName: fluent-bit
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
containers:
- name: fluent-bit
image: fluent/fluent-bit:3.0.0
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
- name: config
mountPath: /fluent-bit/etc/fluent-bit.conf
subPath: fluent-bit.conf
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
- name: config
configMap:
name: fluent-bit-config

八、链路追踪

8.1 OpenTelemetry 在 K8s 中的集成

OpenTelemetry(OTel) 是 CNCF 的可观测性标准框架,统一了指标、日志和链路追踪的数据采集。在 K8s 中,通常部署 OpenTelemetry Collector 作为数据的统一入口:

apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
namespace: observability
spec:
replicas: 2
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
containers:
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.96.0
args:
- --config=/etc/otelcol/config.yaml
ports:
- containerPort: 4317 # OTLP gRPC
- containerPort: 4318 # OTLP HTTP
- containerPort: 8889 # Prometheus metrics
volumeMounts:
- name: config
mountPath: /etc/otelcol
volumes:
- name: config
configMap:
name: otel-collector-config

8.2 分布式追踪最佳实践

实践说明
统一 SDK 接入所有服务使用 OpenTelemetry SDK,自动注入 Trace Context
合理的采样策略生产环境使用尾部采样(Tail Sampling),基于错误率/延迟/状态码决定是否保留
上下文传播确保跨服务调用时 TraceID 正确传播(HTTP Header、gRPC Metadata)
关联日志与追踪在日志中注入 TraceID,实现日志与追踪的联动查询
设置合理的 Span 层级避免过深的 Span 嵌套,关注关键路径和外部调用
TraceID 与日志联动

在应用日志中添加 TraceID 字段,可以在 Grafana 中实现从告警到日志再到追踪的完整排查链路:

# 应用日志示例
2026-04-09 10:23:45 INFO [trace_id=abc123 span_id=def456] Processing order request from user_1234
2026-04-09 10:23:46 ERROR [trace_id=abc123 span_id=def456] Failed to call payment service: timeout

九、本章小结

本文从安全与可观测性两个维度,系统梳理了 Kubernetes 生产环境中的关键能力:

安全体系方面,我们覆盖了从 4C 安全模型到具体实践的完整链路:

  • RBAC 提供了精细的权限控制,通过 Role/ClusterRole 和 Binding 的组合,实现最小权限原则。ClusterRole 还支持 aggregationRule 聚合机制,便于扩展默认角色权限。
  • Pod Security Standards 替代了已废弃的 PSP,通过 PSA 标签为命名空间设置安全基线。v1.34 中 Baseline 策略新增了 Host Probes/Lifecycle Hooks 控制,SELinux 新增 container_engine_t 类型,安全 sysctl 列表也进一步扩展。
  • ServiceAccount Token 管理 教会我们如何控制 Pod 的 API Server 访问权限,避免不必要的凭证暴露。

可观测性体系方面,我们构建了三大支柱的完整图景:

  • Prometheus + Grafana 负责指标采集、可视化与告警,是监控体系的核心
  • Fluent Bit + Loki 提供轻量高效的日志收集与查询能力
  • OpenTelemetry + Jaeger 实现了分布式链路追踪,让跨服务调用路径一目了然

安全与可观测性不是孤立的话题——良好的可观测性是安全事件响应的基础,而安全策略本身也需要被持续监控。在下一篇文章中,我们将深入 Kubernetes 的调度策略与资源管理,探讨如何让集群的每一份资源都物尽其用。


十、官方文档参考

本文内容基于 Kubernetes v1.34 官方文档校验,以下是相关官方文档链接:

安全相关

可观测性相关


系列导航

章节主题状态
0架构设计与核心概念✅ 已发布
1工作负载与 Pod 生命周期深度解析✅ 已发布
2网络模型与服务发现全链路解析✅ 已发布
3存储体系与配置管理深度剖析✅ 已发布
4调度器、资源管理与弹性伸缩✅ 已发布
5安全体系与可观测性全景✅ 已发布
6生产级微服务架构实战✅ 已发布
7有状态应用与 Operator 模式实战✅ 已发布

Kubernetes 全景解析 (4):调度器、资源管理与弹性伸缩

· 21 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

前言

在 Kubernetes 集群中,调度器(Scheduler)扮演着"决策中枢"的角色——每一个 Pod 应该运行在哪个节点上,都由它来决定。而资源管理(Resource Management)与弹性伸缩(Autoscaling)则是保障集群高效、稳定运行的关键机制。这三者共同构成了 K8s 资源层的核心能力。

本文将从资源模型出发,深入剖析 kube-scheduler 的调度机制,全面讲解 HPA/VPA/Cluster Autoscaler 三级弹性伸缩策略,并介绍 ResourceQuota、LimitRange、PriorityClass 等资源治理工具,帮助你构建一套完整的 K8s 资源管理知识体系。


一、资源模型基础

1.1 Kubernetes 可管理资源类型

Kubernetes 对容器可以使用的资源进行了抽象,目前支持以下几种核心资源类型:

资源类型缩写说明可压缩
CPUcpu计算资源,以核心(core)为单位,支持小数(如 0.5 = 500m)
Memorymemory内存资源,以字节为单位(支持 Ki/Mi/Gi)
Ephemeral Storageephemeral-storage临时存储(日志、EmptyDir 等),以字节为单位
Extended Resourcesnvidia.com/gpu扩展资源(如 GPU、Infiniband),由设备插件注册
可压缩 vs 不可压缩资源
  • 可压缩资源(Compressible):CPU 是可压缩的。当 Pod 超过 CPU Limit 时,不会被杀掉,而是被限流(throttled),表现为性能下降。
  • 不可压缩资源(Incompressible):内存和存储是不可压缩的。当 Pod 超过 Memory Limit 时,会被 OOM Killer 杀掉并重启。

理解这一区别对于合理设置资源配额至关重要。

1.2 Request vs Limit

Kubernetes 通过 requestslimits 两个字段来控制容器的资源使用:

  • Request(请求量):调度器依据此值决定将 Pod 调度到哪个节点(保证最低可用资源)
  • Limit(限制量):运行时容器可使用的资源上限(硬限制)
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
cpu: "250m" # 0.25 核,调度依据
memory: "256Mi" # 256 MiB,调度依据
limits:
cpu: "500m" # 0.5 核,运行时上限
memory: "512Mi" # 512 MiB,运行时上限,超出则 OOM Kill
Limit 可以省略吗?

如果只设置了 requests 而没有设置 limits,在默认情况下(未配置 LimitRange),limits 默认等于节点可分配资源上限,这意味着容器可以无限使用资源。在生产环境中,强烈建议同时设置 requests 和 limits

1.3 QoS 服务质量类别

Kubernetes 根据资源配额的设置方式,将 Pod 分为三个 QoS(Quality of Service)等级。当节点资源不足时,K8s 会优先驱逐低 QoS 的 Pod。

三个 QoS 等级的详细对比:

QoS 等级条件CPU 行为内存行为驱逐优先级
Guaranteed所有容器 Request == Limit(CPU + Memory)稳定,不会被限流超限则 OOM Kill最低(最后驱逐)
Burstable至少一个容器设置了 Request 或 Limit(但不满足 Guaranteed)可能被限流超限则 OOM Kill中等
BestEffort所有容器均未设置 Request 和 Limit最先被限流最先被 OOM Kill最高(最先驱逐)
生产环境建议

对于核心业务(如支付、订单),建议设置为 Guaranteed 级别,确保资源独占;对于一般业务(如日志处理),设置为 Burstable 即可;BestEffort 仅适用于测试或临时任务。


二、kube-scheduler:调度器深度解析

2.1 调度流程概览

kube-scheduler 是 Kubernetes 的核心组件之一,负责将新创建的、未调度的 Pod 分配到合适的节点上。根据官方文档,kube-scheduler 通过**两步操作(2-step operation)**完成节点选择:

kube-scheduler selects a node for the pod in a 2-step operation: 1. Filtering 2. Scoring —— Kubernetes Scheduler 官方文档

Scheduling Profiles vs Scheduling Policies

官方文档指出,有两种方式配置调度器的过滤和打分行为:

  1. Scheduling Profiles(推荐):通过配置插件(Plugins)实现不同调度阶段,包括 QueueSortFilterScoreBindReservePermit 等扩展点。
  2. Scheduling Policies(旧版方式):通过配置 Predicates(过滤)和 Priorities(打分)来定义调度策略。

2.2 过滤阶段(Filtering)

过滤阶段的目标是快速排除不满足条件的节点,缩小候选范围。通过过滤的节点称为可行节点(Feasible Nodes)。以下是常见的过滤策略:

过滤策略说明配置方式
NodeName直接指定节点名称,跳过所有调度逻辑spec.nodeName
nodeSelector基于节点标签的简单匹配spec.nodeSelector
nodeAffinity基于节点标签的高级匹配(支持软约束)spec.affinity.nodeAffinity
podAffinityPod 亲和性,倾向于与某些 Pod 部署在一起spec.affinity.podAffinity
podAntiAffinityPod 反亲和性,倾向于远离某些 Podspec.affinity.podAntiAffinity
Taint/Toleration节点污点与 Pod 容忍度匹配spec.tolerations
资源检查节点剩余资源是否满足 Pod 的 Request自动
Volume 检查节点是否能挂载 Pod 所需的存储卷自动

2.3 打分阶段(Scoring)

经过过滤后,调度器对剩余的候选节点进行打分,选择得分最高的节点。常见的打分策略包括:

打分策略权重说明
NodeResourcesFit默认 1资源均衡分配,倾向于选择资源使用率更均衡的节点
NodeAffinity默认 1满足节点亲和性软约束的节点获得加分
PodAffinity默认 1满足 Pod 亲和性软约束的节点获得加分
ImageLocality默认 1节点上已存在 Pod 所需镜像时加分(减少拉取时间)
TaintToleration默认 1容忍节点污点的 Pod 获得加分
InterPodAffinity默认 1Pod 间亲和/反亲和性评分
VolumeBinding默认 1PV/PVC 绑定评分
自定义调度器与 Scheduler Framework

Kubernetes 允许你编写自定义调度器(Custom Scheduler),通过实现 Scheduler Framework 的扩展点(Extension Points)来插入自定义逻辑。Scheduling Profiles 配置中支持的插件阶段包括:QueueSortFilterScoreBindReservePermitPreBindPostBind 等。更多详情请参阅 kube-scheduler 配置参考

2.4 nodeSelector:简单节点选择

nodeSelector 是最简单的节点选择方式,通过标签匹配来约束 Pod 的调度目标:

apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
nodeSelector:
gpu: "nvidia-tesla-t4" # 只调度到具有此标签的节点
disktype: "ssd"
containers:
- name: cuda-app
image: nvidia/cuda:12.0-base
resources:
limits:
nvidia.com/gpu: "1" # 申请 1 块 GPU

2.5 nodeAffinity:高级节点亲和性

nodeAffinity 支持更灵活的匹配规则,包括硬约束(required)软约束(preferred)

apiVersion: v1
kind: Pod
metadata:
name: affinity-pod
spec:
affinity:
nodeAffinity:
# 硬约束:必须满足,否则 Pod 无法调度
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["us-east-1a", "us-east-1b"]
- key: node-type
operator: NotIn
values: ["spot-instance"]
# 软约束:尽量满足,不满足也能调度
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: node-role.kubernetes.io/worker
operator: In
values: ["high-memory"]
containers:
- name: app
image: nginx:1.25
操作符说明

nodeAffinity 支持的操作符:InNotInExistsDoesNotExistGtLt。其中 GtLt 仅用于数值比较。

2.6 podAffinity 与 podAntiAffinity

Pod 亲和性用于控制 Pod 之间的部署位置关系:

apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
# Pod 亲和性:与 cache Pod 部署在同一可用区
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: cache
topologyKey: topology.kubernetes.io/zone
# Pod 反亲和性:不同副本尽量分布在不同节点
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
containers:
- name: web
image: nginx:1.25
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
topologyKey 的重要性

topologyKey 是亲和性规则的关键字段,它定义了拓扑域的划分维度。常用的值包括:

  • kubernetes.io/hostname:节点级别
  • topology.kubernetes.io/zone:可用区级别
  • topology.kubernetes.io/region:区域级别

选择合适的 topologyKey 对于实现高可用部署至关重要。

2.7 Taint 与 Toleration:污点容忍机制

Taint(污点)是作用于节点上的标记,用于排斥不容忍该污点的 Pod。Toleration(容忍度)是 Pod 上的声明,表示可以容忍特定的污点。

# 给节点添加污点
# kubectl taint nodes node1 dedicated=gpu:NoSchedule

apiVersion: v1
kind: Pod
metadata:
name: gpu-workload
spec:
# 声明容忍度
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: cuda-app
image: nvidia/cuda:12.0-base

Taint 的 effect 类型:

Effect说明
NoSchedule不调度新的不容忍 Pod(已运行的 Pod 不受影响)
PreferNoSchedule尽量不调度(软约束)
NoExecute不调度,且驱逐已运行的不容忍 Pod
常见内置 Taint

Kubernetes 自动为特定场景的节点添加 Taint:

  • node.kubernetes.io/not-ready:节点未就绪
  • node.kubernetes.io/unreachable:节点不可达
  • node.kubernetes.io/memory-pressure:内存压力
  • node.kubernetes.io/disk-pressure:磁盘压力
  • node.kubernetes.io/network-unavailable:网络不可用
  • node.kubernetes.io/unschedulable:节点被标记为不可调度(cordon)

三、HPA:水平 Pod 自动伸缩

3.1 HPA 工作原理

Horizontal Pod Autoscaler(HPA)通过监控 Pod 的资源使用指标,自动调整 Deployment/ReplicaSet/StatefulSet 的副本数量,使应用能够根据负载变化自动扩缩。

3.2 扩缩算法详解

HPA 的核心算法如下:

期望副本数 = ceil(当前副本数 × (当前指标值 / 目标指标值))
算法示例

假设 Deployment 当前有 4 个副本,目标 CPU 利用率为 50%:

  • 当前平均 CPU 利用率为 80% → 期望副本数 = ceil(4 × 80/50) = ceil(6.4) = 7
  • 当前平均 CPU 利用率为 20% → 期望副本数 = ceil(4 × 20/50) = ceil(1.6) = 2

注意:HPA 不会将副本数缩减到低于 spec.replicas.minReplicas(默认为 1)。

3.3 指标类型

HPA 支持四种指标类型:

指标类型数据来源示例
ResourceMetrics Server(CPU/内存)CPU 利用率 50%
Container ResourceMetrics Server(容器级别)容器内存使用量
Object自定义指标(如 Ingress QPS)每秒请求数
External外部指标系统(如 Prometheus)Kafka 队列积压消息数

3.4 行为配置

从 Kubernetes 1.18 开始,HPA 引入了 behavior 字段,允许精细控制扩缩行为:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: "500Mi"
behavior:
# 缩容冷却窗口与策略
scaleDown:
stabilizationWindowSeconds: 300 # 5 分钟内不重复缩容
policies:
- type: Percent
value: 10 # 每次最多缩容 10%
periodSeconds: 60 # 每 60 秒允许一次缩容
- type: Pods
value: 2 # 或每次最多缩容 2 个 Pod
periodSeconds: 60
selectPolicy: Min # 取两种策略中更保守的
# 扩容策略
scaleUp:
stabilizationWindowSeconds: 0 # 扩容不需要冷却
policies:
- type: Percent
value: 100 # 允许一次扩容 100%
periodSeconds: 15 # 每 15 秒允许一次扩容
- type: Pods
value: 4 # 或每次最多扩容 4 个 Pod
periodSeconds: 15
selectPolicy: Max # 取两种策略中更激进的
扩缩行为建议
  • 扩容应该快:用户不希望等待太久,建议设置较短的 periodSeconds(如 15s)
  • 缩容应该慢:避免频繁缩容导致的服务抖动,建议设置较长的 stabilizationWindowSeconds(如 300s)
  • 使用 selectPolicy:扩容选 Max(激进),缩容选 Min(保守)

四、VPA:垂直 Pod 自动伸缩

4.1 VPA 工作模式

Vertical Pod Autoscaler(VPA)通过调整 Pod 的 CPU 和内存 Request/Limit 来实现垂直伸缩。VPA 支持三种工作模式:

模式说明适用场景
Auto自动更新 Pod 的资源配额(会重启 Pod)非关键业务,可容忍重启
Recreate自动更新,且在更新时重启 Pod同 Auto
Off仅提供建议,不执行变更评估阶段,收集数据

4.2 VPA 与 HPA 的协作与冲突

VPA 与 HPA 的冲突

VPA 和 HPA 不能同时基于 CPU/内存指标工作。原因很简单:HPA 通过增加副本数来降低单个 Pod 的资源使用率,而 VPA 通过增加单个 Pod 的资源配额来满足需求。两者同时基于 CPU/内存工作会导致"扩容循环"——HPA 增加 Pod 数量导致单个 Pod 负载降低,VPA 随之降低资源配额,然后 HPA 又需要更多 Pod 来满足需求。

解决方案:HPA 基于 CPU/内存指标伸缩,VPA 仅基于自定义指标(如内存使用量)工作;或者使用 HPA 基于 CPU 伸缩,VPA 仅调整内存。

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
updatePolicy:
updateMode: "Auto" # Auto / Recreate / Off
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: "100m"
memory: "128Mi"
maxAllowed:
cpu: "2"
memory: "2Gi"
controlledResources: ["cpu", "memory"]
recommenders:
- name: custom-recommender # 可自定义推荐器

五、Cluster Autoscaler:节点级伸缩

5.1 CA 工作原理

Cluster Autoscaler(CA)负责在集群级别自动调整节点数量。当 Pod 因资源不足而无法调度(Pending)时,CA 会自动添加新节点;当节点利用率持续偏低时,CA 会自动移除空闲节点。

CA 的核心工作逻辑:

  1. 扩容触发:检测到有 Pod 处于 Pending 状态,且原因是资源不足
  2. 评估节点组:根据 Pod 的资源需求、节点亲和性等约束,选择合适的节点组
  3. 创建节点:调用云厂商 API 创建新节点
  4. 缩容触发:节点利用率持续低于阈值(默认 50%),且节点上的 Pod 可以被迁移到其他节点
  5. 驱逐 Pod:安全驱逐节点上的 Pod(非 Critical Pod、非 DaemonSet Pod)
  6. 删除节点:调用云厂商 API 删除节点

5.2 CA 与 HPA 的配合

CA 和 HPA 的配合构成了 Kubernetes 的两级弹性伸缩体系

层级组件伸缩维度响应速度粒度
第一级HPAPod 数量秒级细粒度
第二级Cluster Autoscaler节点数量分钟级粗粒度

典型工作流程:负载增加 → HPA 增加 Pod 副本 → 节点资源不足 → Pod Pending → CA 添加新节点 → 新 Pod 被调度到新节点。

5.3 云厂商集成

CA 需要与云厂商的 API 集成来管理节点池:

云厂商节点组实现CA 配置
AWSASG(Auto Scaling Group) / EKS Managed Node Group--nodegroup-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled
GCPMIG(Managed Instance Group) / GKE Node Pool自动发现
AzureVMSS(Virtual Machine Scale Set) / AKS Node Pool--nodegroup-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled
阿里云ECI / ACK 节点池--nodegroup-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled
CA 的安全限制

Cluster Autoscaler 不会驱逐以下 Pod:

  • 通过 PDB(PodDisruptionBudget)保护的 Pod(驱逐会违反最小可用数)
  • 没有被 Controller 管理的裸 Pod(Bare Pod)
  • 使用本地存储的 Pod(数据会随节点删除而丢失)
  • kube-system 命名空间中且不是 DaemonSet 管理的 Pod
  • 配置了 "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" 注解的 Pod

六、资源配额与限制

6.1 ResourceQuota:命名空间级资源配额

ResourceQuota 用于限制一个命名空间中可以创建的资源总量,防止某个团队或项目占用过多集群资源。

apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
# 计算资源配额
requests.cpu: "20" # 该命名空间最多请求 20 核 CPU
requests.memory: "40Gi" # 最多请求 40Gi 内存
limits.cpu: "40" # 最多限制 40 核 CPU
limits.memory: "80Gi" # 最多限制 80Gi 内存
# 对象数量配额
pods: "50" # 最多 50 个 Pod
services: "10" # 最多 10 个 Service
persistentvolumeclaims: "20" # 最多 20 个 PVC
configmaps: "20" # 最多 20 个 ConfigMap
secrets: "20" # 最多 20 个 Secret
# 存储
requests.storage: "100Gi" # 最多请求 100Gi 存储
ResourceQuota 的作用范围

ResourceQuota 只限制设置了 requestslimits 的 Pod。如果一个 Pod 没有设置资源请求,它不会计入 ResourceQuota 的配额,但也不会被调度(除非命名空间配置了 LimitRange 来提供默认值)。

6.2 LimitRange:默认资源限制

LimitRange 用于为命名空间中的 Pod 或 Container 设置默认的资源请求和限制值,确保即使 Pod 的 YAML 中没有声明资源,也能获得合理的默认值。

apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-a
spec:
limits:
# Container 级别默认值
- type: Container
default: # 默认 Limit
cpu: "500m"
memory: "512Mi"
defaultRequest: # 默认 Request
cpu: "100m"
memory: "128Mi"
max: # 最大允许值
cpu: "2"
memory: "2Gi"
min: # 最小允许值
cpu: "50m"
memory: "64Mi"
# Pod 级别限制
- type: Pod
max:
cpu: "4"
memory: "4Gi"

6.3 PriorityClass:优先级与抢占

PriorityClass 用于定义 Pod 的优先级。当集群资源不足时,高优先级的 Pod 可以抢占低优先级 Pod 的资源。

# 定义高优先级类
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
description: "核心业务 Pod,优先调度"
value: 1000000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
# 定义低优先级类
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority
description: "批处理任务,资源空闲时运行"
value: 100
globalDefault: false
preemptionPolicy: PreemptLowerPriority
# 使用优先级类
apiVersion: v1
kind: Pod
metadata:
name: critical-app
spec:
priorityClassName: high-priority
containers:
- name: app
image: nginx:1.25
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
抢占机制

当高优先级 Pod 无法调度时,调度器会尝试驱逐低优先级 Pod 来释放资源。抢占过程分为两步:

  1. 驱逐(Eviction):找到可以抢占的低优先级 Pod
  2. 等待(Waiting):等待被驱逐的 Pod 优雅终止(graceful shutdown)

系统保留的 PriorityClass:

  • system-cluster-critical(值 2000000000):系统组件专用
  • system-node-critical(值 2000001000):节点关键组件专用(如 kube-proxy)

七、调度策略最佳实践

7.1 生产环境调度建议

场景建议策略
核心业务Guaranteed QoS + nodeAffinity 硬约束 + 高优先级 + PDB 保护
批处理任务BestEffort/Burstable QoS + 低优先级 + 反亲和性避免影响在线业务
GPU 工作负载nodeSelector + Taint/Toleration + ResourceQuota 限制 GPU 数量
高可用部署podAntiAffinity(hostname 级别)+ topologySpreadConstraints
多可用区部署nodeAffinity(zone 级别)+ topologySpreadConstraints

7.2 常见调度问题排查

问题现象可能原因排查命令
Pod 一直 Pending资源不足 / 亲和性不满足 / Taint 不匹配kubectl describe pod <name>
Pod 频繁被驱逐节点资源压力 / QoS 等级过低kubectl get events --sort-by=.metadata.creationTimestamp
节点资源不均衡缺少反亲和性配置 / 打分权重不合理kubectl top nodes
HPA 不生效未安装 Metrics Server / 指标未就绪kubectl get hpa -w
VPA 与 HPA 冲突同时基于 CPU/内存工作检查 VPA 和 HPA 的指标配置
排查 Pending Pod 的黄金法则

当 Pod 处于 Pending 状态时,第一步永远是执行 kubectl describe pod <name>,查看 Events 部分。调度器会在 Events 中详细记录过滤失败的原因,例如:

0/5 nodes are available: 1 Insufficient cpu, 3 node(s) had taint {node.kubernetes.io/disk-pressure:}, that the pod didn't tolerate, 1 node(s) didn't match node selector.

这条信息清晰地告诉你:1 个节点 CPU 不足,3 个节点有磁盘压力污点,1 个节点不匹配 nodeSelector。


八、官方文档参考

本文内容基于 Kubernetes v1.34 官方文档校验,以下是相关官方文档链接:

调度相关

资源管理相关

配额与限制


九、本章小结

本文深入剖析了 Kubernetes 调度与资源管理的核心机制,主要知识点回顾如下:

  1. 资源模型:K8s 通过 Request/Limit 控制容器的资源使用,QoS 等级(Guaranteed/Burstable/BestEffort)决定了资源不足时的驱逐顺序。

  2. 调度器:kube-scheduler 通过官方定义的"Filtering → Scoring"两步操作完成节点选择,随后通过 Binding 将 Pod 绑定到目标节点。nodeSelector/nodeAffinity/podAffinity/Taint-Toleration 提供了灵活的调度约束。

  3. 弹性伸缩

    • HPA:水平伸缩,调整副本数量,响应最快
    • VPA:垂直伸缩,调整资源配额,适合优化资源利用率
    • Cluster Autoscaler:节点级伸缩,配合 HPA 实现完整的弹性能力
  4. 资源治理:ResourceQuota 限制命名空间资源总量,LimitRange 提供默认资源值,PriorityClass 实现优先级与抢占。

  5. 最佳实践:核心业务使用 Guaranteed QoS + 高优先级 + PDB 保护;批处理任务使用低优先级 + 反亲和性;多可用区部署使用 topologySpreadConstraints。

掌握这些机制,你就能在生产环境中构建一个高效、稳定、弹性的 Kubernetes 资源管理体系。