Organizing a cluster
As you can imagine, there may be a lot of resources inside a cluster. In fact, at the moment of writing this Kubernetes supports over 100 000 pods in a single cluster.
Namespaces are used to keep resources separated. A company which uses 1 cluster but has multiple projects can use namespaces to split the cluster into virtual clusters, one for each project. Most commonly they would be used to separate environments such as production, testing, staging. DNS entry for services includes the namespace so you can still have projects communicate with each other if needed through service.namespace address. e.g if the example-service from a previous section was in a namespace "ns-test" it could be found from other namespaces via "http://example-service.ns-test".
Accessing namespaces with kubectl is achieved by using the
-n flag. For example, you can see what the namespace kube-system has with
$ kubectl get pods -n kube-system
To see everything you can use
$ kubectl get all --all-namespaces
Namespaces should be kept separate - you could run all of the examples and do the exercises of this course in a cluster that is shared with critical software. An administrator should set a ResourceQuota for that namespace so that you can safely run anything there. We'll look into resource limits and requests later.
Defining a namespace is a oneliner, but requires the namespace not to exist already (
kubectl create namespace example-namespace):
... metadata: namespace: example-namespace name: example ...
If you're using a namespace constantly, you can set the namespace to be used by default with
kubectl config set-context --current --namespace=<name>.
Kubernetes Best Practices - Organizing Kubernetes with Namespaces
Labels are used to separate an application from others inside a namespace and to group different resources together. Labels are key-value pairs and they can be modified, added or removed at any time. Labels are identifying and you can query resources that have a certain label.
Let's look at the labels in Deployment yamls. This is the first yaml we created:
apiVersion: apps/v1 kind: Deployment metadata: name: hashgenerator-dep spec: replicas: 1 selector: matchLabels: app: hashgenerator template: metadata: labels: app: hashgenerator spec: containers: - name: hashgenerator image: jakousa/dwk-app1:78031863af07c4c4cc3c96d07af68e8ce6e3afba
The selector and matchLabels reveal that the instructions of the deployment are directed to pods with the following label. matchLabels is a key-value pair but we could've used matchExpressions instead. While the template metadata includes a label with key-value pair app and hashgenerator. We can use the same label on multiple namespaces and the namespace would keep them from interfering with each other.
Grouping is simple. Either add the label into the file or if you've already deployed the hashgenerator above add the label and you can query with
$ kubectl label po hashgenerator-dep-7b9b88f8bf-lvcv4 examplelabel=smart pod/hashgenerator-dep-7b9b88f8bf-lvcv4 labeled $ kubectl get po -l examplelabel=smart NAME READY STATUS RESTARTS AGE hashgenerator-dep-7b9b88f8bf-lvcv4 1/1 Running 0 17m
With labels we can even move pods to labeled nodes. Let's say we have a few nodes which have qualities that we wish to avoid. For example they might have a slower network. With labels and nodeSelector configured to deployment we can do just that. First add nodeSelector to the deployment and then label the node(s):
... spec: containers: - name: hashgenerator image: jakousa/dwk-app1:78031863af07c4c4cc3c96d07af68e8ce6e3afba nodeSelector: networkquality: excellent
If you already had it running, it won't move the pod to avoid unwanted changes in the system. We'll delete the pod so that Kubernetes will move the new version to the correct node.
$ kubectl delete po hashgenerator-dep-7b9b88f8bf-tnvfg pod "hashgenerator-dep-7b9b88f8bf-tnvfg" deleted $ kubectl get po NAME READY STATUS RESTARTS AGE hashgenerator-dep-7b9b88f8bf-lvcv4 0/1 Pending 0 4s
Now the status is "Pending" as there are no nodes with an excellent network quality. Next, label the agent-1 as being one with excellent network quality and Kubernetes will know where the pod is able to run .
$ kubectl label nodes k3d-k3s-default-agent-1 networkquality=excellent node/k3d-k3s-default-agent-1 labeled $ kubectl get po NAME READY STATUS RESTARTS AGE hashgenerator-dep-7b9b88f8bf-lvcv4 1/1 Running 0 5m30s
nodeSelector is a blunt tool. Let's say you have a cluster of various machines, ranging from a fighter jet to a toaster to a supercomputer. Kubernetes can use affinity and anti-affinity to select which nodes are prioritized for which applications and taints with tolerances so that a pod can avoid certain nodes. For example, if a machine has a high network latency and we wouldn't want it to do some latency critical tasks.