Delivering software consists of many activities besides writing the actual code. Even before a developer can start writing the code, there are usually a few steps to prepare and gather the necessary requirements. The software delivery process, however, is not done after all the necessary code is written. All the code that developers produce needs to be integrated and deployed. Without that integration and deployment process, it's just code, which doesn't do anything.
Back in the day, integrating and deploying the code was a painful, long, and manual process. People from different teams had to meet once a week or month or quarter to merge all the code, fix any ad-hoc issues, and finally deploy it to the production environment. Only after that, all the new code written in the last weeks or months could actually bring some business value. Nowadays we use (semi)automated continuous integration and continuous delivery/deployment systems (CI/CD) for that. In this post, you'll learn what CI/CD is, what its key components are, and how they work.
Benefits of CI/CD
Before we break down CI/CD into pieces, let's discuss what benefits it brings.
The main point of a well-designed CI/CD system is to deliver code faster and decrease time to get it on the market. With optimally written tests, you will be able to deploy multiple times a day, instead of once a week or month. At the same time, a good CI/CD system greatly improves the quality of the code. How? I'm glad you asked. First of all, CI/CD pipelines will automatically test all the new code before deploying it anywhere. Therefore, developers will be able to spot and fix the most obvious issues before deploying the code. Second, well-performing pipelines will encourage developers to follow good DevOps practices and commit their code more often, which helps to avoid merge conflicts.
Another important aspect is that people are often afraid of deploying to production, and good CI/CD can fix that. The better the CI/CD, the less risk for such deployments. People make mistakes and forget things. Automated CI/CD with well-designed testing won't make mistakes. It will help you spot bugs earlier and prevent you from deploying faulty code.
First, let's explain what CI and CD are.
Continuous Integration (CI)
CI is the process of merging the code, which the developer wrote to a centralized software version control system. This process makes sure that no one else made changes to the same part of code and that all the changes or new code don't create any conflicts with existing code.
Continuous Delivery/Continuous Deployment (CD)
CD is a bit more complicated. It can be in a form of continuous delivery or continuous deployment. Continuous delivery is a process of making the code "ready to be deployed." That means creating a software release (usually in the form of an artifact), testing it, and maybe preparing the infrastructure. Continuous deployment takes this one step further and actually deploys the code. It usually means that some extra steps need to be done, like attaching some configuration or reconfiguring load balancers.
What Does CI/CD Do?
Let's break down what needs to happen after a developer finishes writing new code.
All that code that's usually written on their machine needs to be pushed into a software version control system. From there, ideally, it should be tested first. If the code passes the tests, it can then be integrated into the main branch. Then another set of tests should be run. If all looks good, a new software release can be made. Depending on the language used, it can be a binary file, docker image, or other formats. Next, it should be deployed to some sort of non-production environment, and after another round of tests, it can be promoted (deployed) to a production environment.
All these tasks can be (semi)automated with a CI/CD system. You can define the so-called pipeline, which tells your CI/CD system what to do. The pipeline defines all the different steps, tests, and environments promotion. Most CI/CD systems nowadays provide UI interfaces so you can follow the process and see which stage of the deployment your pipeline is on.
CI/CD systems are very much personalized. Every company has different requirements and processes. Some steps depend on the programming languages and frameworks used. There are, however, a few key components that you'll find in every CI/CD pipeline. Let's discuss them.
The build phase is usually the one that starts the whole pipeline. Whenever the developer pushes the code to a repository, the build phase of CI/CD will be triggered. As mentioned in the previous section, the outcome of the build phase will depend on the languages and technologies used. Nevertheless, the successful completion of the build phase should result in a new software release being created.
The Test phase can happen a few times in the whole process. You can execute a different set of tests at the beginning and at the end of the pipeline. After the initial build phase, it's common to run unit tests on the newly created software release. This step will determine if written code does what it's supposed to do. Later in the process, you can run the test phase again to execute integration or any other tests. In fact, you can run the test phase after every other phase in the process.
Remember that one of the key points of CI/CD is to spot issues as soon as possible. Therefore, instead of running one test phase at the end of the pipeline with all possible tests, it's better to split them logically into smaller test phases. For example, there is no need to run integration tests if unit tests are failing.
The deploy phase can also happen multiple times in one pipeline. First, in a development environment, staging and production shouldn't happen at the same time, right? It's common to run basic tests first, then deploy to a staging environment, then run more tests and only then deploy to production.
Make Your Own
The three components described above are the most common ones. They are not the only ones, though. Depending on your needs, you may create other steps in the pipeline. For example, if you need a very high level of security, you can include a step that will scan the code for security issues. If you need specific infrastructure, you can provision whole clusters as part of the CI/CD pipeline. You can also create additional reports or other files. The possibilities are endless.
CI/CD Building Blocks
In the previous section, we explained the basic CI/CD building blocks. You could use the three of them to create a basic build > test > deploy pipeline. In real life, however, you can mix and match them to create a more complex system. In fact, you can use all of them multiple times to create a bulletproof deployment process.
It resembles building modern software in general—many smaller pieces are better than one big monolith. If you squish all the tasks that need to happen in your pipeline into three steps, then you'll probably end up with a system that takes a lot of time to provide some feedback. To remind you once again, the sooner the developer gets some feedback, the better. If your pipeline provides the first passed/failed results after 10 minutes, then developers will push the code less often to not waste time waiting for the build to complete. On the other hand, if you split one big phase into a few smaller pieces, the first passed/failed status will be seen after just a few seconds or minutes.
Nowadays, CI/CD systems are a very crucial part of the infrastructure. The quality of your CI/CD pipeline will directly impact the performance of your developers. No one likes to wait too long for the CI/CD to finish. Well-designed pipelines, on the other hand, will encourage developers to follow good DevOps practices and push code more often. Moreover, the more feedback they'll get, the better understanding they'll have of the whole platform. This will allow developers to improve the overall quality of the code. If you want to know more about creating a successful CI/CD pipeline, read this blog post.