..is the smallest deployable unit one can create and manage inside Kubernetes(K8s). A Pod can have one or more running containers, so it is a set of running containers.

What is a container?

A container image is a binary containing an application you created and all that needs for its running like system and application libraries, configuration files, etc. When you run a container image it becomes container. You can imagine a container image as a software-package but when you run it becomes container.

Why there is a difference? A container image can be changed. While a container is immutable, meaning that you can not change it once you create it. If there is a new version of a container image, the only way to apply those changes to the container is to destroy the old one and start new.

The container runtime is the software responsible for running containers. K8s supports any container runtime that implements Kubernetes CRI (Container Runtime Interface) like Docker, containerd, CRI-O.

What is a Pod?

As already mentioned a Pod is the smallest deployable unit in K8s. It is as well a set of containers. That set can have one or more containers bound by some logic.

What a Pod does?

You can think of a Pod as a single machine, a host. It is not that but you can imagine it like that. A Pod has:

  • a unique IP address
  • persistent storage volumes(optional, if required)
  • configuration, which defines how container(s) should be run

From K8s point, a Pod is a process running in a cluster. That process has a unique IP address so other processes(Pods) can communicate with it. On the other hand containers in a Pod share the same IP address. This means if they want to communicate with outside they are using unique ports. So, no two containers are on the same port.

Inter container communication in the same Pod goes over localhost. If there is attached persistent storage volume that can be used as a means of communication as well.

Basic operations with a Pod

I’m running these examples on the local cluster based on the k3d. If you do not have access to other K8s clusters where you can execute these examples, go to my quick intro to k3d.

Basic Pod configuration

Let’s start by running:

> kubectl run nginx-ser --image nginx --restart=Never --dry-run=client -o yaml

With this kubectl command you say that you want the Pod named nginx-ser made from nginx image(in this case, default, it is Docker image). Other flags --dry-run prevents its deployment, and -o specify output to be YAML format. The result should be something like this:

apiVersion: v1
kind: Pod
  creationTimestamp: null
    run: nginx-ser
  name: nginx-ser
  - image: nginx
    name: nginx-ser
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Lets dump this into file:

> kubectl run nginx-ser --image nginx --restart=Never --dry-run=client -o yaml > pod.yaml

Open this file pod.yaml any editor you like and remove unneeded lines so it looks like:

apiVersion: v1
kind: Pod
    run: nginx-ser
  name: nginx-ser
  - image: nginx
    name: nginx-ser

To create a Pod run:

> kubectl apply -f pod.yaml

If you look inside pod.yaml file you’ll see a basic Pod configuration:

  • apiVersion: tells which version of K8s API to use
  • kind: what K8s resource to operate with
  • metadata: these are labels and annotations. You use them to organize your Pods
  • spec: a Pod configuration specification where containers is defined

Under spec.containers you put an array of container definitions. Each container definition should have at least name. The image property is not required as it can be defaulted or managed by higher config management. In my case, I’m using Docker runtime so it is a docker image. This docker image is pulled from Docker Hub.

Inspect a Pod

You can check the status of a Pod:

❯ kubectl get pods
nginx-ser   1/1     Running   0          14m

Here you see a Pod:

  • name
  • ready status: is pod healthy and if it is ready to receive status
  • status
  • number of restarts
  • age

You can get more information if you add the option -o wide:

❯ kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE    IP           NODE                           NOMINATED NODE   READINESS GATES
nginx-ser   1/1     Running   0          6h4m   k3d-private-cluster-server-0   <none>           <none>

In this example, you see internal IP, IP number inside a cluster, and a node name where Pod is scheduled.

You get a YAML definition of a Pod if you do:

❯ kubectl get pods -o yaml

This could be quite verbose so redirect it some file and open it in an editor. Specifying output option -o you can set the format of output, where most interesting and used are wide, yaml and json.

A good way to see a Pod is to describe it:

❯ kubectl describe pods nginx-ser
Name:         nginx-ser
Namespace:    default
Priority:     0
Node:         k3d-private-cluster-server-0/
Start Time:   Sun, 21 Mar 2021 12:42:17 +0100
Labels:       run=nginx-ser
Annotations:  <none>
Status:       Running
    Container ID:   containerd://34b8f75b1f3b3ad891791198409cf25412e6bbc18468a2706aa441ee9001a41c
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:d2925188effb4ddca9f14f162d6fba9b5fab232028aa07ae5c1dab764dca8f9f
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 21 Mar 2021 12:42:19 +0100
    Ready:          True
    Restart Count:  0
    Environment:    <none>
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-j6lht (ro)
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-j6lht
    Optional:    false
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:          <none>

You can check container logs:

kubectl logs nginx-ser

Modifying a Pod

To modify a Pod you need to modify its specification. Either you get a Pod as YAML file and modify it:

> kubectl get pod nginx-ser > nginx-ser.yaml

Then open file nginx-ser.yaml and modify it. Then apply it again:

> kubectl apply -f nginx-ser.yaml

Or edit it directly inside K8s:

> kubectl edit pods nginx-ser

This will open Pod’s YAML configuration inside the vi editor. Once you save your modifications and exit the editor your changes will be applied.

Delete a Pod

Just do:

> kubectl delete pod nginx-ser


Let’s try to access to running nginx server on deployed Pod. At the moment this Pos is not visible outside. That means you can access it only inside a K8s cluster. One way is to run temporary with curl command:

❯ kubectl run curl --image curlimages/curl --restart=Never  -it --rm -- curl http://<target ip>
<!DOCTYPE html>
<title>Welcome to nginx!</title>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
pod "curl" deleted

Above kubectl command uses curlimages/curl Docker image to create a Pod named curl. It creates an interactive terminal with -it so it writes output to your terminal. Delete this Pod after execution with --rm. Executes a command curl <target ip>.

❓ Do you remember how to get the target pod internal IP?

Now try to run pod named httpd with image httpd. Check what is assigned IP and try to curl it. If are successful you should get:

<html><body><h1>It works!</h1></body></html>