Deploy packages from a Cloudsmith repository with Puppet

What is Puppet?

Puppet is a Continuous Configuration Automation tool that’s you can use to automate the configuration of your entire infrastructure. You can use it to manage the configuration of anywhere from a few, to thousands of servers or devices.

Puppet consists of two main components:

The Puppet Server

The Puppet server is where you create and store your configurations and define which nodes specific configurations will be applied to. Puppet uses modules and manifests to describe how a machine should be configured and they are written in a ruby-like syntax that describes the desired state of a node.

The Puppet Agent

The Puppet agent is installed and runs on each of your nodes. The agent pulls configurations from the Puppet server and then applies them to a node to bring the node into the desired state.  It can be configured to periodically check the Puppet server for new or updated configurations (which would be the usual configuration in a Puppet deployment), or it can be started manually on a node as required.

The Puppet server must be installed on Linux but the Puppet agents can be installed on, and manage, Unix / Linux like systems, MacOS, or Windows.  Installing the Puppet server and agent(s) is beyond the scope of this article, but for further details, you can see the official Puppet documentation.

 

Why Puppet and Cloudsmith?

You can use a private Cloudsmith repository in combination with the automation power provided by Puppet to bolster your pipeline with more security and control over your builds and dependencies. Puppet is an ideal tool to automate the configuration of a Cloudsmith repository on nodes in your infrastructure, and to then also install any required packages and dependencies from this repository.  The key is control - control over your packages via your Cloudsmith repository, and control over your builds and configurations via Puppet.

For this example, we will use Puppet to set up a Cloudsmith repository for Debian packages, but Puppet also provides official modules to support the most popular repository types, like yum, pip, npm, Docker and more.  

 

A worked example:

On our example Puppet server, we will create a module to configure a Cloudsmith repo and install a package. I have created a directory for this module, called cloudsmith-repo.  In this directory, I have also created a manifests directory, and this is where we create our manifest (called init.pp).   

Let’s look at each bit of this manifest and explain what it does.

 

Our manifest starts with a class called cloudsmith-repo, the same as the module name.

First we add the puppet “apt module” with:

include apt

Since our Cloudsmith repository works as a native apt repo, we can use the class and types from the apt module to define the configuration of our repo.

The next thing we do is use the apt:key type to set up the GPG key for our repository. We need to add the 20 Byte Fingerprint of the repository GPG key, which we can get from the signing keys section of our Cloudsmith repo, and the URL for the key:

apt::key { 'cloudsmith-examples':

    id      => '20-BYTE-FINGERPRINT',

    source  => 'https://dl.cloudsmith.io/TOKEN/OWNER/REPOSITORY/cfg/gpg/gpg.8-BYTE-FINGERPRINT.key',

  }

After this, we then use the apt:source type to set up the repository itself. We give the repository a short description, then add the URL for the repository - which also contains an access token as this is a private repository. In your Cloudsmith repo settings, you can create as many of these access tokens as you like, and add restrictions to each token. Or you can also use HTTP basic authentication instead, we support both types of auth:

apt::source { 'cloudsmith-examples':

    comment  => 'An Example Cloudsmith Repository',

    location => 'https://dl.cloudsmith.io/TOKEN/OWNER/REPOSITORY/deb/debian',

    release  => VERSION,

    repos    => 'main',

    pin      => 500,

We will also add our Debian distribution version, and we also specify that this is a Debian source and binary repository, as Cloudsmith repos support both types of Debian package:

include  => {

      'src' => true,

      'deb' => true,

    },

  }

Finally, we declare the package that we would like installed, and we use ensure to specify the version of the package we would like - in this case the latest version:

package { 'PACKAGE-NAME':

    ensure  => 'latest',

  }

So, putting that all together and adding in details for the repository and owner etc, we would have something that looks like this:

class cloudsmith_repo {

  include apt

  apt::key { 'cloudsmith-examples':

    id      => '7DF1831D968E392DAFD802A97D4D4CE49534374A',

    source  => 'https://dl.cloudsmith.io/QOH0JBRgKQx5lE7S/demo/examples-repo/cfg/gpg/gpg.7D4D4CE49534374A.key',

  }

  ~> apt::source { 'cloudsmith-examples':

    comment  => 'An Example Cloudsmith Repository',

    location => 'https://dl.cloudsmith.io/QOH0JBRgKQx5lE7S/demo/examples-repo/deb/debian',

    release  => 'buster',

    repos    => 'main',

    pin      => 500,

    include  => {

      'src' => true,

      'deb' => true,

    },

  }

  ~> package { 'cloudsmith-debian-example':

    ensure  => 'latest',

  }

}

As stated previously, you would normally configure Puppet nodes to periodically check in with the puppet server to pull and apply configurations, but we will just kick off the puppet agent by running it manually with:

sudo puppet agent -t
The puppet agent will now connect to the puppet server and will retrieve and apply the configuration:

We can then check to see that the Cloudsmith repo has been added as a source for apt in /etc/apt/sources.list.d/ :

And if we check that our cloudsmith-debian-example package is now present (with apt-cache showpkg cloudsmith-debian-example), we can see that it has been installed:

In Summary

It really is quick and easy to set up a Cloudsmith repository and deploy your packages using Puppet.  We try to ensure that things "Just Work", and when using the built-in apt_module support in Puppet (or other modules to support other repository types, like yum or pip) you should be up and running in minutes, not hours. 

Using a private Cloudsmith repository allows you to level up the control you have over your packages and software artifacts, and using Puppet allows you to automate and control your infrastructure configurations. It's a great combination.