Understand Pods in Kubernetes

kubernetes podsPods are the smallest deployable units of computing that you can create and manage in Kubernetes.

A Pod contains one or more containers. Containers are grouped into Pods so Kubernetes can provide services that are not supported in containers. For example, Pods provide shared storage/network resources, and a specification for how to run the containers. Docker is the most commonly known runtime, but it can be other types.

In short, Pods enable you to manage several tightly coupled application containers as a single unit.

Kubernetes can run Windows. So the command to manage Pods running Windows are the same as those running Linux. But you should know that you define Windows or Linux when you create the cluster.

In this article, you learn about how Pods work, how you can have multiple containers in a Pod, the lifecycle of a Pod, how Kubernetes handles networking with a Pod, and how to define a Pod using a PodTemplate in a Deployment, Job, or other Kubernetes resource.

Kubernetes manages Pods rather than managing the containers directly.

You can think of a Pod as a wrapper around containers that allow Kubernetes to scale and allow containers to share resources (like storage and networking.)

Pods give Kubernetes a way to scale, configure, and apply patches to containers. Pods gives Kubernetes a way to orchestrate containers deployed at large scale. Containers share resources in a secure way in Pods. Kubernetes performs actions to make Pods self-healing without manual intervention.

There are two ways that Pods work in a cluster:

  • Pods with single containers. Typically you will deploy a single container in a Pod.
  • Pods with multiple containers. You may want to have multiple containers share resources.  For example, you may want a web server Pod to contain an nginx container and a Ruby container. In another example, you may want for an application of two containers to share a volume. In this case,  one container could sends files when another container acts as the web server.  There will be a separate article describing multiple containers in this blog.

The following diagram shows a Pod with two containers and how Pods sharing the network.

Pods

Each Pod is meant to run a single instance of a your application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you define replicas.  A replica is the number of instances of the Pod that will be created and maintained by Kubernetes across the Nodes in the cluster.

Using Pods

You can inspect the status of a Pod in kubectl. But you do not create Pods by themselves.

You will use Kubernetes objects to create your Pods, such as Deployment or Job. If your Pods need to track state, consider the StatefulSet resource.

Pod Lifecycle

When a Pod gets created (directly by you, or indirectly by a controller), the new Pod is scheduled to run on a Nodein your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails.

Pods follow a defined lifecycle:

  1. Starting in the Pending phase
  2. Moving through Running if at least one of its primary containers starts OK
  3. Then either the Succeeded or Failed phases depending on whether any container in the Pod terminated in failure.

Within a Pod, Kubernetes tracks different container states and determines what action to take to make the Pod healthy again.

Use kubectl get pods to check the state of the Pods.

For more information, see Pod Lifecycle.

Use a PodTemplate specification

Use a PodSpec template to describe the workload objects, such as DeploymentsJobs, and StatefulSets. The PodTemplate is the part of the template that describes the Pod.

The PodSpec description is consistent when you define the workload object. For example, the PodTemplate part of a Deployments object describes the desired state for the Pod on the cluster to run continuously The same description is used for a Jobs object where the Pod can run until completed and then the compute resources are release. In either case, the PodSpec describes the Pod in the same way.

The following YAML file shows a Job object using a PodTemplate on lines 8-13.

apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
# This is the pod template
spec:
containers:
name: hello
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# The pod template ends here

You can define many things in the PodSpec, but mostly you will describe an array of Containers.

Container in the PodSpec

You define one or more of the following into the array of Containers:

  • image. This is the Docker image. You can define the Docker image in the PodSpec or in Deployments or StatefulSets. The image name looks like you would expect, such as
    your.private.registry.example.com/janedoe/jdoe-private:v1

    NOTE: You should avoid using the latest tag when deploying containers in production.

  • name. Name of the container specified as a DNS_LABEL.
  • command. Entrypoint array. Not executed within a shell. The docker image’s ENTRYPOINT is used if this is not provided. 
  • args. A string array of arguments to the entrypoint. The docker image’s CMD is used if this is not provided. 
  • env. List of environment variables to set in the container. 
  • ports. An array of ports to expose from the container.
  • volumeDevices. The list of block devices to be used by the container.
  • volumeMounts. Pod volumes to mount into the container’s filesystem.

The following example shows how you a redis container would be described using a volumeMount.

apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
name: redis
image: redis
volumeMounts:
name: redis-storage
mountPath: /data/redis
volumes:
name: redis-storage
emptyDir: {}

Other settings in PodSpec

You will also be able to set:

  • restartPolicy. Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always.  See RestartPolicy.
  • volumes. List of volumes that can be mounted by containers belonging to the pod. 

