Developer on-boarding can be long, especially for large stacks.

What we have managed to do recently greatly reduces the on-boarding time for our platform, from a few days to a few minutes, while ensuring that the environment is as close to production as possible.

Environment contamination

We’ve all heard at some point “it worked for me”.

A developer’s environment is usually set up the moment he sits first on his chair, but as time goes, it gets “contaminated”.

Software versions are not in sync with the production environment, each task may introduce some changes in the libraries, in the filesystem, that will impact the application in some way… well you know the drill.

Even though we’ve managed to minimise the differences, there is always something, a detail, that can make the application behave differently.

Deployment

If we want clear — pristine — development environments, we need to understand the production deployment.

How the application is deployed in production plays a big role in determining how to deploy an ersatz of it.

Right now the deployment logic is limited to a single file: cloud-init.

Cloud-init is the defacto multi-distribution package that handles early initialization of a cloud instance.

Here’s how you could create an AWS instance with a cloud-init file:

aws ec2 run-instances — image-id ami-xxxxxxxx --key-name xxxx \

--region eu-west-1 --security-group-ids sg-xxxx --instance-type xx.xxxx \

--user-data file://cloud-init.yml

Very straightforward isn’t it? our instances are immutable: we do not bother with incremental updates and maintenance. Popping up and down instances is child play.

But then, what if we could use the very same cloud-init for popping up development, or even staging instances? read on…

Vagrant

For our development environment to be as close as possible from the production, we have to reuse the same deployment process.

I’ve been asked many times my reasons for using Vagrant, so here are my top 3 reasons for using it in this setup:

Mimic the production environment up to the OS-level. Run it everywhere! OSX, Linux, Windows… no need here for boot2docker if you are not running Linux. The environment can be popped up and destroyed in a matter of minutes.

Same behaviour and same bugs guaranteed

So, we create a VM, running CoreOS, into which we inject the cloud-init file.

config.vm.provision :file, source: “.vagrant/files/cloud-init.yml”, destination: “/tmp/vagrantfile-user-data”

This cloud-init adds some systemd services which pull/run docker containers, plus some additional services related to development.

Containers overview

Since a picture is worth a thousand words…

Containers by layer

A few notes:

The Production Setup represents the containers ran in production (initial cloud-init). The Development Setup represents the containers added for facilitating development. The Host runs two containers, one mounts the APP to the local filesystem using SSHFS, the other is a preconfigured version of PhpStorm. The APP-BUILDER is an intermediate container which builds the dependencies/config of the APP, then creates & pushes a scratch ready image. In practice it’s not used within the VM, the builder is called by the CI tool and creates/tags containers x.x.x-env. APP-DB is a trimmed version of the production DB for development purposes.

Preconfigured PhpStorm

Jessie Frazelle’s “Docker Containers on the Desktop” post really inspired me and gave me many ideas… one of them is a preconfigured IDE.

JetBrains’ PhpStorm is arguably one of the best IDE around for PHP, it has many advanced features; configuring it properly though, always takes a non negligible amount of time… that’s when Docker enters the scene.

Imagine the flow with a new hire. He pulls the container and automatically gets everything configured: theme, debugging, formatting, plugins…

Check out the PhpStorm Dockerfile example below.

Running containerised desktop apps is very simple but will only work if you are running Linux on your host, other options are too slow and won’t feel “native”.

Here’s how you run it:

docker run -it \

-v /tmp/.X11-unix:/tmp/.X11-unix \

-v $HOME/.WebIde90:/root/.WebIde90 \

-v $HOME/projects:/workspace \

--device /dev/snd \

-e DISPLAY=$DISPLAY \

jgautheron/phpstorm

What’s next

It is very satisfying when I run vagrant up and everything just clicks together.

Now the interaction with the codebase could be improved, deploying a specific container in the dev workspace that will automatically pull the dev’s fork of the app and ensure it’s up-to-date, we could use a VOLUME also, but I don’t like so much the idea since it’s “out of our control”.

Share your ideas!