In Kubernetes, we have multiple environments, separated by different namespace. I want to ensure that one set of nodes are only used by a specific namespace/environment.
What is the way to achieve it? Heard about mutating webhook admission controllers, Anybody has a sample, to see how it works.
You can use mutating webhook to mutate an incoming pod request from a specific namespace to add node affinity or node selector in the pod spec.
An example of nodeSelector
admission controller here. Full guide on how to use it.
Prepare API Server
Assuming your cluster has been deployed with kubeadm, the kube-apiserver.yaml file is the configuration manifest for the Kubernetes API server. It is located in /etc/kubernetes/manifests. Add the PodNodeSelector admission controller in the --admission-control= flag
Then add a label to a node
kubectl label node kubeprod01 env=production
Then use that label in the annotation of the namespace.
apiVersion: v1
kind: Namespace
metadata:
annotations:
scheduler.alpha.kubernetes.io/node-selector: env=production
An example of adding node affinity via mutating webhook.
func mutatePods(ar v1beta1.AdmissionReview, o *options) *v1beta1.AdmissionResponse {
var reviewResponse = &v1beta1.AdmissionResponse{
Allowed: true,
}
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
if ar.Request.Resource != podResource {
glog.Errorf("expect resource to be %s", podResource)
return nil
}
raw := ar.Request.Object.Raw
pod := v1.Pod{}
// glog.V(2).Infof("Object: %v", string(raw))
if err := json.Unmarshal(raw, &pod); err != nil {
glog.Error(err)
return nil
}
addPodAffinityPatch := fmt.Sprintf(`[
{"op":"add","path":"/spec/affinity","value":{"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"preference":{"matchExpressions":[{"key":"%s","operator":"NotIn","values":["%s"]}]},"weight":1}]}}}
]`, o.PodAffinityKey, o.PodAffinityValue)
glog.V(2).Infof("patching pod")
reviewResponse.Patch = []byte(addPodAffinityPatch)
pt := v1beta1.PatchTypeJSONPatch
reviewResponse.PatchType = &pt
return reviewResponse
}
It can be done via node-selector annotation in the namespace, see an example here