Pods
Goals
- Understand Kubernetes Pods:
- Learn what a pod is and its role in the Kubernetes architecture.
- Basic Example(s):
- Provide (a) basic example(s) of Pods.
- Show how to define a Pod using YAML.
- Pod Spec Explanation:
- Visit the Pod specification while following the example(s) above.
- Direct Pod Access:
- Describe how to create a direct network tunnel to a Pod for testing and/or debugging purposes.
- Exercise:
- Hands-on activity to create a simple Pod (using only the spec).
Understanding Kubernetes Pods:
A Pod is the smallest, most basic deployable object in Kubernetes. It represents a single instance of a running process in your cluster. A pod encapsulates one or more containers, storage resources, a unique network IP, and options that govern how the containers should run.
Basic Pod Example
Here is a basic example of a Kubernetes pod specification in YAML:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx:1.21
ports:
- containerPort: 80
Save this to a file pod.yaml
and create the resource using kubectl apply -f pod.yaml
:
> kubectl apply -f pod.yaml
pod/nginx-pod created
Next, let's take a look at the pods running in our cluster and see if we can find the newly created Pod using kubectl get pods
:
> kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 72s
Let's explain this a little:
NAME
: As we can see on the left side we have the name of the Pod we've just created (remember themetadata.name
?)READY
: To the right of it, we have theREADY
section:1/1
means that1
out of1
Pods of this type are ready to serve traffic. But do we really need this? Well, yes, the maximum number of Pods, for any name, is1
, but what if our Pod is not ready? We should know that when retrieving Pods, so we can know that the reason we are having trouble with our app is cause the Pod is literally not in aRunning
state. Usually, we won't launch just 1 Pod of this type, we'll be using a Set resource to help us deploy multiple and manage them, but then themetadata.name
provided will be the prefix for the final name of the pod (i.enginx-pod-134af
)STATUS
: Next, we have theSTATUS
section, which lets us know what status our Pod is in ("Pending" | "Running" | "Succeeded" | "Failed" | "Unknown"
)RESTARTS
:RESTARTS
show us how many times has the Pod restarted since it has been created, along with how much time has it passed since the last restart (if there has been any)AGE
: lastly, theAGE
, which shows us how old the Pod is
After creating the resource, we should also take a look at the state it is in, we can do this by making use of the kubectl describe pods/nginx-pod
:
> kubectl describe pods/nginx-pod
Name: nginx-pod
Namespace: default
Priority: 0
Service Account: default
Node: minikube/192.168.49.2
Start Time: Mon, 05 Aug 2024 12:07:28 +0300
Labels: <none>
Annotations: <none>
Status: Running
IP: 10.244.0.45
IPs:
IP: 10.244.0.45
Containers:
nginx-container:
Container ID: docker://7b219a363f96823719c9f68f0e0e5106007808c6d4b840d1521ab1383606e99b
Image: nginx:1.21
Image ID: docker-pullable://nginx@sha256:2bcabc23b45489fb0885d69a06ba1d648aeda973fae7bb981bafbb884165e514
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 05 Aug 2024 12:07:39 +0300
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-kwl7s (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-kwl7s:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
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:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 25m default-scheduler Successfully assigned default/nginx-pod to minikube
Normal Pulling 25m kubelet Pulling image "nginx:1.21"
Normal Pulled 25m kubelet Successfully pulled image "nginx:1.21" in 9.687s (9.687s including waiting). Image size: 141526528 bytes.
Normal Created 25m kubelet Created container nginx-container
Normal Started 25m kubelet Started container nginx-container
A lot of information, I know, but bare with me, we can digest most of it, but we don't even need to.
The describe
function, though, lets us see exactly why stuff went wrong, went it did, well that's what it's mostly used for, or making sure nothing did, in fact, went wrong, so we can go in search of the real culprit that is giving us headaches.
What is of most interest are the next things:
- containers' ports
- containers' ready state
- conditions
- events
If we know these things, we can see pretty quick (at least for our use cases) if the Pod is set up properly. While most of the data is pretty self explanatory, emphasis should be put on the Events
section, which gives us a detailed trace of each step that happened. If a problem did happen, you'd be pretty sure it is found here.
Explanation of the Pod Spec:
- apiVersion: v1 (hardcoded)
- kind: Pod (type of resource)
- metadata: ObjectMeta
- spec: PodSpec
- status: PodStatus
Direct Pod Access
Great, we've deployed our first resource, a Pod! But what can we do with it? Can we access it? Well, usually, you'd want to put it behind a Service (so that it can be accessed from a hostname), that would also be behind an Ingress (so that outside traffic can enter the cluster).
Since we haven't done any of those, we'll create a direct tunnel to the Pod:
> kubectl port-forward nginx-pod 8000:80
Forwarding from 127.0.0.1:8000 -> 80
Forwarding from [::1]:8000 -> 80
With this simple command (don't close the terminal!!!), our machine's port 8000
is made so it proxies traffic to the port 80
of our container
If you are using WSL2, the things aren't that simple. WSL2 has a different network interface than Windows, which means you need to start your browser from WSL2 (usually install it in WSL2 again, cause it's basically another operating system) or forward traffic from Windows to WSL2.
Now to test it and make sure it works, we can do a simple curl http://localhost:8000
command in the terminal:
> curl http://localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
And just like that we got to have our first Pod, create a tunnel to it and see that it works!
Exercises:
-
Write a YAML file named
multi-container-pod.yaml
that defines a Pod having 2 containers: a container namednginx-container
, but on port3000
, that is the same as the one provided in the example, and another container namedbusybox-container
that uses thebusybox
image and that provides it the next command: `/bin/sh -c echo BusyBox Hello! && sleep 3600'tipIt is usually recommended to split commands into multiple parts as follows: first being the exectuable run (in our case
/bin/sh
) and aftewards each argument by itself (-c
,echo BusyBox Hello! && sleep 3600
).So in the end it looks like:
['/bin/sh', '-c', 'echo BusyBox Hello! && sleep 3600']
when you pass it to the containerCreate the resource using
kubectl apply
, create a tunnel to send a request and make sure it works when you request the webpage, and also check the logs of the Pod using thekubectl logs
command -
Write a YAML file named
resource-limited-pod.yaml
to define a pod with one container,resource-limited-container
, using thebusybox
image, the['/bin/sh', '-c', 'while true; do echo Hello Kubernetes!; sleep 5; done']
command and with the next resources:- Resource requests:
- CPU:
100m
- Memory:
64Mi
- CPU:
- Resource limits:
- CPU:
200m
- Memory:
128Mi
- CPU:
Create the Pod and monitor its usage using the
kubectl top
commandTry running a resource-intensive command
yes > /dev/null
and observe the behavior of the Pod under resource limitstipWhen using minikube, make sure you enable the
metrics-server
:> minikube addons enable metrics-server
tipTo run commands inside Pods, you can make use of the
kubectl exec
command as follows:> kubectl exec -it __POD_NAME__ -- /bin/sh -c "echo Hello"
- Resource requests: