Understanding Basic Kubernetes Concepts II - Using Deployments To Manage Your Services Declaratively
• Jun 29, 2016
This post is the second in a series of blog posts about basic Kubernetes concepts. In the first one I explained the concepts of Pods, Labels, and Replica Sets. In this post we will talk about Deployments. The third post explains the Services concept and in the forth we look at Secrets and ConfigMaps. In the fifth and final post we talk about Daemon Sets and Jobs.
As you might have heard (or read) me saying before, in the Kubernetes community it is sometimes hard to find the best way to do things. On the service/app deployment side of things, this results in for example people deploying their containers manually with pods and then adding replication controllers on top to keep them alive and scale them and then at some point using
kubectl rolling-update to do updates. This is at least in parts an imperative form of managing software. It usually involves manual work/commands and can be pretty opaque if you work in a team.
Therefore, the declarative Deployment object was added in Kubernetes 1.2. However, looking around there’s very few resources mentioning it and why you should use it. Sure, it is included in the official docs and there was a nice blog post about it on April 1st (maybe people thought it was a joke), but I don’t see many people using it and even less explicitly mentioning it in their blog posts and examples. So I thought of writing a little piece on why I think you should use deployments.
Sidenote: As of this writing usually system services or addons (e.g. DNS, Dashboard, Metrics) on most Kubernetes installs out there are still deployed with replication controllers, but some official addons are already being moved to deployments. Monitoring has done the move already and we merged a PR just a few days ago that moves Dashboard to deployments. On Giant Swarm all of these system services are already running as deployments.
The Declarative vs. The Imperative Way
The main argument for Deployments is a general one between the declarative and the imperative way of deploying and managing software. It applies not only on the application-level, but also on the infrastructure-level (but that’s for another post to contemplate). Note: If you are already convinced that declarative management is the way to go you can skip this chapter and jump directly into the Kubernetes Deployments concept further below.
The Imperative Way
The imperative way is usually the one you use to try out things and get to a working system. You manually tweak it and at some point it is to your liking. However, if you keep on using this imperative style for deploying and managing your software you will encounter several problems (even if you automate the steps).
- If you want to know what has been last deployed, you can only resort to checking the currently deployed version, which is not necessarily what was planned to be deployed.
- If you change something manually, someone else might overwrite your changes or they might get reverted. For example because you only started new pods manually and didn’t change the replication controller.
- Keeping track of how a service has developed over time is hard and needs to be documented somewhere separately. This is especially important when working in teams.
- You need several commands to get one service to the desired state. Even if these steps get automated, they might lead to different outcomes when run in different environments.
The Declarative Way
The declarative way on the other hand, is what you should come up with once you go into actually deploying and managing your software in production or integrating with continuous delivery pipelines. You might have tried out stuff the imperative way before, but once you know how it should look like, you sit down and “make it official” by writing it into a declarative definition. This avoids the above-mentioned problems and even brings some added benefits.
- It makes you think and plan how you want things to look once they are running (plan the state).
- It describes the way things should look like when running and not the steps that are needed to get there (define the desired state not the process).
- Changes can be easily documented by keeping track of (or versioning) the declarative definition, which makes work and communication in teams easier (but is also a good/clean approach for single devs).
Deployments in Kubernetes
As mentioned above the deployments resource is pretty new and still not widely-used. However, for now it is the best primitive we have for deploying and managing our software in Kubernetes, so it is important to understand what it does and what you can use it for.
Before deployments, there were replication controllers, which managed pods and ensured a certain number of them were running. Now with deployments we move to replica sets, which are basically the next-generation of replication controllers. Only this time we don’t manage them, but they get managed by the deployments we define. Thus, the chain is like following: Deployment -> Replica Set -> Pod(s). And we only have to take care of the first.
Additional to what replication controllers (or replica sets) offer, deployments give you declarative control over the update strategy used for the deployment. This replaces the old
kubectl rolling-update way of updating, but offers the same flexibility in terms of defining
maxUnavailable, i.e. how many additional and how many unavailable pods are allowed. Defining this in a deployment enables you to “spec once use many times”, which helps even more when working in teams or managing a multitude of deployments.
Deployments manage your updates for you. They even go as far as to check whether or not a new revision that is being rolled out is working and stop the rollout in case it is not.
You can additionally define a wait time (
minReadySeconds) that a pod needs to be ready without any of its containers crashing before a pod is considered available, which again helps against “bad updates” and gives certain containers a bit more time to get ready for traffic.
You can further use the update/revision functionality of deployments to concurrently deploy multiple revisions of a deployment. This enables blue/green deployments or canary release strategies.
Furthermore, deployments keep a history of their revisions, which is used in rollback situations, as well as an event log, which you can use to audit releases and changes to your deployment.
Getting Started With Deployments
Reading about all the cool stuff you can do with deployments, you might want to check it out yourself.
As deployments (and their replica sets) are a kind of successor to replication controllers, it is quite easy to change replication controllers that you already have to deployments. You only have to change:
apiVersion: v1 kind: ReplicationController
apiVersion: extensions/v1beta1 kind: Deployment
and add a line containing
matchLabels: after the
selector: line (before the actual selectors, do not forget to fix indentation), because the deployments resource supports set-based label requirements.
This should give you a workable deployment. As deployments feature more functionality than their predecessor, there are additional fields that you have not defined, yet. Luckily, these fields get filled automatically on creation with defaults.
However, as we learned above this might result in different outcomes when deployed to different clusters. Sometimes this might be intended, but if not you could look at what you got when applying that deployment to your cluster with
kubectl edit deployment <deployment name> and then copy (part of) that back into your manifest.
The right way, however, would be actually learning the correct usage of deployments by reading up on it in the official documentation on deployments and then writing a manifest that works well for you. (You can still start with “translating” your existing replication controller manifests). The Kubernetes blog post from April is also a good read and shows the way updates and rollbacks work with a nice example.
Have fun exploring deployments and look out for the next basic concepts post soon!