Kubernetes 101 - First 3 Components to Learn (part 1)

Overview

Similar to learning a new coding framework, becoming productive with Kubernetes is mostly about understanding its components and how they’re used. There’s a long list of components and the list is growing daily. However, the 3 foundational pieces that arguably almost everything else builds upon are Pod, Service and Deployment. For someone just learning Kubernetes, I recommend starting with those.

Pod

A pod is a collection of containers that run your application. It’s also the component that you scale to handle load and provide redundancy. For example, if you want to run 5 instances of your website, you specify it in the pod. Kubernetes resources that the app requires, such as networking ports or persistent storage volumes, are also specified in the pod.

The Kubernetes Object Specification (object spec) for Pod defines its characteristics, such as what container to run, how many instances and resources required. Here’s example to run a simple container. Save this YAML in a file named hello-world.yaml.

apiVersion: v1
kind: Pod
metadata:
  name: hello-pod
spec:
  containers:
    - name: hello-container
      image: docker.io/busybox:latest
      command: ["/bin/sh"]
      args: ["-c", "while true; do echo 'Hello'; sleep 3; done"]

Run the pod in your cluster with the following kubectl command.

> kubectl apply -f hello-world.yaml
pod/hello-pod created

You can see it’s running

> kubectl get pod hello-pod
NAME        READY   STATUS    RESTARTS   AGE
hello-pod   1/1     Running   0          7s

and see its console output.

> kubectl logs hello-pod
Hello
Hello
Hello
Hello
Hello
Hello

You can connect interactively to it with a new shell, as follows.

kubectl exec -it hello-pod /bin/sh
/ # ls
bin   dev   etc   home  proc  root  run   sys   tmp   usr   var
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh -c while true; do echo 'Hello'; sleep 3; done
   15 root      0:00 /bin/sh
   26 root      0:00 sleep 3
   27 root      0:00 ps aux
/ # exit
command terminated with exit code 127

Finally, tear down the pod with the kubectl delete command.

> kubectl delete -f hello-world.yaml
pod "hello-pod" deleted

Usually a pod is built to do more interesting work than echoing a hello string. For example, the pod could run a web server listening on a port to provide a microservice. To do that, add a containerPort resource to the object spec.

Pods will sometimes also need more than one container to perform different, but related functions. What containers should be grouped together in a pod and which should have their own pod is a design decision and possibly a good topic for a future post.

In the following example, a second container is added to the pod to run nginx listing on port 80.

apiVersion: v1
kind: Pod
metadata:
  name: hello-pod
spec:
  containers:
    - name: hello-container
      image: docker.io/busybox:latest
      command: ["/bin/sh"]
      args: ["-c", "while true; do echo 'Hello'; sleep 3; done"]
    - name: web-service
      image: docker.io/nginx:latest
      ports:
        - containerPort: 80

After creating the pod again, we can see there are now 2 of 2 running instances.

> kubectl get pod hello-pod 
NAME        READY   STATUS    RESTARTS   AGE
hello-pod   2/2     Running   0          22s

We can use the kubectl port forwarding command to test our nginx web server, as follows.

> kubectl port-forward hello-pod 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

The command tells kubectl to act as a proxy, listening on local port 8080 and forwarding to port 80 of the hello-pod pod. We need a proxy because nginx is listening to the container port 80 and it’s not accessible outside the cluster.

After port forwarding starts, you can use your favorite tool or browser to do a HTTP request and see the default nginx response.

> curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<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>
</body>
</html>

In a more realistic scenario, the nginx container might include with real website code or mount a storage volume with web content. The development process for creating app containers is on the radar for a future post.

Conclusion

To summarize, the Pod is the unit of deployment in Kubernetes. It’s the bundle of containers that make up a deployable piece of your application. That could be the entire app itself or just one of many microservices. As we’ll see later in Part 3, it’s also the scale unit, or the component that’s instantiated or stopped when there’s a change to the number of instances required. The Pod is definitely one of the foundational building blocks that everything else in Kubernetes builds upon.