Kubernetes开发(5)-validateadmission练手
发布日期:2021-06-29 11:37:48 浏览次数:2 分类:技术文章

本文共 6062 字,大约阅读时间需要 20 分钟。

补充好基础知识后,上手实践才是最快的学习方法,所以先写一个validateadmission练练手。模拟一个生产需求,假设生产环境所有的deployment不允许单点,即副本数量不能少于2,如果少于2则不允许创建,且多个Kubernetes集群都有类似需求,那么这个场景用webhook实现就非常简单。

先上一下自己写的demo地址,可以对照查看

思路

之前有提过webhook的调用逻辑,结合当前场景,大致上是以下几个步骤:

  • 创建一个tls 的webserver, 做好路由,路由绑定handler
  • handler 用于接收api-server发来的admission review
  • 创建一个ValidatingWebhookConfiguration,用于注册web server的url 以及 绑定证书。
  • web server 解析admission review ,根据信息做判断
  • 对结果进行处理,然后回调api-server
  • 创建完成

大致的流程就是以上几个步骤,其实非常简单,主要搞清楚几个结构体就可以了,下面开始操作:

// 启动HTTP服务	mux := http.New()	handle.InitHandle(mux)	srv := &go_http.Server{		Handler:      mux.GetRouter(),		Addr:         fmt.Sprintf(":%d", port),		TLSConfig: &tls.Config{			Certificates: []tls.Certificate{cert},		},		WriteTimeout: 15 * time.Hour,		ReadTimeout:  15 * time.Hour,	}	go srv.ListenAndServeTLS("", "")

入口就是一个简单的webserver, 指定好证书路径,以及加载mux路由即可。

