This is the part 1/2 where we describe a basic configuration for a dockerized development environment. In part 2 we'll explain how to put this configuration on steroids so that you never wait for a npm install/gem install anymore.
With a properly setup docker configuration, we now appreciate the following features:
In addition to these features, we want what has now become a standard in any modern coding configuration:
Yep. So we will basically get rid of
All right, let's slaughter the monster !
Here you can find a tiny demo project :
git clone https://github.com/aherve/simple-dockerized-dev-env
Let's have a look at what you can do with it before we go into the details:
This will download the proper containers so you can use an out-of-the-box install of node, mongodb. It will also run an npm install for you.
Note also that if you run this command again, docker will use cache so the npm install and images downloads are not performed twice:
If you change the package.json file, then the npm install command will be run again. Exactly what we need !
docker-compose run test
This will run the tests. If you launched this command for the first-time, did you notice how it installed everything for you ?
Note that a db_1 instance is also launched. Your test suite is actually connected to a mongodb although we don't actually use it here.
docker-compose run hello
> hello is loaded !
docker-compose run autotest
Unlike the simple test command, this one will start a watcher that tracks a change in the code. try changing the /src/spec.js file and watch the test fail instantly !
Note for mac-users : docker run on a virtual environment when using osX. therefore, the file changes are not detected out of the box.
Fortunately, these guys took care of this problem for you. Simply install dinghy and use it as a docker virtual machine. It will then work out of the box.
docker-compose run hello npm list
docker-compose run test env | grep NODE_ENV
run hello <something> will simply override the default command instruction of our docker-compose file.
All the docker-related mechanics are located in two files:
This file describe the instructions for building a container that will be able to run our code.
Note that our source code is not (yet) included in the container.
This file defines and orchestrate containers.
In this example we use our main Dockerfile 3 times to build very similar images: hello, autotest and test. You'll notice that these are actually the same containers, but we pass different environment variables, as well as different default commands.
The volumes instruction will mount our local directory into the container. More importantly, any change in your local src directory will have an instant impact on the running container. As a matter of fact, they are literally the same file.
Unlike what is located in /src, the package.json has been added by an ADD command before running an install command. This means you will have to rebuild the container if the package.json were to change.
And finally, the last db image is a running mongodb image. This image is directly downloaded from docker-hub and will start a working db server out of the box. The other containers can access the db thanks to the links command.
Since you can install the environment regardless of your setup…. then so does the CI-server \o/
Good news, they can read a docker-compose file as well as you can.
Simply add a codeship-steps.yml file where you tell codeship to run your tests:
And codeship will run your test with the EXACT configuration you had. How awesome is that ?
So far we have a working environment that allows any contributor to onboard in one-click, regardless of his/her personnal computer configuration.
The only drawback of this particular setup is that a docker-compose build will run a fresh npm install everytime you change the package.json file. This can take a lot of time, as all the libraries are re-installed from scratch. In part 2. we will improve our configuration to significantly boost this step.
Happy coding !