Apiserver乾的最重要的三個事就是:git
admission controller很是有用,也是常常會用到的k8s的一個擴展方式,今天在源碼級別對其作一下介紹,以及如何本身去開發一個admission controller.github
咱們的應用場景是:咱們但願把全部須要建立的pod都加上一個註解,由於咱們早期是經過podpreset給pod注入lxcfs的配置的,可是用戶在寫yaml文件時很容易忘記加上,因此須要在apiserver上來個自動處理golang
metadata: name: test-net annotations: initializer.kubernetes.io/lxcfs: "true" # 就是在pod的metadata里加上這個配置
已經有不少默認很是有用的admission插件,這裏挑幾個介紹一下:web
名稱 | 做用 |
---|---|
AlwaysPullImages | 把全部鏡像策略都調整成alwaysPull, 多租戶安全時比較有用 |
DefaultStorageClass | 默認存儲類型 |
DefaultTolerationSeconds | 節點notready:NoExecute時的容忍時間,好比有時咱們升級kubelet,但願升級時pod不要漂移就會用到 |
DenyEscalatingExec | 拒絕遠程鏈接容器 |
ExtendedResourceToleration | 好比我有擴展資源,那麼我能夠經過它來玷污節點,防止不須要該資源的pod到個人機器上來,如GPU |
LimitRanger | 在多租戶配額時至關有用,若是pod沒配額,那麼我能夠默認給個很低的配額 |
NamespaceAutoProvision | 這個也很是有用,資源的namespace不存在時就建立一個 |
PodPreset | 能夠對pod進行一些預處理設置 |
ResourceQuota | 多租戶配額時比較重要,看資源是否知足resource quota中的配置 |
多租戶時常常會開啓這個,強制全部的鏡像必須去拉取,由於若是不這樣,那麼別的租戶若是知道了你的鏡像名就能夠寫一個yaml去啓動你的鏡像,強制拉時猶豫須要image pull secret因此沒法拉取你的鏡像。json
因此這個admission乾的事就是把鏡像拉取策略都改爲alwaysPull:api
代碼位置:安全
kubernetes/plugin/pkg/admission/alwayspullimages/admission.go func (a *AlwaysPullImages) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) { // 你能夠在attibutes裏獲取到對象的一切信息,用戶信息等 if shouldIgnore(attributes) { // 檢查一下是否是你關注的object, 好比建立的一個configmap 那麼顯然能夠忽視 return nil } pod, ok := attributes.GetObject().(*api.Pod) // 這裏把initContainer和Container的拉取策略都給改了 for i := range pod.Spec.InitContainers { pod.Spec.InitContainers[i].ImagePullPolicy = api.PullAlways } for i := range pod.Spec.Containers { pod.Spec.Containers[i].ImagePullPolicy = api.PullAlways } return nil } # 還提供一個校驗接口,看是否是真的都已經被改了 func (a *AlwaysPullImages) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) { pod, ok := attributes.GetObject().(*api.Pod) for i := range pod.Spec.InitContainers { if pod.Spec.InitContainers[i].ImagePullPolicy != api.PullAlways { return admission.NewForbidden(attributes, field.NotSupported(field.NewPath("spec", "initContainers").Index(i).Child("imagePullPolicy"), pod.Spec.InitContainers[i].ImagePullPolicy, []string{string(api.PullAlways)}, ), ) } } ... return nil }
而後實現一個註冊函數:函數
func Register(plugins *admission.Plugins) { plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { return NewAlwaysPullImages(), nil }) } type AlwaysPullImages struct { *admission.Handler }
最後須要在plugin裏面把其註冊進去:this
kubernetes/pkg/kubeapiserver/options/plugins.go func RegisterAllAdmissionPlugins(plugins *admission.Plugins) { imagepolicy.Register(plugins) ... }
因此實現一個admission很是簡單,主要就是實現兩個接口便可。spa
不少狀況下咱們並不但願大動干戈去改apiserver代碼,因此apiserver提供了一種動態擴展admission的方式,很是推薦。
有兩種類型:
比較重要的是這個AdmissionReview結構體,包含一個請求一個響應
請求:有Object的詳細信息,用戶信息
響應: 最重要的是 1. 是否容許 2. 修改(patch)的類型 3. 修改(patch)的值, 這個符合json patch標準 (kubectl patch)
可在此 找到一個webhook server的例子
看一個具體例子,labelpatch,是給對象的元數據里加一些label的。
const ( // 特定的json patch格式 addFirstLabelPatch string = `[ { "op": "add", "path": "/metadata/labels", "value": {"added-label": "yes"}} ]` addAdditionalLabelPatch string = `[ { "op": "add", "path": "/metadata/labels/added-label", "value": "yes" } ]` ) // Add a label {"added-label": "yes"} to the object func addLabel(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { obj := struct { metav1.ObjectMeta Data map[string]string }{} raw := ar.Request.Object.Raw err := json.Unmarshal(raw, &obj) if err != nil { klog.Error(err) return toAdmissionResponse(err) } reviewResponse := v1beta1.AdmissionResponse{} reviewResponse.Allowed = true if len(obj.ObjectMeta.Labels) == 0 { reviewResponse.Patch = []byte(addFirstLabelPatch) // 這裏最須要注意的就是修改時是經過patch的方式 } else { reviewResponse.Patch = []byte(addAdditionalLabelPatch) } pt := v1beta1.PatchTypeJSONPatch reviewResponse.PatchType = &pt return &reviewResponse }
把這個放到http handle裏。
把這個HTTPS服務起一個service, 這樣apiserver就能夠自動發現它。
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: # 最好明確一下該hook關心哪些api,防止帶來沒必要要的額外開銷。 - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: "Namespaced" clientConfig: service: namespace: <namespace of the front-end service> # webhook server的namespace name: <name of the front-end service> # service name caBundle: <pem encoded ca cert that signs the server cert used by the webhook> # 由於須要經過https訪問,因此要給apiserver配置ca admissionReviewVersions: - v1beta1 timeoutSeconds: 1
adminssion control 是很是重要的APIserver擴展的方式,掌握了其開發不少地方就能以比較優雅的方式解決一些實際問題。是基於k8s開發PaaS平臺的利器
更多精彩: https://sealyun.com