From Mock to Docker for RPMs

9 February 2017, Rhodri Pugh

Here at Owsy we package all our applications using RPM to Yum repositories. Is that still new and sexy in the tech world these days? Probably not, right? For us though it provides a very stable and standardised method of packaging/deploying applications written in various languages (we have apps written in PHP, Clojure, Scala, Java, etc…)

Until now we’d been using Mock to build these RPMs, but in a world where everything needs to keep getter faster it was proving too much to spend 10 minutes building packages (especially if you do it 10 times a day!). So we wanted something faster…

Mock

The way we were using Mock was on a VM provisioned by Ansible that each developer ran. This VM used the now venerable Jenkins CI to wrap the calls to a script which then called Mock to build the RPM. The advantages we got from this were:

  1. Clean builds inside the chroot
  2. Consistent builds for each developer
  3. Easy management of build dependencies

But as I said this is slow, mainly because:

  1. Mock’s root is cached, but the build deps aren’t
  2. The build deps can be Yum cached, but it’s still slow
  3. We were building an SRPM first too (we might have been able to remove this but the first two points already mean it takes too long)

There’s also the fact that as we use a standard OS image for all our instances we don’t need Mock to be able to build to multiple architectures.

Other Systems

So if we’re not using all the features of Mock, and are looking for ways to make packaging and deploying faster, would it be worth looking at alternative systems?

Perhaps in the future, but at the moment we are pretty happy with our setup, and given the fact we have established infrastructure it wouldn’t be a good idea to try to reinvent our whole architecture, just trying to make a peice of it faster.

Docker

We’ve been slowly dipping our toes into the Docker ecosystem, mainly as a way of managing dependencies for scripts and tools we run (eg. we deploy with Ansible, so instead of requiring everyone has that installed at the right version with the right dependencies and ancilliary bits that get called they can all go in a Docker image that we start with a simple shell script). So we’d actually already moved away from the Jenkins in a VM setup from above and put that in Docker - but still using Mock.

Given that some of the features of Mock weren’t of any interest to us, and the reproducability aspect could now be replaced through Dockers container isolation

  • why not just drop Mock and build our RPMs directly with rpmbuild.
    So that’s what we did.

CONCLUSION

So our setup now is Docker, with a shell script that looks something like this pseudocode:

1
2
3
4
5
#!/bin/bash

# 1. Checkout RPM Specfile
# 2. Invoke rpmbuild
# 3. Upload result to Yum repository

With all dependency caches like Composer and Maven mounted into the container our package times are down from around 10 minutes, to 20-30 seconds (our bottleneck has now moved from building the package to uploading it to the Yum repo - always chasing the bottleneck!)