Continuous integration/continuous delivery (CI/CD) is a modern approach to managing the entire life cycle of writing, updating, and delivering applications. The agile and lightweight design of NGINX and NGINX Plus makes them extremely useful tools in support of many parts of a CI/CD platform.
With CI/CD, everything from bug fixes to major feature changes are delivered to users on an ongoing basis. Different parts of an app can use different programming languages, different database schemas, and different development and release schedules.
CI/CD is part of a group of related practices, each of which supports the others:
- The use of tools such as Bamboo and Jenkins for continuous integration
- The use of Git or similar tools for flexible source code control
- The use of containers for development, test, and production
- The use of container management systems such as Kubernetes and Mesosphere for development, test, and production
- The move to microservices for development and deployment
- NGINX, deployed as a reverse proxy server and web server
- Underlying everything else, the use of an agile approach to the management of software development and related disciplines
The byword of CI/CD is automation – the key factor that enables both integration and delivery to be continuous. Once code is solid, the goal is to eliminate the need for human intervention between the submission of code for integration and the delivery of the same code into the production environment.
The Growth of CI/CD
In a recent NGINX survey, roughly two‑thirds of organizations reported researching or implementing containers, CI/CD, or both. These changes are also associated with both NGINX software and the move to the cloud. More than 40% of AWS deployments use NGINX, and the NGINX Docker image is the #1 downloaded application image on Docker Hub.
NGINX handles proxying, load balancing, container management, and support for microservices. At the same time, NGINX provides portability across containers, virtual machines, different cloud platforms, and bare metal.
NGINX Plus features other advantages relevant to CI/CD. Both real‑time resolution of DNS
SRV records and the NGINX Plus API for dynamic configuration fo upstrem groups eliminate the need to manually manage and reload your load balancer’s configuration file. NGINX Plus sends health checks to confirm applications are performing correctly, directing production traffic away from unhealthy servers and thus eliminating the kinds of failures and outages that mar your clients’ experience at your site. One example of combining health checks and automation is creating a system that automatically reverts to the previous version of an app when health checks reveal problems like
5xx errors from a newly deployed app version.
Implementing CI/CD properly requires a holistic look at all the steps and tools in the development and delivery process to create a supportive platform. In this blog post, we:
- Set out the major components of a CI/CD platform – while recognizing that each organization may create its own specific process
- Describe what to expect from the software development, testing, and delivery process when using CI/CD
- Highlight the role of the open source NGINX software and NGINX Plus in a robust, modern CI/CD platform
Note: The terms “continuous delivery” and “continuous deployment” are often confused with each other. Continuous delivery means constantly moving changed software to a ready‑to‑deploy stage; we think this captures the core value of the process. You can then choose whether to also implement continuous deployment – moving each and every software change immediately to production, rather than potentially allowing changes to accumulate between deployments. CI/CD, as a whole, makes the entire process friction‑free. Truly continuous deployment can be easily implemented when that’s what the business needs.
What Makes CI/CD Different
CI/CD is a means of implementing agile development principles across the software testing and delivery process, which thereby makes software development more nearly interactive as well. CI/CD allows for nearly constant updates to software, making the whole process highly responsive to business requirements and user needs.
Continuous integration and continuous delivery, as part of a set of new tools and new approaches, bring speed and flexibility to the entire app development process:
- Continuous integration uses automation to eliminate the need for big blocks of development time, followed by separate integration testing. When a change is made in software, however small, the changed software is built and tested automatically. During the build phase, tests are run to validate the code’s syntax. After deployment to a specific environment, application‑specific tests verify that the new application version performs correctly.
- Continuous delivery takes the steps used to implement CI further, enabling the automatic deployment of application changes across environments after software passes the tests you have set in place.
With CI and CD together, development and QA can implement changes more freely, without red tape and without restrictions.
Establishing a platform for continuous integration and continuous delivery creates a much more efficient workflow for your release process. Automating redundant testing processes and operational tasks gives your development team the power to release their changes without the need for manual interaction from the various teams that are responsible for each environment. This frees up operations teams so that they can monitor, maintain, and improve the existing application infrastructure. It gives developers time to work on new projects and be more effective at their jobs, while giving QA teams the ability to focus on improving their automated testing environment. At the same time, they can begin learning more about the applications they support.
Establishing a CI/CD platform also creates an additional safety net for an application by monitoring and testing changes that might impact its users. Establishing proper automated tests allows the QA team to automatically catch problems before they are released to a production environment.
The overall CI/CD process varies across different communities of practice and between one organization and the next. However, there are three overall keys to CI/CD:
- Simplification – The number of steps in the process is reduced, with each step made as simple as possible
- Automation – Each part of the process is made automatic wherever possible, eliminating wait states
- Standardization – Each step is the same every time, regardless of the magnitude of changes in the software
The diagram shows the relatively standard process that has evolved for CI/CD.
The process has five steps:
- Source control. Software is developed or updated, then moved to the “main” branch. In this example, we focus on commits that are planned for the production pipeline. For simplicity, we call this the main branch, but it could have a different name, depending on your source control branching.
- Continuous integration. Software is run through build unit tests; if it passes, it’s moved to packaging and initial deployment.
- Testing. (Testing occurs at the transition to every step, so this step could be called major testing instead.) Advanced acceptance tests of the core software and the package are run. The testing phase can also include other tests, such as user acceptance tests (UAT). The UAT phase is not automated, so there is controversy over whether it belongs in a true CI/CD process. We’re including them here. If the tests are passed, the software moves to ready‑to‑deploy status.
- Continuous delivery. Move immediately to production, or hold software here across multiple updates, with a formal decision process for moving any one update to production. In some definitions of CD, this step must be automated; other views allow release to production to be gated by business and service level agreement (SLA) requirements.
- Performance or deployment testing. Post‑deployment tests can trigger a rollback to a previous, “known good” version – usually a manual step – followed by new development to fix problems. Usability problems and new feature requirements can cause new software to be developed and deployed without the need for an intervening rollback.
There are acceptance tests for moving software from each stage to the next stage, which means there are four sets of acceptance tests. Failure at any step means the software is not moved forward, but returned to development for repair and possible further updating.
If failure occurs in deployed software, the deployed software is automatically rolled back to the previous non‑failed version, and updating proceeds from there.
A Closer Look at the Steps in the CI/CD Process
As CI/CD implementation progresses, manual processes – and the people who formerly performed them – are removed from the ongoing integration and deployment process. Instead, the people who formerly did the manual work are tasked with developing and maintaining the automated “production line” that integrates, tests, deploys, and monitors code.
As people are removed from the testing, deployment, and delivery process, the developer’s responsibilities extend deeper and deeper, and come to encompass the entire code lifecycle. When automated processes kick code back from any given step, the developer has to decipher what’s happened, fix it, and track its progress through the process on a subsequent try.
While no single, specific change is absolutely required, a full move to CI/CD can thoroughly revamp what a developer does:
- Application architecture is likely to move to microservices, with small pieces of code (potentially written in different languages) which manage their own data stores where needed, and which interact with other services through APIs.
- Source code control is likely to move to Git‑based or similar tools that enable shared access to code and easy management of changes from multiple sources.
- Code can be, and increasingly is likely to be, developed and deployed in containers, isolating it from the details of any specific development, test, or production environment.
- Code is frequently updated to accommodate changes, from major (requiring many code updates in concert) to minor.
- The coding work process is likely to become thoroughly agile, organized into two‑week sprints with daily scrums of two‑pizza teams.
- Work responsibilities are also likely to become agile, with developers responsible for a set of services they own from inception, through deployment, to the handoff or eventual demise of each service.
In sum, the move to CI/CD is likely to dramatically change the work responsibilities and daily life of a developer. Instead of dozens of people co‑owning and managing megabytes of code, one or two people manage kilobytes of code. The developer becomes a DevOps professional, with responsibilities that extend from the initial development of code, to overseeing test and deployment, to receiving a midnight phone call to fix code that suffers from problems in deployment.
The CI/CD process is eased if developers run code analysis tools and automated testing processes before checking in code.
While the move to CI/CD has large effects on developers, there are smaller, more subtle effects too. Developers who work on microservices are likely to find themselves obsessing about the code size, performance, interfaces, robustness in deployment, and security profile of the services they own. While perfection may be impossible, the pursuit of it can become a passion.
The CI/CD process starts when a developer commits code to the main branch. The new code undergoes build unit tests. If these fail, the developer is notified of the problems that caused failure.
The developer deploys code to test. If two developers have changed the same code, the merge process throws up a flag. If there’s any problem in the initial testing process, the code is kicked back to the developer. Instead of several people handling the processes of merging, deploying, and testing – and needing to speak to one another, and the developer, when there’s a problem – the developer is alerted directly.
Developers meet in scrums to discuss changes, then merge the changed code. If the problem is with the tool chain used for integration, testing, and deployment, rather than the code itself, the operations or QA team gets involved to improve or fix the delivery pipeline or testing.
As the delivery pipeline gets stronger, developers take on more responsibility. Their skills may become broader, across a range of responsibilities, rather than deeper in terms of optimizing large swathes of code.
The microservices approach, in which code is divided into individual services which communicate via APIs, can help this. Developers are responsible for smaller, but more critical, chunks of code.
Each service is optimized to within an inch of its life. In one shop, the code base for a given application went from gigabytes to hundreds of kilobytes, as the framework that the code was developed and delivered in took over functionality that more typically is duplicated in each app.
Automation at the integration step can be extended all the way through the integration, test, and delivery process, giving developers more power – and more responsibility. In the strongest definition of CI/CD, it’s a developer, not an operations person, who gets a phone call when bugs crop up on an e‑commerce site during the busy holiday season.
Testing is changed greatly in a CI/CD environment. Testing of one kind or another takes place throughout the CI/CD pipeline. This testing step refers to one or two specific types of tests:
- Automated acceptance tests. Many software environments that are not CI/CD implementations include some degree of automated acceptance tests. In CI/CD, the operations team seeks to continually strengthen this and other testing steps to reject any and all code that isn’t ready for production. Developers need to be actively involved with the team that manages the automated acceptance tests, to ensure the tests in place are efficient and able to catch problems with critical parts of the application.
- User acceptance testing (UAT). This is an opportunity to expose software changes to users in a real‑world scenario before the changes are deployed. However, this step is controversial because it requires human involvement in the CI/CD chain. Many sites minimize or eliminate this step in favor of stronger automated testing, while others use testing by humans to check the user’s experience and estimate the business impact of potential problems.
Continuous delivery means that code passes, quickly and automatically, from development to ready‑to‑deploy status. Continuous deployment – putting each individual code change into production as soon as it’s ready – is not a requirement for continuous delivery, nor for calling the entire process CI/CD.
Rather than deploying continuously, code changes are often allowed to accumulate so that stakeholders do not have to deal with constant changes in the available software. Reasons for not making deployment as continuous as integration, testing, and delivery include the need to write documentation, the need to make updates to integrated code, and the need to perform user testing against an accumulated set of changes.
In some cases these accumulated changes can be deployed automatically, on a scheduled basis. However, if you choose to do so, it is critical that you are properly monitoring and alerting on the process and the application. This way, you can minimize the impact on stakeholders or the business as a whole from any issues resulting from changes.
Performance or Deployment Testing
Deployed code is continually tested, in a sense, by users. Users employ various means to report actual and perceived problems to the organization responsible for a website. This can be as direct as sending an email to the organization and as indirect as a user writing a blog post complaining about problems with a site.
Organizations often test their own deployed code, especially in areas of functionality known to have changed recently. Tests can include the usability of the application and the performance of the application. Ideally, usability tests are performed against changed code so a problem can be caught before many users suffer from it. Performance tests are best performed regularly against the entire app to meet performance and related usability goals. These tests typically enforce the business’s requirements, for example, the maximum load time of a search query or the time to calculate shipping and tax on a shopping cart.
CI/CD is an important part of a modern, automated application development and delivery system, with testing built in. The system as a whole enables organizations to accomplish much more with its apps.