應用上雲,怎能沒有容器!點擊上方

容器魔方

關注我

1.什麼是Admission Controller

Admission Controller(准入控制)

是Kubernetes API Server用於攔截請求的一種手段。Admission可以做到對請求的資源對象進行校驗,修改。

service mesh最近很火的項目Istio天生支持Kubernetes,利用的就是admission對服務實例自動注入sidecar。

假如對Kubernetes有一定的了解的話,應該會知道在Kubernetes中還有authn/authz,為什麼還會引入admission這種機制?

1)

authn/authz

是Kubernetes的認證鑒權,運行在filter中,只能獲取http請求essay-header以及證書,並不能獲取請求的body。所以authn/authz只能對客戶端進行認證和鑒權,不可以對請求的對象進行任何操作,因為這裡根本還獲取不到對象。

2)

Admission

運行在API Server的增刪改查handler中,可以自然地操作API resource。

下面將對Admission Controller工作流做一番詳解。

 

API Server

接收到客戶端請求後首先進行認證鑒權,認證鑒權通過後才會進行後續的

endpoint handler

處理。

1)

當API Server接收到對象後首先根據http的路徑可以知道對象的版本號,然後將request body反序列化成versioned object.

2)

versioned object轉化為internal object,即沒有版本的內部類型,這種資源類型是所有versioned類型的超集。只有轉化為internal後才能適配所有的客戶端versioned object的校驗。

3)

Admission Controller具體的admit操作,可以通過這裡修改資源對象,例如為Pod掛載一個默認的Service Account等。

4)

API Server internal object validation,校驗某個資源對象數據和格式是否合法,例如:Service Name的字元個數不能超過63等。

5)

Admission Controller validate,可以自定義任何的對象校驗規則。

6)

internal object轉化為versioned object,並且持久化存儲到etcd。

註:

以上versioned object和internal object直接的轉換關係會在《深度剖析Kubernetes API Server三部曲 - part 2》詳細解釋,歡迎持續關注。

2.如何使用admission controller

Kubernetes 1.10

之前的版本可以使用

--admission-control

打開Admission Controller。同時

--admission-control

的順序決定Admission運行的先後。其實這種方式對於用戶來講其實是挺複雜的,因為這要求用戶對所有的Admission Controllers需要完全了解。

如果使用Kubernetes 1.10之後的版本,

--admission-control

已經廢棄,建議使用

--enable-admission-plugins --disable-admission-plugins

指定需要打開或者關閉的Admission Controller。 同時用戶指定的順序並不影響實際Admission Controllers的執行順序,對用戶來講非常友好。

值得一提的是,有些Admission Controller可能會使用Alpha版本的API,這時必須首先使能其使用的API版本。否則Admission Controller不能工作,可能會影響系統功能。

2.1 webhook admission

目前Kubernetes中已經有非常多的

Admission

插件, 但是並不能保證滿足所有開發者的需求。 眾所周知,Kbernetes之所以受到推崇,它的可擴展能力功不可沒。Admission也提供了一種

webhook

的擴展機制。 

● 

MutatingAdmissionWebhook:在對象持久化之前進行修改

● 

ValidatingAdmissionWebhook:在對象持久化之前進行

可能有讀者接觸過另外一種動態可擴展的機制Initializers,不過至今還是Apha特性,社區討論有可能會把它移除。所以選擇動態Admission首選webhook。

2.2 如何使用webhook admission

Webhook Admission屬於同步調用,需要用戶部署自己的webhook server,創建自定義的配置資源對象: ValidatingWebhookConfiguration或MutatingWebhookConfiguration。

● 

開發webhook server

這裡我推薦參考

社區e2e測試用的server

,對細節源代碼感興趣的讀者可以自行參考

https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/main.go

,這裡面利用golang 標準庫實現的一個基本的http server,並註冊多個路由,同時服務於多種resource的准入控制。重點關注一下資源對象的decode過程,這是k8s apimachinery的高級功能。利用了apimachinery的scheme的能力,使用之前必須要將api註冊到scheme中,代碼詳見:

(https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/scheme.go)。

一個典型的webhook修改資源對象(Pod)的樣例代碼如下所示。

  func

mutatePods

(

ar v1beta1

.

AdmissionReview

) *

v1beta1

.

AdmissionResponse

{  

glog

.

V

(

2

).

Info

(

"mutating pods"

)  

podResource

:=

metav1

.

GroupVersionResource

{

Group

:

""

,

Version

:

"v1"

,

Resource

:

"pods"

}  

if

ar

.

Request

.

Resource

!=

podResource

{     

glog

.

Errorf

(

"expect resource to be %s"

,

podResource

)     

return

nil  

}  

raw

:=

ar

.

Request

.

Object

.

Raw  

pod

:=

corev1

.

Pod

{}  

deserializer

:=

codecs

.

UniversalDeserializer

()

// pod

的解碼,利用

apimachinery  

if

_

,

_

,

err

:=

deserializer

.

Decode

(

raw

,

nil

,

&

pod

)

;

err

!=

nil

{     

glog

.

Error

(

err

)     

return

toAdmissionResponse

(

err

)   }  

reviewResponse

:=

v1beta1

.

AdmissionResponse

{}  

reviewResponse

.

Allowed

=

true  

if

pod

.

Name

==

"webhook-to-be-mutated"

{     

reviewResponse

.

Patch

= []

byte

(

addInitContainerPatch

)     

pt

:=

v1beta1

.

PatchTypeJSONPatch     

reviewResponse

.

PatchType

= &

pt  

}  

return

&

reviewResponse

  }

