Reading Time: 9 minutes
UPDATE: With January 1st, 2017 we rebranded our hosted CI Platform for Docker from “Jet” to what is now known as “Codeship Pro”. Please be aware that the name “Jet” is only being used four our local development CLI tool. The Jet CLI is used to locally debug and test builds for Codeship Pro, as well as to assist with several important tasks like encrypting secure credentials.
Regardless of an organization’s size, onboarding new developers and getting them up to speed as quickly as possible remains a distinct challenge. The longer the time between being hired and being productive, the more expensive the investment — especially when talking about more experienced developers.
Given that, two key considerations for any efficient onboarding workflow are:
- How can time from sit-down to project familiarity be reduced to as small a window as possible?
- How can new hires get up and running as quickly as possible?
Actually, a better question is: How can we get developers, regardless of whether they’re new to our organization or simply new to a project, up and running as quickly as possible?
For the purposes of this discussion, productivity can mean adding new features, fixing existing bugs, and/or being able to investigate the codebase using a working development installation.
A number of technologies are available to answer these questions. These include shell scripts, WAMP, MAMP, and LAMP stacks, and virtual machines. But the one I find most compelling is Docker. Docker’s the new kid on the proverbial block in the DevOps space; the latest in a long line of technologies aimed at making the transition from development to production environment as smooth as possible.
Of course, it’s easy to let yourself drink the KoolAidtm of new technology and believe that it can do anything and everything. However, Docker really is particularly adept at reducing the onboarding time for new developers. Today, I’m going to look at five specific ways Docker can significantly reduce the startup time for new hires.
1 – Docker Is The Only Dependency
If you’ve been developing for at least five years, you’ll be familiar with a range of different approaches for building development environments.
Originally, there were (L,W,M)AMP stacks, where the developer’s machine contained all of the various development libraries and packages. While great for a few projects, this approach often leads to machines quickly becoming messy. This is especially the case when different projects require different versions of the same library, such as encryption, string, math, or SSL.
Development machines can also quickly become filled with numerous packages, sporting a range of configurations. As a result, it becomes almost impossible to recreate that environment in a production setting — or anywhere else for that matter. This in turn results in the infamous “works for me” response.
With Docker, this isn’t a concern anymore. Docker, via DockerHub, has a range of preconfigured Docker containers for all kinds of development needs. If you’re creating a Ruby app, grab a Ruby container. If you’re creating a Go or a Python app, grab a Go or a Python container. Moving further up the food chain, if you’re creating an app based on a framework, such as Zend Expressive for PHP, then grab a container configuration for that.
If your app requires more than that, determine what it needs and create a custom container setup that combines the necessary containers to support it. If you build a custom container, one not available already, consider uploading it so that others can use it as well.
Regardless of what you need, development machines no longer need to be polluted with all manner and type of library, package, or competing configuration. They can be left free and clean, avoiding dependency hell. And developers can no longer abdicate responsibility by saying “it works for me.”
2 – It’s Easy To Know How The Environment Is Built
Let’s consider how Docker can simplify configuration requirements. For a long time after installing everything locally fell out of vogue, virtual machines became the go-to tool to create development environments. And for good reason. With virtual machines based on tools such as VirtualBox, Parallels, and VMWare, development environments could be built to work exactly like testing, staging, production, or any other environment. Within them, you could virtually mimic the environment where the code would be hosted.
However, a virtual machine wasn’t that different from a machine running on bare metal hardware. All the software, libraries, extensions, and dependencies still had to be installed and configured. Given that, the time to build them was still no small task, and replicating them for different projects was also non-trivial. As a result, tools such as Vagrant, Puppet, Chef, Salt, and Ansible arose to answer the need. These tools could create replicable and versionable provisioning scripts, scripts which could create immutable virtual machines, regardless of environment.
But regardless of the provisioning tool chosen, the learning curve wasn’t insignificant. Some tools require more effort than others to successfully learn. But even with the simplest (Ansible), a configuration for a setup that can run a PHP application with caching, logging, email, and database support isn’t trivial. A recent configuration I created for just such a project, one that provisioned development, testing, and production environments encompassed 15 directories and 34 files.
Then there’s the issue of available resources. Imagine that you need to simulate a production environment that has a web, database, queueing, and caching server on separate machines. You’ll have at least four virtual machines running on your development machine, which can quickly add up as each of them are complete server instances. Consequently, they each need memory, cpu, and drive space allocated.
With Docker, all of this changes. You don’t need to spend much time at all getting an environment set up. Using Docker Compose, depending on the application you’re working with, a configuration for an application could be as brief as this:
version: '2' services: nginx: image: nginx ports: - 8080:80 volumes: - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf volumes_from: - php php: build: ./docker/php/ expose: - 9000 volumes: - .:/var/www/html
Here, we’re creating an environment for a PHP application. We have two containers, one running NGINX and one running PHP via FPM. This is in stark contrast to an Ansible or Puppet configuration. There, you have to specify all the packages required. With Docker, you take a base image, which is shared between containers, and only add in the things you need.
As we only need these two components to run the application, that’s all we need to care about. This has several benefits:
- We don’t have to worry about all the related binaries.
- The configuration is extremely minimalist.
- The learning curve is greatly reduced.
It doesn’t matter if someone’s never seen Docker before. I suggest that they could, inside 20 to 30 minutes, learn enough to know what’s going on and where everything is set up, such as where the files are in the container. The don’t need to go on lengthy training courses, nor do they have to become a DevOps guru to make changes if need be.
Container configurations can be created quite quickly, by stringing together a group of existing containers and supplying any extra configuration required. Given that, DevOps can create development environment configurations quite quickly instead of spending exorbitant amounts of time with other technologies.
3 – It Provides Portability Across Machines
In many respects, Docker is the ultimate answer to portability concerns, even on Windows and Mac.
Now, Docker is a Linux-only technology; it’s based on Linux Containers (LXC), cgroups, and kernel namespaces which, by default, exclude Mac and Windows from running Docker natively. In 2014, Microsoft announced initial support to improve Windows Server so that it can natively support it. However, I’m not aware that it’s complete at the time of writing or that such support from Apple exists.
Despite all that, Docker can still be run on both platforms, via Docker for Windows and Docker for Mac respectively. These packages provide a thin Linux foundation upon which Docker environments can be run. Given these changes and packages, regardless of the platform your developers are using, they can make use of a Docker configuration and tools to rapidly boot an environment that provides them with all they need to begin work.
Given that it’s either one or a series of text files, they can be maintained solely with a text editor, which exist in abundance on all major operating systems. What’s more, that makes the configurations easy to store under version control.
I appreciate that there can be the desire to implement corporate IT policies, restricting allowed operating systems. However, this is often a poor choice. And as Docker is available for all the major platforms, there’s no reason to limit developers to a single choice.
4 – There Is Consistency Across Development Environments
This is a benefit that I really like, and one that I’m not familiar with when using virtual machines. When you use a Docker container, you can move it across machines. So long as the machine that you’re moving the container to runs Docker, you’re fine. You can take the application and its dependencies, neatly bundled up in a container, and move it from machine to machine.
It doesn’t matter what the host machine is running; Docker ensures that it can run without any compatibility issues. This is something I tried to do some time ago when building virtual machines with Docker, and I didn’t meet with much success.
5 – Environments Are Lightweight
This is an interesting, if perhaps slightly contentious, issue. Docker runs only one process per container. As a result, a container’s resource requirements are often quite modest. I don’t have sufficient space to detail exactly how it all works, but because the resource requirements are quite small, everything else about working with them can be quite modest and nimble as well.
Take the example of developing using Mac OS X as the host operating system and using Docker for Mac to provide the transition layer between the Mac and Docker. When Docker for Mac is started, that’s the longest startup time completed.
When you boot your container configuration, it usually happens in a matter of seconds, not minutes (or longer) as with virtual machines. This includes the original creation of the containers (whether one or several) or booting an existing container configuration. Compare this to either the provisioning time of a single virtual machine using VirtualBox and Ansible or the boot time, regardless of what you’re using. It’s likely that Docker will always be up and running faster.
Let’s say however, that the foundation for the virtual machine was a tiny distribution like BusyBox. BusyBox clocks in at 5mb, which is tiny for a Linux distribution. If you were to use it, you’d expect that it would be very light and nimble, and it is. But given how virtual machines and Docker work, Docker is still going to be faster to get up and running.
I did, admittedly, make some broad generalizations there. For what it’s worth, I’m not seeking to denigrate VirtualBox, Vagrant, Ansible, or anything else. I’ve used them all and continue to do so quite happily.
While Docker is still a new kid on the block, it’s not a new technology when it comes to building, managing, and deploying applications. What’s more, it has a host of benefits that make it a prime candidate for building development environments that can dramatically reduce startup time for developers who are new to a company, a department, or a project.
If you’ve not tried it out yet, I strongly encourage you to. If you’re keen to get your feet wet, why not request a 14-day trial of Codeship’s Jet? Reducing cost and building applications is what it’s all about. Give Docker a try and see how it can help you do both better.