Travis-CI is a crucial component in Continuous Integration/Continuous Deployment. We use it a lot to run unit tests and building/uploading Python modules.

Recently I had to solve a problem of building RPMs on Travis-CI with Docker containers. In this post I will describe step-by-step how to do that.

We distribute our backup tool as RPM packages for CentOS 6 and 7. But Travis-CI slaves run Ubuntu trusty. In theory I could use a tool like fpm and build RPMs on Ubuntu (never tried that, but should be possible). However I like to have a .spec file. It gives you full flexibility on how RPM behaves and it’s easier to maintain it.

Travis-CI supports Docker containers, so I decided to go that way.

At high level the process is following. A Travis-CI slave starts a docker daemon. A script starts a docker container and in the container it starts a build job. How do RPMs get onto the host machine (=travis-ci)? The container mounts a volume where the build script puts the packages. So, after the build is done the RPMs are available on the travis-ci slave.


All travis-ci configuration is done in .travis.yml file that is stored in a root directory of a source code repo.


Enable Docker

By default a travis-ci slave doesn’t run docker service. It has to be explicitly enabled.

Running Centos in container

To run two instances of travis-ci slaves we need to define an environment matrix.

OS_VERSION=6 means that on a travis-ci slave there will be an environment variable OS_VERSION with value 6. We will use it to decide which CentOS to run.

The docker container is started by a script. The script also does all work on preparing container for the build, installing required packages and builds the RPMs.

Let’s see what make docker-rpm does.

So, the script starts a container and runs in it. task is:

  • Install required packages
  • Start MySQL (we need it for integration tests)
  • Run the tests
  • Build RPM

UPDATE: Things are moving fast. We build RPM/DEB packages with Omnibus now. Yet, here’s content.

Once the build script successfully finishes, the next and last step is to upload packages.

Upload RPM to PackageCloud

We use PackageCloud as our YUM repo provider.
One and decisive reason why we went with PackageCloud is it integrates very well with Travis-CI.

So the relevant part of .travis-ci.yaml goes next.

That means that Travis-CI will look for packages in build/rpmbuild, will upload everything it finds to repo called main under el/${OS_VERSION} that belongs to PackageCloud user twindb and will use API key from encrypted secure string.

This way Travis-CI automates all CI/CD steps starting from pulling new source code revision, to running tests, building packages and landing them into a packages repository.