0 | 字面理解
- apiserver == api Server == api 服务端 == 对外提供 api 接口的服务端 == 将特定路径的访问请求转发给对应服务进行处理
- 所以 apiserver 的作用
- 暴露 api 接口(供 client 端访问)
- 将访问请求转发到对应的服务
1 | 首先理解 APIService
- 我们可以通过 APIService 对象来动态的往 kube-apiserver 上注册我们自己的服务。具体如下:
首先往集群里创建一个 APIService 对象来告知 k8s 我们要注册的服务相关信息,完整 yaml 如下
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1alpha1.custom-metrics.metrics.k8s.io
spec:
insecureSkipTLSVerify: true
group: custom-metrics.metrics.k8s.io # Kubernetes API 组,用于构成对外提供服务的 path 路径
groupPriorityMinimum: 1000
versionPriority: 15
service: # 实际提供服务的 k8s Service,如我们自己的服务,在 custom-metrics 名为 api 的 k8s Service
name: api
namespace: custom-metrics
version: v1alpha1 # Kubernetes API 版本,用于构成对外提供服务的 path 路径
重点关注 spec.group
、spec.version
以及 spec.service
这几个字段。
上述对象创建后即可使用以下地址进行访问,具体的路径拼接规则为:
proxyPath := "/apis/" + apiService.Spec.Group + "/" + apiService.Spec.Version
注意以下几点:
-
后端服务则需要以 k8s Service 方式暴露出来。
-
结合上面的例子拼接出来的 URL 就是
/apis/custom-metrics.metrics.k8s.io/v1alpha1
。 -
我们请求该地址时请求会被转发到
custom-metrics
这个 namespace 下的名叫api
的 service 上。
2 | 理解 k8s kube-apiserver 组件结构
kube-apiserver 其实包含三种 APIServer:
- AggregatorServer:负责处理
apiregistration.k8s.io
组下的 APIService 资源请求,同时将来自用户的请求拦截转发给 Aggregated APIServer(AA); - KubeAPIServer:负责对请求的一些通用处理,包括:认证、鉴权以及各个内建资源(pod, deployment,service)的 REST 服务等;
- ApiExtensionsServer:负责 CustomResourceDefinition(CRD)apiResources 以及 apiVersions 的注册,同时处理 CRD 以及相应 CustomResource(CR)的REST请求(如果对应 CR 不能被处理的话则会返回404),也是 apiserver Delegation 的最后一环;
- 可以理解为上面三个 Server 都是 kube-apiserver 组件中的一个进程,负责处理各自对应的请求,并调用对应的 handler 进行处理
kube-apiserver 中以责任链方式将这三个不同的 server 服务串起来,形成了 kube-apiserver,具体如下:
- 服务首先由 APIAggregator 进行处理,如果匹配不上则由 APIServer 处理,最后才是 CRDServer。
3 | 简单描述 APIAggregator 内部原理
知道 kube-apiserver 实现后再回过头来看 APIAggregator 的实现,为什么我们创建一个 APIService 对象,然后就能请求了,动态注册是什么做到的。
实际上内部一直有一个 controller 在 watch APIService 对象的变化,我们刚创建 APIService 对象,controller 这边就感知到了,然后拿到具体信息,根据规则拼接处【访问地址】,并根据 spec.service
中的信息【拿到对应的 service 构建 handler】,用于将具体请求转发到 service。
之后 APIAggregator 的内部 http 数据结构有个 map 数据结构,存储该【访问地址】和【 handler 】的对应关系,用于后续的请求处理
如果熟悉 http 框架的话应该知道,大部分 http 框架最终都是用一个 map 结构来存放 path 和 handler 的一个映射关系,因此这里动态注册可以理解为往这个 map 对象里添加了一个值。
4 | APIAggregator 的作用
APIAggregator 作用就是 API Aggregation ( API 聚合,可以理解为提供一种控制面集成你自定义的 API 接口的方法)
API Aggregation
允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API
,即将第三方服务注册到 Kubernetes API 中,这样就可以通过 Kubernetes API 来访问外部服务。
备注:另外一种扩展 Kubernetes API 的方法是使用 CustomResourceDefinition (CRD)。
4.1 何时使用 Aggregation
满足以下条件时使用 API Aggregation | 满足以下条件时使用独立 API |
---|---|
您的 API 是声明式的。 | 您的 API 不适合声明式模型。 |
您希望使用kubectl. | kubectl 不需要支持 |
您希望在 Kubernetes UI(例如仪表板)中查看新类型以及内置类型。 | 不需要 Kubernetes UI 支持。 |
您正在开发新的 API。 | 您已经有一个程序可以为您的 API 提供服务并且运行良好。 |
您愿意接受 Kubernetes 对 REST 资源路径(例如 API 组和命名空间)施加的格式限制。(请参阅API 概述。) | 您需要具有特定的 REST 路径才能与已定义的 REST API 兼容。 |
您的资源自然地限定于集群或集群的命名空间。 | 集群或命名空间范围的资源不适合;您需要控制资源路径的细节。 |
您想重用Kubernetes API 支持功能。 | 您不需要这些功能。 |
5 | APIAggregator 与 metric Server
- metric Server 是获取 Kubernetes 核心监控指标的一组 API 接口,与 Prometheus(指标监控)、HPA(横向扩容)等功能有关
5.1 | 题外话:Prometheus 介绍
Prometheus 项目与 Kubernetes 项目一样,也来自于 Google 的 Borg
体系,它的原型系统,叫作 BorgMon,是一个几乎与 Borg 同时诞生的内部监控系统。而 Prometheus 项目的发起原因也跟 Kubernetes 很类似,都是希望通过对用户更友好的方式,将 Google 内部系统的设计理念,传递给用户和开发者。
作为一个监控系统,Prometheus 项目的作用和工作方式,其实可以用如下所示的一张官方示意图来解释。
可以看到,Prometheus 项目工作的核心,是使用 Pull (抓取)的方式去搜集被监控对象的 Metrics 数据(监控指标数据),然后,再把这些数据保存在一个 TSDB (时间序列数据库,比如 OpenTSDB、InfluxDB 等)当中,以便后续可以按照时间进行检索。
有了这套核心监控机制, Prometheus
剩下的组件就是用来配合这套机制的运行。比如 Pushgateway
,可以允许被监控对象以 Push 的方式向 Prometheus 推送 Metrics 数据。而 Alertmanager
,则可以根据 Metrics 信息灵活地设置报警。当然, Prometheus 最受用户欢迎的功能,还是通过 Grafana
对外暴露出的、可以灵活配置的监控数据可视化界面。
有了 Prometheus 之后,我们就可以按照 Metrics 数据的来源,来对 Kubernetes 的监控体系做一个汇总了。
5.1.1 监控对象类型
1. 主机监控数据
第一种 Metrics,是宿主机的监控数据。这部分数据的提供,需要借助一个由 Prometheus 维护的Node Exporter 工具。一般来说,Node Exporter
会以 DaemonSet
的方式运行在宿主机上。其实,所谓的 Exporter,就是代替被监控对象来对 Prometheus 暴露出可以被“抓取”的 Metrics 信息的一个辅助进程。
而 Node Exporter
可以暴露给 Prometheus
采集的 Metrics
数据, 也不单单是节点的负载(Load)、CPU 、内存、磁盘以及网络这样的常规信息,它的 Metrics 指标可以说是“包罗万象”,你可以查看这个列表来感受一下。
2. k8s 组件监控数据
第二种 Metrics,是来自于 Kubernetes
的 API Server
、kubelet
等组件的 /metrics API
。除了常规的 CPU、内存的信息外,这部分信息还主要包括了各个组件的核心监控指标。比如,对于 API Server 来说,它就会在 /metrics API 里,暴露出各个 Controller
的工作队列(Work Queue)的长度、请求的 QPS 和延迟数据等等。这些信息,是检查 Kubernetes 本身工作情况的主要依据。
3. k8s 资源监控数据
第三种 Metrics,是 Kubernetes 相关的监控数据。这部分数据,一般叫作 Kubernetes
核心监控数据(core metrics)。这其中包括了 Pod、Node、容器、Service 等主要 Kubernetes 核心概念的 Metrics
。
其中,容器相关的 Metrics 主要来自于 kubelet
内置的 cAdvisor
服务。在 kubelet 启动后,cAdvisor 服务也随之启动,而它能够提供的信息,可以细化到每一个容器的 CPU 、文件系统、内存、网络等资源的使用情况。
5.2 | 回归正题:Metrics Server简介
需要注意的是,上面提到第三种的 Kubernetes 核心监控数据,其实使用的是 Kubernetes 的一个非常重要的扩展能力,叫作 Metrics Server
。我们可以通过在--api-server
标志设置为 true的情况下运行 Heapster 的资源指标 API实现
Metrics Server
在 Kubernetes
社区的定位,其实是用来取代 Heapster
这个项目的。在 Kubernetes 项目发展的初期,Heapster
是用户获取 Kubernetes 监控数据(比如 Pod
和 Node
的资源使用情况) 的主要渠道。而后面提出来的 Metrics Server
,则把这些信息,通过标准的 Kubernetes API
暴露了出来。这样,Metrics 信息就跟 Heapster
完成了解耦,允许 Heapster
项目慢慢退出舞台。
而有了 Metrics Server
之后,用户就可以通过标准的 Kubernetes API
来访问到这些监控数据了。比如,下面这个 URL
:
http://127.0.0.1:8001/apis/metrics.k8s.io/v1beta1/namespaces/<namespace-name>/pods/<pod-name>
当你访问这个 Metrics API
时,它就会为你返回一个 Pod
的监控数据,而这些数据,其实是从 kubelet
的 Summary API
(即 <kubelet_ip>:<kubelet_port>/stats/summary
)采集而来的。Summary API
返回的信息,既包括了 cAdVisor
的监控数据,也包括了 kubelet
本身汇总的信息。
需要指出的是, Metrics Server
并不是 kube-apiserver
的一部分,而是通过 Aggregator
这种插件机制,在独立部署的情况下同 kube-apiserver 一起统一对外服务的。
系统资源的采集均使用Metrics-Server服务,可以通过Metrics-Server服务采集节点和Pod的内存、磁盘、CPU和网络的使用率等信息。
特性:
- Metrics API 只可以查询当前的度量数据,并不保存历史数据
- Metrics API URI 为 /apis/metrics.k8s.io/,在 k8s.io/metrics维护
- 必须部署
metrics-server
才能使用该 API,metrics-server 通过调用Kubelet Summary API
获取数据
5.3 | Metric Server 原理
- 当部署
metrics-server
完以后会在集群中创建一个名为v1beta1.metrics.k8s.io
的apiservice
- 当通过
Kubernetes API
访问监控数据时,实际上就是通过kube-apiserver
中的AggregatorServer
转到该APIService
实际对应的kube-system
中的metrics-server
k8s Service 进行处理http://127.0.0.1:8001/apis/metrics.k8s.io/v1beta1/namespaces/<namespace-name>/pods/<pod-name>
[dev@172.16.8.7_server0 k8s]$ kubectl get apiservices v1beta1.metrics.k8s.io -o yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
creationTimestamp: "2019-12-13T09:36:38Z"
name: v1beta1.metrics.k8s.io
resourceVersion: "4621101195"
uid: 0fa09ed2-1d8c-11ea-941e-fa4055edae04
spec:
group: metrics.k8s.io # Kubernetes API 组
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service: # 实际提供服务的 Kubernetes Service
name: metrics-server
namespace: kube-system
port: 443
version: v1beta1 # Kubernetes API 版本
versionPriority: 100
status:
conditions:
- lastTransitionTime: "2021-12-27T06:33:42Z"
message: all checks passed
reason: Passed
status: "True"
type: Available
6 | API接口扩展机制分析
主要有两种
- Aggregated API Server(就是上面提到的 Aggregator 机制,同一件事):
- 可以通过
APIService
的定义将其支持的 API 注册到 Kubernetes 集群中。 - Aggregated API Server 不是一个独立的 API Server 实例,而是在 kube-apiserver 进程中实现的扩展机制。
- 当你在集群中创建一个
APIService
对象时,Kubernetes 会自动在 Aggregated API Server 中注册相应的 API 路径和版本。通过这种方式,你可以在 Aggregated API Server 中引入和注册自定义的 API 扩展,从而通过一个入口点访问多个 API Server (这里不是指 k8s apiserver,而是指提供多个接口的服务端)的功能。 Aggregated API Server 可以与APIService
一起使用,以支持灵活的 API 扩展和集成。 - 主要关注 API 访问的聚合,而不是对应用程序的具体管理
- 可以通过
- CRD(Custom Resource Definitions)
- CRD 是 Kubernetes 中的一种扩展机制,允许用户定义和引入自定义资源类型。通过 CRD,用户可以扩展 Kubernetes API,引入自定义的 API 资源。
- Operator 解决了应用程序的自动化管理问题,通过自定义控制器实现应用的自动操作,主要关注应用程序的生命周期,包括部署、升级、配置和维护
总结
- 个人理解
Aggregated API Server
扩展机制主要是引入【其他服务或 API Server(此处是指接口服务端,如上面提到的 metric Server)】,并通过kubernetes API
形式利用k8s 的 kube-apiserver
实例暴露出去,主要关注 API 访问的聚合(扩展 apiserver 提供的 API 接口),而不是对应用程序的具体管理CRD(Custom Resource Definitions)
是定义一种【新资源(如Foo)】,也会暴露个 API 接口,该资源也可以通过如curl -k https://127.0.0.1:9443/apis/demo.jeremyxu2010.me/v1beta1/foos
这样的路径进行访问,但一般和Operator或Controller
配合一起工作,从而实现相应的资源管控、操作和生命周期管理
7 | 附录
7.1 | Metrics Server部署
7.1.1 下载并解压Metrics-Server
wget https://github.com/kubernetes-sigs/metrics-server/archive/v0.3.6.tar.gz
tar -zxvf v0.3.6.tar.gz
7.1.2 修改Metrics-Server配置文件
$ cd metrics-server-0.3.6/deploy/1.8+/
$ vim metrics-server-deployment.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: metrics-server
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server
namespace: kube-system
labels:
k8s-app: metrics-server
spec:
selector:
matchLabels:
k8s-app: metrics-server
template:
metadata:
name: metrics-server
labels:
k8s-app: metrics-server
spec:
serviceAccountName: metrics-server
volumes:
# mount in tmp so we can safely use from-scratch images and/or read-only containers
- name: tmp-dir
emptyDir: {}
containers:
- name: metrics-server
# 修改image 和 imagePullPolicy
image: mirrorgooglecontainers/metrics-server-amd64:v0.3.6
imagePullPolicy: IfNotPresent
# 新增command配置
command:
- /metrics-server
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalDNS,InternalIP,ExternalDNS,ExternalIP,Hostname
volumeMounts:
- name: tmp-dir
mountPath: /tmp
# 新增resources配置
resources:
limits:
cpu: 300m
memory: 200Mi
requests:
cpu: 200m
memory: 100Mi
7.1.3 安装Metrics-Server
kubectl apply -f metrics-server-0.3.6/deploy/1.8+/
7.1.4 查看metric-server监控信息
$ kubectl get apiservice |grep metric
v1beta1.metrics.k8s.io kube-system/metrics-server True 16h
$ kubectl api-resources |grep metric
nodes metrics.k8s.io/v1beta1 false NodeMetrics
pods metrics.k8s.io/v1beta1 true PodMetrics
$ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 332m 16% 1222Mi 64%
node1 192m 9% 845Mi 44%
node2 202m 10% 855Mi 45%
$ kubectl top pod
NAME CPU(cores) MEMORY(bytes)
image-bouncer-webhook-57f5ff98f4-hwtlm 1m 4Mi
$ kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
calico-kube-controllers-57fc9c76cc-knw5x 1m 24Mi
calico-node-9nqnh 43m 40Mi
calico-node-p7xcc 43m 62Mi
calico-node-zqfcb 40m 55Mi
coredns-74ff55c5b-nvmcs 7m 17Mi
coredns-74ff55c5b-psm62 4m 8Mi
etcd-master 23m 59Mi
kube-apiserver-master 88m 292Mi
kube-controller-manager-master 28m 46Mi
kube-proxy-6khfc 1m 24Mi
kube-proxy-b6gjh 1m 16Mi
kube-proxy-dtc84 1m 12Mi
kube-scheduler-master 4m 18Mi
metrics-server-b7cff9c67-jsrrx 1m 11Mi
通过API方式获取监控值
$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq
{
"kind": "NodeMetricsList",
"apiVersion": "metrics.k8s.io/v1beta1",
"metadata": {
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"
},
"items": [
{
"metadata": {
"name": "master",
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/master",
"creationTimestamp": "2021-09-02T15:47:07Z"
},
"timestamp": "2021-09-02T15:46:26Z",
"window": "30s",
"usage": {
"cpu": "287982098n",
"memory": "1156520Ki"
}
},
{
"metadata": {
"name": "node1",
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/node1",
"creationTimestamp": "2021-09-02T15:47:07Z"
},
"timestamp": "2021-09-02T15:46:30Z",
"window": "30s",
"usage": {
"cpu": "208820792n",
"memory": "866488Ki"
}
},
{
"metadata": {
"name": "node2",
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/node2",
"creationTimestamp": "2021-09-02T15:47:07Z"
},
"timestamp": "2021-09-02T15:46:31Z",
"window": "30s",
"usage": {
"cpu": "191420274n",
"memory": "878348Ki"
}
}
]
}
Metrics-Server
收集到节点信息,说明Metrics-Server
安装成功
7.2 | Aggregator 的开启(也就是Aggregated API Server机制的基础)
而 Aggregator
模式的开启也非常简单:
- 如果你是使用
kubeadm
或者官方的 kube-up.sh 脚本部署 Kubernetes 集群的话,Aggregator模式就是默认开启的; - 如果是手动 DIY 搭建的话,你就需要在
kube-apiserver
的启动参数里加上如下所示的配置:
--requestheader-client-ca-file=<path to aggregator CA cert>
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=<path to aggregator proxy cert>
--proxy-client-key-file=<path to aggregator proxy key>
而这些配置的作用,主要就是为 Aggregator 这一层设置对应的 Key 和 Cert 文件。而这些文件的生成,就需要你自己手动完成了,具体流程请参考这篇官方文档。
Aggregator
功能开启之后,你只需要将 Metrics Server
的 YAML 文件部署起来,如下所示:
$ git clone https://github.com/kubernetes-incubator/metrics-server
$ cd metrics-server
$ kubectl create -f deploy/1.8+/
接下来,你就会看到 metrics.k8s.io
这个 API 出现在了你的 Kubernetes API
列表当中。
在理解了 Prometheus 关心的三种监控数据源,以及 Kubernetes 的核心 Metrics 之后,作为用户,你其实要做的就是将 Prometheus Operator
在 Kubernetes 集群里部署起来。
7.3 | 扩展 API 的创建
- 确保开启
APIService API
(默认开启,可用kubectl get apiservice
命令验证) - 创建
RBAC
规则 - 创建一个
namespace
,用来运行扩展的 API 服务 - 创建
CA
和证书,用于https
- 创建一个存储证书的
secret
- 创建一个部署扩展 API 服务的
deployment
,并使用上一步的 secret 配置证书,开启 https 服务 - 确保你的扩展 apiserver 从该卷中加载了那些证书,并在 HTTPS 握手过程中使用它们
- 创建一个
user
、ClusterRole
和ClusterRoleBinding
- 用你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到你创建的角色上
- 用你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到
system:auth-delegator
集群角色,以将 auth 决策委派给 Kubernetes 核心 API 服务器。 - 以你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到
extension-apiserver-authentication-reader
角色。 这将让你的扩展api-server
能够访问extension-apiserver-authentication configmap
。 - 创建一个非
namespace
的apiservice
,注意设置spec.caBundle
- 运行
kubectl get <resource-name>
,正常应该返回No resources found
.
可以使用 apiserver-builder 工具自动化上面的步骤:
# 初始化项目
$ cd GOPATH/src/github.com/my-org/my-project
$ apiserver-boot init repo --domain <your-domain>
$ apiserver-boot init glide
# 创建资源
$ apiserver-boot create group version resource --group <group> --version <version> --kind <Kind>
# 编译
$ apiserver-boot build executables
$ apiserver-boot build docs
# 本地运行
$ apiserver-boot run local
# 集群运行
$ apiserver-boot run in-cluster --name nameofservicetorun --namespace default --image gcr.io/myrepo/myimage:mytag
$ kubectl create -f sample/<type>.yaml
参考
- Kubernetes教程(十七)— Kubernetes Extension: Aggregated API -
- Kubernetes 【监控】1. Metrics Server、Aggregator APIServer和Prometheus监控体系_prometheus aggregate_ghostwritten的博客-CSDN博客
- mac 上学习k8s系列(15)kube-apiserver源码阅读-腾讯云开发者社区-腾讯云
- design-proposals-archive/api-machinery/aggregated-api-servers.md at acc25e14ca83dfda4f66d8cb1f1b491f26e78ffe · kubernetes/design-proposals-archive k8s api-machinery 设计文档
- 二十 监控系统 — Zeusro’s awesome-kubernetes-notes 1.0.0 文档
- Kubernetes metrics-server原理解析 - XniLe - Ops 2.0
- 使用Aggregated APIServer的方式构建API服务 - jeremy的技术点滴
- 绿色记忆:编写Kubernetes风格的APIServer