● 

部署webhook server

    # kubectl create –f webhook-server.yaml

apiVersion:

v1

kind:

Namespace

metadata:  name:

e2e-tests-webhook-gbgt6

spec:  finalizers: 

- kubernetes---

apiVersion:

extensions/v1beta1

kind:

Deployment

metadata:  labels:    app:

sample-webhook   

webhook:

"true" 

name:

sample-webhook-deployment 

namespace:

e2e-tests-webhook-gbgt6

spec:  replicas:

selector:    matchLabels:      app:

sample-webhook     

webhook:

"true" 

template:    metadata:      labels:        app:

sample-webhook       

webhook:

"true"   

spec:      containers:     

-

args:       

- --tls-cert-file=/webhook.local.config/certificates/tls.crt        - --tls-private-key-file=/webhook.local.config/certificates/tls.key        - --alsologtostderr        - -v=4        - 2>&1       

image:

gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.10v2       

imagePullPolicy:

IfNotPresent       

name:

sample-webhook       

volumeMounts:       

-

mountPath:

/webhook.local.config/certificates         

name:

webhook-certs         

readOnly:

true     

volumes:     

-

name:

webhook-certs        

secret:          defaultMode:

420         

secretName:

sample-webhook-secret---

apiVersion:

v1

kind:

Service

metadata:  labels:    test:

webhook 

name:

e2e-test-webhook 

namespace:

e2e-tests-webhook-gbgt6

spec:  ports: 

-

port:

443   

protocol:

TCP   

targetPort:

443 

selector:    webhook:

"true"

 

sessionAffinity:

None 

type:

ClusterIP

 

創建webhook server Deployment以及Service,供API Server調用。

● 

創建MutatingWebhookConfiguration

 

    # kubectl create –f webhook-config.yaml

apiVersion:

admissionregistration.k8s.io/v1beta1

kind:

MutatingWebhookConfiguration

metadata:  name:

e2e-test-mutating-webhook-pod

webhooks:

-

clientConfig:    caBundle:

LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lCQURBTkJna

3Foa2lHOXcwQkFRc0ZBREFkTVJzd0dRWURWUVFERXhKbE1tVXQKYzJWeWRtVnlMV05sY25RdFkyRXdIaGNOTVRnd056RTVNRGMwT1RJeFdoY05Namd3TnpFMk1EYzBPVEl4V2pBZApNUnN3R1FZRFZRUURFeEpsTW1VdGMyVnlkbVZ5TFdObGNuUXRZMkV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURFVVFEWVN6SGl3SUFHU1dHSWRBSmVBbnMrNFhaYjlZc3VuQlBVTkJPdHZqeFoKV3NSbUxydE0zVU9lcEszeGsvMzZCSS96RkdXdUNpMlJ0TWUxSWtEa2tVMzNEZE83K0ExVyt2NVZNVnFqL0lDTApsc29USml3TFhTcGowTHNwSUNVdGtqT1dlRjVhK3lJVHgyR01TMG9ZbWtuaHB0RXMrc2tKQjFMWm1uVTBaWFpzClRKak9Lb05ueHdVaTl4QnRUTXBQRWw2cVhmb3dCWlpvYjlkUzNtNzFLbjJCdU5Ec0s3YnVRcGJvdk9XdUQyNDAKdzNLQVJnT04xcjA4Vm4zd1I1MHVXS09tSkVsLzRUZ2JnSTRkaG85WHNIWUhUdnk4R3JRMXhYZE43ZEhSTlpHNQo5aDhmOUUzdjg1VWxwSEVWQThqUHB4RE5SSm9qRXVGQk9raFJEZEY1QWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDWWl4VUsKYkhsRUpCK2t4THdqdktySDQ1OVVsNUJjb0VXZE1BNnArUC8yWXVZa2NuWC9GRVNjUFRxUS9vdkF3ejU1ZG1FUwpJTjVZOWd2ZlJxdWhZcEdWOHVFSWpzVkczTjdKQm1wM0NyclEyd3FYeHV3cndkVXV1dDltQSt2RkQ4Q2FQSE8xCmVad1J6NEkzTktFQ0xHMHJXQWxseEVvUm9tQ2UvaWZIUnRNRklTRk5sSnZVNlhIbzFDVWNFQ2FwOG9hYXN2cFcKT2JBQjVqQzc5WWJXN2lWVm54cjZGMnRvOG9oSEdNSEpXR1pwSTNKbVpNbGVOK01kVm5ySFdXSXBkOG9iS2E3TgpqSlZTczgzRmlDMzd4d2dqMUQyaTNHUnh5bHNKZEdJWTl4WVpQVmNNUTh6Z2FMMUpJUk1BdVZYbHczUkRzSDR0Cms5WmFybGY1NG9BOUN0Nk8KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=   

