So far I’ve been deploying all my applications on VMs directly using provisioning tools (Ansible) or for simpler applications deployment scripts (like Python’s Fabric). In case of applications running on AWS, I was leveraging a potential of using AMI images for EC2 instances to speed up new instance creation within AutoScaling groups. Although that way of deploying apps proved to be very reliable, running for years in production with no issues, I was looking for some ways to make deployments even more unified across all projects in the organization. Docker turns out to be a good candidate to fulfill such requirements, it defines a deployment unit - container, which is built and always launched in the same way regardless of the app inside, whether it’s Python, Node.js or Java application, the process of running container doesn’t change.
Docker itself wouldn’t be sufficient to provide fully automated environment with safe blue/green deployments, monitoring, replacing containers that are failing, load balancing and more. There are a few tools in the market that offer such capabilities: Kubernetes, Docker Swarm, Mesos + Marathon, AWS ECS. In this post I will focus on explaining how Kubernetes works and what value it brings in managing the infrastructure through Docker containers.
Kubernetes basic concepts
Before diving into managing Kubernetes cluster with a command-line tool
kubectl, I would like to explain some basic objects.
Pod - simplest Kubernetes object, defines a process running in the cluster, it wraps one or more (if they are co-located and need to share the same resources) Docker containers
Service - defines access policy to the Pods, so how to make a logical group of Pods available to other pods and possibly external network
Deployment - declarative definition for the application, mainly informs the cluster how many replicas of a given Pod should be running, which version of the Docker image should be used, how much resources should be assigned. When executing a deployment definition, Kubernetes handles the whole process of creating, updating and deleting Pods automatically.
There are many more objects in Kubernetes, but I purposefully skipped more advanced parts to show the minimal setup to deploy an application inside the cluster.
Our application for deployment
To keep it simple, I will deploy the “Hello World” Python application (the code and all configuration files are available on GitHub)
We can now build the image:
docker build -t docker-kubernetes:0.0.1 .
and then run our container to see if it works as expected
docker run -p 5000:5000 -it docker-kubernetes:0.0.1
We expect to see:
Installing Kubernetes locally
kubectl first, which is a command-line tool for managing Kubernetes cluster - scheduling deployments, creating services, listing running services, etc.
$ minikube start --vm-driver=virtualbox
To verify that minikube has created a cluster correctly, run
$ minikube ip
they both should show the same ip address, meaning kubectl is correctly configured to send requests to Kubernetes API.
First Pod and Service
Kubernetes cluster can be configured with yaml configuration files, that specify all the details about deployments. To see our application in action we will need to create 2 Kubernetes objects: Pod and Service. Let’s start with Pod.
metadata.name to be our deployment’s name, we will need to provide it every time we want to check or change something in our configuration.
spec.replicas defines how many pods should be running in the cluster, in our case it translates directly to 2 containers with codeidea/docker-kubernetes:0.0.1 image.
Deployment configuration example:
Deploying selected image on containers is as simple as executing one command with the configuration file passed as an argument.
$ kubectl apply -f pod.yml
You should see the following output after executing
kubectl get pods:
The last step is to expose our Pods as a Service, we need to prepare a similar yaml configuration:
Remember about executing that config with:
kubectl apply -f service.yml
In this case we expose port
5000 from our VM running Kubernetes cluster, there are other options as well, I will cover them in other posts.
That’s it, we have our first application running on Kubernetes.
Updating code with no downtime
When we’ve got our application running on Kubernetes cluster, now it’s essential to keep it running without any disruptions,
even while updating the containers. Unfortunately the basic configuration that was provided earlier is not sufficient to support zero-downtime deployments. It can be easily checked by running
ab (Apache Benchmark) against our endpoint and updating the container’s image while
ab is running.
We have 2 possible ways of updating container’s image:
1) Updating image in yaml file with the configuration of our Pod and executing
kubectl apply -f pod.yml
kubectl set image deployment/docker-kubernetes docker-kubernetes=codeidea/docker-kubernetes:0.0.2
If we do it while performing a benchmark test, at the time when containers are being replaced we will see an error:
Requests are failing, because for a brief moment application is not running on any of the containers, but Service is still accepting requests.
It takes some time to initialize the application, so we need to check if the container is running the application first, before we can accept any traffic. We will need to set up
readinessProbe which is used to check, when Container is ready for accepting traffic.
initialDelaySeconds - configures how much time should pass before performing the first check
periodSeconds - defines interval at which the probe should be performed
After updating deployment configuration with
kubectl apply -f pod.yml, we can perform our test again (run
ab and replace the image in the meanwhile), this time there is no downtime during deployment as expected:
It’s fairly easy to start deploying application to Kubernetes. We define our deployments as yaml configuration files, Kubernetes handles container creation for us and with the right config offers zero-downtime deployments. Of course it was just an example of local single-node cluster and there is much more work involved in managing production cluster, but those first step already show that Kubernetes is a very promising solution for managing container-based infrastructure. In the next articles, I will try to cover other important aspects of running Kubernetes cluster: monitoring, alerting, logging, adding more nodes, load balancing and finally deploying and managing production cluster in automated way on AWS.