func valiDateAdmission(res http.ResponseWriter, req *http.Request) {	// 解析收到的报文	reqContent, err := ioutil.ReadAll(req.Body)	defer req.Body.Close()	if err != nil {		klog.Errorf("[webhook] 请求报文解析失败")		common.ReqBodyInvalid(res)		return	}	// 定义resp的报文	var admissionResponse *admissionv1.AdmissionResponse	requestedAdmissionReview := admissionv1.AdmissionReview{}	// 对api-server传过来的报文做解析	_, _, err = deserializer.Decode(reqContent, nil, &requestedAdmissionReview)	if err != nil {		klog.Errorf("[webhook] 请求报文解析失败: %v", err)		admissionResponse = &admissionv1.AdmissionResponse{			Result: &metav1.Status{				Code:    http.StatusInternalServerError,				Message: err.Error(),			},		}	// 解析成功,进行具体的拦截	} else {		admissionResponse = controller.Validate(&requestedAdmissionReview)	}	// 构造返回的 AdmissionReview 这个结构体	responseAdmissionReview := admissionv1.AdmissionReview{}	// admission/v1	responseAdmissionReview.APIVersion = requestedAdmissionReview.APIVersion	responseAdmissionReview.Kind = requestedAdmissionReview.Kind	if admissionResponse != nil {		responseAdmissionReview.Response = admissionResponse		if requestedAdmissionReview.Request != nil { // 返回相同的 UID			responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID		}	}	klog.Infof("[webhook] 回调api-server, 发送报文: %v",responseAdmissionReview.Response)	// send response	respBytes, err := json.Marshal(responseAdmissionReview)	if err != nil {		klog.Errorf("[webhook] 无法解析回调报文: %v", err)		http.Error(res, fmt.Sprintf("Can't write reponse: %v", err), http.StatusBadRequest)		return	}	klog.Info("[webhook] 准备发送回包")	if _, err := res.Write(respBytes); err != nil {		klog.Errorf("[webhook] 无法发送回调报文: %v", err)		http.Error(res, fmt.Sprintf("Can't write reponse: %v", err), http.StatusBadRequest)	}}

其中**admissionResponse=controller.Validate(&requestedAdmissionReview)**才是具体的拦截逻辑,前面的处理可以独立出来作为一个单独的装饰函数,因为都是用来解析admission review的

func Validate(ar *admissionv1.AdmissionReview) *admissionv1.AdmissionResponse {	req := ar.Request	var (		allowed = true		code    = http.StatusOK		message = ""	)

admission的具体结构可以看之前的文章,之前也有提到,拦截是否允许主要就是看allowed这个字段,之前的需求是判断副本数量,所以需要对admission进行解析

var dep appsv1.Deployment	if err := json.Unmarshal(req.Object.Raw, &dep); err != nil {		klog.Errorf("[webhook] 无法解析AdmissionReview object raw: %v", err)		allowed = false		code = http.StatusBadRequest		return &admissionv1.AdmissionResponse{			Allowed: allowed,			Result: &metav1.Status{				Code:    int32(code),				Message: err.Error(),			},		}	}

因为处理的是deployment, 所以需要对以appsv1.Deployment对结构体进行解析,然后进行判断

// 处理真正的业务逻辑	replicas := *dep.Spec.Replicas	if replicas < 3 {		klog.Infof("[webhook] deployment不满足最低副本数量,无法创建")		allowed = false		code = http.StatusForbidden		message = "need 3 replicas at least, create deployment failed"	}

然后打包成docker镜像,以deployment 部署在kubernetes 集群内,然后进行部署一个service, 用于api-server的调用,之后部署ValidatingWebhookConfiguration

apiVersion: admissionregistration.k8s.io/v1kind: ValidatingWebhookConfigurationmetadata:  name: admission-registrywebhooks:- name: zyx.test.admission-registry  rules:  - apiGroups:   ["apps"]    apiVersions: ["v1"]    operations:  ["CREATE"]    #resources:   ["pods","deployments"]    resources:   ["deployments"]  clientConfig:    service:      namespace: default      name: admission-registry      path: "/v1/api/validate"    caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURuakNDQW9hZ0F3SUJBZ0lVT2RVeWVCenVVcFdIenFvMGczOE5XeE1SNm9jd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1p6RUxNQWtHQTFVRUJoTUNRMDR4RVRBUEJnTlZCQWdUQ0ZOb1lXNW5hR0ZwTVJFd0R3WURWUVFIRXdoVAphR0Z1WjJoaGFURU1NQW9HQTFVRUNoTURhemh6TVE4d0RRWURWUVFMRXdaVGVYTjBaVzB4RXpBUkJnTlZCQU1UCkNtdDFZbVZ5Ym1WMFpYTXdIaGNOTWpFd05USTBNRGMwT1RBd1doY05Nall3TlRJek1EYzBPVEF3V2pCbk1Rc3cKQ1FZRFZRUUdFd0pEVGpFUk1BOEdBMVVFQ0JNSVUyaGhibWRvWVdreEVUQVBCZ05WQkFjVENGTm9ZVzVuYUdGcApNUXd3Q2dZRFZRUUtFd05yT0hNeER6QU5CZ05WQkFzVEJsTjVjM1JsYlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1ClpYUmxjekNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFLTWJLT0Q5WGMzMDhlWlQKK0J2MGYzR3QxTGtzWk1jUXNUUG5rQXpWeVRQSDdFSkpORkVoVzI0UE8yNzgvaTNWcEdPNU12MVZCcW1rcGwrSgorZ1dwZW5TSDNIbTdsOTZmckt4TmRGWG94Y3VLaWNPOHhvVUVxWCt0cVIvR0toUGYrcjBCWXFUR1o1aVVCZGdVCjU0STJIQjREc1Exc0lCY1JBUms5WVJ5ZjRLYXRZVVEzdGRuNFRyNmFhUXg5OE9Gd1hUNXpiNktINVQ2MTNKdk8KUExpV0JNWUxUZG5WZ256ZzVXeDUreDkvV0FtaTJSK0JjTllLUjY0RWgzeWJZam5NeGtGL1JEMTZPSTlFOTJNRApEaVB6U09oemplQ3RIY1NRcStpTllIQzhzSUJlRFlxL256bTFDR0hTL1NpMDdZVFBjZTBXeE5RelRpMlM2dlZXCkdrWGVPaWNDQXdFQUFhTkNNRUF3RGdZRFZSMFBBUUgvQkFRREFnRUdNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHcKSFFZRFZSME9CQllFRlB0S2U2TXFoTjlLaEJ5S3Ntdy9sR3pZd25iL01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQgpBUUFqNnVyVTVhS0I5MWZuQTF2dE1DVjZRVHFmenMrd1dFcHZVbElXOHdZYXVydDZPWUc1YkxFSHoyRUJJRXplCjMvcGM4ZUkvamJSU0JNZDJGbk9Sa0pVTmh5MDBBZE05MTRFUFo5Y0FIOFpGUVI1UTZCUmw1Qnl6Mk5jOHN3dGMKMmtraW0vWUJ4TkFFYnFLQjBhTmw0TW5LbTc3TzgzSXpwREN2SzBWdlRCVXJVYnlzd1l6d0lCaEZxSTl5ZUo2Zgo1U1JpemdrUHVYRG1qSlZiN092dzNTNkxRT1o4VmdJRS9wZGJvRTBsTHpmZ2pROWVDVFM0ZmRXSE9oNGp1TXJMCklqeG1pMHhOVVVkTXdPeFNvQlJKa3J3eU1Fa1FoN2swYmZROFdsRkFNenVST29RVmVraU1BNkhLeDdQOFd1UmUKYzhKRkVOVmk5VEVMTXkwWHpJNWhoOVlwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K  admissionReviewVersions: ["v1"]  sideEffects: None

其中rules 就是对资源的限制条件,path是之前webserver的url, caBundle 是客户端的ca证书,cat **.pem | bare64即可。

个人公众号, 分享一些日常开发,运维工作中的日常以及一些学习感悟,欢迎大家互相学习,交流

在这里插入图片描述

转载地址:https://blog.csdn.net/zyxpaomian/article/details/117443963 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Kubernetes开发(6)-MutatingAdmissionWebhook练手
下一篇:Kubernetes开发(4)-webhook 实现拦截请求

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月12日 16时00分07秒