【k8s源码分析-Apiserver-1】理解 apiserver 的结构(AggregatorServer、KubeAPIServer、ApiExtensionsServer)

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.groupspec.version 以及 spec.service 这几个字段。

上述对象创建后即可使用以下地址进行访问,具体的路径拼接规则为:

proxyPath := "/apis/" + apiService.Spec.Group + "/" + apiService.Spec.Version 

注意以下几点:

  1. 后端服务则需要以 k8s Service 方式暴露出来。

  2. 结合上面的例子拼接出来的 URL 就是 /apis/custom-metrics.metrics.k8s.io/v1alpha1

  3. 我们请求该地址时请求会被转发到 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,是来自于 KubernetesAPI Serverkubelet 等组件的 /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 ServerKubernetes 社区的定位,其实是用来取代 Heapster 这个项目的。在 Kubernetes 项目发展的初期,Heapster 是用户获取 Kubernetes 监控数据(比如 PodNode 的资源使用情况) 的主要渠道。而后面提出来的 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 的监控数据,而这些数据,其实是从 kubeletSummary 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.ioapiservice
  • 当通过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接口扩展机制分析

主要有两种

  1. 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 访问的聚合,而不是对应用程序的具体管理
  2. 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 的创建

  1. 确保开启 APIService API(默认开启,可用 kubectl get apiservice 命令验证)
  2. 创建 RBAC 规则
  3. 创建一个 namespace,用来运行扩展的 API 服务
  4. 创建 CA 和证书,用于 https
  5. 创建一个存储证书的 secret
  6. 创建一个部署扩展 API 服务的 deployment,并使用上一步的 secret 配置证书,开启 https 服务
  7. 确保你的扩展 apiserver 从该卷中加载了那些证书,并在 HTTPS 握手过程中使用它们
  8. 创建一个userClusterRoleClusterRoleBinding
  9. 用你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到你创建的角色上
  10. 用你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到 system:auth-delegator 集群角色,以将 auth 决策委派给 Kubernetes 核心 API 服务器。
  11. 以你命名空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到 extension-apiserver-authentication-reader 角色。 这将让你的扩展 api-server能够访问 extension-apiserver-authentication configmap
  12. 创建一个非 namespaceapiservice,注意设置 spec.caBundle
  13. 运行 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 

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值