目錄
1.前提條件
2.開始創(chuàng)建核心組件Pod的Webhook
2.1.什么是Webhook
?2.2.在本地k8s集群安裝cert-manager
2.3.創(chuàng)建一個空的文件夾
2.4. 生成工程框架
2.5.?生成核心組件Pod的API
2.6.生成Webhook
2.7.開始實現(xiàn)Webhook相關代碼
2.7.1.修改相關配置
2.7.2.修改代碼
2.7.3.按照最新配置更新yaml
2.7.4.集群運行測試
2.7.4.1.修改Makefile文件
2.7.4.2.將應用部署到k8s集群上
2.7.5.測試
2.7.5.1.準備測試Deployment的yaml配置
2.7.5.2.部署這個Pod demo
?2.7.5.3.停止測試
參考文章
1.前提條件
可以按之前的文章配置,配置好之后,我們會準備好以下內容:
- 本地多節(jié)點集群
- kubectl 客戶端命令工具
- Lens k8s dashboard 可視化客戶端工具
- golang開發(fā)語言
- VScode Linux 版
- kubebuilder
2.開始創(chuàng)建核心組件Pod的Webhook
????????K8s的核心組件就那些幾個:Deployment、Pod、Service、Ingress、ConfigMap、Secret、……
????????在Kubebuilder的官方文檔中,也有提到webhook的內容,但是比較簡單,而且有些參考文章是基于CRD做的Webhook示例,此處我將演示核心組件Pod的Webhook。

2.1.什么是Webhook
? ? ? ? ?從我的角度看,Webhook就是一個回調動作,舉個例子方便理解:例如,我們希望在pod創(chuàng)建的時候,在annotation中增加一個標簽,如author:geoff之類的,就可以利用這個webhook實現(xiàn),當創(chuàng)建調用鏈完成之后,利用“回調”在這個創(chuàng)建動作之后絲滑地加入“增加annotation的額外動作”??梢越Y合Js的回調、java的AOP切片來理解。我們看看其中的原理:

? ? ? ? 從圖中可以看到,Webhook是在Mutating Admission或者Vaildating Admission階段往Webhook發(fā)送一個“請求”并接受來自Webhook的“響應”。我們此時不妨大膽推測一下,實現(xiàn)這兩點,要做些什么呢?我可以不負責任推測一下步驟:
- 在XXX Admission Controller配置一個請求,請求會往Webhook接受、處理并返回
- Webhook開發(fā)一個接收這個請求的Handler(類似Java的controller)
????????事實也正如我們瞎想的哪樣,確實核心就是這兩個動作。這里我們看到,一共有兩種Admission Controller,有點點區(qū)別:
- Mutating Admission Controller? ? ? ?# 可以修改資源
- Vaildating Admission Controller? ? ?# 驗證資源,可以通過或者不通過
2.2.在本地k8s集群安裝cert-manager
? ? ? ? 這個算是提前準備了,需要注意的是,k8s集群的版本和cert-manage需要注意下,不然版本差別過多,可能會有些意想不到的問題
# 查看本地集群的版本
kind version
# 在集群上安裝cert-maneger,其中v1.7.1就是cert-manager版本。
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml
# 驗證對應的資源實例是否安裝成功
kubectl get all -n cert-manager
# 看對應的Pod是否被成功創(chuàng)建,可能一開始pod的replicas=0,因為集群節(jié)點是image container,下載image可能比較慢
kubectl get pods -n cert-manager

????????事實上,有時候,get pods可能會發(fā)現(xiàn)無資源,這可能是local cluster有問題,建議先刪除,后新建:
# 先刪除本地的集群
kind delete cluster --name k8s-local-dev
# 再新建
## 創(chuàng)建集群配置文件,1個master node,1個worker node。
cat << EOF > kind-clusters-mutil-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOF
## start to create cluster
kind create cluster --name k8s-local-dev --config ./kind-clusters-mutil-config.yaml
## copy kubeconfig to Lens kubecofig
## 不然Lens在Kind集群更新后,配置文件沒更新,會打不開
cp ~/.kube/config /mnt/c/Users/${current_user}/.kube/config
2.3.創(chuàng)建一個空的文件夾
# 創(chuàng)建一個空的文件節(jié)夾
mkdir create-pod-webhook-demo
# 進入空文件夾
cd create-pod-webhook-demo
2.4. 生成工程框架
# 生成工程框架
kubebuilder init --domain geoff.wh.demo --repo k8s-operator/kubebuilder-webhook-demo
?????????生成文件目錄如下,?此處,我不贅述了,上一篇文章已經有比較清晰的介紹了。
? create-pod-webhook-demo tree
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── config
│?? ├── default
│?? │?? ├── kustomization.yaml
│?? │?? ├── manager_auth_proxy_patch.yaml
│?? │?? └── manager_config_patch.yaml
│?? ├── manager
│?? │?? ├── controller_manager_config.yaml
│?? │?? ├── kustomization.yaml
│?? │?? └── manager.yaml
│?? ├── prometheus
│?? │?? ├── kustomization.yaml
│?? │?? └── monitor.yaml
│?? └── rbac
│?? ├── auth_proxy_client_clusterrole.yaml
│?? ├── auth_proxy_role.yaml
│?? ├── auth_proxy_role_binding.yaml
│?? ├── auth_proxy_service.yaml
│?? ├── kustomization.yaml
│?? ├── leader_election_role.yaml
│?? ├── leader_election_role_binding.yaml
│?? ├── role_binding.yaml
│?? └── service_account.yaml
├── go.mod
├── go.sum
├── hack
│?? └── boilerplate.go.txt
└── main.go
6 directories, 25 files
2.5.?生成核心組件Pod的API
? ? ? ? 從這里之前,和創(chuàng)建Operator的步驟基本是一致的,從這里開始,要開始有點不一樣了
# 定義API,此處要實現(xiàn)Pod的Webhook,因此直接按Pod的Api創(chuàng)建
kubebuilder create api --group core --version v1 --kind Pod
# 之后的option我們不創(chuàng)建Resource和Controller,因此都選擇n
????????之后的option我們不創(chuàng)建Resource和Controller,因此都選擇n

2.6.生成Webhook
# --Kind這里,可以指定現(xiàn)存的PAAS組件,也可以
kubebuilder create webhook --group core --version v1 --kind Pod --defaulting --webhook-version v1
? ? ? ? 生成webhook的代碼結構如下:?
? create-pod-webhook-demo tree
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
│?? └── v1
│?? ├── pod_webhook.go
│?? └── webhook_suite_test.go
├── bin
│?? └── controller-gen
├── config
│?? ├── certmanager
│?? │?? ├── certificate.yaml
│?? │?? ├── kustomization.yaml
│?? │?? └── kustomizeconfig.yaml
│?? ├── default
│?? │?? ├── kustomization.yaml
│?? │?? ├── manager_auth_proxy_patch.yaml
│?? │?? ├── manager_config_patch.yaml
│?? │?? ├── manager_webhook_patch.yaml
│?? │?? └── webhookcainjection_patch.yaml
│?? ├── manager
│?? │?? ├── controller_manager_config.yaml
│?? │?? ├── kustomization.yaml
│?? │?? └── manager.yaml
│?? ├── prometheus
│?? │?? ├── kustomization.yaml
│?? │?? └── monitor.yaml
│?? ├── rbac
│?? │?? ├── auth_proxy_client_clusterrole.yaml
│?? │?? ├── auth_proxy_role.yaml
│?? │?? ├── auth_proxy_role_binding.yaml
│?? │?? ├── auth_proxy_service.yaml
│?? │?? ├── kustomization.yaml
│?? │?? ├── leader_election_role.yaml
│?? │?? ├── leader_election_role_binding.yaml
│?? │?? ├── role_binding.yaml
│?? │?? └── service_account.yaml
│?? └── webhook
│?? ├── kustomization.yaml
│?? ├── kustomizeconfig.yaml
│?? └── service.yaml
├── go.mod
├── go.sum
├── hack
│?? └── boilerplate.go.txt
└── main.go
11 directories, 36 files
到這一步之后,我們直接轉轉入VScode開發(fā)
# 當前工程目錄打開VScode
code .

