以下大部分来自于k8s document, 笔者只是总结归纳, 解释不足的地方请参阅相关文档
Intention
Non-sustainable way to customize Kubernetes
- Fork & Sending PRs to upstream
- without extensibility...
- 增加k8s维护团队负担
- 可能脱离k8s规范
Extension Patterns
webhook 通过http post一个请求,然后通过远程的server来决策, plugin是通过调用一个二进制可执行程序来决策, controller是实现资源自动化的一种方式,通过声明式的资源定义,定义一个资源的期望状态,然后controller不断获取实际状态进行状态转换到达期望状态,所以他会不断地读取api-server的信息, 系统中内置的kube-controller-manager就包含许多这样的controller。
Extension Points
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的事件循环如下
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
主要有以下三个作用
- Provide an API for registering API servers.
- Summarize discovery information from all the servers.
- Proxy client requests to individual servers.
注册一个apiserver的大致流程
- setup extension apiserver
- run as a Deployment
- register with the core apiserver using an apiregistration.k8s.io/v1beta1/APIService
- setup etcd storage for the extension apiserver
- run as StatefulSet or etcd operator
- 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中监控数据暴露给集群使用, 可以使用这些监控数据实现自定义方式的扩缩容和调度。整个自动扩缩容架构如下所示 :
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
自定义的三种方式:
- 其实是通过kube-scheduler的--policy-config-file flag来配置, 参见这里
- 直接配置一个新的scheduler,与kube-scheuler并排执行, 通过pod启动时的spec.schedulerName来选择scheduler。参见这里
- schduler extender, 在kube-schduler调用结果之后调用附加的webhook,使用方式就是在上面kube-scheduler的--policy-config-file flag的配置文件中增加一个extender字段来配置extender。参见这里
Infrastructure Extensions
基础设施层的扩展大多数都已经称为规范,由于涉及较多,此处不做讨论