Post

Kubernetes - Pods

Lab assignment for creating pods using kubectl

Kubernetes - Pods

Prerequisites

  • Kubernetes
  • kubectl

Assignment

  • Create a nginx webserver by running a simple pod with a single nginx container
1
kubectl run nginx --image=nginx
  • Query our running pods
1
kubectl get pods
  • Check the logs of the pod using the
1
kubectl logs pod/nginx
  • Query the running pods with the -o option to get more information including it’s IP address
1
kubectl get pods -o wide
  • Capture the IP address for this pod and confirm that we can ping it from control plane
1
NGINX_IP=$(kubectl get pods -o wide | awk '/nginx/ { print $6 }'); echo $NGINX_IP
1
ping -c 3 $NGINX_IP
  • We can verify if the pod is accessible from other nodes in the cluster
1
ssh <node-name> ping -c 3 $NGINX_IP
  • You can use port-forward to forward the port on the localhost and access the nginx webpage from the browser
1
kubectl port-forward pod/nginx 8080:80
  • Navigate to http://localhost:8080 and verify that you are able to access the page.

  • We can also query the nginx pod by running curl, in another pod and pointing it at the pod IP address -

1
kubectl run -it --rm curl --image=curlimages/curl:8.4.0 --restart=Never -- http://$NGINX_IP
  • You’ll see that this pod, automatically cleaned itself after it was run owing to the –rm option -
1
kubectl get pods -o wide
  • Let’s explore an alternative approach, we’ll run a pod with ubuntu that just runs with sleep infinity, we’ll also pass in the variable for our NGINX_IP pod so that it’s accessible as an environment variable within the pod -
1
kubectl run --image=ubuntu ubuntu --env="NGINX_IP=$NGINX_IP" -- sleep infinity

And check that the pod is running -

1
kubectl get pods -o wide
  • We’ll now execute a shell process, in the running ubuntu pod
1
kubectl exec -it ubuntu -- bash
  • If we take a look whilst in this shell, we’ll see that sleep infinity, is process id 1, we will have our bash shell and then the ps command that we ran, is a subprocess of the bash shell -
1
ps -ef
  • As this is a ubuntu container, we can use the apt package manager to install curl. We will do an apt update, followed by an apt install -y curl
1
apt update && apt install -y curl
  • And now we can query the nginx pod, using the NGINX_IP variable that we passed in at the start
1
curl $NGINX_IP
  • Exit from the ubuntu container
1
exit
  • And let’s remove these pods
1
kubectl delete pod/nginx pod/ubuntu --now
  • We can use the kubectl options of -o yaml, along with --dry-run=client, to show the yaml declaration that the cli is using, let’s tee this to a file called nginx.yaml at the same time
1
kubectl run nginx --image=nginx --dry-run=client -o yaml | tee nginx.yaml
  • Notice the restartPolicy option, if we wish to know more about a particular section of Kubernetes yaml, we can use the kubectl explain command. For example, to query this we would use pod (as per the entry Kind), then the path, spec.restartPolicy
1
kubectl explain pod.spec.restartPolicy
  • Let’s create this in kubernetes using the imperative approach of kubectl create with -f to specify the filename
1
kubectl create -f nginx.yaml
  • Whilst this succeeded this time, subsequent attempts will fail as kubectl cannot create an entity that already exists
1
kubectl create -f nginx.yaml
  • An alternative approach is to use the declarative approach of apply, meaning we are applying what this entity should look like. You will get a warning initially if you do this to an entity that was created -
1
kubectl apply -f nginx.yaml
  • However, subsequent attempts will succeed
1
kubectl apply -f nginx.yaml
  • Let’s capture a ubuntu pod example, as yaml also, we won’t need the NGINX_IP variable
1
kubectl run --image=ubuntu --dry-run=client -o yaml ubuntu sleep infinity | tee ubuntu.yaml
  • Then we also apply this
1
kubectl apply -f ubuntu.yaml
  • And check our pods, we will now have both nginx and ubuntu running successfully, via yaml files
1
kubectl get pods -o wide
  • Let’s remove both of these pods
1
kubectl delete pod/nginx pod/ubuntu --now
  • Currently we have two separate files, but a yaml file can contain multiple declarations, let’s combine the two files with a — yaml separator, we will use tee to save this to combined.yaml
1
{ cat nginx.yaml; echo "---"; cat ubuntu.yaml; } | tee combined.yaml
  • If we apply this combined.yaml file, it will create both entities at the same time
1
kubectl apply -f combined.yaml
  • And we can see both pods in our Kubernetes cluster
1
kubectl get pods -o wide
  • We can also use this file to delete both entities, at the same time with the kubectl delete command
1
kubectl delete -f combined.yaml --now
  • Modify the combined.yaml file so that we are running a single pod, with two containers, moving the ubuntu containers section, into the nginx section.
  • The ubuntu container will be configured as a sidecar that echo’s a log and exit’s if a file (/tmp/crash) exists.
  • We will also update the metadata to match. The following command will create a working example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat <<EOF > combined.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mypod
  name: mypod
spec:
  containers:
  - image: nginx
    name: webserver
    resources: {}
  - image: ubuntu
    name: sidecar
    args:
    - /bin/sh
    - -c
    - while true; do echo "\$(date +'%T') - Hello from the sidecar"; sleep 5; if [ -f /tmp/crash ]; then exit 1; fi; done
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF
  • Apply the new combined.yaml file
1
kubectl apply -f combined.yaml
  • You’ll now see that we have a single pod showing 2/2 to indicate that it is running 2 of 2 containers in the pod
1
kubectl get pods -o wide
  • Using kubectl we can describe the pod for further information, in particular the IP address and each of the containers (named webserver and sidecar)
1
kubectl describe pod/mypod
  • Let’s capture the mypod IP address
1
MYPOD_IP=$(kubectl get pods -o wide | awk '/mypod/ { print $6 }'); echo $MYPOD_IP
  • And check that this is accessible using a throwaway curl pod (n.b. in the video lesson I used curlimages/curl:latest, this image is found to have frequent changes and instability, therefore for the lab, I’ve fixed the tag to a known working version)
1
kubectl run -it --rm --image=curlimages/curl:8.4.0 --restart=Never curl -- http://$MYPOD_IP
  • If we check the logs for the sidecar container, we will see this is working as expected, note the use of -c to specify the particular container, ctrl-c to exit
1
kubectl logs pod/mypod -c sidecar
  • Let’s crash the sidecar container, by creating the /tmp/crash file that it is looking for as an exit criteria
1
kubectl exec -it mypod -c sidecar -- touch /tmp/crash
  • If we check our pods again, this will transition to a restart of 1, where it restarted the crashed container
1
kubectl get pods -o wide
  • And if we check the sidecar logs, this will have restarted
1
kubectl logs pod/mypod -c sidecar
  • If however, we wish to see the previous logs, we can do so with the -p option
1
kubectl logs pod/mypod -p -c sidecar
  • Let’s remove the pod
1
kubectl delete pod/mypod --now
  • And remove the yaml files
1
rm nginx.yaml ubuntu.yaml combined.yaml
This post is licensed under CC BY 4.0 by the author.