Kubernetes控制平面组件:API Server详解(二)
云原生学习路线导航页(持续更新中)
- kubernetes学习系列快捷链接
- Kubernetes架构原则和对象设计(一)
- Kubernetes架构原则和对象设计(二)
- Kubernetes架构原则和对象设计(三)
- Kubernetes控制平面组件:etcd(一)
- Kubernetes控制平面组件:etcd(二)
- Kubernetes控制平面组件:API Server详解(一)
- Kubernetes常见问题解答
- 查看云机器的一些常用配置
本文是kubernetes的控制面组件API Server详解(二),首先总览了API Server的整个处理流程,然后对 max-in-flight限流限制、authorization授权鉴权机制、aggregator扩展apiserver机制、内置apiserver的请求转换处理和admission准入控制模块 分别进行了详细介绍
- 希望大家多多 点赞 关注 评论 收藏,作者会更有动力继续编写技术文章
1.API Server处理流程概览
- request-timeout:request进来,会先去做request-timeout
- authenatication:进行身份认证
- audit:认证通过后会进行 审计日志 Audit 的记录,主要是记录什么人做了什么修改操作,方便在出问题时定位请求的来源,比如对象被删时可以用来定责
- impersonation:用于模拟用户身份的字段
- 在request-header中有一个impersonation header,可以指定该值来模拟用户身份。
- 比如a用户发起的一个请求,但是它可以通过 impersonation header 把这个请求模拟成b用户,Kubernetes会把该请求认为是b用户,即a用户代替b用户来做操作,且后续的鉴权将会按照b用户进行
- 一个不太常用的功能
- max-in-flight:用于做限流(正在飞的请求–正在运行的请求)
- 可以配置 允许API Server同时处理多少请求,即允许有多少尚未返回的请求
- authorization:鉴权
- kubernetes aggregator:扩展API Server处理器
- Kubernetes为 内置资源提供了 默认的 API Server处理器,可以处理pod、deployment等内置资源
- 但如果你希望自己来处理资源,也可以自己编写一个API Server处理器,挂载上来
- 那么在kubernetes aggregator这里,就会判断使用哪个处理器,进而往下走
- resource handler
- kubernetes内置apiserver处理器的核心逻辑,包括解码、版本转换、默认值填充、准入、校验、和etcd交互等
- decoding:解码
- request conversion & defaulting:当用户请求的 API 版本与最新版本不一致时,转成内部通用版本,然后进行默认值填充
- admission:准入校验
- rest logic:rest处理模块
- storage conversion & defaulting:将请求转成rest请求,操作存储etcd
- result conversion:处理响应
- encoding:对响应编码
request-timeout、authenatication、audit、impersonation 模块,请见 Kubernetes控制平面组件:API Server详解(一)
2.max-in-flight 请求限流
- Kubernetes控制平面组件:APIServer 限流机制详解
3.authorization授权鉴权
3.1.认证和授权概念辨析
- 在 Kubernetes控制平面组件:API Server详解(一) 中,我们详细讲解了 apiserver 的认证机制,那么认证和授权有什么区别呢?
- 认证(Authentication)
- 目的:验证请求者的身份,侧重于身份的校验,拦截非法身份
- 支持方式:
- 静态密码文件
- X509证书
- Bearer Token
- ServiceAccount Token
- Webhook 等
- 失败响应:认证失败返回
401 Unauthorized
- 授权鉴权(Authorization)
- 目的:验证请求者 有没有权限 执行当前操作,此时已经知道请求者身份了,侧重于权限校验,拦截 用户越权 的行为
- 三要素:
- 操作主体(Subject)
- 目标资源(Resource)
- 操作动作(Verb)
- 核心问题:谁(Who)能对什么资源(What)执行什么操作(How)
- 失败响应:鉴权失败返回
403 Forbidden
3.2.API Server 支持的授权模式
以下是补充了缩写全称的表格:
模式 | 全称 | 特点 | 适用场景 |
---|---|---|---|
ABAC | Attribute-Based Access Control | 基于属性配置,需重启API Server | 简单测试环境 |
RBAC | Role-Based Access Control | 通过API对象动态配置 | 生产环境主流方案 |
Webhook | Webhook Authorization | 对接外部授权系统 | 企业统一权限体系 |
Node | Node Authorization | 节点组件专用授权 | kubelet权限控制 |
3.3.RBAC 与 ABAC 对比
3.3.1.ABAC 特点
- 使用方法
# 需在 apiserver master 节点配置策略文件 --authorization-policy-file=/etc/kubernetes/policy.json
- 缺点:
- 静态文件方式定义授权策略,每次更改都需要重启API Server
- 策略更新困难
- 缺乏灵活性
3.3.2.RBAC 优势
- 通过API对象管理权限(Role/ClusterRole),无需重启API Server即可更新授权策略
- 支持动态更新
- 细粒度权限控制
- 支持命名空间隔离
3.4. authorization 4种授权模式详解
3.4.1.ABAC授权模式详解
3.4.2.RBAC授权模式详解
3.4.3.Webhook授权模式详解
3.4.4.Node授权模式详解
3.5.与权限相关的最佳实践
4.kubernetes aggregator 扩展 APIServer 处理器
4.1.APIServer扩展 基本原理
4.1.1.APIServer 扩展核心组件
- Kubernetes Aggregator(聚合层)是 Kubernetes APIServer 的扩展机制,允许将自定义或第三方 APIServer 无缝集成到主 APIServer(kube-apiserver)中。
- 核心组件包括:
- APIService 对象:声明 API 组和版本的访问规则,并关联后端服务(Service)。
- 聚合层(Aggregator):作为七层负载均衡,动态路由请求到扩展APIServer。
- GenericAPIServer:提供通用 APIServer 功能(如认证、鉴权、路由),所有子 APIServer 均基于此构建。
4.1.2.APIServer扩展工作流程
- 请求入口:客户端通过主 APIServer 发起请求(如
/apis/custom.group/v1
)。 - 路由决策:聚合层根据 APIService 配置匹配请求路径,转发到扩展 APIService 的 Service。
- 安全认证:主 APIServer 使用 TLS 证书与扩展 APIServer 双向认证,确保通信安全。
- 代理与响应:扩展 APIServer 处理请求后,结果通过主 APIServer 返回客户端。
4.2.自定义 APIServer 的开发步骤
4.2.1.开发准备
- 技术选型:基于
k8s.io/apiserver
库构建,实现标准的 Kubernetes API 接口。 - 核心接口:
- REST.Storage:处理资源的增删查改操作,需实现
Getter
、Lister
等接口。 - Scheme 注册:定义资源的序列化规则(如
runtime.Object
结构体)。
- REST.Storage:处理资源的增删查改操作,需实现
4.2.2.代码结构
// 示例代码框架(基于 k8s.io/apiserver)
func main() {config := genericapiserver.NewConfig() // 创建通用配置config.EnableMetrics = true// 注册自定义资源 Schemescheme := runtime.NewScheme()customv1.AddToScheme(scheme)// 构建 APIGroupInfoapiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(...)apiGroupInfo.VersionedResourcesStorageMap["v1"] = storageMap// 初始化 GenericAPIServerserver, _ := config.Complete().New("my-apiserver", genericapiserver.NewEmptyDelegate())server.InstallAPIGroup(&apiGroupInfo)server.PrepareRun().Run(stopCh)
}
4.2.3.关键组件实现
- 存储层:对接数据库或自定义存储(需实现
etcd3.Store
接口)。 - 认证与鉴权:
- 复用 Kubernetes 的 RBAC 机制,通过
SubjectAccessReview
验证权限。 - 使用
--requestheader-client-ca-file
和--proxy-client-cert-file
配置 TLS 证书。
- 复用 Kubernetes 的 RBAC 机制,通过
4.3.与 kube-apiserver 的集成
4.3.1.创建 APIService 对象
# APIService 定义示例
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:name: v1.custom.group
spec:group: custom.groupversion: v1service:namespace: custom-systemname: custom-api-server # 指向自定义 APIServer 的 Serviceport: 443caBundle: <base64-encoded-CA> # 用于验证扩展 APIServer 的 CA
4.3.2.服务发现与负载均衡
- Service 配置:需创建 ClusterIP 或 NodePort 类型的 Service,确保主 APIServer 可访问。
- Endpoints 验证:通过
kubectl get endpoints
检查后端 Pod 状态。
4.3.3.权限配置
- RBAC 规则:需为自定义 APIServer 分配
system:auth-delegator
角色,允许代理请求。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: custom-apiserver-auth-delegator
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: system:auth-delegator
subjects:
- kind: ServiceAccountname: custom-apiservernamespace: custom-system
4.4.注意事项
1. 安全与证书管理
- CA 一致性:主 APIServer 与扩展 APIServer 的证书必须由同一 CA 签发。
- 证书轮换:定期更新 TLS 证书,避免过期导致通信中断。
2. 性能与调试
- 请求代理开销:聚合层代理可能增加延迟,建议优化扩展 APIServer 处理逻辑。
- 日志与监控:启用 APIServer 的
--v=4
日志级别,结合 Prometheus 监控指标。
3. 版本兼容性
- 多版本共存:支持
v1
和v1beta1
等版本,通过spec.versionPriority
控制优先级。 - 废弃策略:逐步淘汰旧版本,使用
deprecated
注解标记。
4.5.实操案例:Metrics Server 的实现
4.5.1.案例背景
- Metrics Server 是 Kubernetes 官方提供的聚合 APIServer,用于采集 Node 和 Pod 的 CPU/内存指标。
4.5.2.实现步骤
- APIService 注册:
apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata:name: v1beta1.metrics.k8s.io spec:service:name: metrics-servernamespace: kube-systemgroup: metrics.k8s.ioversion: v1beta1
- 自定义 APIServer:实现
metrics/v1beta1
组资源的GET /nodes/{node}/metrics
接口。 - 权限配置:为
metrics-server
ServiceAccount 绑定system:metrics-server
角色。
4.5.3.验证
kubectl top nodes # 查看节点指标
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq # 直接访问 API
5.resource handler 内置 APIServer 处理器
5.1.请求conversion & defaulting
5.1.1.基础概念
-
Conversion(版本转换)
• 定义:将不同 API 版本的资源对象转换为统一 内部版本(Internal Version) 的机制,确保多版本兼容性。例如,用户提交的apps/v1beta1.Deployment
会被转换为apps/v1.Deployment
的内部表示。
• 核心目标:实现 API 版本的平滑升级和降级,避免因版本变更导致数据丢失或服务中断。 -
Defaulting(默认值填充)
• 定义:为资源对象中未显式指定的字段填充默认值的机制。例如,未设置 Pod 的imagePullPolicy
时,默认填充IfNotPresent
。
• 核心目标:简化用户配置,确保资源的完整性和一致性,避免因字段缺失导致运行时错误。
5.1.2.设计理念
- 多版本兼容性
- 向后兼容:通过版本转换支持旧版本 API 请求,允许用户逐步迁移到新版本。
- 版本共存:API Server 可同时处理多个版本的资源对象(如
v1
和v1beta1
)。
- 配置简洁性
- 用户友好:通过默认值隐藏复杂配置细节,例如自动填充
Service
的ClusterIP
或Deployment
的滚动更新策略。 - 规范化:确保资源对象符合 Schema 定义,减少人工校验成本。
- 扩展性与解耦
- 插件化机制:Conversion 和 Defaulting 均可通过扩展点(如
CustomResourceDefinition
或 Admission Webhook)实现自定义逻辑。- mutatingwebhookconfigurations:修改资源属性
- validatingwebhookconfigurations:校验资源
5.1.3.实现原理
- Conversion 实现机制
- 版本注册表:每个 API 组(如
apps
、batch
)注册其支持的版本及转换函数。 - 转换链(Conversion Chain):
- 步骤1:将用户提交的外部版本(如
v1beta1
)转换为内部版本。 - 步骤2:持久化到 etcd 时,转换为存储版本(Storage Version)。
- 步骤3:响应时根据请求的 API 版本反向转换。
- 步骤1:将用户提交的外部版本(如
- 转换函数:通过
conversion-gen
工具自动生成或手动实现字段映射逻辑。
- Defaulting 实现机制
- Schema 定义:在资源的 OpenAPI Schema 中声明字段的
default
值(如spec.replicas: 1
)。 - 准入控制阶段:在请求验证前,由
Mutating Admission Controller
或内置逻辑填充默认值。 - 自定义默认值:通过编写 Admission Webhook 动态填充(如根据 Namespace 设置资源配额)。
5.1.4.处理流程
-
Conversion 流程
• 用户请求携带apiVersion
字段(如apps/v1beta1
)。
• API Server 根据注册的转换函数,将对象转换为内部版本。
• 存储到 etcd 时,转换为存储版本(由--storage-versions
指定)。 -
Defaulting 流程
• 在验证阶段前遍历资源对象字段。
• 若字段未设置且 Schema 中定义默认值,则自动填充。
5.1.5.参数配置
-
Conversion 相关配置
• API 版本启用:通过--runtime-config=apps/v1beta1=true
启用特定 API 版本。
• 存储版本设置:在 CRD 中指定spec.versions.storage: true
定义存储版本。 -
Defaulting 相关配置
• Schema 默认值:在 CRD 的 OpenAPI Schema 中定义default
字段:spec:versions:- name: v1schema:openAPIV3Schema:properties:spec:properties:replicas:type: integerdefault: 1
• Admission Webhook:配置 Mutating Webhook 实现动态默认值。
5.1.6.实操案例
-
自定义 Conversion 函数
场景:将自定义资源MyApp
从v1alpha1
升级到v1
。
步骤:
• 定义转换函数:func Convert_v1alpha1_MyApp_To_v1_MyApp(in *v1alpha1.MyApp, out *v1.MyApp, s conversion.Scope) error {out.Spec.Replicas = in.Spec.ReplicaCount // 字段重命名映射return nil }
• 注册转换函数到
scheme
:scheme.AddConversionFunc(&v1alpha1.MyApp{}, &v1.MyApp{}, Convert_v1alpha1_MyApp_To_v1_MyApp)
• 更新 CRD 的
spec.versions
和storage
标志。 -
动态 Defaulting 示例
场景:为所有新创建的 Pod 自动添加env: prod
标签。
步骤:
• 编写 Mutating Webhook:func mutatePod(ar v1.AdmissionReview) *v1.AdmissionResponse {pod := corev1.Pod{}if err := json.Unmarshal(ar.Request.Object.Raw, &pod); err != nil {return denyRequest(err)}if pod.Labels == nil {pod.Labels = make(map[string]string)}pod.Labels["env"] = "prod"return createPatchResponse(ar.Request.Object.Raw, pod) }
• 配置 Webhook 的
ValidatingWebhookConfiguration
,指定匹配规则为CREATE Pod
。
5.1.7.优化与注意事项
-
性能优化
• Conversion 缓存:缓存常用版本的转换结果,减少重复计算。
• Defaulting 延迟加载:仅在必要时填充默认值,避免资源浪费。 -
兼容性风险
• 版本废弃策略:通过deprecated
注解标记旧版本,逐步淘汰。
• 默认值变更:修改 Schema 默认值时需考虑已存在资源的影响。 -
调试工具
• 查看内部版本:使用kubectl get --raw /apis/<group>/<version>/<resource>?as=internal
查看转换后的内部对象。
• Dry-Run 模式:通过kubectl apply --dry-run=server
验证默认值填充逻辑。
5.2.admission准入控制
- 请见:Kubernetes控制平面组件:APIServer 准入控制机制详解
6.API Server代码学习
Kubernetes控制平面组件:API Server代码基础概念
7.应用案例:如何搭建一个多租户的kubernetes集群
- 基于前面对kubernetes集群架构 + API Server的学习,现在应该具备设计一个多租户kubernetes集群的能力。下面介绍基本思路。
- 1.以ns为隔离域的租户隔离设计
- 首先通过准入控制的 Webhook + Controller,在ns create阶段自动为ns绑定用户权限,实现:只有指定用户才可以访问某个ns。具体实现如下:
- 在ns创建时,通过一个mutatingwebhookconfigurations变形webhook插件,将用户信息写入ns的annotation
- 2.做好用户访问的授权鉴权
- 关闭匿名访问,只允许可信用户操作
- 鉴权时,判断请求用户信息是否存在于ns的annotation,即可判断当前用户是否有权限访问该ns
- 管理员可以控制指定用户的ns权限和可见范围,其实就是控制ns上anno中是否包含某个用户的信息
- 3.做好ns的配额管理
- 通过在ns下创建ResourceQuota,定义ns下资源的配额,比如最多允许的pod数量、cm数量、service/ingress数量等
- 还可以编写一个Controller,监听ns create事件,自动创建配额。
- 1.以ns为隔离域的租户隔离设计
- 用户视角下的隔离性
- 可见性隔离,用户只能看到自己创建的ns下面的应用和服务,没有其他ns权限
- 资源隔离,用户只能使用自己ns下的资源配额之内的资源,其他的用不了;另外,特有node上可以通过 打上污点Taint 的方式,防止其他用户调度上来,实现资源层隔离
- 应用访问隔离,用户可以对自己应用配置访问限制
- 实现以上内容,集群其实就已经是一个多租户集群了