kubernetes extension point

时间:2021-08-18 07:06:35

以下大部分来自于k8s document, 笔者只是总结归纳, 解释不足的地方请参阅相关文档

Intention

Non-sustainable way to customize Kubernetes

  • Fork & Sending PRs to upstream
  • without extensibility...
  • 增加k8s维护团队负担
  • 可能脱离k8s规范

Extension Patterns

kubernetes extension point

webhook 通过http post一个请求,然后通过远程的server来决策, plugin是通过调用一个二进制可执行程序来决策, controller是实现资源自动化的一种方式,通过声明式的资源定义,定义一个资源的期望状态,然后controller不断获取实际状态进行状态转换到达期望状态,所以他会不断地读取api-server的信息, 系统中内置的kube-controller-manager就包含许多这样的controller。

Extension Points

kubernetes extension point

kubectl plugin

可以实现kubectl自定义的命令 ,在k8s v1.10为alpha version

Plugin loader会在 Search order 中依次查找以下plugin.yaml及其对应的binary, plugin.yaml 对自定义命令进行声明,binary实现具体的程序逻辑。

API Access Extensions

Webhook Token Authentication

让外部的webhook server来决策是否允许该请求通过认证。

--authentication-token-webhook-config-file flag指定配置文件, 配置文件的格式如kubeconfig形式

# clusters refers to the remote service.
clusters:
- name: name-of-remote-authn-service
cluster:
certificate-authority: /path/to/ca.pem # CA for verifying the remote service.
server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'. # users refers to the API server's webhook configuration.
users:
- name: name-of-api-server
user:
client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
client-key: /path/to/key.pem # key matching the cert # kubeconfig files require a context. Provide one for the API server.
current-context: webhook
contexts:
- context:
cluster: name-of-remote-authn-service
user: name-of-api-sever
name: webhook

当api-server收到上述请求之后会POST一个 authentication.k8s.io/v1beta1 TokenReview对象给webhook, 服务器会返回对应的状态和用户信息,形如:

{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
"token": "(BEARERTOKEN)"
}
}
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
"username": "janedoe@example.com",
"uid": "42",
"groups": [
"developers",
"qa"
],
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
}
}
}

Authenticating Proxy

通过添加一个api-server信任的proxy, 在proxy 这一层进行用户身份认证,通过后proxy 会将用户信息传递给api-server

Authorization Webhook

用户授权的webhook, 工作原理与上述Authentication webhook 大致相同

Admission control

admissoin controller 是编译在api-server中的一系列binary, 通过在api-server的flag中指定执行哪些controller进行插件式的使用,实现资源、权限等的检查和修改。例如resourceQuta, limitRanger, 官方提供的controller必须提前编译进api-server, reload必须重启服务,基于上述不足,k8s提供了不同的扩展方式。

Dynamic Admission Controller

用户提供一个webhook来进行自定义(beta in 1.9), webhook分为MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。 MutatingAdmissionWebhook执行修改操作,为用户未设置的资源字段提供默认值等, ValidatingAdmissionWebhook 执行一些检查操作,可以拒绝用户的请求来增加额外的准入策略,例如可以控制所有的容器镜像都是来自一个特定的registry, 拒绝来自其他镜像仓库的pod部署 。

使用的时候通过一个config file (--admission-control-config-file)来配置webhook server的地址:

apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: <name of this configuration object>
webhooks:
- name: <webhook name, e.g., pod-policy.example.io>
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
clientConfig:
service:
namespace: <namespace of the front-end service>
name: <name of the front-end service>
caBundle: <pem encoded ca cert that signs the server cert used by the webhook>

但是会有一些侧面效应,比如改了用户的配置会让用户感到莫名其妙,可能破坏一些自动化contoller的执行逻辑,在将来的版本中会对可更改的字段进行限制。

ref: github example-webhook-admission-controller

PodPreset

