Deployments
Related Videos
Deployments Part 1
Deployments Part 2
Deployments Part 3
Deployments Part 4
Deployments Part 5
Deployments Part 6
Deployments Part 7
The Kubernetes Deployment resource is designed to support the continuos delivery of application releases beyond the abilities of Pods and ReplicaSets.
Using a Deployment, the deployment process is controlled by a deployment controller running within the Kubernetes cluster.
Creating the First Deployment
Create the first deployment by deploying the application version "blue".
Create a file 20-deployment-blue.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-gamma
labels:
app: app-gamma
spec:
selector:
matchLabels:
run: app-gamma
replicas: 1
template:
metadata:
labels:
run: app-gamma
spec:
containers:
- name: app-gamma-blue
image: fischerjulian/smpl-go-web:blue
ports:
- containerPort: 8080
Apply it:
kubectl create -f 20-deployment-blue.yaml
Verify the deployment has been successful:
kubectl get deployments
It's also worth having a look at the list of ReplicaSets:
kubectl get replicasets
You should also find a ReplicaSet blue as a Kubernetes Deployment internally creates a ReplicaSet which in turn creates one or more Pods creating one or more containers. So it's no surprise to find blue Pods:
kubectl get pods
Now in order to access the application we also have to create a service and an ingress again, just like we did in the ReplicaSet lesson.
Create a file 40-service.yaml
:
apiVersion: v1
kind: Service
metadata:
name: app-gamma-service
spec:
selector:
run: app-gamma
ports:
- port: 8080
Apply it:
kubectl apply -f 40-service.yaml
Create a file 50-ingress.yaml
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-gamma-ingress
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: 'nginx'
spec:
tls:
- hosts:
- myapp.example.org
secretName: k9s-anynines-com-tls
rules:
- host: myapp.example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-gamma-service
port:
number: 8080
Apply it:
kubectl apply -f 50-ingress.yaml
Obtain the URL with:
kubectl get ingresses
Browse to the URL or use
curl --insecure https://myapp.example.org
and it should say "I am blue".
Note : We are reusing the DNS entry in
/etc/hosts
so make sure it is still there and valid.
Scaling the Deployment
So far we have declared the desired state of our resources such as ReplicaSets, Services and Deployments using YAML files and applied them use kubectl apply -f <filename>
. So this is what we will try again. A copy of the file 20-deployment-blue.yaml
with an increased replicas
setting can be found in 60-deployment-blue-scale-out.yaml
. All it does is to set replicas: 2
indicating we desire two application instances to be running.
So let's give it a try!
Create a file 60-deployment-blue-scale-out.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-gamma
labels:
app: app-gamma
spec:
selector:
matchLabels:
run: app-gamma
replicas: 2
template:
metadata:
labels:
run: app-gamma
spec:
containers:
- name: app-gamma-blue
image: fischerjulian/smpl-go-web:blue
ports:
- containerPort: 8080
Apply it:
kubectl apply -f 60-deployment-blue-scale-out.yaml
And you will see the following error message:
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply deployment.extensions/app-gamma configured
Try the following command instead:
kubectl replace -f 60-deployment-blue-scale-out.yaml --save-config
This overwrites the existing spec stored in the Kubernetes cluster with the newly provided one. See [1] for more details on this.
Once --save-config
has been used, subsequent updates can be performed using kubectl apply -f
again.
Exercise
Change the replica count to 3 and update your deployment using kubectl apply -f
. Did it work?
Updating the Deployment with a new Application Version
A successful real world application is likely to be under constant development. Subsequently, the application team has to deploy new software versions regularly.
The new software version is delivered by creating a new container version. Compare the YAML file 70-deployment-green.yaml
with the previous version and look for differences. You will see that the container name and container image (tag) have changed. Hence, the team had to build a new container version and upload it to the default container registry of the Kubernetes cluster which is https://hub.docker.com/, by default.
Create a file 70-deployment-green.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-gamma
labels:
app: app-gamma
spec:
selector:
matchLabels:
run: app-gamma
replicas: 2
template:
metadata:
labels:
run: app-gamma
spec:
containers:
- name: app-gamma-green
image: fischerjulian/smpl-go-web:green
ports:
- containerPort: 8080
Perform the update:
kubectl apply -f 70-deployment-green.yaml
Try running the following command directly after running the update:
kubectl describe deployment app-gamma
You should see that the fields OldReplicaSets
and NewReplicaSet
both have a value, e.g. app-gamma-7464575685
and app-gamma-75457966b7
.
After the deployment has been completed successfully this will be different: OldReplicaSets: <none>
. This also tells how the rollout works: by replacing underlying ReplicaSets. At this point it becomes clear what the added value of a Deployment is. Deployments stay, ReplicaSets come and go. The Deployment provides a Kubernetes entity that allows you to manage the lifecycle of an application across application versions each represented by a dedicated ReplicaSet.
The status of a rollout can be retrieved by executing:
kubectl rollout status deployments app-gamma
Which will provide you with a brief success message such as deployment "app-gamma" successfully rolled out
.
Reloading the app in your browser should now tell you "I am green."
.
Note, if you reload your browser repeatedly you may see both blue and green application versions alternating. This is due to the default Deployment Strategy which will be covered later in detail.
Controlling a Rollout
More control is offered with commands such as
kubectl rollout pause deployments app-gamma
and
kubectl rollout resume deployments app-gamma
which become handy if the rollout produces unpredicted behavior, for example.
Rollout History
Deployments also collect metadata on which rollouts have been performed in the past:
kubectl rollout history deployment app-gamma
This allows you to dig into a particular revision:
kubectl rollout history deployment app-gamma --revision 1
And provides you information about the structure and annotation of the ReplicaSet corresponding to the given revision.
Ups, Kaputt! Undoing a Rollout
While it is possible to pause and resume a rollout, sometimes it may be necessary to undo it. Undoing a rollout is another major advantage of using a Deployment over plain ReplicaSets. As the Deployment knows which ReplicaSets have been representing previous versions it's easy to bring them back to "life".
kubectl rollout undo deployments app-gamma
And the browser should turn from the "green" back to the "blue" version.
While the rollout undo
option does the trick of going back to the last rollout, it has a bad taste to it. The command modifies the live Kubernetes objects without reflecting this in our local YAML files.
The preferable alternative would be to deploy the "green" version by applying it's original YAML file and thus creating another rollout instead of a rollback.
kubectl apply -f 20-deployment-blue.yaml
Check the status of the deployment:
kubectl rollout status deployments app-gamma
Tidying Up - Part 1 of 2
Remove the Deployment:
kubectl delete -f 20-deployment-blue.yaml
Deployment Strategies
The deployment strategy determines how the Kubernetes deployment controller starts and stops ReplicaSets during an application rollout.
Two strategies are provided by default:
- Recreate
- RollingUpgrade
Recreate Strategy
The Recreate strategy is straight forward. The existing ReplicaSet with all its belonging Pods is destroyed and only after the termination of the last Pod, Pods of the new ReplicaSet will be started.
For this reason the Recreate
-strategy is not recommended for productive use. However, there are cases where this strategy makes sense. For example, if avoiding the coexistence of two application version is necessary.
Create a first deployment with a file 80-deployment-blue-recreate.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-gamma
labels:
app: app-gamma
spec:
selector:
matchLabels:
run: app-gamma
replicas: 2
strategy:
type: Recreate
template:
metadata:
labels:
run: app-gamma
spec:
containers:
- name: app-gamma-blue
image: fischerjulian/smpl-go-web:blue
ports:
- containerPort: 8080
Apply it:
kubectl create -f 80-deployment-blue-recreate.yaml --save-config
Update the deployment by creating a file 90-deployment-green-recreate.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-gamma
labels:
app: app-gamma
spec:
selector:
matchLabels:
run: app-gamma
replicas: 2
strategy:
type: Recreate
template:
metadata:
labels:
run: app-gamma
spec:
containers:
- name: app-gamma-green
image: fischerjulian/smpl-go-web:green
ports:
- containerPort: 8080
And apply it:
kubectl apply -f 90-deployment-green-recreate.yaml
The complete termination of all Pods of one ReplicaSet before creating the new ReplicaSet with new Pods leads to a downtime of the application during the deployment. This is the case even when the number of replicas is set to a value greater than 1. You can find a great illustration of the Recreate deployment strategy here.
RollingUpdate Strategy
The RollingUpdate strategy terminates a number of Pods from the old (blue) ReplicaSet and start a number of new Pods with the new version (green). So gradually the new application version is rolled out.
Be aware: The gradual or "rolling" update means that Pods of both the old (blue) and new (green) versions are being served traffic simultaneously. This implies that two adjacent application versions need to coexist peacefully. If the new (green) version requires a different database schema, for example, this may become problematic as a schema migration can either be executed or not. The application therefore should be architected in a way that schema migrations happen gradually over multiple versions while maintaining compatibility among adjacent versions.
Engineers must decide yourself whether the increased application availability is worth the increased effort in development.
Other Strategies
There are many more possible deployment patterns. They do not represent strategies in the sense that they can be pasted as a strategy: <my-strategy>
into the deployment specification but rather represent higher level methodologies on how to perform a rollout [3][4]. This includes patterns such as blue-green and canary deployments.
Tidying Up - Part 2 of 2
All resources of this lesson can be deleted:
kubectl delete deployment app-gamma
kubectl delete -f 50-ingress.yaml
kubectl delete -f 40-service.yaml
You can also now remove your local DNS entry, by removing it from /etc/hosts
with
sudo nano /etc/hosts
Links
- Kubernetes Documentation, Concepts, Working With Objects, https://kubernetes.io/docs/concepts/overview/working-with-objects/object-management/
- Kubernetes Up & Running, 2nd Edition, O'Reilly, 2019, https://learning.oreilly.com/library/view/kubernetes-up-and/9781492046523/
- Deployment Strategies, ContainerSolutions, https://blog.container-solutions.com/kubernetes-deployment-strategies
- Kubernetes Patterns, O'Reilly, 2019, https://learning.oreilly.com/library/view/kubernetes-patterns/9781492050278/