Kubernetes deployments allow to define and enforce desired state of applications running in Kubernetes. Kubernetes deployments achieve that using ReplicaSets. ReplicaSet guarantees running the desired number of Kubernetes pods. Below, we’ll explore deployments and ReplicaSets concepts. In addition, I’ll demo how to manage them using kubectl
. Keep reading to find out more.
Introduction
In the last post we explored Kubernetes Pods. We saw that they are the most basic Kubernetes objects and that they live only once. Today, I’ll introduce you to Kubernetes deployments and their relation to pods. In addition, we’ll see how to manage them using kubectl
.
Kubernetes Deployments Concepts
We already know that Kubernetes can maintain the desired state of applications. More specifically, their availability and desired scale. How to declare desired state of the applications (their pods)? For that purpose Kubernetes deployments exist. In addition to declaring desired state of application pods, they allow rolling updates of pods. More specifically ReplicaSets of pods.
Most common example of app desired state is its scale. More specifically, number of app pods. So, when we declare Kubernetes deployment, we have to specify the desired number of replicas (pods) of an application. How does ReplicaSet fit in? Well, Kubernetes deployments manage pods using ReplicaSets
. In short, these are Kubernetes objects which ensure that the required number of pods are available. So, ReplicaSets
provide important Kubernetes promises like: self-healing, fault tolerance and scale.
We said in Kubernetes Pods Introduction that we don’t have to create pods directly. I’ll add now that we don’t have to create ReplicaSets
directly as well. The only thing we need to do is to create Kubernetes deployments.
Enough talking. Now, let’s see some Kubernetes deployments demo.
Prerequisites
Install on your machine:
minikube
The tutorial assumes familiarity with basic kubectl
commands.
Declare Kubernetes Deployments using yaml
We usually create Kubernetes deployment using kubectl create
and kubectl apply
and supply deployment manifests as input.
While it’s possible to declare manifests using JSON, we’ll pick yaml
. Mostly, because I find it more readable. But, where do we get the manifest? Should we write it ourselves? I’d rather not. Why? See yourself. Sample Kubernetes deployment is defined below:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.13.2
ports:
- containerPort: 80
Luckily, there’s a nice trick using kubectl
which will save us.
Though first, let’s start Kubernetes cluster using minikube
. kubectl
will be auto-configured to use it. Let’s follow the same path as in Kubernetes Pods Introduction and create a multi-node cluster.
minikube start --nodes 3 -p multinode-demo
.
Next, we’ll generate deployment manifest in yaml
format using kubectl
:
kubectl create deploy nginx --image=nginx:1.13.2 --dry-run=client -o yaml > app.yaml
Thanks to --dry-run
we get app.yaml
that looks like below:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.13.2
name: nginx
resources: {}
status: {}
Nice way to save time, right?
Now, let’s start the deployment.
Manage Kubernetes Deployments using kubectl
Start nginx
deployment:
$ kubectl create -f app.yaml
After a little while, nginx
images are pulled and run.
$ kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 80s
Any pods involved? Of course.
Deployment spec
specifies container image nginx
pods run. In addition, it specifies the label nginx
pod will have: app: nginx
. Of course, deployment itself has the same label. Let’s see all Kubernetes objects having this label.
$ kubectl get all -l app=nginx
NAME READY STATUS RESTARTS AGE
pod/nginx-6d67674bb5-kq9jh 1/1 Running 0 3m22s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 3m22s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-6d67674bb5 1 1 1 3m22s
Noticed ReplicaSet
object? While we haven’t created it explicitly, creating deployment did. It’s because Kubernetes deployment uses ReplicaSets
to manage the pods. How does ReplicaSet know which pods to manage? Of course, it uses selector
which matches the label app: nginx
we specified in the deployment spec
.
Let’s scale nginx and see ReplicaSet in action.
Run kubectl scale deploy nginx --replicas 3
Note 3 pods which is desired number of replicas ReplicaSet maintains:
$ kubectl get all -l app=nginx
NAME READY STATUS RESTARTS AGE
pod/nginx-6d67674bb5-5g9nm 1/1 Running 0 12s
pod/nginx-6d67674bb5-kq9jh 1/1 Running 0 18m
pod/nginx-6d67674bb5-wfjtt 1/1 Running 0 12s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 3/3 3 3 18m
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-6d67674bb5 3 3 3 18m
Moreover, describing ReplicaSet shows us that indeed ReplicaSet-Controller created the pods after we scaled the deployment.
$ kubectl describe rs -l app=nginx
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 23m replicaset-controller Created pod: nginx-6d67674bb5-kq9jh
Normal SuccessfulCreate 4m34s replicaset-controller Created pod: nginx-6d67674bb5-5g9nm
Normal SuccessfulCreate 4m34s replicaset-controller Created pod: nginx-6d67674bb5-wfjtt
What if we want to access our highly available nginx
service. Of course, we can use kubectl port-forward
as we did in Kubernetes Pods Introduction:
$ kubectl port-forward deployment/nginx 8090:80
Navigating to http://localhost:8090/
will show nginx
welcome screen.
Is nginx
Kubernetes deployment load-balanced?
Not really.
To be sure, let’s open new terminal and run there:
$ minikube -p multinode-demo kubectl -- logs -f deployment/nginx
…
Found 3 pods, using pod/nginx-6d67674bb5-kq9jh
We see that only one pod pod/nginx-6d67674bb5-kq9jh
serves the traffic. And if you are not convinced, inspect the logs of the mentioned pod while doing a few refreshes in the browser.
$ minikube -p multinode-demo kubectl -- logs pod/nginx-6d67674bb5-kq9jh
You should see GET
requests there, while other pods` logs are empty.
So how to achieve load balancing between Kubernetes deployment pods? We’ll cover that in future posts when we talk about Kubernetes services and Ingress.
For cleaning up, let’s delete nginx
deployment:
$ kubectl delete deployment/nginx
You will see that deployment, ReplicaSet
and pods are gone:
$ kubectl get all -l app=nginx
No resources found in default namespace.
Finally, let’s stop our minikube
cluster.
minikube stop -p multinode-demo
Summary
That’s it about Kubernetes deployment. Stay tuned for more Kubernetes related posts. And, as always, feel free to share and comment.
Bonus:
Recommended Kubernetes courses on Pluralsight:
Sign up using this link to get exclusive discounts like 50% off your first month or 15% off an annual subscription)
Recommended Kubernetes books on Amazon:
You may find interesting below articles I wrote: