Puppet in Docker


Alternative Text by Thijs Schnitger

At Container Solutions we’re big fans of Arnold Schwarzenegger. His 6 rules of success are highly motivational to us and we keep them in mind in our daily work. Of course we like to joke about them a bit (“Sleep faster!”) but there are times when they really do drive our motivation. Like the time when I was asked to provide Puppet scripts for setting up Artifactory. To me this seemed like an excellent opportunity to try a proper Puppet master-slave setup in Docker containers, something I have been wanting to do for a while since I came across James Turnbull’s presentation from last year’s PuppetConf. I asked my colleagues how to go about it and they frowned and said I don’t like it. It’s not nice. You shouldn’t do that. It can’t be done. Which only made me more determined, because it reminded me of rule #4: Don’t listen to the naysayers!

There’s a few ways to go about this. Of couse you can do the whole thing in one container with a simple puppet apply but that’s not really any fun and it doesn’t reflect the desired setup with a master and slave. The other option is to create a container with a master and another with a slave. The Puppet master part is relatively easy if you follow the directions:

I added the autosign because I don’t want to manually sign every cert for each client that connects. The file just contains a single ‘*’. The image from this Dockerfile is also available on the Docker hub. For our purpose, installing Artifactory, we need a few modules so I decided to create a new image from the basic puppetmaster:

For the agent we have 2 choices: you can either run puppet agent -t at runtime which goes against the idea of immutable containers, or run it at buildtime like James Turnbull suggests. The problem with CentOS7 however is that it uses systemd which needs to run in a privileged container. Running privileged containers at buildtime is still an issue, so I decided to go for the runtime Puppet build.
This means we first need a generic Puppet slave image (also available on the Docker Hub):

You need to put init as the command to run, because at some point Puppet will try to start services using systemd. I guess you could either add puppet agent -t or start the agent in daemon mode and wait for it to fire, but I decided to execute the puppet agent -t manually.

Then I used docker-compose to spin up the containers with the proper settings. I add the manifests directory and my module directory as a volume at runtime, so I can edit the nodes and scripts without restarting the containers. The slaves need privileged mode. The documentation for the CentOS image seems to be a bit outdated, which is confusing, because the steps listed there don’t seem to be necessary anymore. My slave ran just fine without either CAP_SYS_ADMIN or the cgroups mounted.

After docker-compose up , exec into the postgresql container: docker exec -it artifactory_postgresql_1 /bin/bash and do puppet agent -t. You’ll see the Puppet master complain it can’t resolve the address of the slave to a hostname, but it returns the config for our postgresql node anyway. I guess after it finishes, you could probably commit the image and ship it, but I didn’t go that far (yet).

The Puppet scripts are like this:

And then we define the nodes like this in the manifests directory:

As you can see, the scripts still require some work, like starting Artifactory and applying the license and configuration. But the basic idea is clear and it is working, a Puppet master-slave setup in containers!


  1. Very cool setup, thanks for posting it. I think it’s pretty reasonable to leave a master running in a container. Although generally people do (as you mention) commit after the initial puppet agent run, IMO there’s nothing *wrong* with letting the agent run over time either.

    I have one comment on terminology, though: please don’t refer to puppet agents as “slaves”!

  2. Good article!

    I was one of the people who said “don’t do it”! I still stand by this advice in general, as you move away from immutable containers and reproducible builds with this approach. However, many people will still want to use puppet, and many of them will have valid use cases.

    I hope I never said “it can’t be done” though 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *