kubebuilder(6)webhook

<p>operator中的webhook也是很重要的一塊功能。也是相對(duì)比較獨(dú)立的模塊,所以放在后面講。</p><p>webhook是一個(gè)callback,注冊(cè)到k8s的api-server上。當(dāng)某個(gè)特定的時(shí)間發(fā)生時(shí),api server就會(huì)查詢注冊(cè)的webhook,并根據(jù)一些邏輯確認(rèn)轉(zhuǎn)發(fā)消息給某個(gè)webhook</p><p>在k8s中,有3類webhook,admission webhook, authorization webhook 和 CRD conversion webhook.</p><p>在kubebuilder的底層controller-runtime框架里,支持admission webhooks and CRD conversion webhooks。</p><p>這篇筆記講的是admission webhook。(以下的webhook就是指admission webhook)。CRD conversion webhooks用于多版本api轉(zhuǎn)換時(shí),目前入門階段先不討論這個(gè)話題。</p><p>admission webhook又可以分成2類。</p><p>一種是校驗(yàn)類的webhook,只讀取信息,做校驗(yàn)判斷,不會(huì)改變消息,稱為validating類型。這里的校驗(yàn)就可以寫復(fù)雜的業(yè)務(wù)了,前面的代碼里我們也配置過(guò)簡(jiǎn)單的validation校驗(yàn)。</p> // +kubebuilder:validation:Required
Image string json:"image,omitempty"
<p>另一種就是可修改對(duì)象的webhook,比如設(shè)置默認(rèn)值功能,稱為mutating類型。</p><h3><span/><span>執(zhí)行順序</span><span/></h3><p>先執(zhí)行mutating webhook,后執(zhí)行validating webhook</p><p>就是說(shuō)先設(shè)置,后校驗(yàn)。不需要擔(dān)心,校驗(yàn)完了之后,另一個(gè)webhook又修改了值。</p><h2><span/><span>工作流</span><span/><span> </span></h2><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-5f394d00fc3a39c9.jpeg" img-data="{"format":"jpeg","size":52646,"width":797,"height":680,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>
<ol><li>用戶創(chuàng)建一個(gè)CRD的實(shí)例</li><li>k8s api-server將這個(gè)請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的webhook</li><li>webhook完成默認(rèn)的參數(shù)配置操作,并進(jìn)行一些參數(shù)校驗(yàn)操作。成功之后將cr返回給api-server。api-server進(jìn)行落庫(kù)</li><li>我們編寫的controller的在后臺(tái)監(jiān)控cr,拉取cr內(nèi)容,并執(zhí)行我們編寫的邏輯</li><li>cr的執(zhí)行結(jié)果同步回api-server</li></ol><h2><span/><span>創(chuàng)建webhook</span><span/><span> </span></h2><p>和創(chuàng)建api一樣,webhook也由kubebuilder創(chuàng)建腳手架代碼。</p><p>我們?cè)谥暗拇a框架上繼續(xù)操作。</p>kubebuilder create webhook --group tutorial --version v1 --kind Demo --defaulting --programmatic-validation
<p>--defaulting 是會(huì)創(chuàng)建配置默認(rèn)值的webhook</p><p>--programmatic-validation 創(chuàng)建有校驗(yàn)功能的webhook</p><p>kubebuilder的參數(shù)</p>Flags:
--conversion if set, scaffold the conversion webhook
--defaulting if set, scaffold the defaulting webhook
--force attempt to create resource even if it already exists
--group string resource Group
-h, --help help for webhook
--kind string resource Kind
--plural string resource irregular plural form
--programmatic-validation if set, scaffold the validating webhook
--version string resource Version
<p>--conversion 就是創(chuàng)建CRD conversion webhooks。用于多版本api轉(zhuǎn)換時(shí),現(xiàn)在先不用管。</p><p>執(zhí)行完之后,看看生成的代碼</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-cfb0ad97e36dcf91.jpeg" img-data="{"format":"jpeg","size":62312,"width":702,"height":447,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318145925949<p>查看main.go</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-9c2a5a672a3373c9.jpeg" img-data="{"format":"jpeg","size":38740,"width":1080,"height":282,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318151327123<p>作用就是在manager中注冊(cè)了我們的webhook</p><h2><span/><span>業(yè)務(wù)代碼</span><span/><span> </span></h2><p>更重要的文件是生成的這個(gè)webhook文件,我們的業(yè)務(wù)代碼是寫在這里的</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-bde194c5b912078e.jpeg" img-data="{"format":"jpeg","size":30559,"width":837,"height":301,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318152519441<div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-567af7fa2cf7e552.jpeg" img-data="{"format":"jpeg","size":23639,"width":907,"height":259,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318154234686<p>我們的Demo實(shí)現(xiàn)了webhook.Defaulter接口。即擁有了配置crd的默認(rèn)值的能力。</p><p>稍后我們?cè)谶@個(gè)Default()方法里編寫配置默認(rèn)值的操作。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-74c2c02fd90d5bd2.jpeg" img-data="{"format":"jpeg","size":69320,"width":916,"height":713,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318154438377<p>我們的Demo實(shí)現(xiàn)了webhook.Validator接口,在crd進(jìn)行增刪改時(shí)可以進(jìn)行驗(yàn)證操作</p><p>簡(jiǎn)單實(shí)現(xiàn)幾個(gè)方法</p>func (r *Demo) Default() {
demolog.Info("default", "name", r.Name)

// TODO(user): fill in your defaulting logic.
if r.Spec.Replicas == nil {
r.Spec.Replicas = new(int32)
*r.Spec.Replicas = 1
demolog.Info("配置默認(rèn)值", "replicas", *r.Spec.Replicas)
}
}
// 創(chuàng)建和更新調(diào)一下validate方法
func (r *Demo) ValidateCreate() error {
demolog.Info("validate create", "name", r.Name)

// TODO(user): fill in your validation logic upon object creation.
// 調(diào)用 r.validate() 方法,來(lái)驗(yàn)證對(duì)象的合法性。
return r.validate()
}

func (r *Demo) validate() error {
var allErrs field.ErrorList
if *r.Spec.Replicas > 10 {
err := field.Invalid(field.NewPath("spec").Child("replicas"),
*r.Spec.Replicas,
"副本數(shù)不能大于10")

allErrs = append(allErrs, err)
}

if len(allErrs) == 0 {
demolog.Info("參數(shù)合法")
return nil
}

return apierrors.NewInvalid(schema.GroupKind{
Group: "tutorial",
Kind: "Demo"},
r.Name, allErrs)
}
<p>在部署webhook前,還需要修改下配置</p><p>在config/default/kustomization.yaml中</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-54741a5c8abf0c4c.jpeg" img-data="{"format":"jpeg","size":98683,"width":875,"height":875,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318173558821<p>注釋全都放開(kāi)</p><p>在config/crd/kustomization.yaml中</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-f981ba6a40e8b1c7.jpeg" img-data="{"format":"jpeg","size":49407,"width":789,"height":454,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240318173642764<p>注釋放開(kāi)</p><h2><span/><span>部署前準(zhǔn)備</span><span/><span> </span></h2><h3><span/><span>安裝cert-manager</span><span/></h3><p>因?yàn)閍pi-server是通過(guò)https調(diào)用webhook,所以需要部署cert-manager來(lái)自動(dòng)管理證書。</p><p>這也是kubebuilder官方建議的方案</p>kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.7.3/cert-manager.yaml
<div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-4db757040873b8e6.jpeg" img-data="{"format":"jpeg","size":35791,"width":818,"height":388,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240320171742770<p>因?yàn)槲业臏y(cè)試環(huán)境是1.18的k8s,所以選擇1.7版本的cert manager。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-49bf1e133c502df7.jpeg" img-data="{"format":"jpeg","size":81232,"width":965,"height":415,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240320171848151<h3><span/><span>清理環(huán)境</span><span/></h3><p>先把之前測(cè)試的資源全部刪除</p><p>刪除測(cè)試demo</p>kubectl delete -f config/samples/tutorial_v1_demo.yaml
<p>刪除operator</p>kubectl delete -f demo-operator.yaml
<p>刪除crd</p>make uninstall
<h2><span/><span>部署</span><span/><span> </span></h2>make install
make docker-build docker-push IMG=harbor-test.xxx.net/paas/demo-operator:2.0
make deploy IMG=harbor-test.xxx.net/paas/demo-operator:2.0
<div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-2f74dc04c60458dd.jpeg" img-data="{"format":"jpeg","size":43717,"width":1080,"height":248,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240320173017108<h2><span/><span>測(cè)試</span><span/><span> </span></h2><h3><span/><span>測(cè)試默認(rèn)值功能</span><span/></h3><p>修改一下之前的yaml,去掉replicas字段</p>apiVersion: tutorial.demo.com/v1
kind: Demo
metadata:
namespace: demo
name: demo-sample
spec:
image: nginx:1.22
svcName: demo-ng
<p>查看manager的日志</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-5c582dbfe61fc025.jpeg" img-data="{"format":"jpeg","size":23010,"width":1080,"height":85,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240320173733830<p>調(diào)用了配置默認(rèn)值的代碼</p><h3><span/><span>測(cè)試參數(shù)校驗(yàn)功能</span><span/></h3><p>將yaml中的replicas字段設(shè)置為15,超過(guò)我們的最大值</p>[root@paas-m-k8s-master-1 demo-operator]# kubectl apply -f config/samples/tutorial_v1_demo.yaml
The Demo "demo-sample" is invalid: spec.replicas: Invalid value: 15: 副本數(shù)不能大于10
<p>直接報(bào)錯(cuò)</p><p>查看日志</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/5149787-40c16b6727df715e.jpeg" img-data="{"format":"jpeg","size":12993,"width":1080,"height":59,"space":"srgb","channels":3,"depth":"uchar","density":72,"chromaSubsampling":"4:2:0","isProgressive":false,"hasProfile":false,"hasAlpha":false}" contenteditable="false" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div>image-20240320174235546<p>進(jìn)行了校驗(yàn)</p><p>
</p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容