Introduction to Pods

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: vim firstapp.yaml

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 Pod

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: vim firstapp.yaml

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.

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#logs

Getting started with containers

https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/

https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/

Seyi Ewegbemi

Seyi Ewegbemi

Student Worker