Using Docker to validate (RPM and Debian) packages

Validating the integration of a package is usually quite far in the delivery pipeline, which means a mistake can take long time to identify and resolve..

But not anymore using Docker, this process can be improved to test and validate the packages install, start, stop, and uninstall correctly in minutes from the developer workstation!

Indeed, the validation process that a package integrate correctly on a system usually requires lengthy steps to create an application/daemon, package it into a .deb or .rpm file, deliver it to a repository, deploy a machine of the correct distribution and release type, then install using a package manager.

Many steps can go wrong in this process, and eventually the package can fail to install, update, uninstall or the service might fail to start or fail for another reason. Each of which can take long time to identify and resolve as the full process need to redone from the start each time.

Docker Image

Using Docker, a machine of the correct distribution (Ubuntu, Debian, CentOS) and of the correct version (14.04, 16.04, Wheezy, 6, 7.. etc) can be up and running in minutes. And with the correct option –rm, which will remove the image after use, this machine can be a temporary, clean and empty each time.

The following commands allow to deploy quickly a Ubuntu Xenial (16.04) or CentOS 7 image simply (Docker need to be install and started as a prerequisite):

# Starts a temporary Ubuntu Xenial image
docker run -ti --rm ubuntu:xenial /bin/bash

# Starts a temporary CentOS 7 image
docker run -ti --rm centos:7 /bin/bash

Docker image, commands, and prompt

The next steps are to add the various preliminary commands to prepare the image for installing, or installing directly, the custom package. A common step is to clean, update or add a repository, such as the following:

# Starts a temporary Ubuntu Xenial image, then clean and update APT repositories
docker run -ti --rm ubuntu:xenial /bin/bash -c "apt clean all && apt update"

# Starts a temporary CentOS 7 image, then clean YUM repositories
docker run -ti --rmcentos:7 /bin/bash -c "yum clean all"

Unfortunately, this image will be destroyed immediately after execution of the commands, without returning to the prompt, which is not really useful.. We might want for example to run further commands to check everything is in place. The trick is to add the $SHELL directive to the command passed to Docker to return to the prompt on commands completion, such as:

# Starts a temporary Ubuntu Xenial image, then return to prompt after preparing APT repositories
docker run -ti --rm ubuntu:xenial /bin/bash -c "apt clean all && apt update; $SHELL"

# Starts a temporary CentOS 7 image, then return to prompt after preparing YUM repositories
docker run -ti --rm centos:7 /bin/bash -c "yum clean all; $SHELL"

Fantastic, we have now an image running either Ubuntu or CentOS, ready to receive a new package to be installed!

systemctl replacement

The final steps are to add the required repository, install prerequisite packages, add users and groups, install the custom package, run some commands to check services are starting and stopping correctly, then probably manually stopping and uninstalling the service(s). Unfortunately, the Docker images implementation don’t allow to run SystemD commands, as it abstract from the host OS. There are multiple solutions to replace systemctl on Docker, but the simplest and fastest is to download and use the docker-systemctl-replacement from GitHub (Thanks Guido Draheim!):

# Download and replace systemctl
wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py
cp /usr/bin/systemctl /usr/bin/systemctl.bak    # Keep a backup of systemctl in case we mess up
yes | cp -f systemctl.py /usr/bin/systemctl
chmod a+x /usr/bin/systemctl
test -L /bin/systemctl || ln -sf /usr/bin/systemctl /bin/systemctl

The systemctl replacement will allow to run all the systemctl commands (systemctl list, systemctl status …etc) the same way than if on a fully deployed machine.

Reference Commands

Finally, to conclude this article and keep reference for later use, the following commands will prepare an image and install a package of your own making.

On a Ubuntu Xenial 16.04 image

# Validate latest .deb package on a local Ubuntu image with Docker
docker run -i -t -p 8080:8080 --rm ubuntu:xenial /bin/bash -c ' apt clean all && apt update && apt install -y python wget vim ; \
    wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py ; \
    cp /usr/bin/systemctl /usr/bin/systemctl.bak ; \
    yes | cp -f systemctl.py /usr/bin/systemctl ; \
    chmod a+x /usr/bin/systemctl ; \
    test -L /bin/systemctl || ln -sf /usr/bin/systemctl /bin/systemctl ; \
    echo "deb http://dl.bintray.com/<CUSTOM_REPO>/debian /" | tee -a /etc/apt/sources.list.d/<CUSTOM_REPO>.list ; \
    apt-key adv --recv-keys --keyserver keyserver.ubuntu.com <CUSTOM_APT_KEY> ; \
    apt clean all ; \
    apt update ; \
    apt install -y <CUSTOM_PACKAGE> ; \
    systemctl status <CUSTOM_SERVICE> ; \
    $SHELL '

On a CentOS 7 image

# Validate latest .rpm package on a local CentOS image with Docker
docker run -i -t -p 8080:8080 --rm centos:7 /bin/bash -c ' yum clean all && yum install -y python wget vim ; \
    yum install -y epel-release ; \
    wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py ; \
    cp /usr/bin/systemctl /usr/bin/systemctl.bak ; \
    yes | cp -f systemctl.py /usr/bin/systemctl ; \
    chmod a+x /usr/bin/systemctl ; \
    test -L /bin/systemctl || ln -sf /usr/bin/systemctl /bin/systemctl ; \
    useradd -MU www-data && usermod -L www-data ; \
    echo -e "[<CUSTOM_REPO>]\nname=<CUSTOM_REPO>\nbaseurl=http://dl.bintray.com/<CUSTOM_REPO>/rpm\ngpgcheck=0\nrepo_gpgcheck=0\nenabled=1" |\
        tee -a /etc/yum.repos.d/<CUSTOM_REPO>.repo ; \
    yum install -y <CUSTOM_PACKAGE>  ; \
    systemctl status <CUSTOM_SERVICE> ; \
    $SHELL '

Conclusion

You should now be able to spinup images quickly to validate the integration of your .deb and .rpm packages efficiently, thanks to Docker!