Kubernetes 101, part II, pods

leandronsp

Leandro Proença

Posted on March 1, 2023

Kubernetes 101, part II, pods

In the previous post we've seen the fundamentals of Kubernetes as well as an introduction to its main architecture.

Once we got introduced, it's time to explore how we can run an application in Kubernetes.


A wrapper for containers

In Kubernetes, we aren't able to create single containers directly. Instead, for the better, we can wrap containers into a single unit which comprises:

  • a specification: where multiple containers can use the same specification as deployable units
  • a shared storage: they can use a shared storage so the same volumes are mounted across multiple containers
  • a single network: containers under the same wrapper can share a single network, so they can communicate to each other

Comparing to Docker, such wrapper is similar to docker-compose.yml, where different services (containers) can share a common specification, volumes and network.

Yes, we are talking about Pods.


Pods

Pods are the smallest deployable unit you can create and manage in Kubernetes.

Within Pods, we can group multiple containers that should communicate to each other somehow, either using the same network or through shared volumes.

Different Pods using their containers

Let's create some Pods.

Using YAML for good

Up to this point, we've used kubectl in order to create pods, for instance:



$ kubectl run <container_name> --image=<some_image>


Enter fullscreen mode Exit fullscreen mode

It works pretty well for running experimental Pods, creating temporary resources and other workloads in k8s (we'll talk about workloads later).

We could create multiple Pods using kubectl run ..., but what if we want to share with other people, team or even the open-source community how we declared our Pods?

How about sharing in a VCS repository like Git the representation of the desired state of our application in k8s using a standard serialization format?

Kubernetes brings a serialization format which can be used to represent our Pods, and yes, you may like it or not, it's the well known YAML.

Creating a Pod

With YAML, we can declare Kubernetes objects using the kind attribute. K8s employs many different kind of objects which we'll explore on later posts, but at this moment we'll start with the most common and smallest unit in Kubernetes: a Pod.

Our Pod specification should be composed by:

  • a container called "server", backed by the ubuntu image, that shares a volume with the Pod. This container will create in the shared volume a UNIX named pipe, a.k.a FIFO, listening for some message coming into the FIFO.

  • a container called "client", also backed by an ubuntu image, that shares a volume with the Pod. This container will write to the shared volume a simple message called "Hey".

A Pod sharing a volume with its internal containers

Expectation

When the server is started, the FIFO will be created in the shared volume. The server keeps waiting for some message arriving into the FIFO.

When the client is started, it will write the message "Hey" into the shared volume.

Afterwards, we look at the container server logs, as it should print the message Hey that was sent by the client.

a more detailed overview of Pods using shared volumes

Let's declare the YAMl file fifo-pod.yml:



kind: Pod
apiVersion: v1
metadata:
  name: fifo-pod
spec:
  volumes:
    - name: queue
      emptyDir: {}
  containers:
    - name: server
      image: ubuntu
      volumeMounts:
        - name: queue
          mountPath: /var/lib/queue
      command: ["/bin/sh"]
      args: ["-c", "mkfifo /var/lib/queue/fifo; cat /var/lib/queue/fifo"]
    - name: client
      image: ubuntu
      volumeMounts:
        - name: queue
          mountPath: /var/lib/queue
      command: ["/bin/sh"]
      args: ["-c", "echo Hey > /var/lib/queue/fifo"]


Enter fullscreen mode Exit fullscreen mode
  • kind: the object kind. In this case, simply Pod
  • metadata name: the name of the Pod in the cluster, under the current default namespace (we'll talk about namespaces in later posts)
  • volumes: the shared volume of the Pod. We're using emptyDir which will share any empty directory in the Pod's filesystem
  • volumeMounts: mounting the Pod's shared volume into some directory of the container's filesystem
  • command: the command to be executed in the container

After declaration, we can share the YAMl file with our friends, co-workers etc using Git. But the object is yet to be created in our cluster. We do this by using the command kubectl apply:



$ kubectl apply -f fifo-pod.yml
pod/fifo-pod created


Enter fullscreen mode Exit fullscreen mode

Let's check the logs of the server container. We can use the command kubectl logs <pod> so we get the logs of every container in the Pod. However we want to fetch logs from the server container only:



$ kubectl logs fifo-pod -c server
Hey


Enter fullscreen mode Exit fullscreen mode

Yay! It works! 🚀

Getting the list of Pods

Using kubectl we can get the list of Pods in our cluster:



$ kubectl get pods

NAME         READY   STATUS      RESTARTS      AGE
nginx        1/1     Running     1 (92m ago)   6d3h
fifo-pod     0/2     Completed   0             64m


Enter fullscreen mode Exit fullscreen mode

We have a Pod called nginx which is Running for 6 days. It's quite comprehensible, since I've run the kubectl run nginx --image=nginx 6 days ago. Also, it's well known that NGINX is a web server that keeps running (listening for TCP connections), so that's why the Pod is still in a Running status.

But the Pod fifo-pod we just created is returning a Completed status. Why?

Pod Lifecycle

Pods follow a lifecycle in Kubernetes.

Like containers in Docker, Pods are designed to be ephemeral. Once a Pod is scheduled (assigned) to a Node, the Pod runs on that Node until it stops or is terminated.

A Pod lifecycle works by phases. Let's understand each phase.

Pending

It's when a Pod is accepted by the cluster but its containers are not ready yet. The Pod is NOT yet scheduled to any Node.

pod phase pending

Running

All containers are created and the Pod has been scheduled to a Node.

At least one of the containers are still running or being started.

pod phase running

Succeeded / Failed

If all containers are Terminated in success, then the Pod status is Succeeded.

But in case all containers have terminated but at least 1 container terminated in failure, the Pod status is Failed.

pod phase succeeded/failed

Terminated / Completed

Indicates that all the containers are terminated (internally by Kubernetes) or completed.


More about Pod Lifecycle

Pods lifecycle is a quite big topic in Kubernetes, covering Pod conditions, readiness, liveness and so on. We'll dig into further details about lifecycles in later posts.


Wrapping Up

This post showed a bit more about Pods, which are the smallest and main deployable unit in Kubernetes.

On top of that, we also created a Pod with two containers communicating to each other using FIFO and a shared volume.

In addition, we've seen a bit about Pod lifecycle. Hence, the Pod lifecycle and its lifetime will be crucial to understand the subject of the upcoming post: self-healing capabilities in Kubernetes.

Stay tuned, and Cheers!

💖 💪 🙅 🚩
leandronsp
Leandro Proença

Posted on March 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related