service:      name:

e2e-test-webhook     

namespace:

e2e-tests-webhook-gbgt6     

path:

/mutating-pods 

failurePolicy:

Ignore 

name:

adding-init-container.k8s.io 

namespaceSelector:

{} 

rules: 

-

apiGroups:   

-

""   

apiVersions:   

- v1   

operations:   

- CREATE   

resources:   

- pods

rules

表示對於core/v1/pods資源對象創建的時候調用

mutating webhook

。server的地址及路徑通過clientConfig指明。

/mutating-pods

是指調用webhook server執行mutatePods,為pod增加init

initContainers

func

mutatePods

(

ar v1beta1

.

AdmissionReview

) *

v1beta1

.

AdmissionResponse

{  

glog

.

V

(

2

).

Info

(

"mutating pods"

)  

podResource

:=

metav1

.

GroupVersionResource

{

Group

:

""

,

Version

:

"v1"

,

Resource

:

"pods"

}  

if

ar

.

Request

.

Resource

!=

podResource

{     

glog

.

Errorf

(

"expect resource to be %s"

,

podResource

)     

return

nil  

}  

raw

:=

ar

.

Request

.

Object

.

Raw  

pod

:=

corev1

.

Pod

{}  

deserializer

:=

codecs

.

UniversalDeserializer

()  

if

_

,

_

,

err

:=

deserializer

.

Decode

(

raw

,

nil

,

&

pod

)

;

err

!=

nil

{     

glog

.

Error

(

err

)     

return

toAdmissionResponse

(

err

)   }  

reviewResponse

:=

v1beta1

.

AdmissionResponse

{}  

reviewResponse

.

Allowed

=

true  

if

pod

.

Name

==

"webhook-to-be-mutated"

{     

reviewResponse

.

Patch

= []

byte

(

addInitContainerPatch

)     

pt

:=

v1beta1

.

PatchTypeJSONPatch     

reviewResponse

.

PatchType

= &

pt  

}  

return

&

reviewResponse

}

 

創建Pod

    kubectl create –f pod.yaml

apiVersion:

v1

kind:

Pod

metadata:  name:

webhook-to-be-mutated 

namespace:

e2e-tests-webhook-gbgt6

spec:  containers: 

-

image:

k8s.gcr.io/pause:3.1   

name:

example

查詢Pod

    # kubectl get pod webhook-to-be-mutated –n e2e-tests-webhook-gbgt6 -oyaml

apiVersion:

v1

kind:

Pod

metadata:  creationTimestamp:

2018-07-19T07:49:37Z 

name:

webhook-to-be-mutated 

namespace:

e2e-tests-webhook-gbgt6 

resourceVersion:

"806" 

selfLink:

/api/v1/namespaces/e2e-tests-webhook-gbgt6/pods/webhook-to-be-mutated 

uid:

48d2e91d-8b28-11e8-b16d-286ed488dc10

spec:  containers: 

-

image:

k8s.gcr.io/pause:3.1   

imagePullPolicy:

IfNotPresent   

name:

example   

resources:

{}   

terminationMessagePath:

/dev/termination-log   

terminationMessagePolicy:

File   

volumeMounts:   

-

mountPath:

/var/run/secrets/kubernetes.io/serviceaccount     

name:

default-token-jhqlb     

readOnly:

true 

dnsPolicy:

ClusterFirst 

initContainers: 

-

image:

webhook-added-image   

imagePullPolicy:

Always   

name:

webhook-added-init-container   

resources:

{}   

terminationMessagePath:

/dev/termination-log   

terminationMessagePolicy:

File 

nodeName:

127.0.0.1 

priority:

restartPolicy:

Always 

schedulerName:

default-scheduler 

securityContext:

{} 

serviceAccount:

default 

serviceAccountName:

default 

terminationGracePeriodSeconds:

30 

tolerations: 

-

effect:

NoExecute   

key:

node.kubernetes.io/not-ready   

operator:

Exists   

tolerationSeconds:

300  -

effect:

NoExecute   

key:

node.kubernetes.io/unreachable   

operator:

Exists   

tolerationSeconds:

300 

volumes: 

-

name:

default-token-jhqlb   

secret:      defaultMode:

420     

secretName:

default-token-jhqlb

 

可以看出,創建成功的pod已經多了一個名字為webhook-added-init-container的initContainers。

最後我們來總結下webhook Admission的優勢

webhook可動態擴展Admission能力,滿足自定義客戶的需求

不需要重啟API Server,可通過創建webhook configuration熱載入webhook admission。

參考:

1)https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/

2)https://www.slideshare.net/sttts/kubecon-eu-2018-sig-api-machinery-deep-dive

推薦閱讀

K8S上的分散式系統應用編排

Kubernetes網路一年發展動態與未來趨勢

點擊

閱讀原文,

回帖即可

報名


推薦閱讀:
相关文章