What is a Pod?
A pod is the smallest object that can be created in Kubernetes. It consists of one or more containers that are tightly coupled and is the central object type on top of which others build their functionalities. Containers in a pod are created, managed, and destroyed together. Containers in the same pod share the same resources such as storage, network, namespace, among others and can easily communicate with one another on localhost. A container in one pod can communicate with a container in another pod using the pod IP address.
The Lifecycle of a Pod
The Pod lifecycle has five possible phases. The Pod phase is the high-level summary of the current state of the Pod within its lifecycle. Below are the five Pod phases and their description
- Pending: The Kubernetes system has accepted the pod but the creation of the container image(s) and/or pulling of the container image(s) from a repository is still in progress. This state includes the period when the node on which the pod will be run or scheduled is checked.
- Running: The state changes to running after the pod has been scheduled on a node and the container(s) has been created and also in a running state or is in the process of starting.
- Succeeded: The container(s) in the pod has terminated successfully with exit code 0 and will not restart.
- Failed: The container(s) in the pod terminated in failure with non zero exit code or it was terminated by the system.
- Unknown: The Pod is unreachable, thus, its state could not be determined.
Declarative and Imperative Ways of Starting a Pod
Pods can be created using either a declarative or imperative mode (check part 2 of this series if you don’t know what the difference is).
Creating a pod using the imperative mode entails using kubectl command-line tool
$kubectl run <pod name> <image> --restart=Never. The command is passed like flags on the command line of a running cluster. In contrast, the declarative mode involves starting a pod using a configuration (YAML or JSON syntax) manifest file. The configuration file is first created and then deployed using
$kubectl create -f <YAML/JSON file name>. More information on declarative and imperative ways of creating Kubernetes objects can be found in part 2 of this series under Kubernetes declarative and imperative.\
How to Manage the Lifecycle of a Pod
In this section, we will cover how to imperatively and declaratively manage Pods. A running Kubernetes cluster is needed for this exercise. Check part 2 of this series for different ways to get a Kubernetes cluster running.
Creating a Pod Imperatively
Step 1: Create a pod with an nginx container image:
$ kubectl run nginx --image=nginx --port=80 --restart=Never` pod/nginx created
- nginx: The name of the pod to be created
- –image=nginx: The container image which is stored in the image repository
- –port=80: Port definition which is shared by both the pod and the container
- –restart=Never: To create a pod directly on the cluster. Creating a pod without this flag will create a deployment instead of a pod. We will expatiate more on deployment in part 4 of this series.
Step 2: Check the status of the pod:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 12s
We can see that our Pod is now running on the cluster.
Step 3: To learn more about the pod, check the detailed status of the pod:
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE nginx 1/1 Running 0 12m 10.40.0.1 node01 <none>
- Name → represents the name of the Pod
- Ready → One out of one container has been created successfully
- Status → The container is running
- Restarts → The container has neither failed nor restarted
- Age → The time since when the container has been up
- IP → The pod IP address
- Node → The node where the container is running
- Nominated Node → No special assignment of a pod to a particular node
Step 4: To view the description of the Pod which entails when the Pod was created, the label assigned to it, the container image running in the Pod and its ID, as well as the events associated with the Pod.
$ kubectl describe pod Name: nginx Namespace: default Priority: 0 Node: node01/172.17.0.31 Start Time: Tue, 21 Jul 2020 17:15:46 +0000 Labels: run=nginx Annotations: <none> Status: Running IP: 10.244.2.3 IPs: Containers: nginx: Container ID: docker://61385d48e96f7ec6129da12ddb772f60532885e0d3c56dea8e10f70822b4cf55 Image: nginx Image ID: docker-pullable://nginx@sha256:a93c8a0b0974c967aebe868a186e5c205f4d3bcb5423a56559f2f9599074bbcd Port: 80/TCP Host Port: 0/TCP State: Running Started: Tue, 21 Jul 2020 17:15:57 +0000 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-ttjk9 (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-ttjk9: Type: Secret (a volume populated by a Secret) SecretName: default-token-ttjk9 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 14m default-scheduler Successfully assigned default/nginx to node01 Normal Pulling 14m kubelet, node01 Pulling image "nginx" Normal Pulled 14m kubelet, node01 Successfully pulled image "nginx" Normal Created 14m kubelet, node01 Created container nginx Normal Started 14m kubelet, node01 Started container nginx
Step 5: Now that we have checked the status of the Pod and seen that it is healthy, we need to perform a clean up of the Pod:
# where nginx is the name of the pod $ kubectl delete pods nginx pod "nginx" deleted
Step 6: Check to be sure that the cleanup is done and the pod has successfully been deleted
$ kubectl get pod No resources found in default namespace.
Creating a Pod Declaratively
Creating a pod declaratively requires the declaration of the Pod configuration using a YAML or JSON manifest file. The configuration source code comprises different properties and values.
You need to be familiar with the VIM editor to follow this task. However, other IDEs like Atom, visual studio among others can be used to create the configuration file.
First, make sure you have a running Kubernetes cluster with kubectl command-line tool configured and connected to it. (see part 2 of this series to get one started). Next, you need to create the configuration file. To do this, create a YAML file. You can use any name, but make sure to add the YAML extension when using YAML syntax. The correct indentation is also essential; otherwise, the file won’t work.
Enter your file:
Then copy and paste the configuration below into the file created above, save, and exit
apiVersion: v1 kind: Pod metadata: name: myfirst-pod labels: app: my-app spec: containers: - name: nginx-container image: nginx
The above configuration file defined a pod object named myfirst-pod with Pod as the value of its kind property. It will create a containerised application with nginx-container as the container name and nginx as the image. Note, the kind property value must be in the sentence case; otherwise, it will give an error.
Once we have created the configuration file, we need to deploy it to the cluster by running the below command.
$ kubectl create -f firstapp.yaml pod/myfirst-pod created
This will create a pod named myfirst-pod. To check the status, detailed status, description, clean up and other pod commands, use the same commands used in the imperative approach exercise above.
Multi-container pods are pods with more than one closely related containers that work together as a unit and share resources like inter-process communication, shared volumes, network space, etc.
To create a multi-container pod, simply add another container name and image under the spec property of the previous configuration file by editing the yaml file using this command:
The configuration source code will look like this:
apiVersion: v1 kind: Pod metadata: name: myfirst-pod labels: app: my-app spec: containers: - name: nginx-container image: nginx - name: redis-container image: redis
Save and exit the terminal. Create the multi-container pods by using the command below:
$ kubectl create -f firstapp.yaml pod/myfirst-pod created $ kubectl get pods NAME READY STATUS RESTARTS AGE myfirst-pod 2/2 Running 0 26s
The pod named myfirst-pod has been created while the 2/2 under the ready column means that the two out of two containers have successfully been created and are running. To check the detailed status, description and clean up, simply use the pod commands used on our first exercise. Congratulations!!! You have successfully created, deleted, and checked the detailed information of a Pod both in a declarative and imperative manner as well as worked with multi-container pods.
Getting Logs from and Exec-ing into a Pod
Logging is a process that gives you ongoing activities in a container. It is useful for debugging and viewing the past and current events in your applications.
You need to have a container running in a pod on a cluster to perform these tasks.
kubectl get pods command will display the available pods and running containers in the cluster.
You can get logs from a specific pod by running this command:
kubectl logs <pod name>
Using our previous example with the pod name myfirst-pod, run the below command when the pod status is in the running state.
$ kubectl logs myfirst-pod /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Configuration complete; ready for start up
To get only the five most recent lines of activity in a Pod run:
kubectl logs --tail=5 myfirst-pod:
$ kubectl logs --tail=5 myfirst-pod /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\ 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf\ 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\ /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\ /docker-entrypoint.sh: Configuration complete; ready for start up
The output here gives you the five lines of recent activities. You can specify the desired number of lines of recent activities depending on the problem you want to debug.
To get the last 2 hours of logs:
kubectl logs --since=2h myfirst-pod
$ kubectl logs --since=2h myfirst-pod /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\ /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\ 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf\ 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\ /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\ /docker-entrypoint.sh: Configuration complete; ready for start up
The time can also be changed to any desired time frame.
Exec-ing into a Pod:
Exec-ing refers to the process of getting a shell into a running container by running kubectl commands. It allows the command execution on a container in a Pod.
Get into a shell running container using our previous example:
#where myfirst-pod is the pod name the --stdin which can also be represented as -i gives you an interactive session, and --tty which can also be represented as -t requests that you allocate TTY for that session. $ kubectl exec --stdin --tty myfirst-pod -- /bin/bash root@node01:/# # You can now run different root commands in the shell. root@node01:/# ls ## to list all the files root@node01:/# uname ## To show the name of the operating system root@node01:/# IP address ## To display the IP address root@node01:/# ps ef ## To view the running processes root@node01:/# curl localhost ## To view the container image information root@node01:/# df -kh ## To check disk utilisation root@node01:/# exit ## To exit out of the shell and end kubectl-exec
Summary: Knowing the nitty-gritty of a pod is essential because it forms the basis of your Kubernetes journey. However, working with or creating a Pod directly is not recommended especially if your Pod is not intended to be ephemeral or if it is running in production Instead, deployments should be used to create a pod which will give you the opportunity of using replicas and other deployment properties and values.
The next part of our series will give more insight into deployment and replica sets, their features and usage as well as practice tasks.