可以在pod创建的时候注入一些信息, 例如一些volume mounts, secrets, environment variables 甚至是一个sidecar, podPreset通过匹配lable来判断是否对该pod注入,如果注入失败并不会影响原来pod的正常运行。流程:

  • Retrieve all PodPresets available for use.
  • Check if the label selectors of any PodPreset matches the labels on the pod being created.
  • Attempt to merge the various resources defined by the PodPreset into the Pod being created.
  • On error, throw an event documenting the merge error on the pod, and create the pod without any injected resources from the PodPreset.
  • Annotate the resulting modified Pod spec to indicate that it has been modified by a PodPreset. The annotation is of the form podpreset.admission.kubernetes.io/podpreset-: "".

如果想要显式拒绝这种注入, 可以定义一个annotataion: podpreset.admission.kubernetes.io/exclude: "true".

下面是podPreset的定义:


apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
name: allow-database
spec:
selector:
matchLabels:
role: frontend
env:
- name: DB_PORT
value: "6379"
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}

Initializers

initializers比上述两者功能都强大,可以对某种类型的资源进行更改, 通过配置InitializerConfiguration 来决定一种资源类型应该被什么initializers处理, 配置文件如下:

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
name: example-config
initializers:
# the name needs to be fully qualified, i.e., containing at least two "."
- name: podimage.example.com
rules:
# apiGroups, apiVersion, resources all support wildcard "*".
# "*" cannot be mixed with non-wildcard.
- apiGroups:
- ""
apiVersions:
- v1
resources:
- pods

一个资源类型可以有多个initializers串行初始化,每种initilizers需要实现对应的controller, controller执行更改或验证操作,然后从metadata.initalizers.pending list中移除该initializers, 当所有的initializer都被移除之后pod才能被调度到node之上,如果initializers未执行完,则默认无法看到该资源对象。

反过来说,如果一个initialier controller 下线后,该资源类型都无法创建成功。

ref:

ImagePolicyWebhook

通过一个webhook 来判断是否允许拉取指定的镜像

User-Defined Types

在k8s中每一种资源都由group, version, kind三要素来唯一标识, 对于自定义的资源也需要定义这三要素,k8s提供了两种自定义资源的方式,CRD与API Aggregation, CRD是通过K8S CustomResourceDefinition类型将声明的类型添加到k8s中, API Aggregation则提供了一个可以注册自己编写的api-server的方式,让自定义的api-server来提供自定义类型。资源定义只是一种静态的方式,资源的行为的自动化才能为资源提供生命力,而controller就是来实现资源的自动化的方式。

Custom Resource Definitions (CRD)

  • Do not require programming
  • Easy to deploy: kubectl create -f crd.yaml
  • No new point-of-failure

举个栗子: etcd operator, 定义好一个etcd资源后,一键部署,告别复杂配置, controller会将所有的配置负责

官方提供的sample controller 是一个从编写crd到controller很好的例子, 整个流程需要注意的几点:

  • CustomResourceDefinition yaml 编写yaml配置文件
  • code-gen 使用code generator生成自定义资源的client-go sdk, 来实现controller
  • informer 监听api-server资源变化的事件,在相应事件发生的时候进行webhook回调
  • controller 添加自动化的程序逻辑
  • interagation with others: events, Garbage conllector(ownerReferences) 配置event事件,GC等
  • resource management, requests and limit, 像cpu和memory一样可以指定request, 和limit进行资源管理

    整个controller的事件循环如下

    kubernetes extension point

    CoreOS团队开源了一个快速提供controller的工具,可以快速开发出一个controller,值得参考一下

    ref: some awesome operators

API Aggregation

  • Require coding, built atop k8s.io/apiserver library
  • Highly customizable, like adding a new verb, create/delete hooks
  • Typed fields, validation, defaults
  • Multi-versioning, supporting old clients
  • Generated OpenAPI schema
  • Supports protobuf
  • Supports strategic merge patch

