您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么部署一個webhook”,在日常操作中,相信很多人在怎么部署一個webhook問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么部署一個webhook”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
我們什么時候需要用External Admission Webhooks呢?當集群管理員需要強制對某些請求或者所有請求都進行校驗或者修改的時候,就可以考慮使用ValidatingAdmissionWebhook或MutatingAdmissionWebhook,二者區別如下:
MutatingAdmissionWebhook允許你在webhook中對object進行mutate修改;
ValidatingAdmissionWebhook(Kubernetes 1.9之前叫GenericAdmissionWebhook)不允許你在webhook中對Object進行mutate修改,只是返回validate結果為true or false;
前面提到,需要在每個kube-apiserver實例(考慮到Kubernetes Master HA)中--admission-controll
中添加ValidatingAdmissionWebhook
,MutatingAdmissionWebhook
。
另外,還需要在每個kube-apiserver實例的--runtime-config
中添加admissionregistration.k8s.io/v1alpha1
。disable的時候,也記得要從這里刪除。
beta in 1.9;
需要注意,MutatingAdmissionWebhook是讓匹配的webhooks串行執行的,因為每個webhook都可能會mutate object。
同Initializers的使用類似,MutatingAdmissionWebhook是通過創建MutatingWebhookConfiguration來配置什么樣的request會觸發哪個webhook。
注意apiserver調用webhook時一定是通過TLS認證的,所以MutatingWebhookConfiguration中一定要配置caBundle。
alpha in 1.8,beta in 1.9;
需要注意,ValidatingAdmissionWebhook是讓匹配的webhooks并發執行的,因為每個webhook只會進行validate操作,而不會mutate object。
同Initializers的使用類似,ValidatingAdmissionWebhook是通過創建ValidatingWebhookConfiguration來配置什么樣的request會觸發哪個webhook。
注意apiserver調用webhook時一定是通過TLS認證的,所以ValidatingWebhookConfiguration中一定要配置caBundle。
我們以ValidatingAdmissionWebhook為例子,看看怎么玩。
部署ValidatingWebhook,比如我們就簡單的以Pod部署一個webhook,并創建對應的Service:
apiVersion: v1 kind: Pod metadata: labels: role: webhook name: webhook spec: containers: - name: webhook image: example-webhook:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: labels: role: webhook name: webhook spec: ports: - port: 443 targetPort: 8000 selector: role: webhook
其中example-webhook為github的項目caesarxuchao/example-webhook-admission-controller,通過github repo根目錄下的Dockerfile制作example-webhook鏡像。
FROM golang:1.8 WORKDIR /go/src RUN mkdir -p github.com/caesarxuchao/example-webhook-admission-controller COPY . ./github.com/caesarxuchao/example-webhook-admission-controller RUN go install github.com/caesarxuchao/example-webhook-admission-controller CMD ["example-webhook-admission-controller","--alsologtostderr","-v=4","2>&1"]
創建ValidatingWebhookConfiguration Object,比如:
apiVersion: admissionregistration.k8s.io/v1alpha1 kind: ValidatingWebhookConfiguration metadata: name: config1 externalAdmissionHooks: - name: podimage.k8s.io rules: - operations: - CREATE apiGroups: - "" apiVersions: - v1 resources: - pods failurePolicy: Ignore clientConfig: caBundle: xxxx service: namespace: default name: webhook
- 注意failurePolicy可以為Ignore或者Fail,意味著如果和webhook通信出現問題導致調用失敗,那么將根據failurePolicy進行抉擇,是忽略失敗(admit)還是認為準入失敗(reject)。在Kubernetes 1.7中,該值只允許配置為Ignore。 - 對比initializerConfiguration,ValidatingWebhookConfiguration和MutatingWebhookConfiguration在rule的定義時,增加了operations field,在resources定義時候可以指定subresource,格式為resource/subresource。
ExternalAdmissionHookConfiguration創建后,你需要等待幾秒,然后通過通過Deployment或者直接創建Pod,這時創建Pod的請求就會被apiserver攔住,調用ValidatingAdmissionWebhook進行檢查是否Admit通過。比如,上面的example-webhook是檢查容器鏡像是否以"gcr.io"為前綴的。
admission controller實際上發送一個admissionReview請求給webhook server,然后webhook server從admissionReview.spec中獲取object,oldobject,userInfo等信息,進行mutate或者validate后再發回一個admissionReview作為返回,其中返回的admissionReivew.status中有admission決定。
下面是AdmissionReview結構體的定義:
type AdmissionReview struct { metav1.TypeMeta `json:",inline"` // Request describes the attributes for the admission request. // +optional Request *AdmissionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"` // Response describes the attributes for the admission response. // +optional Response *AdmissionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"` } // AdmissionRequest describes the admission.Attributes for the admission request. type AdmissionRequest struct { // UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are // otherwise identical (parallel requests, requests when earlier requests did not modify etc) // The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request. // It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging. UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` // Kind is the type of object being manipulated. For example: Pod Kind metav1.GroupVersionKind `json:"kind" protobuf:"bytes,2,opt,name=kind"` // Resource is the name of the resource being requested. This is not the kind. For example: pods Resource metav1.GroupVersionResource `json:"resource" protobuf:"bytes,3,opt,name=resource"` // SubResource is the name of the subresource being requested. This is a different resource, scoped to the parent // resource, but it may have a different kind. For instance, /pods has the resource "pods" and the kind "Pod", while // /pods/foo/status has the resource "pods", the sub resource "status", and the kind "Pod" (because status operates on // pods). The binding resource for a pod though may be /pods/foo/binding, which has resource "pods", subresource // "binding", and kind "Binding". // +optional SubResource string `json:"subResource,omitempty" protobuf:"bytes,4,opt,name=subResource"` // Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and // rely on the server to generate the name. If that is the case, this method will return the empty string. // +optional Name string `json:"name,omitempty" protobuf:"bytes,5,opt,name=name"` // Namespace is the namespace associated with the request (if any). // +optional Namespace string `json:"namespace,omitempty" protobuf:"bytes,6,opt,name=namespace"` // Operation is the operation being performed Operation Operation `json:"operation" protobuf:"bytes,7,opt,name=operation"` // UserInfo is information about the requesting user UserInfo authenticationv1.UserInfo `json:"userInfo" protobuf:"bytes,8,opt,name=userInfo"` // Object is the object from the incoming request prior to default values being applied // +optional Object runtime.RawExtension `json:"object,omitempty" protobuf:"bytes,9,opt,name=object"` // OldObject is the existing object. Only populated for UPDATE requests. // +optional OldObject runtime.RawExtension `json:"oldObject,omitempty" protobuf:"bytes,10,opt,name=oldObject"` } // AdmissionResponse describes an admission response. type AdmissionResponse struct { // UID is an identifier for the individual request/response. // This should be copied over from the corresponding AdmissionRequest. UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` // Allowed indicates whether or not the admission request was permitted. Allowed bool `json:"allowed" protobuf:"varint,2,opt,name=allowed"` // Result contains extra details into why an admission request was denied. // This field IS NOT consulted in any way if "Allowed" is "true". // +optional Result *metav1.Status `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` // The patch body. Currently we only support "JSONPatch" which implements RFC 6902. // +optional Patch []byte `json:"patch,omitempty" protobuf:"bytes,4,opt,name=patch"` // The type of Patch. Currently we only allow "JSONPatch". // +optional PatchType *PatchType `json:"patchType,omitempty" protobuf:"bytes,5,opt,name=patchType"` }
下面是前面提到的example-webhook的main文件,可以借鑒它來開發自己的AdmissionWebhook。
// only allow pods to pull images from specific registry. func admit(data []byte) *v1alpha1.AdmissionReviewStatus { ar := v1alpha1.AdmissionReview{} if err := json.Unmarshal(data, &ar); err != nil { glog.Error(err) return nil } // The externalAdmissionHookConfiguration registered via selfRegistration // asks the kube-apiserver only sends admission request regarding pods. podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} if ar.Spec.Resource != podResource { glog.Errorf("expect resource to be %s", podResource) return nil } raw := ar.Spec.Object.Raw pod := v1.Pod{} if err := json.Unmarshal(raw, &pod); err != nil { glog.Error(err) return nil } reviewStatus := v1alpha1.AdmissionReviewStatus{} for _, container := range pod.Spec.Containers { // gcr.io is just an example. if !strings.Contains(container.Image, "gcr.io") { reviewStatus.Allowed = false reviewStatus.Result = &metav1.Status{ Reason: "can only pull image from grc.io", } return &reviewStatus } } reviewStatus.Allowed = true return &reviewStatus } func serve(w http.ResponseWriter, r *http.Request) { var body []byte if r.Body != nil { if data, err := ioutil.ReadAll(r.Body); err == nil { body = data } } // verify the content type is accurate contentType := r.Header.Get("Content-Type") if contentType != "application/json" { glog.Errorf("contentType=%s, expect application/json", contentType) return } reviewStatus := admit(body) ar := v1alpha1.AdmissionReview{ Status: *reviewStatus, } resp, err := json.Marshal(ar) if err != nil { glog.Error(err) } if _, err := w.Write(resp); err != nil { glog.Error(err) } } func main() { flag.Parse() http.HandleFunc("/", serve) clientset := getClient() server := &http.Server{ Addr: ":8000", TLSConfig: configTLS(clientset), } go selfRegistration(clientset, caCert) server.ListenAndServeTLS("", "") }
我們發現,MutatingAdmissionWebhook其實跟Initializers的目的都是一樣的,都是對object做修改,只是實現的方式不同而已。那為什么兩者要并存呢?深度剖析Kubernetes動態準入控制之Initializers中提到,Initializers具有如下缺陷:
如果你部署的Initializers Controllers不能正常工作了或者性能很低,在高并發場景下會導致大量的相關對象停留在uninitialized狀態,無法進行后續的調度。這可能會影響你的業務,比如你使用了HPA對相關Deployment對象進行彈性擴容,當負載上來的時候,你的Initializers Controllers不能正常工作了,會導致你的應用不能彈性伸縮,后果可想而知!
所以我個人的理解是,MutatingAdmissionWebhook是mutate object的一種比Initializers更優雅的、性能更好的實現方式。而且從Kubernetes 1.9發布的情況來看,MutatingAdmissionWebhook是Beta,而Initializers還停留在Alpha,并且前面提到的Kubernetes 1.9中官方推薦的--adminssion-control
配置中推薦的是MutatingAdmissionWebhook
,而不是Initializers
。因此我覺得社區其實是想用MutatingAdmissionWebhook替代Initializers。
到此,關于“怎么部署一個webhook”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。