Dedicated nodes for Namespace

4/24/2020

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.

  1. Nodes of specific labels should reject all pods, which doesn't belong to a namespace
  2. Pods from a specific namespace should always choose nodes with the labels configured.

What is the way to achieve it? Heard about mutating webhook admission controllers, Anybody has a sample, to see how it works.

-- Ysak
kubernetes
mutating-webhook

2 Answers

4/24/2020

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
}
-- Arghya Sadhu
Source: StackOverflow

4/24/2020

It can be done via node-selector annotation in the namespace, see an example here

-- Anton Matsiuk
Source: StackOverflow