1. 背景

k8s中在创建资源前需要校验,修改pod的一些属性,优雅的像java的拦截器,过滤器一样工作,需要加准入控制。概念去官网搜,不占用篇幅。本文主要讲例子,学技术还是脚踏实地作出demo。

2. 资料

本文参考github上demo,可以自己找些例子,我主要讲解:GitHub - stackrox/admission-controller-webhook-demo: Kubernetes admission controller webhook example

3. 项目讲解

项目结构还是很简单

3.1 main.go

cmd/webhook-server/main.go

前两行是密钥对路径。

下面创建server,路径是mutate,端口是8443,加载密钥对。

处理函数是admitFuncHandler参数是applySecurityDefaults这也是个函数,真正的处理在applySecurityDefaults逻辑写在这里,其他都是框架。

看下函数实现

func applySecurityDefaults(req *admission.AdmissionRequest) ([]patchOperation, error) {
	// This handler should only get called on Pod objects as per the MutatingWebhookConfiguration in the YAML file.
	// However, if (for whatever reason) this gets invoked on an object of a different kind, issue a log message but
	// let the object request pass through otherwise.
	if req.Resource != podResource {
		log.Printf("expect resource to be %s", podResource)
		return nil, nil
	}

	// Parse the Pod object.
	raw := req.Object.Raw
	pod := corev1.Pod{}
	if _, _, err := universalDeserializer.Decode(raw, nil, &pod); err != nil {
		return nil, fmt.Errorf("could not deserialize pod object: %v", err)
	}

	// Retrieve the `runAsNonRoot` and `runAsUser` values.
	var runAsNonRoot *bool
	var runAsUser *int64
	if pod.Spec.SecurityContext != nil {
		runAsNonRoot = pod.Spec.SecurityContext.RunAsNonRoot
		runAsUser = pod.Spec.SecurityContext.RunAsUser
	}

	// Create patch operations to apply sensible defaults, if those options are not set explicitly.
	var patches []patchOperation
	if runAsNonRoot == nil {
		patches = append(patches, patchOperation{
			Op:   "add",
			Path: "/spec/securityContext/runAsNonRoot",
			// The value must not be true if runAsUser is set to 0, as otherwise we would create a conflicting
			// configuration ourselves.
			Value: runAsUser == nil || *runAsUser != 0,
		})

		if runAsUser == nil {
			patches = append(patches, patchOperation{
				Op:    "add",
				Path:  "/spec/securityContext/runAsUser",
				Value: 1234,
			})
		}
	} else if *runAsNonRoot == true && (runAsUser != nil && *runAsUser == 0) {
		// Make sure that the settings are not contradictory, and fail the object creation if they are.
		return nil, errors.New("runAsNonRoot specified, but runAsUser set to 0 (the root user)")
	}

	return patches, nil
}

主要业务就是判断pod里面的属性,配置的RunAsNonRoot以及RunAsUser,具体是啥可以不用了解。只要知道这个函数加自己的处理逻辑就好,拿到请求序列化的数据,反序列化成pod对象。然后判断pod里面的属性即可。

里面涉及了创建patches

自己去发现这个path路径的规则。

如果是其他属性自己拼写,假如是容器里面的,就应该是/spec/containers/xxx。这里只是拿pod属性举例,如果是deployment或其他资源,自己加路径,/spec/template/spec/xxx

3.2 deploy.sh

调用generate-keys.sh生成密钥对。

创建webhook-demo命名空间。

根据密钥对创建secret,启动webhook的时候挂载进去。

再看一下deployment.yaml.template

这里会被sed把密钥替换进去。

最终效果

部署好了之后

查询部署的admission的pod log

自己修改代码加一些log,但是要记住,Makefile构建出自己的镜像。

我其实把IMAGE镜像名字换了。可以换成自己的,上面截图没有替换,需要自己换一下。然后在deployment中改一下image

换成自己的。

work了。

 说明已经生效了。看看创建的pod,效果。

例子中给了

其实如果你想控制其他的资源,配置这里。例如deploy,sts,vcjob

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