Erick Matsen   Field Notes

Trivial Travis testing via Docker

In this post I’ll show how to use the Travis continuous-integration system to test a project via Docker. This is not a description of building Docker containers using Travis. Specifically, the setup is:

  • you have a project on GitHub which contains a Dockerfile specifying how to install your project’s dependencies into a Docker image
  • you have some means of building and testing that project within the corresponding Docker container
  • you would like this build/test to happen automatically on push.

For background on how to set up the first two steps, see a previous post about Docker.

Travis

Travis is an industry-standard continuous-integration (CI) service that is nicely integrated with GitHub. It can do all sorts of fancy pipelines, but here we’ll just get it to do one simple thing: run a command in a Docker container.

To demonstrate we’ll use the same cowsay-test repository as in the previous post. This time let’s look at the .travis.yml file in that repository, which is in YAML format:

language: minimal

services:
  - docker

script:
  - docker run -t matsen/cowsay-test /bin/bash -c "cowsay hello"

Travis has all sorts of preconfigured machines to run code in a variety of languages. In the first line, we are specifying that we want to use a “minimal” machine, which isn’t designed for a specific language. This image just has a collection of standard tools, including Docker. The second block specifies that we would like to use Docker.

The third and final block specifies what command we’d like Travis to run. It runs cowsay hello via bash inside the matsen/cowsay-test Docker image from Docker Hub.

We can test this locally with a local clone of the repository. If we want to test the whole process, we can execute the

docker build -t matsen/cowsay-test .

command inside the repository, and then copy and paste the docker run command from the .travis.yml file (without the leading -):

docker run -t matsen/cowsay-test /bin/bash -c "cowsay hello"

If we want to test the version that’s on Docker Hub, we can instead do docker pull -t matsen/cowsay-test rather than the above docker build command.

To automate this process for any repository, we just need these files committed to our repository, and to:

  • set up an automated build on Docker Hub as described previously
  • make an account on travis-ci.org, signing in via your GitHub account
  • go to https://travis-ci.org/account/repositories and find the repository you want to test
  • click on the switch to activate testing of your repository
  • click on the hamburger menu button (☰) in the upper right, and select “Trigger build” using the default values
  • add a Travis badge (see the cowsay-test repository for an example that makes the badge a link to your build page)

Using quay.io

Docker-the-software is great and very popular. Docker-the-company is struggling somewhat and it shows in that Docker Hub is slow and sometimes unreliable. quay.io is an alternative service that we are starting to use.

If you want to try it out, fork the cowsay-test repository on GitHub then:

  • make an account on quay.io
  • click on “Create New Repository” on the upper right of your user page
  • name your repository in the text box
  • Follow the prompts, selecting
    • Public repository
    • Link to a GitHub Repository Push
    • Select your forked repository
    • your Dockerfile is /Dockerfile as per the help on the right hand side
    • your build context is just / as per the help on the right hand side
  • Continue to the page for your build
  • Select “Start New Build”

On the Travis side, all you need to do is to add quay.io/ to the start of your Docker image name, like so:

script:
  - docker run -t quay.io/matsen/cowsay-test /bin/bash -c "cowsay hello"

Adding Conda

Conda is a great cross-platform package manager that has a lot of traction. You can incorporate Conda as follows, which I’ll describe using the example astronaut-requests repository. This example uses the requests Python library to fetch the collection of astronauts currently in space.

We just need one more file, which is the environment.yml file. This file specifies your Conda dependencies. It’s a helpful file for folks to have in general if they wish to install your software via conda, as they can just execute

conda env create -f environment.yml

and get a Conda environment ready for them. In the example environment.yml file I show how to combine pip and conda.

The astronaut-requests Dockerfile just builds the corresponding Conda environment:

FROM continuumio/anaconda3:2019.07

COPY environment.yml .

RUN /opt/conda/bin/conda env create -f environment.yml

Here we use the continuumio/anaconda3:2019.07 base image (using a specific tag is a good idea to avoid future breakage!). We then copy the environment.yml file in from the repository, and use it to make our Conda environment (note that we need to use the full path to conda). In our case it creates a Conda environment called requests.

The astronaut-requests Travis YAML file just gets a tiny bit more complex. I’ll break it down:

  • docker run -t quay.io/matsen/astronaut-requests runs commands in the astronaut-requests container hosted on quay.io as before
  • -v ${PWD}:/astronauts mounts the current directory (containing the clone of the repository on Travis) as /astronauts inside the container
  • /bin/bash -c "..." runs ... as a bash command inside the container
  • /opt/conda/bin/conda run -n requests ... runs ... inside the requests Conda environment that we built in our Docker container
  • python /astronauts/get-astronauts.py is the command we are running

If we look at the Travis page for the repository we can see a JSON blob at the bottom with the current astronauts in space at the bottom. Success!

Note: conda run is not documented as of right now on the online Conda documentation, but it’s lovely and is documented via conda run --help on your local installation.

Wrap

That’s it! In practice, you’ll want Travis to build and test your code. You can see an example of all of this working in our libsbn repository.

I emphasize that we used Docker as a build environment and that the code is brought in from the outside. If you want to build a Docker container with the code built in, you can push the resulting Docker image to a registry.


Questions? Comments? Tweet @ematsen, or email .