published on 27 January 2014

Creating a Docker Dockerfile to build an application is pretty easy. But what if you already have a large collection of Puppet modules (or Chef cookbooks) that you want to use to build your applications? We’re going to see how easy it is to make use of those modules inside a Dockerfile.

We’re first going to build an image that has Docker apps with Puppet installed. We’ll also add Tim Sharpe’s very cool Librarian-Puppet to the image. Librarian-Puppet is a bundler for your Puppet modules. You can use it to select and install modules from GitHub or the Puppet Labs Forge.

Let’s create a Dockerfile to build our Puppet image.

FROM ubuntu:12.10
MAINTAINER James Turnbull ""

RUN apt-get -y update
RUN apt-get -y install rubygems 
RUN echo "gem: --no-ri --no-rdoc" > ~/.gemrc
RUN gem install puppet librarian-puppet

This Dockerfile will use an Ubuntu-based image and then install Puppet and Librarian-Puppet via RubyGems.

To build this image we run:

$ sudo docker build -t="jamtur01/puppetbase" .

Here we’ve built a new image called jamtur01/puppetbase. We’re going to use this image as the basis for our new application image.

Next we need to create a Puppetfile file which Librarian-Puppet uses to install the required Puppet modules. As our example we’re going to install a basic Nginx server.

mod "nginx",
       :git => ""

The Puppetfile tells Librarian-Puppet to install the puppet-nginx module from GitHub.

Now we need to create another Dockerfile for our application image.

FROM jamtur01/puppetbase
MAINTAINER James Turnbull ""

RUN apt-get -y -q install wget git-core
ADD Puppetfile /
RUN librarian-puppet install
RUN puppet apply --modulepath=/modules -e "class { 'nginx': }"
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
CMD ["nginx"]

This Dockerfile uses the jamtur01/puppetbase image we’ve just created. It adds our local Puppetfile file to the root of the image and then runs librarian-puppet install to install our required modules (by default into /modules).

We then install Nginx via the puppet-nginx module using the puppet apply command. This runs Puppet locally on the host (i.e. without a client-server Puppet installation).

In this image we’re just installing Nginx itself. We could also install virtual hosts or a web application or anything else that the Nginx module supports.

We can now build our application image like so:

$ sudo docker build -t="jamtur01/nginx" .

Finally let’s launch a container from it.

$ sudo docker run -P -d jamtur01/nginx

We’ve launched a new container with the ID of fd461a1418c6, run it daemonized and told it to open any exposed ports, in our case port 80 that we EXPOSE‘ed in the Dockerfile. Let’s check the container and see what port it has mapped to Nginx.

 $ sudo docker port fd461a1418c6 80

Now let’s browse to port 49158 to see if Nginx is running.

message showing nginx server is installed

Woot! We’ve got Nginx installed via Puppet. You could easily repeat this process for any Puppet-based (or other CM tool) application or infrastructure.

*This article originally appeared on James Turnbull's blog.

James Turnbull

About the author: A former IT executive in the banking industry and author of five technology books, James has been involved in IT Operations for 20 years and is an advocate of open source technology. He joined Puppet Labs in March 2010 as the VP of Operations, was VP of Engineering at Venmo and is currently VP of Services at Docker Inc. We highly recommend that you read his blog and follow him on Twitter.

Learn More

Share via:
Posted in:

Use instead :

RUN apt-get -y update
RUN apt-get -y install ruby1.9.1 ruby1.9.1-dev rubygems1.9.1 \
irb1.9.1 ri1.9.1 rdoc1.9.1 build-essential \
libopenssl-ruby1.9.1 libssl-dev zlib1g-dev
RUN update-alternatives --install /usr/bin/ruby ruby /usr/bin/ruby1.9.1 400 \
--slave /usr/share/man/man1/ruby.1.gz ruby.1.gz \
/usr/share/man/man1/ruby1.9.1.1.gz \
--slave /usr/bin/ri ri /usr/bin/ri1.9.1 \
--slave /usr/bin/irb irb /usr/bin/irb1.9.1 \
--slave /usr/bin/rdoc rdoc /usr/bin/rdoc1.9.1
sudo update-alternatives --config ruby
sudo update-alternatives --config gem

RUN gem install puppet
RUN gem install librarian-puppet -v 1.0.3

to get rubygems dependencies solved.

Something is missing under Dockefile as I encountered this issue:

Step 5 : RUN puppet apply --modulepath=/modules -e "class { 'nginx': }"
---> Running in 28f47c999c7a
Error: Unknown function merge at /modules/nginx/manifests/params.pp:81 on node fbc229a23508
Error: Unknown function merge at /modules/nginx/manifests/params.pp:81 on node fbc229a23508
2015/04/08 23:10:03 The command [/bin/sh -c puppet apply --modulepath=/modules -e "class { 'nginx': }"] returned a non-zero code: 1

Hi Ajeet

My guess here is that the nginx module is not yet compatible with puppet 4. And since the blog post was published this has been released to rubygems, and the current Dockerfile installs the latest version.

Try and replace the relevant line with to test this out:

RUN gem install puppet -v 3.8.1


@Ajeet : I was facing the same problem and figured out what is wrong. It is not about puppet release, this nginx module has actually 2 dependencies. You need apt and stdlib (which provides the merge function) modules.

I made this work using this Puppetfile :

# cat Puppetfile
mod 'apt',
:git => ""

mod 'stdlib',
:git => ""

mod "nginx",
:git => ""

Hope this help :)

I'm facing the same problem "E: Package 'rubygems' has no installation candidate". I have replace the original line with "RUN gem install puppet -v 3.8." to no avail. I want to try EthanM solution but I don't know how to run this Puppetfile, obviously there must be a sequence (that I don't know) to follow.
I guess I could also add the equivalent command to the Dockerfile but definitely want to learn how to run Puppetfile.
Any help will be appreciated

How I do to generate my own image for?

I try this:

docker::image {'impdb':
    image       => 'impdb',
    image_tag   => '1',
    docker_dir  => '/tmp/',
    subscribe   => File['/tmp/Dockerfile'],
    require     => Service['docker']



FROM debian:jessie

MAINTAINER Eduardo Dicarte ""

ADD sources.list /etc/apt/sources.list

RUN apt-get -y update
RUN apt-get -y -q install wget git-core rubygems
RUN gem install --no-ri --no-rdoc puppet librarian-puppet

RUN mkdir /puppet
WORKDIR   /puppet

ADD site.pp /puppet/site.pp
ADD Puppetfile /puppet/Puppetfile

RUN librarian-puppet install
RUN puppet apply --modulepath=/modules site.pp

But, the image created, hasn't name, how below:
REPOSITORY          TAG                 IMAGE ID            CREATED
<none>              <none>              385981385121        4 minutes ago
I would like this =>
REPOSITORY          TAG                 IMAGE ID            CREATED
impdb              1              385981385121        4 minutes ago

Any help (please :))?

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.