by Dmitry Krasnov
Software development practices evolve day by day. Around 10 years ago many companies were using monolith application, deploying and testing them manually. Today microservice architecture is becoming the industry standard along with orchestration tools and CI/CD practices. Then there is a question, which tool to choose? You can think of every tool as a lego. There are hundreds of the lego pieces and we have to select the correct ones and make a scalable and manageable stack.
Let’s imagine we have a small company developing a SaaS solution. It is advised that in the early stages of your application you shouldn’t try to apply all best practices at once, like microservices, event sourcing, Kubernetes or other advanced level stuff. But it doesn’t mean you have to implement a monolith app. You have to design your application with an idea that you will convert it to small microservices at some point.
Before selecting a tool or a platform you should outline your workflow and decide about your environments. Start with asking yourself the following questions:
- Do you want to deploy your applications in the cloud?
- Are you going to release your apps frequently?
- Do you want to make automation end to end?
- Do you want to use orchestration tools?
- Do you want to use Chat/Ops? Like do you want to deploy from your slackbot.
If you have answered ‘yes’ to at least several of the questions, you should think about adopting CI/CD practices.
CI/CD Workflow in Kubernetes and ‘the traditional way’
In general, CI/CD consists of several automated steps: code integration, builds, tests and deployment to production. Ideally, it looks as follows: push and get the result. However, the process is different depending on the environment.
We can think of 3 approaches — traditional one, deployment with Docker and deployment with Kubernetes. In all three cases we have to create builds/images, test and deploy applications. However, their approach to the last stage is a little different.
Deploying the ‘traditional’ way
Let’s say we have a single machine with Tomcat. In order to deploy a new version of the app, we have to replace existing
war file or stop tomcat — replace
war file — start tomcat. We can’t but allow for some downtime during the operation, which makes the system not highly available. If the machine crashes, our whole production system might go down. If we have multiple machines then we have to repeat the process for each machine.
Deploying using only Docker
Now let’s assume that we use docker without orchestration. We have a docker container that runs in the cloud (say, AWS EC2). Before deploying a new image, we push it to a registry. Then we stop the running container and instantly pull & deploy a new one. Needless to say, the service will be unavailable for some time.
Docker has its own orchestration tool, docker compose. If you use docker-compose, you can deploy in rolling update manner. But compared to Kubernetes Docker compose has limited functionality. It cant’t orchestrate machines and ensure high availability.
Deploying with Kubernetes
In Kubernetes, deployment process looks as follows: after you push an image and update the deployment, Kubernetes will create a pod with a new version. After it is up, the old pod will be deleted. The service will be available throughout the whole process.
If you use Kubernetes you will most likely have more than one microservice. In case of a more traditional approach this would mean quite a lot of downtime since you have to manually update many applications. With Kubernetes the services will always be available regardless of deployment frequency, even if the deployment process fails.
Kubernetes and GitOps
Kubernetes allows easy transition to GitOps. This approach means you don’t touch anything in your system. If you want to deploy a new release you just push code to your git repository, and your CI/CD pipeline automatically triggers and deploy the new version. This is what I call the ‘true’ CI/CD which aims at automating everything that can be automated.
The advantage of GitOps is that you always know which version is deployed in your system. If you have a lot of microservices, you can easily track their versions.
Things to consider before adopting CI/CD?
Kubernetes — do I need it?
Kubernetes has become very popular, but it doesn’t mean you have to use it from day one. If you are a small startup and your immediate aim is to develop a minimum product, Kubernetes can wait. However, if you already need to scale, use microservice orchestration, and you have some experience with Kubernetes, you should not postpone its adoption.
Aim at simplicity
CI/CD process must be simple, so you should select tools that are compatible with your workflow. For example, if you use Kubernetes as an orchestrator you should consider GitLab for CI/CD. It natively supports Kubernetes and works with multiple clusters.
Everything as Code
Be prepared to describe all operations throughout all levels as code. In Jenkins you will have to write a Jenkinsfile, in Gitlab it is gitlab-ci.yml, etc. As with any code, you should be consistent, otherwise you won’t be able to understand your CI/CD forkflow after some time.
You can also use Terraform or CloudFormation to describe and build your Infrastructure as Code.
Some popular CI/CD tools
Now let’s look at some of the most popular CI/CD tools for small and medium/large projects.
Early Stages — Startups
Startups usually don’t have time to implement CI/CD best practices from the very beginning. Their first and foremost objective is to focus on the basic product features. In this case rather that doing zero DevOps they can use simpler tools which do not require much configuration but help save time and prepare the team for full-scale DevOps adoption.
Travis is one of the easiest-to-configure tools. You can easily connect it to your GitHub repositories and start working on the projects. It is a cloud based solution so you don’t have to worry about availability — basically it is always there. Also, it is free for open source projects.
Just as Travis, Circle is a ‘log-in-via-GitHub-and-work’ kind of solution. Circle-CI has a very friendly UI for managing builds/jobs. It also supports many alerting options, so you can easily get notification via Slack, email, etc. In a nutshell, it is an easy and useful tool for early stage projects.
After you have a ready MVP and can concentrate on new features, it’s time to move on to more advanced tools with flexible configuration and customization capabilities like Jenkins, GitLab, and TeamCity.
Jenkins is a tool popular for its wide range of plugins and advanced features. It is not the easiest tools to configure, and if you use open source plugins, their performance is not guaranteed (which is OK for open source). If you are looking for a more stable solution, the commercial version is available as CloudBees.
GitLab is a CI tool and a repository in one product. You can trigger your builds for each commit, merge request etc. without third-party plugins. Besides, it is easily integrated with Kubernetes clusters.
Unlike the two previous tools, TeamCity is not an open source project. Free version is restricted to three build agents. Support is also available on commercial basis. However, teams often choose TeamCity due to the ease of installation and configuration as well as for a good number of features out of the box.
There is no exact set of tools that is suitable for every use case. You should first define your objectives and budget, then decide about short and long term tools and practices you want to adopt. But there are some basic principles that apply to every project. Everything as Code is one of them. If you write your whole Infrastructure as Code then it will be very easy to spin up a new environment.
Microservices, CI/CD and Kubernetes have allowed us to solve a lot of problems that we used to deal with earlier. Even if you don’t feel like adopting the technologies right now, make it your priority in the nearest future. We all know how difficult it is to overcome technological gaps.