First thing’s first – you will need to get Docker. This will probably be the hardest part of this exercise!
- If you are on Windows 10 and are willing to use Window’s HyperVisor for any VMs you need, you can try my installation script (you may want to remove some programs you don’t want from it).
- If you are Windows 7/10 (and don’t want to use Docker for Windows since you need VirtualBox) or on Mac, try Docker Toolbox.
- If you are on Linux, you may be able to download a package if you are on a late enough version of Docker. I would also recommend downloading docker-compose.
Once you have Docker installed, make sure you can run the hello-world image to verify it is properly installed.
docker run hello-world
You should see…
Hello from Docker!
This message shows that your installation appears to be working correctly.
Getting Code from GitHub and Running the Test
This code will be from an exercise in a previous post, where we installed Python manually. I encourage you to read that post if you are not familiar with unit testing.
Now let’s get my code from GitHub. Clone/download it onto your computer from the following GitHub site: docker-and-unit-test
Once you have that, go into the docker directory and run the following:
This is where magic happens. Ok, it’s not magic… but it’s really, really cool and hands-off for the users of the Docker image (you in this case).
You should see something similar to the following:
Step 1 : FROM python:3.6
Step 2 : RUN pip install coverage nose nose-watch
---> Running in 91f782d3b2c2
Downloading coverage-4.4.1-cp36-cp36m-manylinux1_x86_64.whl (196kB)
Downloading nose-1.3.7-py3-none-any.whl (154kB)
Collecting watchdog>=0.6 (from nose-watch)
Downloading watchdog-0.8.3.tar.gz (83kB)
Collecting PyYAML>=3.10 (from watchdog>=0.6->nose-watch)
Downloading PyYAML-3.12.tar.gz (253kB)
Collecting argh>=0.24.1 (from watchdog>=0.6->nose-watch)
Collecting pathtools>=0.1.1 (from watchdog>=0.6->nose-watch)
Building wheels for collected packages: nose-watch, watchdog, PyYAML, pathtools
Running setup.py bdist_wheel for nose-watch: started
Running setup.py bdist_wheel for nose-watch: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/d6/a5/a9/876966b4e753eb3ef7c4a520635445ccc8fed1b903cab173e4
Running setup.py bdist_wheel for watchdog: started
Running setup.py bdist_wheel for watchdog: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/3c/9c/be/e82ae5a37c19baf8abe88623d1f47d2d502bed7b54d4f34740
Running setup.py bdist_wheel for PyYAML: started
Running setup.py bdist_wheel for PyYAML: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/2c/f7/79/13f3a12cd723892437c0cfbde1230ab4d82947ff7b3839a4fc
Running setup.py bdist_wheel for pathtools: started
Running setup.py bdist_wheel for pathtools: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/60/0d/2a/ffe065d190b580be6af9a862c68ed6a8a89c1778bd5c7ba7b8
Successfully built nose-watch watchdog PyYAML pathtools
Installing collected packages: coverage, nose, PyYAML, argh, pathtools, watchdog, nose-watch
Successfully installed PyYAML-3.12 argh-0.26.2 coverage-4.4.1 nose-1.3.7 nose-watch-0.9.2 pathtools-0.1.2 watchdog-0.8.3
Removing intermediate container 91f782d3b2c2
Successfully built 7b5419f7d1f9
WARNING: Image for service nosetest was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Attaching to dockerandunittest_nosetest_1
nosetest_1 | .
nosetest_1 | ----------------------------------------------------------------------
nosetest_1 | Ran 1 test in 0.004s
nosetest_1 | OK
dockerandunittest_nosetest_1 exited with code 0
This builds a Docker image from that docker-compose.yml file. Let’s briefly look at this file.
It has a ‘service’ called ‘nosetests’. A docker-compose file can be used to launch multiple “services” (different Docker containers) by running that one docker-compose up command.
build: docker tells Docker that it will build a new image based on the “docker” directory (which has a Dockerfile with instructions in it). The Dockerfile states to start from the python:3.6 container and pip install a few packages in it.
The volumes command tells Docker that the current directory will be mapped to the /usr/src/testdir directory inside the container that is launched.
The command is run inside Docker. In this case, it changes to the directory that has the code in it (the one that we mapped with the volume command), then it runs nosetests on it.
Finally, we tell it not to create a custom network but to use the existing Docker bridge network.
The really cool thing about this is even if you don’t have any of the necessary Docker images, they will get downloaded with the docker-compose up command. The first time you run the compose command, it will take a lot longer since it is downloading a lot of images. The next time though, it will run very quickly… in a matter of milliseconds/seconds.
Congratulations on running your first useful Docker container! You did not have to download Python or any of its dependencies. If you already have Docker, you only have to download code from Github and run docker-compose up on it. Want to run the same environment on a continuous integration server? Follow the same steps you just took for your own laptop! Want to share this test environment with a co-worker? It’s as simple as git clone and docker-compose up!
The best part is that this same command can be used to run a multitude of different environments with completely different purposes. That, ladies and gentlemen, is the power of Docker.