How to build a PodSpec

As mentioned several times, in production you will want to deploy your Pod object as a PodSpec that is part of a Deployment or Job object. But, how to figure out what the information you will need for my Deployment or Job objects?

For this exercise, you will need at least a single node cluster running and to log into your cluster. Install Kubernetes, kubectl on your development computer. Start with kubectl.

Dry run of a Pod

You can do a dry run of a Pod to get a starting point for your YAML. The idea is to see the YAML defaults generated by kubectl run –dry-run command.

kubectl run mysecondpod –image=nginx –dry-run=client -o yaml

The results return with the basic spec that you can use in a Deployment template.

 

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mysecondpod
  name: mysecondpod
spec:
  containers:
  - image: nginx
    name: mysecondpod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Deployments are explained further in a future blog post. But for now, you can use the Kubernetes documentation to get started using Deployments. You can use the section of the YAML in the Podspec in the Deployment YAML.

Next, you can create and run a Pod as shown in the following sections.

Run Pod

The following code uses kubectl run to create a Pod and Deployment named test using the container image nginx and exposing a HTTP API on port 80.

kubectl run test –image=nginx –port=80
view raw run-pod.sh hosted with ❤ by GitHub

You can replace nginx with your own container name.

Get a list of the running Pods using kubectl get command.

kubectl get pods -o wide

The name of the Pods will be in the list.

Use kubectl describe command to see the yaml description of the Deployment.

kubectl describe pod nginx-app-6cc6d7964d-rvkwr

Use the name of Pod to get the description.

The description returned looks like the following:

Name:         test
Namespace:    default
Priority:     0
Node:         aks-agentpool-13037616-vmss000000/10.240.0.4
Start Time:   Sat, 07 Nov 2020 19:41:25 +0000
Labels:       run=test
Annotations:  
Status:       Running
IP:           10.244.0.10
IPs:
  IP:  10.244.0.10
Containers:
  test:
    Container ID:   docker://a6f7a2c1ec0588908368a356c711df8bf609f7fb623e580494074c31cbd4d0f0
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:aeade65e99e5d5e7ce162833636f692354c227ff438556e5f3ed0335b7cc2f1b
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 07 Nov 2020 19:41:27 +0000
    Ready:          True
    Restart Count:  0
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-zjrn4 (ro)
// some information removed for brevity //

Next, learn how to get the PodSpec.

Get Podspec from kubectl

You can get the YAML used for the deployment and the current status using the following code.

 

kubectl get pods test -o yaml
view raw get-pod-yaml.sh hosted with ❤ by GitHub

About halfway down the YAML, you can see the spec used to create in the Pod.

spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: test
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-zjrn4
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: aks-agentpool-13037616-vmss000000
  priority: 0
  restartPolicy: Always
// some lines removed for clarity //
  volumes:
  - name: default-token-zjrn4
    secret:
      defaultMode: 420
      secretName: default-token-zjrn4

View Pod in Azure portal

If you are using Azure to deploy your Pod, you can see it in the Azure portal. Navigate to the AKS resource. In the Kubernetes resource. Click Pods.

Next, click the Pod name link. Then click YAML to see the YAML file. Scroll down to see the spec.

You can also see the status in the YAML a few lines underneath the Podspec.

Delete Pod

Once you are done with the test Deployment, you can delete it.

kubectl delete deployment test
view raw delete-pod.sh hosted with ❤ by GitHub

Brief explanation of Pod networking

Containers in a Pod run on a “logical host”; they use the same network namespace (in other words, the same IP address and port space), and the same IPC namespace. They can also use shared volumes. These properties make it possible for these containers to efficiently communicate, ensuring data locality. 

A pod consists of one or more containers that are co-located on the same host within the cluster. Pods are configured to share a network stack and other resources such as volumes. Inside the Pod, Kubernetes creates a special container for each pod whose only purpose is to provide a network interface for the other containers.

An IP address is assigned to a pod and that IP address stays with the pod until the pod is deleted. When a container crashes and restarts, it has the same IP address as it did before it crashed. In contrast, when a pod is deleted, it loses its IP address all together.

Your application needs to be completely independent of IP addresses, or be able to handle IP address changes of application instances. Do not depend on your application IP address to remain static.

There is all kinds of amazing magic going on. But what you need to know is that you will use a Service to define the network connections between your Pods and the outside world. A Kubernetes Service describes a domain name and which pods traffic is directed to.

For more details, see Kubernetes networking for developers from IBM, who recommend that if you are curious and want to dive deeper into Kubernetes networking, see:

References

 


Leave a Reply