主要有以下三个作用

  1. Provide an API for registering API servers.
  2. Summarize discovery information from all the servers.
  3. Proxy client requests to individual servers.

注册一个apiserver的大致流程

  1. setup extension apiserver
    • run as a Deployment
    • register with the core apiserver using an apiregistration.k8s.io/v1beta1/APIService
  2. setup etcd storage for the extension apiserver
    • run as StatefulSet or etcd operator
  3. setup the extension controller-manager
    • run as a Deployment (maybe the same Pod as the extension apiserver)
    • configure to talk to the core apiserver (extension APIs are used through core

使用起来较为复杂,官方仓库中的 apiserver library 提供了一些基础模块以及一些api interface, kubernetes-incubator/apiserver-builder 则提供了一个framwork, 可以在其上快速构建一个自己的api-server。

ref: sample api-server

kubernetes-incubator api aggregation

  • service catalog (提供了Open service broker API, 可以将外部的服务暴露出来, 使用起来如同pv&pvc)
  • metrics-server (官方提供的轻量级的heapster实现,收集node和pod的信息 )

此处整理一下github中关于apiserver的几个项目

  • kubernetes/apiserver library为其他api server提供了基础模块,其中kubernetes, Aggregator, service catalog都是使用该库来实现的
  • kubernetes/kube-aggregator 是为api server提供聚合功能的组件,可以自定义api server注册到aggerator中
  • kubernetes/sample-apiserver是演示apisever library的官方demo
  • kubernetes/apiextensions-apiserver 是CRD的实现,This API server provides the implementation for CustomResourceDefinitions which is included as delegate server inside of kube-apiserver.
  • kubernetes-incubator/service catalog 是具体使用aggregator机制的一种第三方的api server
  • kubernetes-incubator/Apiserver-builder 提供了一个framwork,The Apiserver-builder is a complete framework for generating the apiserver, client libraries, and the installation program.

还有关于metric的几个项目

  • kubernetes/metrics Kubernetes metrics API type definitions and clients. 定义了规范, 数据类型, 被heapster, metric server所实现
  • kub ernetes-incubator/custom-metrics-apiserver 实现自定义Metric的框架,可以更方便的实现metric规范
  • kubernetes-incubator/metrics-server 从1.8开始资源使用的Metric数据可以直接从metricAPI获得,通过kubectl top就可以看到,之前需要部署一个Heapster才可以, 通过metric-server来服务,通过shell脚本安装的话会自动安装该aggregrator,可以用来Horizontal Pod Autoscaler , schedualer 调度,是一个轻量级的内存服务器, 可以代替heapster
  • Prometheus Adapter. 非官方项目,但是用的比较多,也是一个自定义Metic实现,同上述metrics-server功能类似,但是可以将prometheus中监控数据暴露给集群使用, 可以使用这些监控数据实现自定义方式的扩缩容和调度。整个自动扩缩容架构如下所示 : kubernetes extension point

CRD summary

其实CRD, APIServer 本身就是两种类型,分别位于group下: apiextensions.k8s.io/v1beta1 apiregistration.k8s.io/v1,只是这另种resource比较特殊,可以定义其他resource, 与其说是将扩展,不如说是使用了这两种resource,不过重难点在于controller的实现 。

scheduler

kubernetes scheduler component, 首先是predicates 过滤掉不符合的node, 然后priority来选择合适的node

自定义的三种方式:

  1. 其实是通过kube-scheduler的--policy-config-file flag来配置, 参见这里
  2. 直接配置一个新的scheduler,与kube-scheuler并排执行, 通过pod启动时的spec.schedulerName来选择scheduler。参见这里
  3. schduler extender, 在kube-schduler调用结果之后调用附加的webhook,使用方式就是在上面kube-scheduler的--policy-config-file flag的配置文件中增加一个extender字段来配置extender。参见这里

Infrastructure Extensions

基础设施层的扩展大多数都已经称为规范,由于涉及较多,此处不做讨论