KIA CH03 Pods: running containers in Kubernetes
Ch 3 notes for Kubernetes in Action. Learn pod lifecycle basics (create, run, stop), resource organization via labels and namespaces, executing bulk operations on labeled pods, and scheduling workloads onto specific types of cluster worker nodes.
Hi there.
Today, let us read Chapter 03: Pods - running containers in Kubernetes (Part II: Core Concepts) of Kubernetes in Action.
- Creating, running, and stopping pods
- Organizing pods and other resources with labels
- Performing an operation on all pods with a specific label
- Using namespaces to split pods into non-overlapping groups
- Scheduling pods onto specific types of worker nodes
a pod is a co-located group of containers and represents the basic building block in Kubernetes.
- a pod may include one or more containers
- multiple containers in a pod must remain in the SAME worker node; a pod never spans multiple worker nodes.
Running each process in its own container (multiple containers) is better than combining processes in one container.
- (easy recovery) only restart the crashed process rather than all processes
- (easy management) logs are only kept for the single process in each container
A pod allows you to run closely related processes together, and provide them with almost the same environment (as if they were all running in a single container) while keeping them partially isolated.
-
the partial isolation among containers inside the same pod.
- all containers of same pod share the same set of Linux namespaces
-
containers in the same pod share the same IP and Port space
- containers in same pod run in the same Network namespace; containers in different pods run in different Network namespaces
- containers in same pod may NOT to bind to the same port numbers, to avoid port conflicts
-
the flat inter-pod network
- All pods (in a Kubernetes cluster) reside in a single flat, shared, network-address space; every pod can access other pod by the IP address of the target pod.
- achieved through a SDN layer on top of like computers on a LAN
- no NAT gateways exist
- Regardless of which worker nodes the pods are scheduled
- All pods (in a Kubernetes cluster) reside in a single flat, shared, network-address space; every pod can access other pod by the IP address of the target pod.
-
for tightly related components or processes that must work as a single whole, organize them into the same pod
- E.g., a main process and other complementary processes
-
for multi-tier app that can run on different hosts, organize apps into multiple pods
- different pods, deployed on different worker nodes, can run on different worker nodes, thereby improving the utilization of computational resources.
- E.g., a multi-tier application, with a frontend server and a backend database, should be configured as different pods so that they can be deployed on different worker nodes.
- different pods, deployed on different worker nodes, can run on different worker nodes, thereby improving the utilization of computational resources.
-
for individual scaling of independent components that have different scaling requirements, organize apps into multiple pods.
- A pod is the basic unit of scaling.
To create pods (and other Kubernetes resources), post a JSON or YAML manifest to Kubernetes REST API endpoint.
Use “kubectl get pods” with flag -o yaml to get the whole YAML definition of the pod.
kubectl get pods kubia-zxzij -o yaml- Metadata: name, namespace, labels, etc.
- Spec: actual description of the pod’s contents, e.g., containers, volumes, etc.
- Status: current information about the running pod, e.g., condition the pod, description and status of each container, internal IP, etc.
Note: status is not required during creating a new pod.
Kubernetes reference documentation and “kubectl explain” command list possible fields in a manifest.
apiVersion: v1kind: Podmetadata: name: kubia-manualspec: containers: - image: ${yourDockerRegistryID}/kubia name: kubia ports: - containerPort: 8080 protocol: TCPNote: use two spaces, NOT tab.
We need to explicitly defining ports in YAML file:
- let others know which ports your cluster is exposing
- assign a name to each port
Use “kubectl create” with flag -f to create pod from YAML/JSON file.
kubectl create -f kubia-manual.yamlUse “kubectl get” to get full info about the pod, in the format of YAML/JSON:
kubectl get pods kubia-manual -o YAMLkubectl get pods kubia-manual -o JSONIn container runtime, i.e., Docker, use “docker logs” to redirect stdout and stderr streams to files
docker logs ${ContainerID}use “kubectl logs” to get logs of all containers or of the specific container of the pod:
# get all logs in pod `kubia-manual`kubectl logs kubia-manual
# get logs only in container `kubia` of pod `kubia-manual`kubectl logs kubia-manual -c kubiaUse “kubectl port-forward” command to forward a local network port to a port in the pod.
kubectl port-forward kubia-manual 8888:8080Node: Port forwarding is a convenient way of testing single pod.
- “
kubectl port-forward” command forwards local port8888to port8080in pod - use “
curl localhost:8888” command to access the service in pod.
Background: When running multiple microservices, pods structure can be complicated:
- multiple pods
- multiple replicas of each pod
- different releases of the same microservice
Kubernetes uses labels to organize all sorts of Kubernetes resources: pods and other objects.
A label is an arbitrary key-value pair attached to a resource, which is then utilized when selecting resources using label selectors.
A resource can have more than one (unique) labels.
A typical practice for labelling:
| app=warehouse | app=product | app=order | |
|---|---|---|---|
| rel=stable | _ | _ | _ |
| rel=beta | _ | _ | _ |
| rel=canary | _ | _ | * |
- label app: which app, component, or microservice the pod belongs to
- label rel: which release the pod is - E.g., stable, beta, and canary (only a small fraction of user hit the new version, before rolling new version out to all users)
Add “labels” to YAML to add labels to the pod
apiVersion: v1kind: Podmetadata: name: kubia-manual-v2 # add labels to the pod labels: creation_method: manual env: prodspec: containers: - image: ${yourDockerRegistryID}/kubia name: kubia ports: - containerPort: 8080 protocol: TCPNote: this YAML added two labels
- creation_method
- env
To create pods, run with “kubectl create”
kubectl create -f kubia-manual-with-labels.yamlUse “kubectl get” to show labels:
kubectl get pods --show-labels: show all labelskubectl get pods -L creation_method,env: only show labels namedcreation_methodandenv
To add a new label to existing pod, use “kubectl label”
kubectl label pods kubia-manual-v2 creation_date_format=yyyyMMddkubectl label pods kubia-manual-v2 creator=adminTo overwrite an existing label of the pod, use “kubectl label” with flag “--overwrite”
kubectl label po kubia-manual-v2 env=debug --overwriteUse label selectors to filter resources:
- does/doesn’t contain a label and a certain key
- contains a label with a certain key and value
- contains a label with a certain key, but with different value from your specification
Use “kubectl get pods” with flag -l to filter pods:
- chooses pods with label
env
kubectl get pods -l 'env'- choose pods without label
env
kubectl get pods -l '!env'- choose pods whose label
envisprod
kubectl get pods -l 'env=prod'- choose pods whose label
envis notdev
kubectl get pods -l 'env!=dev'- choose pods whose label
envisdev,test, ordebug
kubectl get pods -l env in '(dev, test, debug)'- choose pods whose label
envis neitherdevnordebug
kubectl get pods -l env notin '(dev, test, debug)'use “kubectl get pods -l” with comma to separate multiple conditions
kubectl get pods -l 'env notin (prod, dev)','creation_method=manual'Generally(homogenous hardware infrastructure), we would NOT care about which worker node a pod is scheduled to, when each pod gets the exact amount of computational resources, because we want to decouple applications from infrastructure.
However, when hardware infrastructure is NOT homogenous, e.g., some nodes with GPU-specialized hardware or high-speed SSDs, we want to schedule certain pods to one group of worker nodes.
Kubernetes uses node labels and node label selectors to select a node that matches those requirements.
Use “kubectl label” to specify the type of hardware the node provides, for later scheduling pods:
# 1) mark the node `kind-worker2`, with label `ssd` is `true`kubectl label nodes kind-worker2 ssd=true
# 2) mark the node `kind-worker3`, with labels both `ssd` and `gpu` are `true`kubectl label nodes kind-worker3 ssd=truekubectl label nodes kind-worker3 gpu=trueUse “kubectl get nodes” with flag -l (lowercase) to filter nodes:
# choose the node with both `ssd` and `gpu` are `true`# which, will turn out to be the node named `kind-worker3`kubectl get nodes -l ssd=true,gpu=trueUse “kubectl get nodes” with flag -L (uppercase) to list labels in table columns:
| NAME | STATUS | ROLES | AGE | VERSION | SSD | GPU |
|---|---|---|---|---|---|---|
| kind-control-plane | Ready | control-plane | 5h40m | v1.29.2 | ||
| kind-worker | Ready | <none> | 5h40m | v1.29.2 | ||
| kind-worker2 | Ready | <none> | 5h40m | v1.29.2 | true | |
| kind-worker3 | Ready | <none> | 5h40m | v1.29.2 | true | true |
In the “spec” section, add a “nodeSelector” field to let scheduler choose only among the worker nodes that contain the label with a specific value.
apiVersion: v1kind: Podmetadata: name: kubia-gpuspec: nodeSelector: gpu: "true" containers: - image: ${yourDockerRegistryID}/kubia name: kubiaIn this case, the pod kubia-gpu will only be scheduled to the nodes whose label gpu is true, i.e., kind-worker3 - This statement can be verified by command “kubectl get pods” with flag -o wide:
kubectl get pods -o wide# result:# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES# kubia-gpu 1/1 Running 0 93s 10.244.3.7 kind-worker3 <none> <none>Now we can see the pod kubia-gpu is scheduled to kind-worker3.
- use “
kubectl get nodes” command with flag-L "kubernetes.io/hostname"to list all posts with label “kubernetes.io/hostname”:
kubectl get nodes -L "kubernetes.io/hostname"# NAME STATUS ROLES AGE VERSION HOSTNAME# kind-control-plane Ready control-plane 17h v1.29.2 kind-control-plane# kind-worker Ready <none> 17h v1.29.2 kind-worker# kind-worker2 Ready <none> 17h v1.29.2 kind-worker2# kind-worker3 Ready <none> 17h v1.29.2 kind-worker3- write a new YAML file to designate the target node
Note: This is not recommended: the pod may become unschedulable if the node is offline.
apiVersion: v1kind: Podmetadata: name: kubia-specific-worker2spec: nodeSelector: kubernetes.io/hostname: 'kind-worker2' containers: - image: ${yourDockerRegistryID}/kubia name: kubia- create pod with “
kubectl create” command, and verify its info
kubectl create -f kubia-specific-node.yamlkubectl get pods -o wide# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES# kubia-specific-worker2 1/1 Running 0 9m42s 10.244.2.4 kind-worker2 <none> <none>Annotations adds description to each pod or other API object, making collaboration on the cluster easier.
| selection | grouping objects | info size | |
|---|---|---|---|
| labels | by label selectors | true | small |
| annotations | cannot be selected | false | large blobs ofg data, up to 256KB |
Use “kubectl describe” or “kubectl get” with flag -o yaml look up annotations:
kubectl describe pods ${podName}kubectl get pod ${podName} -o yamlUse “kubectl annotate” to add/modify an annotation:
kubectl annotate pod ${podName} ${yourPrefix}/${keyName}="${value}"
# to verify the annotation, use `kubectl describe` commandkubectl describe pod ${podName}Kubernetes utilizes namespaces to divide objects into distinct and non-overlapping groups, particularly when multiple objects possess identical labels.
Kubernetes uses namespaces to split complex systems with numerous components into smaller distinct groups, each containing the same unique resource name.
- multi-tenant environments
- different development stages - production - development - QA environment And by keeping resources in separate namespaces:
- isolating resource
- keeps everything organized
- prevents inadvertently deleting others’ resources.
- access control: allowing only certain users access to particular resources
- quota limiting: limiting the amount of computational resources available to individual users
NOTE: Some resources cannot be namespaced, like Worker Nodes, are thus global.
Use “kubectl get namespaces” to list all namespaces in the cluster
kubectl get namespaceskubectl get nsUse “kubectl get pods” with flag --namespace to list pods with a specific namespace
kubectl get pods --namespace ${namespaceName}kubectl get pods -n ${namespaceName}There are two ways of creating a namespace:
-
Use “
kubectl create namespace” command to create a custom namespaceTerminal window kubectl create namespace ${namespaceName} -
Use “
kubectl create” with flag-fto create namespace from YAML file:Terminal window kubectl create -f custom-namespace.yamlAnd the content of
custom-namespace.yamlis shown below:custom-namespace.yaml apiVersion: v1kind: Namespacemetadata:name: custom-namespace
NOTE: namespace names could contain: letters, digits, and dashes; namespace names cannot contain: dots.
Use “kubectl create” with flag -n to assign the namespace at creation:
# 1)kubectl create -f kubia-manual.yaml --namespace custom-namespace
# 2)kubectl create -f kubia-manual.yaml --namespace custom-namespaceUse “kubectl config” to switch namespaces:
kubectl config set-context $(kubectl config current-context) --namespace ${newNamespaceName}best practice: create an alias for quickly changing namespaces
alias kcd='kubectl config set-context $(kubectl config current-context) --namespace '
# use `kcd` to quickly change namespaces to `custom-namespace`kcd custom-namespaceNamespaces only logically isolates objects into distinct groups, and do NOT prevent inter-namespace network communication, such as sending HTTP request traffic via the IP address of a pod in another namespace.
Use “kubectl delete” to delete any number of pods by name:
kubectl delete pods kubia-gpu kubia-manual-v2Kubernetes sends “SIGTERM” requests to all pods in the list, i.e., kubia-gpu and kubia-manual-v2 , waiting for them to shut down gracefully.
Use “kubectl delete pods” with flag -l to delete pods by label selector
kubectl delete pods -l rel=canaryThis will delete all pods in current namespace, with label rel is canary
Use “kubectl delete namespace” to delete the whole namespace along with all pods inside it.
kubectl delete namespace custom-namespaceThis command will delete all pods inside namespace custom-namespace
Simply using “kubectl delete pods” with flag --all will not absolutely delete all pods as expected, because the Kubernetes will restart some pods; certain resources are preserved and need to be deleted explicitly, for example, a deployments.app will automatically create a new pod in the current namespace:
# 1) create deployments.appkubectl create deployment kubia --image=${yourDockerRegistryID}/kubia --port=8080# deployment.apps/kubia created
# 2) get all pods in current namespacekubectl get pods# NAME READY STATUS RESTARTS AGE# kubia-87dff5498-mhkzs 1/1 Running 0 4s
# 3) delete all pods in the current namespacekubectl delete pods --all# pod "kubia-87dff5498-mhkzs" deleted
# 4) check if all pods are deletedkubectl get pods# NAME READY STATUS RESTARTS AGE# kubia-87dff5498-c5btd 1/1 Running 0 35sAnd this test shows that, after deleting the pod kubia-87dff5498-mhkzs, the deployment.app automatically creates a new pod named kubia-87dff5498-c5btd.
Use “kubectl delete all” with flag --all to delete all resource instances, such as: deployments.app, services, pods, etc.
kubectl delete all --all# pod "kubia-87dff5498-c5btd" deleted# service "kubernetes" deleted# deployment.apps "kubia" deleted# replicaset.apps "kubia-87dff5498" deletedNOTE: the service “kubernetes” will be recreated automatically later.
This chapter talks about pods:
- in a pod, whether certain containers should be grouped together or not
- pods can run multiple processes, just as host computer does
- YAML and JSON are used to create and describe pods
- Labels together with label selectors make organizing and scheduling pods easier
- Node label and label selector can schedule pods only to the specific nodes; however, if the nodes were offline, the pods would be unschedulable.
- Annotations attach larger blob of data (than labels) to the pods, by people, or tool and library
- Namespaces allow different teams to use the same cluster as though they were using separate Kubernetes clusters.
- “
kubectl explain” command is used to quickly look up info on any Kubernetes resources
| Original | Abbreviation |
|---|---|
| pods | po |
| replication controller(deprecated) | rc |
| services | svc |
| namespaces | ns |
best practice about alias in Linux terminal:
# use `k` instead of `kubectl`alias k=kubectl
# use `kcd` to quickly change current namespace, e.g., `kcd default`alias kcd='kubectl config set-context $(kubectl config current-context) --namespace '