Understanding Kubernetes Pods and Containers
Here in this article we will demonstrate the usage Pods which are the most basic deployable units in Kubernetes Cluster. We will also look at and understand about the containers that are encapsulated within a pod and the types of containers that can be launched based on the use case.
Test Environment
Fedora 36 server
Kubernetes Cluster v1.22.5
What are Pods
Pods are the very basic deployable units that we can create in kubernetes cluster. Pods encapsulate and run one or more containers. There is a host process associated with each container that is running within a Pod. Pod is just a logical unit like a wrapper around those containers. These containers share the storage and network resouces. Pod is similar to set of containers with shared namespaces and shared filesystem volumes.
App Containers – Pods with single container
Step1: Run and Describe a nginx pod
As a first step let’s create an instance of nginx image as shown below.
[admin@kubemaster kubernetes]$ kubectl run nginx-inst1 --image=nginx
pod/nginx-inst1 created
Now that our nginx instance is created let us try to get some details about the instance using the below command.
[admin@kubemaster kubernetes]$ kubectl describe pod nginx-inst1
Name: nginx-inst1
Namespace: default
Priority: 0
Service Account: default
Node: kubenode/192.168.122.49
Start Time: Sat, 08 Oct 2022 19:35:51 +0530
Labels: run=nginx-inst1
Annotations: <none>
Status: Running
IP: 10.0.1.5
IPs:
IP: 10.0.1.5
Containers:
nginx-inst1:
Container ID: cri-o://a821354dcdb232c943c2c266ee26f6485cc9ba6c8ef16407859c440cc49b37ce
Image: nginx
Image ID: docker.io/library/nginx@sha256:2f770d2fe27bc85f68fd7fe6a63900ef7076bc703022fe81b980377fe3d27b70
Port: <none>
Host Port: <none>
State: Running
Started: Sat, 08 Oct 2022 19:36:25 +0530
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8pxl6 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-8pxl6:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 77s default-scheduler Successfully assigned default/nginx-inst1 to kubenode
Normal Pulling 76s kubelet Pulling image "nginx"
Normal Pulled 43s kubelet Successfully pulled image "nginx" in 33.527070421s
Normal Created 43s kubelet Created container nginx-inst1
Normal Started 43s kubelet Started container nginx-inst1
The above output provides us with most of the details about the pod. But if you want to get detailed information in either yaml or json format we can use the below commands.
[admin@kubemaster kubernetes]$ kubectl get pod nginx-inst1 -o yaml
[admin@kubemaster kubernetes]$ kubectl get pod nginx-inst1 -o json
Step2: Execute into Pod Containers
From the above nginx pod that we just created we can see that its a single container pod as there is only one continer named nginx within the pod.
As per the below command we are trying to get a interactive bash shell from the running nginx container.
[admin@kubemaster kubernetes]$ kubectl exec -it nginx-inst1 -- bash
root@nginx-inst1:/#
Let us try to check some details about the Pod
Hostname
The hostname of the nginx container is same as the name of the pod.
root@nginx-inst1:/# hostname
nginx-inst1
IP Address
The IP address can be captured from the /etc/hosts file as shown below. This IP address will be allocated based on the POD CIDR range that we provide during the kubernetes cluster initialization.
root@nginx-inst1:/# cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.0.1.5 nginx-inst1
By default the Pod uses a default serviceaccount. serviceaccounts are system id that are used by pods to communicate with the API server.
Here is the secret token for our default serviceaccount that the nginx pod is using.
root@nginx-inst1:/# cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6IjFOckw3anZrY1FLM1BOWGdpV2dvVzF0dzNPWjZmSS1WUmlYUnFoWkhHSTAifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjk2NzczOTUxLCJpYXQiOjE2NjUyMzc5NTEsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueC1pbnN0MSIsInVpZCI6ImFiOTEyMjgxLTMxYmItNGU2MS1hMGFjLTcwOTQyMTBmZTRhZSJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjU4MmQzNzIwLTY1ZDAtNGIwOC04ZjE2LWIyMTJhODg4MDY0ZiJ9LCJ3YXJuYWZ0ZXIiOjE2NjUyNDE1NTh9LCJuYmYiOjE2NjUyMzc5NTEsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.X9cLOh2Vu44rYzdeERYlj5SEQG0KLfS0g03r4tZ7RezWDJOtZboUmrnIQ9jbjjQqLouVXL5Imt-5oVSp1wxBCdfPQKiOoCZmHUsqVnhsHicRnliyKzhsm8kTea1fGo2McP0VNQFDgmcHd7-Bm-l5HwSsVrbyqXHYIsDn1Fi94y0f5h5OMLQ4-v55geoCrKQgg0K9kZdlnJPu1pAlbj-osa4OBMWLiECHbVtv_ueYpPdlScEmx4QggA9V3e_KEfqOwaFSoAX3ER7WJW1oJO2lFmfq2U-TLPTQXNdEr93vELsqG669gdGihmjqq5G0eYy9zB_TnU-UPY6LcLDxCJRH5A
Step3: Replicate Pod
Here we will try to create another instance of the nginx pod to scale the nginx instance horizontally.
[admin@kubemaster kubernetes]$ kubectl run nginx-inst2 --image=nginx
pod/nginx-inst2 created
Now let’s try to get the details of the IP address that is allocated and the node on which these two pods are scheduled as shown below.
[admin@kubemaster kubernetes]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-inst1 1/1 Running 0 4m10s 10.0.1.5 kubenode <none> <none>
nginx-inst2 1/1 Running 0 18s 10.0.1.172 kubenode <none> <none>
As you can see the pods are allocated with an IP address from the subnet “10.0.1.x”.
Pods natively provide two kinds of shared resources for their constituent containers: networking and storage.
Step4: Termination of Pod
By default when a pod deletion request is submitted to API server, kubelet tries to grace-fully shutdown the container process with pid 1 in the pod with a default grace period of 30 sec after which kubelet triggers the forcible shutdown with SIGKILL signal.
[admin@kubemaster kubernetes]$ kubectl delete pod nginx-inst1 # This termination of pod tries a grace full shutdown of the container process
If we want to forcibally terminate the pod we can pass grace period with 0 sec and –force flags as shown below.
[admin@kubemaster kubernetes]$ kubectl delete pod nginx-inst2 --force --grace-period=0
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "nginx-inst2" force deleted
Init Containers – Pods with multiple containers
A Pod can have multiple containers running apps within it but Init Containers are a specialized type of containers that are executed before any App Containers are started. The Init Containers need to be executed successfully to their completion state in the order they are defined.
Init containers do not support lifecycle, livenessProbe, readinessProbe, or startupProbe because they must run to completion before the Pod can be ready. Init containers can run with a different view of the filesystem than app containers in the same Pod. Consequently, they can be given access to Secrets that app containers cannot access. Init containers can securely run utilities or custom code that would otherwise make an app container image less secure. By keeping unnecessary tools separate you can limit the attack surface of your app container image.
Step1: Create a Pod with Init Container
Here is a very basic init container demo in which we have one init container which will loop through a count of 100. Once this loops completes the init container should get into completion state and the app container should be initiated and get into running state.
[admin@kubemaster workloads]$ cat initcontainerapp.yml
apiVersion: v1
kind: Pod
metadata:
name: initcontainer-demo
labels:
app.kubernetes.io/name: initcontainer-demo
spec:
containers:
- name: myapp
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "for i in `seq 1 100`; do echo $i; sleep 1; done"]
Let’s apply this yaml definition file as shown below.
[admin@kubemaster workloads]$ kubectl apply -f initcontainerapp.yml
pod/initcontainer-demo created
Now if we check the pod status it is still not in running state as the init container is still running in the pod.
[admin@kubemaster workloads]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
initcontainer-demo 0/1 Init:0/1 0 30s
We can check the logs of the init-myservice container as shown below. Once this init-myservice container count reaches to 100, the init-myservices container execution completes.
[admin@kubemaster workloads]$ kubectl logs initcontainer-demo -c init-myservice
1
2
3
4
...
100
As shown below the pod is now in running state means the app container is initiated and in running state now.
[admin@kubemaster workloads]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
initcontainer-demo 1/1 Running 0 104s
We can check the status of each container using the kubectl describe command as shown below.
[admin@kubemaster workloads]$ kubectl describe pod initcontainer-demo
Name: initcontainer-demo
Namespace: default
Priority: 0
Service Account: default
Node: kubenode/192.168.122.49
Start Time: Sat, 08 Oct 2022 20:34:26 +0530
Labels: app.kubernetes.io/name=initcontainer-demo
Annotations: <none>
Status: Running
IP: 10.0.1.123
IPs:
IP: 10.0.1.123
Init Containers:
init-myservice:
Container ID: cri-o://089101d6704582c964447b7ea62d587214ceaa5ed2518b3bf551d68ff00f7e00
Image: busybox:1.28
Image ID: docker.io/library/busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Port: <none>
Host Port: <none>
Command:
sh
-c
for i in `seq 1 100`; do echo $i; sleep 1; done
State: Terminated
Reason: Completed
Exit Code: 0
Started: Sat, 08 Oct 2022 20:34:27 +0530
Finished: Sat, 08 Oct 2022 20:36:07 +0530
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vbsx4 (ro)
Containers:
myapp:
Container ID: cri-o://8097eebf3c608dab378e5dd3cb6f68117b3993e9d1fdb853e49c48c94d3f0a24
Image: busybox:1.28
Image ID: docker.io/library/busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Port: <none>
Host Port: <none>
Command:
sh
-c
echo The app is running! && sleep 3600
State: Running
Started: Sat, 08 Oct 2022 20:36:08 +0530
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vbsx4 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-vbsx4:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m2s default-scheduler Successfully assigned default/initcontainer-demo to kubenode
Normal Pulled 4m2s kubelet Container image "busybox:1.28" already present on machine
Normal Created 4m2s kubelet Created container init-myservice
Normal Started 4m2s kubelet Started container init-myservice
Normal Pulled 2m21s kubelet Container image "busybox:1.28" already present on machine
Normal Created 2m21s kubelet Created container myapp
Normal Started 2m21s kubelet Started container myapp
Ephemeral Containers – Pods with Debugging Containers
Pods are the basic deployable units which can only be disposed and replaced with a new Pod. We cannot add a new container to an already existing Pod. In order to debug a faulty container in a Pod we need to deploy a ephemeral container with some utility tools which can help us to debug a faulty container in a pod.
Ephemeral containers are created using a special ephemeral containers handler in the API rather than by adding them directly to pod.spec, so it’s not possible to add an ephemeral container using kubectl edit.
Ephemeral containers are useful for interactive troubleshooting when kubectl exec is insufficient because a container has crashed or a container image doesn’t include debugging utilities.
Distroless images are a kind of minimal container images which are built with a reduced attack surface and exposure to bugs and vulnerabilities.
Let’s try to create a pod with a distroless image which does not contain the required utilities to debug the container.
[admin@kubemaster workloads]$ kubectl run ephemeral-demo --image=registry.k8s.io/pause:3.1 --restart=Never
[admin@kubemaster workloads]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ephemeral-demo 1/1 Running 0 14s
Now if we try to get shell into the ephemeral-demo pod we will get an error as the shell utilities are not available in this distroless image.
[admin@kubemaster workloads]$ kubectl exec -it ephemeral-demo -- sh
ERRO[0000] exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
command terminated with exit code 255
Now in order get a view of the ephemeral pod container we will use kubectl debug to instantiate a debugging container and attach it to the pod ephemeral-demo as shown below.
[admin@kubemaster workloads]$ kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
Targeting container "ephemeral-demo". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-cqtwt.
If you don't see a command prompt, try pressing enter.
/ #
This command adds a new busybox container and attaches to it. The –target parameter targets the process namespace of another container. Please note that there are other methods to carry out debugging of the pod containers as mentioned in the Documentation – https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container.
Hope you enjoyed reading this article. Thank you..
Leave a Reply
You must be logged in to post a comment.