2.7.開始實現(xiàn)Webhook相關代碼
2.7.1.修改相關配置
????????修改config/default/kustomize.yaml:
- 注釋-crd 相關內容,因為我們沒有CRD,只是實現(xiàn)Pod webhook
- 打開webhook、cert-manager相關配置,如下圖所示
- 但是要注意屬性縮進對齊,不然會報錯

? ? ? ? 修改config/rdbc/kustomize.yaml:
1.注釋 -role,這個也是和CRD相關,因為我們沒有,所以注釋掉

? ? ? ? 修改config/default/webhookcainjection_patch.yaml:
1.我們?yōu)榱瞬桓氵@么復雜,我們只關心MutatingAdmision,因此可以直接注釋掉ValidateAdmission

2.7.2.修改代碼
????????因為核心組件Pod的Webhook和一般的CRD的webhook不一樣,此處生成的pod_webhook.go只有Default()這個function,因此,我們需要直接重寫整個代碼,最重要的是Handle()方法。
? ? ? ? 修改api/v1/pod_webhook.go文件:
/*
Copyright 2023.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"context"
"encoding/json"
"fmt"
"net/http"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
// log is for logging in this package.
var podlog = logf.Log.WithName("pod-resource")
// 定義核心組件pod的webhook的主struct,類似于java的Class
type PodWebhookMutate struct {
Client client.Client
decoder *admission.Decoder
}
// +kubebuilder:webhook:path=/mutate-core-v1-pod,mutating=true,failurePolicy=fail,sideEffects=None,groups=core,resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io,admissionReviewVersions=v1
func (a *PodWebhookMutate) Handle(ctx context.Context, req admission.Request) admission.Response {
pod := &corev1.Pod{}
err := a.decoder.Decode(req, pod)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
// TODO: 變量marshaledPod是一個Map,可以直接修改pod的一些屬性
marshaledPod, err := json.Marshal(pod)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
// 打印
fmt.Println("======================================================")
fmt.Println(string(marshaledPod))
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
}
func (a *PodWebhookMutate) InjectDecoder(d *admission.Decoder) error {
a.decoder = d
return nil
}
// 注釋掉一開始生成的內容
// func (r *Pod) SetupWebhookWithManager(mgr ctrl.Manager) error {
// return ctrl.NewWebhookManagedBy(mgr).
// For(r).
// Complete()
// }
// // TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// var _ webhook.Defaulter = &Pod{}
// // Default implements webhook.Defaulter so a webhook will be registered for the type
// func (r *Pod) Default() {
// podlog.Info("default", "name", r.Name)
// // TODO(user): fill in your defaulting logic.
// }
? ? ? ? 修改api/v1/xxx_suite_test.go
????????全部注釋掉,替換一個簡單的測試Function。這個測試也是有講究的,有興趣可以研究一下。
/*
Copyright 2023.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"fmt"
"testing"
)
func TestFunc(t *testing.T) {
// 打印
fmt.Println("this is test function......")
}
????????修改main.go文件:
import (
......
# 增加一個依賴包
v1 "k8s-operator/kubebuilder-webhook-demo/api/v1"
......
)
......
// 注釋掉
// if err = (&corev1.Pod{}).SetupWebhookWithManager(mgr); err != nil {
// setupLog.Error(err, "unable to create webhook", "webhook", "Pod")
// os.Exit(1)
// }
// 增加webhook注冊
mgr.GetWebhookServer().Register("/mutate-core-v1-pod", &webhook.Admission{Handler: &v1.PodWebhookMutate{Client: mgr.GetClient()}})
......

? ? ? ? 修改Dockerfile
1.和上面一樣,因為我們是創(chuàng)建Pod的Webhook,不需要自定義Controller,注釋掉。

? ? ? ? ?修改Makefile文件
增加一個kind-load,方便將image上傳到本地集群中
......
# local k8s cluster name
KUBE_CLUSTER = k8s-local-dev
......
.PHONY: kind-load
kind-load: ## load the local image to the kind cluster
kind load docker-image ${IMG} --name ${KUBE_CLUSTER}
......

2.7.3.按照最新配置更新yaml
# 更新yaml,這里和之前main.go和xxx_webhook.go的注釋有點關,生成的代碼是依據(jù)注釋實現(xiàn)的
make mainfests generate
????????這一步比較重要,執(zhí)行后會生成config/webhook/mainfests.yaml文件,切記執(zhí)行
2.7.4.集群運行測試
2.7.4.1.修改Makefile文件
#?增加一個kind-load,方便將本地image上傳到本地k8s集群中
......
# local k8s cluster name
KUBE_CLUSTER = k8s-local-dev?
......
.PHONY: kind-load
kind-load: ## load the local image to the kind cluster
?? ?kind load docker-image ${IMG} --name ${KUBE_CLUSTER}
......

2.7.4.2.將應用部署到k8s集群上
以下是部署到集群的步驟:構建鏡像、上傳到集群容器中、部署
其中IMG是一個可以自行設置鏡像名的變量,此處為:k8s-podwebhook-demo:1.0。
按如下命令執(zhí)行后,即可在k8s集群中看到部署的CRD controller應用。
# 構建鏡像(有時候會失敗,可能是網絡問題,多試幾遍),IMG需要指定,不然后面部署還是有問題
make docker-build IMG=k8s-podwebhook-demo:1.0
# local鏡像上傳到Kind創(chuàng)建的k8s集群所在的所有node中(如果本地是)
make kind-load IMG=k8s-podwebhook-demo:1.0
# 部署controller
make deploy IMG=k8s-podwebhook-demo:1.0
????????在這個過程中,bin/目錄存在一些二進制的工具包,可以先刪除,是之前make deploy時下載的,如果已存在,有可能會報錯。




?????????這個MutatingAdmission的作用是注冊一個endpoint,使得Pod在被創(chuàng)建后,往這個endpoint發(fā)送一個https請求(這也是為什么需要證書的原因)。事實上main.go中
// 增加webhook注冊
mgr.GetWebhookServer().Register("/mutate-core-v1-pod", &webhook.Admission{Handler: &v1.PodWebhookMutate{Client: mgr.GetClient()}})
?這句就類似java controller,接受這個https的請求。
2.7.5.測試
2.7.5.1.準備測試Deployment的yaml配置
? ? ? ? 這里需要說明,因為我們這里創(chuàng)建的是Pod Webhook,但是一般而言,我們不直接創(chuàng)建Pod,而是創(chuàng)建一個deployment,因為deployment最后也是會創(chuàng)建pod的。當然直接創(chuàng)建Pod也是可以的,這里創(chuàng)建一個pod-demo-ngnix.yaml文件去創(chuàng)建一個簡單的pod,這個Pod只是一個基本的Ngnix鏡像。
cat <<EOF >pod-demo-ngnix.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-ngnix
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
EOF
2.7.5.2.部署這個Pod demo
# 部署這個pod demo實例
kubectl apply -f ./pod-demo-ngnix.yaml

?2.7.5.3.停止測試
# 刪除測試Pod
kubectl delete -f ./pod-demo-ngnix.yaml
# undeploy這個webhook
make undeploy
參考文章
8. kubebuilder 進階: webhook - Mohuishou
使用kubebuilder開發(fā)kubernetes核心資源的webhook | 老 宋文章來源:http://www.zghlxwxcb.cn/news/detail-672652.html
調試運行中的 Pod | Kubernetes文章來源地址http://www.zghlxwxcb.cn/news/detail-672652.html
到了這里,關于創(chuàng)建K8s pod Webhook的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!