Deployment
This tutorial goes through the deployment of a simple "Hello World" app, and explains what each resource means.
Before you can continue with this tutorial, make sure you have access to your training cluster and that you're familiar with running Pods in Kubernetes.
A fleet of Pods using a Deployment
Whenever you want to have long-running, stateless apps in Kubernetes, you should use a Deployment. It makes sure that you always have a specific number of your application containers running at all times. It can also manage upgrades to your apps gracefully. They're the primary way to run long-running services in Kubernetes.
Let's create a YAML manifest named demo-deployment.yaml
with the following contents:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
labels:
app: demo
spec:
replicas: 2
selector:
matchLabels:
app: demo-pod
template:
metadata:
labels:
app: demo-pod
spec:
containers:
- image: nginxinc/nginx-unprivileged
name: nginx
ports:
- containerPort: 8080
In this YAML document:
- The
apiVersion
is nowapps/v1
. This is distinct toDeployment
kind. - We have a
spec.template
section, which describes the kind of Pod the deployment should create. Thetemplate
matches the Pod YAML document we created earlier except for thenamespace
andname
fields. - The
spec.replicas
field tells us how many instances of the Pod we should have running at the same time. We can also set this to any number including1
to run a single Pod or even0
to run no Pods at all. - The
spec.selector
field is used for querying for Pods that the Deployment should manage. Normally, you should set thematchLabels
section to match the Pod labels in thetemplate
section. This way the Deployment will know how many replicas it has and which Pods it can shut down. As mentioned before, you can use any labels you want, but make sure the labels don't overlap with Pods that already exist in the same namespace. The labels for the Pod doesn't have to match the labels for the Deployment (i.e.metadata.labels.app
).
Let's create the deployment in Kubernetes:
$ kubectl apply -f demo-deployment.yaml
deployment/demo created
Warning
Deployments are only meant for stateless applications: i.e. the ones that don't store any state on a disk or memory. In the future training sections, we'll learn how to manage stateful applications in Kubernetes.
Examining the deployment
We can use the kubectl rollout
command to check the status of our deployment:
$ kubectl rollout status deployment demo
deployment "demo" successfully rolled out
Note that using kubectl rollout
status is required to check that the Pods were rolled out correctly.
The response from kubectl apply
alone doesn't guarantee this.
We can see that the deployment did indeed create Pods for us:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
demo-pod-79cc4b689c-qrcbn 1/1 Running 0 2m22s
demo-pod-79cc4b689c-xpmn5 1/1 Running 0 2m22s
We can also use get
and describe
to get more information on the Deployment itself:
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
demo 2/2 2 2 5m9s
$ kubectl describe deployment
Name: demo
Namespace: tutorial
CreationTimestamp: Thu, 17 Oct 2019 10:01:22 +0300
Labels: app=demo
...
Scaling up and down
Right now, we should have two Pods running for our demo app.
We can bring in more or delete existing Pods by tuning the replicas count.
To do this, we can edit the demo-deployment.yaml
file we created earlier, change the number of replicas
, and use kubectl apply
to update the deployment.
Kubernetes will then create or delete Pods accordingly.
Alternatively, we can use kubectl scale
command to perform the same thing directly from the command-line.
Let's scale our deployment to 3 Pods:
$ kubectl scale deployment demo --replicas=3
demo deployment.apps/demo scaled
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-pod-79cc4b689c-qrcbn 1/1 Running 0 16m
demo-pod-79cc4b689c-wvv55 1/1 Running 0 20s
demo-pod-79cc4b689c-xpmn5 1/1 Running 0 16m
The downside of using kubectl scale
compared to kubectl apply
is that any local configuration you have is no longer in sync with what Kubernetes has.
Note that trying to delete any of the Pods manually without changing the Deployment, Kubernetes will automatically create a new Pod to replace it.
$ kubectl delete pod demo-79cc4b689c-qrcbn
pod "demo-79cc4b689c-qrcbn" deleted
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-pod-79cc4b689c-wvv55 1/1 Running 0 3m4s
demo-pod-79cc4b689c-xgrrp 1/1 Running 0 11s
demo-pod-79cc4b689c-xpmn5 1/1 Running 0 19m
Safely rolling out changes
Updating your application or the configuration of the application is a normal routine to go through. Deployments in Kubernetes include constructs that support zero-downtime upgrades for your application.
Let's edit the demo-deployment.yaml
to add more details:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
labels:
app: demo
spec:
replicas: 3
progressDeadlineSeconds: 20
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: demo-pod
template:
metadata:
labels:
app: demo-pod
spec:
containers:
- image: nginxinc/nginx-unprivileged
name: nginx
ports:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
successThreshold: 1
httpGet:
path: /
port: 8080
We added three new things to the YAML:
progressDeadlineSeconds
: The maximum number of seconds Kubernetes will wait per Pod until it considers the deployment a failure.strategy
: This determines the strategy for updating Pods when updating the deployment. In this case, we selectRollingUpdate
, which means that Kubernetes will gradually launch updated Pods and take out old Pods. UsingmaxSurge: 1
andmaxUnavailable: 0
setting means that Kubernetes will launch at most one Pod at a time, and doesn't take out any Pods unless there's extra Pods running.readinessProbe
: This is the key element for deciding whether a Pod is ready or not. Kubernetes uses the probe method to continuously "ask", if the Pod is ready or not. Typically, you have a health endpoint in your application that responds200 OK
when it considers itself ready. In this case, Kubernetes polls the root path of the NGINX container for health.
You can also configure a liveness probe that will determine whether the Pod needs to be restarted or not. Normally, you'd want to use both, but the readiness probe should enough for the purpose of this example.
Let's update the deployment and check that it was rolled out correctly.
$ kubectl apply -f demo-deployment.yaml
deployment.apps/demo configured
$ kubectl rollout status deployment demo
deployment "demo" successfully rolled out
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
demo-pod-7f6597f97c-676g7 1/1 Running 0 58s
demo-pod-7f6597f97c-xwqxk 1/1 Running 0 49s
demo-pod-7f6597f97c-zgvs2 1/1 Running 0 39s
Great! Our deployment was rolled out successfully.
Let's try breaking the deployment to see how the deployment status changes. First, let's change the readiness probe HTTP path to something we know doesn't exist in the file demo-deployment.yaml
.
...
httpGet:
path: /does-not-exist
port: 8080
...
Let's apply the change and check how the deployment behaves:
$ kubectl apply -f demo-deployment.yaml
deployment.apps/demo configured
$ kubectl rollout status deployment demo
Waiting for deployment "demo" rollout to finish: 1 old replicas are pending termination...
error: deployment "demo" exceeded its progress deadline
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-pod-7f6597f97c-676g7 1/1 Running 0 2m6s
demo-pod-7f6597f97c-xwqxk 1/1 Running 0 117s
demo-pod-7f6597f97c-zgvs2 1/1 Running 0 107s
demo-pod-847df79d7d-hnb7j 0/1 Running 0 36s
As we can see from the output, the deployment change was applied successfully, but the rollout failed. When the rollout fails, we can see that there's one new Pod that was created, but not ready. The rest of the Pods are the old ones that were still kept available. If we apply a fixed version of the deployment manifest, we can get rid of the failed Pod.
The right way to get back to a working state is to use the deployment rollback feature. First, let's figure out the revision we want to get back to:
$ kubectl rollout history deployment demo
deployment.apps/demo
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
We have three revisions of the deployment as expected. The last one is the one that failed, so let's roll back to revision 2.
$ kubectl rollout undo deployment demo --to-revision=2
deployment.extensions/demo
$ kubectl rollout status deployment demo
deployment "demo" successfully rolled out
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
demo-pod-7f6597f97c-676g7 1/1 Running 0 17m
demo-pod-7f6597f97c-xwqxk 1/1 Running 0 17m
demo-pod-7f6597f97c-zgvs2 1/1 Running 0 16m
We can see that the old Pods still remain.
Note
Do not delete the Deployment, we will be using it later.
Next
In the next section, we'll learn how to configure our applications in Kubernetes.