Everybody should be building Docker images! but what if you don’t want to write all those shell scripts, which is basically what the Dockerfile is, a bunch of shell commands in
RUN
declarations; or if you are already using some Puppet modules to build VMs?
It is easy enough to build a new Docker image from Puppet manifests. For instance I have built this Jenkis slave Docker image, so here are the steps.
The Devops Israel team has built a number of Docker images on CentOS with Puppet preinstalled, so that is a good start.
FROM devopsil/puppet:3.5.1
Otherwise you can just install Puppet in any bare image using the normal installation instructions. Something to have into account is that Docker images are quite simple and may not have some needed packages installed. In this case the centos6 image didn’t have tar
installed and some things failed to run. In some CentOS images the centosplus repo needs to be enabled for the installation to succeed.
FROM centos:centos6 RUN rpm --import https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs && \ rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm # Need to enable centosplus for the image libselinux issue RUN yum install -y yum-utils RUN yum-config-manager --enable centosplus RUN yum install -y puppet tar
Once Puppet is installed we can apply any manifest to the server, we just need to put the right files in the right places. If we need extra modules we can copy them from the host, maybe using librarian-puppet to manage them. Note that I’m avoiding to run librarian or any tool in the image, as that would require installing extra packages that may not be needed at runtime.
ADD modules/ /etc/puppet/modules/
The main manifest can go anywhere but the default place is into /etc/puppet/manifests/site.pp
. Hiera data default configuration goes into /var/lib/hiera/common.yaml
.
ADD site.pp /etc/puppet/manifests/ ADD common.yaml /var/lib/hiera/common.yaml
Then we can just run puppet apply
and check that no errors happened
RUN puppet apply /etc/puppet/manifests/site.pp --verbose --detailed-exitcodes || [ $? -eq 2 ]
After that it’s the usual Docker CMD
configuration. In this case we call Jenkins slave jar from a shell script that handles some environment variables, with information about the Jenkins master, so it can be overriden at runtime with docker run -e
.
ADD cmd.sh /cmd.sh #ENV JENKINS_USERNAME jenkins #ENV JENKINS_PASSWORD jenkins #ENV JENKINS_MASTER http://jenkins:8080 CMD su jenkins-slave -c '/bin/sh /cmd.sh'
The Puppet configuration is simple enough
node 'default' { package { 'wget': ensure => present } -> class { '::jenkins::slave': } }
and Hiera customizations, using a patched Jenkins module for this to work.
# Jenkins slave jenkins::slave::ensure: stopped jenkins::slave::enable: false
And that’s all, you can see the full source code at GitHub. If you are into Docker check out this IBM research paper comparing virtual machines (KVM) and Linux containers (Docker) performance.