以下大部分來自於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
基礎設施層的擴展大多數都已經稱為規范,由於涉及較多,此處不做討論