In this lab, you'll create your first Kubernetes Pod. This lab assumes you've access to a Kubernetes cluster. You can go through the Creating a Kubernetes cluster in Google Cloud lab to create a Kubernetes cluster.
Running your first Kubernetes Pods
Let’s start by creating your first Pod.
apiVersion: v1 kind: Pod metadata: name: hello-pod labels: app.kubernetes.io/name: hello spec: containers: - name: hello-container image: busybox command: ["sh", "-c", "echo Hello from my container! && sleep 3600"]
Save the above YAML to
pod.yaml and use the following command to create the Pod:
kubectl apply -f pod.yaml
If all goes well, you will get the following output:
Kubernetes responds with the resource type and the name of the Pods that it created. You can use the command
kubectl get pods to list all Pods running the
default namespace of the cluster.
$ kubectl get pods NAME READY STATUS RESTARTS AGE hello-pod 1/1 Running 0 7s
You can use the
logs command to see the output from the container running inside the Pod:
$ kubectl logs hello-podHello from my container!
When running multiple containers running inside the same Pod, you can use the
-cflag to specify the container name whose logs you want to get. For example:
kubectl logs hello-pod -c hello-container
If we delete this Pod using
kubectl delete pod hello-pod, the Pod will be gone forever because nothing would automatically restart it.
If you run the
kubectl get pods again, you will notice the Pod is gone:
$ kubectl get pods No resources found in default namespace.
Not automatically recreating the Pod is the opposite of the behavior we want. If you have your containers running in a Pod, you want Kubernetes to reschedule and restart them if something goes wrong automatically.
Keeping the Pods running with ReplicaSets
The job of a ReplicaSet is to maintain a stable number of pod copies or replicas. The ReplicaSet controller guarantees that a specified number of identical Pods is running at all times. We can control and configure the number of replicas with the
replicas field in the resource definition.
To create the pods, ReplicaSet uses the pod template that's part of the resource definition. If you start with a single pod and you want to scale to 5 pods, the ReplicaSet controller uses that current state (one pod) in the cluster and goes and creates four more pods to meet the desired state (5 pods). The ReplicaSet also keeps an eye on the pods, so if you delete one or scale it up or down, it will do the necessary to meet the desired number of replicas.
You can read more about ReplicaSets in the Getting start with Kubernetes article.
Let's look at an example.
apiVersion: apps/v1 kind: ReplicaSet metadata: name: hello labels: app.kubernetes.io/name: hello spec: replicas: 5 selector: matchLabels: app.kubernetes.io/name: hello template: metadata: labels: app.kubernetes.io/name: hello spec: containers: - name: hello-container image: busybox command: ["sh", "-c", "echo Hello from my container! && sleep 3600"]
Save the above YAML to
replicaset.yaml and use the following command to create the ReplicaSet:
kubectl apply -f replicaset.yaml
You can view the ReplicaSet by running the following command:
$ kubectl get replicaset NAME DESIRED CURRENT READY AGE hello 5 5 5 30s
The command will show you the name of the ReplicaSet and the number of desired, current, and ready Pod replicas. If you list the Pods, you will notice that five Pods are running:
$ kubectl get po NAME READY STATUS RESTARTS AGE hello-dwx89 1/1 Running 0 31s hello-fchvr 1/1 Running 0 31s hello-fl6hd 1/1 Running 0 31s hello-n667q 1/1 Running 0 31s hello-rftkf 1/1 Running 0 31s
We can also list the Pods by their labels. For example, if we run
kubectl get po -l=app.kubernetes.io/name=hello, we will get all Pods that have
app.kubernetes.io/name: hello label set. The output includes the five Pods we created.
Let's also look at the
ownerReferences field. We can use the
-o yaml flag to get the YAML representation of any object in Kubernetes. Once we get the YAML, we will search for the
$ kubectl get po hello-dwx89 -o yaml | grep -A5 ownerReferences --- ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: hello
ownerReferences, Kubernetes sets the
hello, and the
ReplicaSet. The name corresponds to the ReplicaSet that owns the Pod.
Notice how we used
po in the command to refer to Pods? Some Kubernetes resources have short names you can use in place of the 'full names'. You can use
po when you mean
deploy when you mean
deployment. To get the full list of supported short names, you can run
Another thing you will notice is how the Pods are named. Previously, where we were creating a single Pod directly, the Pod's name was
hello-pod, because that's what we specified in the YAML. Using the ReplicaSet, Kubernetes names the Pods using the combination of the ReplicaSet name (
hello) and a semi-random string such as
fchrv and so on.
Let's try and delete one of the Pods. To delete a resource from Kubernetes you use the
delete keyword followed by the resource (e.g.
pod) and the resource name
hello-dwx89 (note that your Pod will have a different name):
$ kubectl delete po hello-dwx89 pod "hello-dwx89" deleted
Once we've deleted the Pod, we can run
kubectl get pods again. Did you notice something? There are still five Pods running.
$ kubectl get po NAME READY STATUS RESTARTS AGE hello-fchvr 1/1 Running 0 14m hello-fl6hd 1/1 Running 0 14m hello-n667q 1/1 Running 0 14m hello-rftkf 1/1 Running 0 14m hello-vctkh 1/1 Running 0 48s
If you look at the
AGE column, you will notice four Pods created 14 minutes ago and one created more recently. ReplicaSet created this new Pod. When we deleted one Pod, the number of actual replicas decreased from five to four. The replica set controller detected that and created a new Pod to match the replicas' desired number (5).
Let's try something different now. We will manually create a Pod with labels that match the ReplicaSets selector labels (
apiVersion: v1 kind: Pod metadata: name: stray-pod labels: app.kubernetes.io/name: hello spec: containers: - name: stray-pod-container image: busybox command: ["sh", "-c", "echo Hello from stray pod! && sleep 3600"]
Save the above YAML in the
stray-pod.yaml file, then create the Pod by running:
$ kubectl apply -f stray-pod.yaml pod/stray-pod created
The Pod gets created, and all looks good. However, if you run
kubectl get pods you will notice that the
stray-pod has disappeared. What happened?
The ReplicaSet makes sure only five Pod replicas are running. When we manually created the
stray-pod with the label
app.kubernetes.io/name=hello that matches the selector label on the ReplicaSet, the ReplicaSet took that new Pod for its own. Remember, the manually created Pod didn't have the owner. With this new Pod under ReplicaSets' management, the number of replicas was six and not five, as stated in the ReplicaSet. Therefore, the ReplicaSet did what it's supposed to do; it deleted the new Pod to maintain the desired state of five replicas.
When you've updated your applications in production, it is desired that the deployment/update you do is a zero-downtime update. That means that no production traffic is interrupted when you release the new version of the application.
Unfortunately, we can't zero-downtime updates with a replica set. At least not in a zero-downtime manner.
Let's say we want to change the Docker image used in the original replica set from
busybox:1.31.1. We could use
kubectl edit rs hello to open the replica set YAML in the editor, then update the image value.
Once you save the changes - nothing will happen. Five Pods will still keep running as if nothing has happened. Let's check the image used by one of the Pods:
$ kubectl describe po hello-fchvr | grep image Normal Pulling 14m kubelet, docker-desktop Pulling image "busybox" Normal Pulled 13m kubelet, docker-desktop Successfully pulled image "busybox"
Notice it's referencing the
busybox image, but there's no sign of the
busybox:1.31.1 anywhere. Let's see what happens if we delete this same Pod:
$ kubectl delete po hello-fchvr pod "hello-fchvr" deleted
We already know that ReplicaSet will bring up a new Pod (
hello-q8fnl in this case) to match the desired replica count from the previous test we did. If we run
describe against the new Pod that came up, you will notice how the image has changed:
$ kubectl describe po hello-q8fnl | grep image Normal Pulling 74s kubelet, docker-desktop Pulling image "busybox:1.31" Normal Pulled 73s kubelet, docker-desktop Successfully pulled image "busybox:1.31"
A similar thing will happen if we delete the other Pods still using the old image (
busybox). The ReplicaSet would start new Pods, and this time, the Pods would use the new image
We can use another resource to manage the ReplicaSets, allowing us to update Pods in a controlled manner. Changing the image name can start Pods using the new image names in a controlled way. This resource is called a Deployment.
To delete all Pods, you need to delete the ReplicaSet by running:
kubectl delete rs hello.
rs is the short name for
replicaset. If you list the Pods (
kubectl get po) right after you issued the delete command, you will see the Pods getting terminated:
NAME READY STATUS RESTARTS AGE hello-fchvr 1/1 Terminating 0 18m hello-fl6hd 1/1 Terminating 0 18m hello-n667q 1/1 Terminating 0 18m hello-rftkf 1/1 Terminating 0 18m hello-vctkh 1/1 Terminating 0 7m39s
Once the replica set terminates all Pods, they will be gone, and so will be the ReplicaSet.