Deploying your custom application with Puppet

In the past two weeks, we learned how to create packages for our own applications and how to host them in a repository. The next step is to puppetize the application so that you can deploy your application to nodes through automation. We’ll need to add the repo to our base profile, so all nodes receive it, define a profile that requires the application, and a role class and corresponding hiera yaml to apply the configuration to a specified node. Let’s get started!

Add the repo to the base profile

This step is fairly simple. Last week, we defined the repo and applied it manually with:

  yumrepo {'el-6.5':
    descr    => 'rnelson0 El 6.5 - x86_64',
    baseurl  => 'http://yum.nelson.va/el-6.5/',
    enabled  => 'true',
    gpgcheck => 'false',
  }

Add that to your base profile. It should look something like this now:

[rnelson0@puppet manifests]$ pwd
/home/rnelson0/git/profile/manifests
[rnelson0@puppet manifests]$ cat base.pp
class profile::base {
  include ::motd

  # SSH server and client
  class { '::ssh::server':
    ...
  }
  class { '::ssh::client':
    ...
  }

  class { '::ntp':
    servers => [ '0.pool.ntp.org', '2.centos.pool.ntp.org', '1.rhel.pool.ntp.org'],
  }

  yumrepo {'el-6.5':
    descr    => 'rnelson0 El 6.5 - x86_64',
    baseurl  => 'http://yum.nelson.va/el-6.5/',
    enabled  => 'true',
    gpgcheck => 'false',
  }
}

Be sure to commit/push/r10k. Now, all nodes with the base profile, which should be everyone, will receive the repo and have it enabled. Check the repos available to you, run the agent on the master, and make sure the repo is created:

[rnelson0@puppet manifests]$ yum repolist
...
repo id                               repo name                                                         status
base                                  CentOS-6 - Base                                                    6,367
epel                                  Extra Packages for Enterprise Linux 6 - x86_64                    11,104
extras                                CentOS-6 - Extras                                                     15
puppetlabs                            Puppet Labs Products 6 - x86_64                                      422
puppetlabs-deps                       Puppet Labs Dependencies 6 - x86_64                                   68
puppetlabs-products                   Puppet Labs Products El 6 - x86_64                                   422
updates                               CentOS-6 - Updates                                                 1,487
repolist: 19,885
[rnelson0@puppet manifests]$ sudo puppet agent -t
...
Notice: /Stage[main]/Profile::Base/Yumrepo[el-6.5]/ensure: created
...
[rnelson0@puppet manifests]$ yum repolist
repo id                                                                                repo name                                                                                                         status
base                                  CentOS-6 - Base                                                    6,367
el-6.5                                rnelson0 El 6.5 - x86_64                                               4
epel                                  Extra Packages for Enterprise Linux 6 - x86_64                    11,104
extras                                CentOS-6 - Extras                                                     15
puppetlabs                            Puppet Labs Products 6 - x86_64                                      422
puppetlabs-deps                       Puppet Labs Dependencies 6 - x86_64                                   68
puppetlabs-products                   Puppet Labs Products El 6 - x86_64                                   422
updates                               CentOS-6 - Updates                                                 1,487
repolist: 19,889

Piece of cake!

Create a Profile

Let’s create a profile for our application server. Since the repo is provided by the base profile, all we need to do here is ensure that apache is used and that the application is installed. The package comes from the repo, which should be there, but it’s best to be strict about our relationships. Here’s an example of the profile:

[rnelson0@puppet manifests]$ pwd
/home/rnelson0/git/profile/manifests
[rnelson0@puppet manifests]$ cat helloworld.pp
class profile::helloworld {
  class {'::profile::apache': }
  class {'::apache::mod::php': }

  apache::vhost {'helloworld.nelson.va':
    docroot => '/var/www/html',
  }

  Yumrepo['el-6.5'] -> Package <| |>

  package {'helloworld':
    ensure  => 'present',
  }
}

Our Hello World application relies on apache and mod_php, so the first things we do are to attach the profile for apache and the mod_php class for apache (in a future article we’ll look at creating an httpd package dependency for our RPM, but explicit dependencies in Puppet include more than just the package so we won’t be changing this). We also need to add the apache vhost for our server, appropriately called helloworld.nelson.va and the docroot of /var/www/html. At the bottom, we also ensure that the package helloworld is present.

Right before the package at the end, we have a new operator. The collector, or spaceship operator, takes a resource type (Package) and searches all resources for those that match the query between the operator start/end tokens. In this case, where there is no search query, all resources of the Package type are returned. The resource on the left, the el-6.5 Yumrepo that was already declared, is ordered to be applied before the resource on the right. In other words, our defined Yumrepo is ensured to be realized before the packages, like helloworld, that may rely on it. We could simply order the Yumrepo before the individual package, but if we later add other packages, we’d have to revisit it. As it is, this stanza allows us to cheat a bit about the order.

As an alternative, this ordering could be done in the profile::base class. Whether you want that done for all nodes, including those that may never require a package from the repo, is up to you. If so, move this stanza into profile/manifests/base.pp.

One last night, we’ve simply ensured that the package helloworld is present. If we later upgrade from v1.0 to v1.1, any node that already has that profile applied will continue to run the existing version. You could fix this by changing the ensure value to latest or a version number. We’ll revisit that later.

Create a Role and YAML

This step’s pretty simple. Copy another role manifest to helloworld.pp and update the profile references:

class role::helloworld {
  include profile::base  # All roles should have the base profile
  include profile::helloworld
}

We also need a hiera YAML file, copy an existing one and add the single class to it:

[rnelson0@puppet hiera-tutorial]$ cp puppet_role/yumrepo.yaml puppet_role/helloworld.yaml
[rnelson0@puppet hiera-tutorial]$ vi puppet_role/helloworld.yaml
[rnelson0@puppet hiera-tutorial]$ cat puppet_role/helloworld.yaml
---
classes:
  - role::helloworld

Make sure to save, commit, push, and re-deploy your puppet environments before continuing.

Deploy a VM

Deploy a VM from your template called helloworld. Make sure your DNS configuration is updated to support helloworld.nelson.va or equivalent that points to the IP of your new VM. When it’s deployed, run the agent, sign the cert, and run it again. You should then be able to visit http://helloworld.nelson.va and see your web app. The install of apache is noisy, so I’ve isolated the package management in the output:

[rnelson0@helloworld ~]$ sudo puppet agent -t 2>&1 | grep -i helloworld | grep -i package
Notice: /Stage[main]/Profile::Helloworld/Package[helloworld]/ensure: created

helloworld

Summary

If you already have a repository and some packages, which we’ve covered together, distributing your app is easy. Add the repo to your base profile, create a new profile/role/yaml, deploy a VM with the new puppet_role, and connect it to the puppet master. Next, we can delve further into packaging and automating the process.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s