Surprisingly enough, one of the most interesting conversations I had at the last NodeConf Adventure wasn’t related to Node.js, in particular, but rather to one of the major disruptions in the software industry nowadays: containers. Docker has made a significant impact on the industry, which is seen by its impressive rate of adoption. The image below, from Docker CEO, Ben Golub’s presentation at the Docker Conference event that took place in San Francisco last month, exhibits Docker’s exponential growth over the past year, alone.
There are definitely many benefits of using Docker in production – including seamless deployment, scaling, native support for microservice applications, infrastructure costs, and more. In this post, I would like to focus on the impact on and benefits for development teams, with a focus on how to containerize the git flow process.
The benefits that organizations gain by embracing Docker have a major positive impact on operations. At the Docker conference, Lyft, the peer-to-peer ridesharing company, presented how they leveraged Docker to dramatically improve their Dev team’s productivity without compromising application stability. In fact, their application stability even improved (as seen below). To read more about Lyft’s experience with Docker, see their reference link below.
One fundamental improvement of containerizing git flow is the creation and promotion of a Docker image alongside our code PR (pull request). Git promotes, encourages, and enables work with branches in a much simpler fashion, by assisting teams in code collaboration, working on feature branches, and merging them quickly. However, we’re all aware that code can often behave differently when moved from one environment to another. An application script that works well in a development environment could function completely differently as it’s moved into a production environment. When enhancing git flow with a parallel Docker image flow, we’re not just transporting the code, but rather, moving running code within a container. Basically, we’re transporting an atomic unit of executable code isolated from everything around it. That means that a container that departs from the development environment will move and be executed exactly the same way in staging and production environments, as well.
Below are the steps we take in order to implement git flow using containers. First, however, I would like to add a disclaimer. While I have seen and practiced a few variations of git flow with different organizations, the steps below reflect the current variation that we exercise at Codefresh. Seeing as we constantly make improvements to our approach, we welcome your comments and suggestions. In step one, once we finish implementing a task and successfully run unit and sanity tests locally, we create a pull request.
Upon creating the pull request, three activities are initiated in parallel:
- Unit test execution (CI)
- Code review
- Container image creation and storage in our Docker registry
Once the Docker image is created, we can start running integration tests, ensuring that all processes are running properly. We can also run manual and performance tests on the container. Once all tests pass (it is highly recommended to include a feature preview step at this stage, especially if the task/feature involves changing the UI), we initiate three steps in parallel (please note , that if other code changes pushed to the develop branch after image created these, the previous steps has to re-run before we proceed):
Promote the image to replace the current container in staging (develop)
- Accept the pull request in the git repository.
- Tag the image accordingly to reflect its current status (change the previous container’s tag to reflect that it is no longer the current version of the branch).
Although it seems like adding Docker image management to our lifecycle resulted in more steps than we initially had, the benefits are far superior. Now, we have each PR packaged in a container, DevOps is no longer a bottleneck, and we can spin up a running version of any PR or branch for tests or reviews. Using Docker compose, we can spin up a microservices application in seconds with a smoother deployment. Moreover, we decrease the chance of dealing with subtle but difficult to resolve issues that stem from any friction between different environments.