Skip to content
This repository has been archived by the owner on Apr 14, 2018. It is now read-only.

Latest commit

 

History

History
569 lines (437 loc) · 16.5 KB

WORKSHOP.mkd

File metadata and controls

569 lines (437 loc) · 16.5 KB

Puppetconf 2014 r10k workshop

Deploying environments

We're going to start things off by setting up dynamic environments with r10k. The main purpose of r10k is to manage your Puppet environments by mapping the branches of a version control repository (usually Git) to Puppet environments. In doing so we can take advantage of best practices in code development and get all the advantages of version control and apply them to Puppet environments.

Without further ado, let's get started!

Set up a working directory

We're going to set up a temporary working directory for this workshop. We'll have a few directories for this: src, for the source code that we'll be editing, git, to emulate a workflow with a remote Git server, and puppet, where we'll be actually deploying our Puppet code.

mkdir ~/r10k-workshop
cd ~/r10k-workshop
mkdir src git puppet

Prepare a git repository for your Puppet environments

The vast majority of workflows with r10k rely on having some sort of central Git server. Services like GitHub, Bitbucket, and so forth are common but we want to avoid relying on the network for this workshop. To get around this we create a bare git repository that will behave like we're pushing to a remote Git server.

cd git
git init --bare environments.git

Check out a working copy of your environments

Now that we're created a central repository for our Puppet environments, we can now clone it and start working with it.

cd ../src
git clone ~/r10k-workshop/git/environments.git
cd environments

Prepare your environment

In order to make things a bit more simple later in the workshop we're going to change the default modulepath for our environments. Instead of putting our modules in the standard modules directory we'll put them in site. In addition we want a 1:1 relationship between Git branches and Puppet environments so we're going to rename our branch to "production". When that's done we can push the initial code to our "central" git repository.

cat > environment.conf <<EOD
modulepath = site:modules
manifest   = site.pp
EOD
git add environment.conf
git commit -m "Add environment.conf"
git branch -m production
git push -u origin production

Create a module

Now that we have an environment configured how we want it, we need to start populating it with content. We'll use puppet module generate to scaffold out a new module and add our own init.pp with some simple content.

mkdir site
cd site
yes '' | puppet module generate ashpool/helloworld
mv ashpool-helloworld helloworld
cat > helloworld/manifests/init.pp <<EOD
class helloworld {
  notify { "Hello world!": }
}
EOD
git add helloworld
git commit -m "Add helloworld module"
git push

Include the module in site.pp

cd ~/r10k-workshop/src/environments
cat > site.pp <<EOD
node default {
  include helloworld
}
EOD
git add site.pp
git commit -m 'Add helloworld module to default node'
git push

Set up r10k

So r10k is what this demo is all about, but we need to do a little bit of setup beforehand. We need to tell r10k where to retrieve our environments and where to put it. All this information is kept in r10k.yaml, so we'll fill out that configuration file and use it from here on out.

cd ~/r10k-workshop/puppet
mkdir environments
cat > r10k.yaml <<EOD
sources:
  control:
    basedir: "${PWD}/environments"
    remote: "${PWD}/../git/environments.git"
EOD

In real world environments there are Puppet modules to manage your r10k configuration, such as zack/r10k (https://github.com/acidprime/r10k) so you don't need to manage the configuration of r10k by hand. In this workshop we're trying to show how everything fits together and avoid accessing the network, but if you're using r10k in a production environment you should consider using a Puppet module to manage this configuration.

Set up Puppet

cat > ~/.puppet/puppet.conf <<EOD
[main]
environmentpath = "${HOME}/r10k-workshop/puppet/environments"
EOD

Run r10k to deploy your brand new environment

So r10k is configured and we have our code in Git, all we need to do is actually run r10k.

r10k deploy -c r10k.yaml environment

By default r10k only prints messages that are of level WARN or greater, so if you don't see anything printed then that probably means that everything is okay. If you want to see more information about what's happening you can pass the --verbose flag to get more information

Inspect your new environment

So r10k has run - let's see what was done!

ls environments
ls environments/production
cat environments/production/site/helloworld/manifests/init.pp

As you can see, we now have a directory called production with the contents of our production branch in our environments directory. production is the default environment so when Puppet tries to fetch a catalog it will use this environment by default.

Apply the new puppet code

Let's try using this new environment with puppet apply.

puppet apply --environment production ~/r10k-workshop/puppet/environments/production/site.pp

Make a change to the production environment

Now that we've successfully created the production environment, let's try making some changes to that environment.

cd ~/r10k-workshop/src/environments/site
cat > helloworld/manifests/init.pp <<EOD
class helloworld {
  notify { "Hello world!": message => "I am in the production environment"}
}
EOD
git add helloworld/manifests/init.pp
git commit -m "Update helloworld module to print environment"
git push

Deploy that change

We've made a change to the production branch and pushed it; when we run r10k it will bring those changes down to our production environment.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment

After r10k has run we can look at the file that we changed to verify the new contents.

cat environments/production/site/helloworld/manifests/init.pp

Since 'production' is the default environment, we can call puppet apply without specifically passing the environment.

puppet apply ~/r10k-workshop/puppet/environments/production/site.pp

Create a branch

Making changes is all well and good, but one of the especially valuable things about this whole process is the ability to rapidly create new environments and deploy changes in isolation. As was shown earlier, creating a Git branch called production in Git created a corresponding Puppet environment. Just as easily as we made the production environment, we can make a new Git branch that will be isolated from the production branch.

cd ~/r10k-workshop/src/environments
git checkout -b ashpool_test
cd site
cat > helloworld/manifests/init.pp <<EOD
class helloworld {
  notify { "Hello world!": message => "I am in the \${environment} environment"}
}
EOD
git add helloworld/manifests/init.pp
git commit -m "Update helloworld module for ashpool test environment"
git push -u origin ashpool_test

Run r10k to deploy the ashpool_test environment

We've created a new branch and pushed it to the remote, let's run r10k to actually get that code in our environments directory.

In this example we're calling r10k deploy environment with an argument -- the name of the environment we want to deploy. If you invoke this command with no arguments then all environments will be deployed; if you pass one or more environment names then only those will be deployed. This allows us to deploy exactly what we want, so we don't have to deploy every environment when we only care about a single environment.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment ashpool_test

Inspect your new environment

So we've run r10k, let's inspect the aftermath.

ls environments
ls environments/ashpool_test
cat environments/ashpool_test/site/helloworld/manifests/init.pp

Huzzah! We now have two environments, each with their own version of the helloworld module.

We should be able to run puppet apply against the new environment and receive the updated code.

puppet apply --environment ashpool_test ~/r10k-workshop/puppet/environments/production/site.pp

Merge ashpool_test

On the 'ashpool_test' environment we made a snazzy change that will automatically notify us of the environment being use, and we want to bring that into production. We can use git merge to bring the changes made in ashpool_test into the production branch.

cd ~/r10k-workshop/src/environments
git checkout production
git merge ashpool_test
git push

Aside: automating r10k

You're probably sensing a trend that every time we make a change to Git, we need to run r10k. There are many ways to automate the execution of r10k automatically when changes are pushed to a Git repository, including a variety of post-receive hooks. For this workshop we're going to keep things simple and just run r10k by hand but know there are options available for automating this. In addition there will be a presentation on more advanced r10k workflows later today, be sure to check it out!

Run r10k to deploy the production environment

Let's run through the deploy/verify process to confirm that the merge actually added the changes to the production environment.

Deploy:

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment production

And inspect:

cat environments/production/site/helloworld/manifests/init.pp
puppet apply ~/r10k-workshop/puppet/environments/production/site.pp

Success!

Delete the old environment

All of the changes made to the ashpool_test environment are now in production so we no longer need that branch. We can delete the branch from our working Git repository and the remote repository.

cd ~/r10k-workshop/src/environments
git push origin :ashpool_test
git branch -d ashpool_test

Once it's been deleted we can run r10k and it will automatically delete any environments that are no longer in Git.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment

And for the sake of thoroughness, we can verify that the ashpool_test environment is actually gone.

ls environments

One environment, just as expected.

Managing modules in environments

As you manage more systems with Puppet, you'll probably want to start reusing existing modules instead of writing your own. Unfortunately trying to incorporate external modules into a Git repository have many pitfalls. Git subtrees and Git submodules have a large number of pitfalls and can break in very strange ways. In addition modules from the Puppet Forge cannot be cleanly incorporated into a Git repository without doing a bulk check in of the module. To address this problem, r10k supports the concept of a Puppetfile - a version control file that specifies a set of external modules that should be installed for a given environment.

In this workshop we will not be installing modules from the Puppet Forge, but it's as easy to use modules from the Forge as it is to install modules with Git.

Setting up environment.conf for Puppetfile installed modules

When r10k installs modules specified in a Puppetfile, it installs them to the 'modules' directory relative to the Puppetfile. This means that we need to have multiple directories for our modules - the site directory where we added the helloworld module, and the new modules directory. When we created environment.conf earlier we added the 'modules' directory as well as site, so we can use it here.

Creating an external module

To begin with, we need an external module that we can incorporate into our Puppet environments.

cd ~/r10k-workshop/src
yes '' | puppet module generate tessier/icebreaker
mv tessier-icebreaker icebreaker
cat > icebreaker/manifests/init.pp <<EOD
class icebreaker {
  notify { "Hello icebreaker!": }
}
EOD

Version controlling a module with Git

Now that we have our module created, we can version control it with Git.

cd icebreaker
git init
git add .
git commit -m "Initial commit of icebreaker module"

We also need to make a remote repository that we can push the module to.

cd ~/r10k-workshop/git
git init --bare tessier-icebreaker.git
cd ~/r10k-workshop/src/icebreaker
git remote add origin ~/r10k-workshop/git/tessier-icebreaker.git
git push -u origin master

Note that in this example we created the module first and then added it to Git, while for the environment we created an empty repository and then cloned it. Since we're using puppet module generate to create the module instead of creating it from scratch like we did earlier it's easier to do things in this order.

Creating the Puppetfile

Now that we have a standalone module in Git we can add it to our Puppet environments via a Puppetfile entry.

cd ~/r10k-workshop/src/environments
cat > Puppetfile <<EOD
mod "icebreaker", :git => "${PWD}/../../git/tessier-icebreaker.git"
EOD
git add Puppetfile
git commit -m "Add icebreaker to Puppetfile"
git push

Include the module in site.pp

Since we want to include this new module on our nodes, we'll need to update site.pp to include the module.

cd ~/r10k-workshop/src/environments
cat > site.pp <<EOD
node default {
  include helloworld
  include icebreaker
}
EOD
git add site.pp
git commit -m 'Add icebreaker module to default node'
git push

Deploying Puppetfile modules

We have an external Puppet module ready to do and it's specified in our Puppetfile, so we need to run r10k to deploy it. Since we're deploying an environment that has a Puppetfile, we need to add the --puppetfile option to update the modules specified in the Puppetfile.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment production --puppetfile

Now let's take a look at what was installed.

ls environments/production
ls environments/production/modules
cat environments/production/modules/icebreaker/manifests/init.pp

Inside of our environment we now have a modules directory, which contains our icebreaker module.

We should also be able to run puppet apply to run this new module.

puppet apply ~/r10k-workshop/puppet/environments/production/site.pp

Changing external modules

One of the things that Puppet modules tend to do is change and improve, so we need to be able to make changes to our icebreaker module and deploy those to our environments.

cd ~/r10k-workshop/src/icebreaker
cat > manifests/init.pp <<EOD
class icebreaker {
  notify { "Hello Dorsett!": }
}
EOD
git add manifests/init.pp
git commit -m "Update icebreaker notify for Case"
git push

Deploying a single module

In our previous example, we were using r10k deploy environment --puppetfile to update all modules in a given Puppetfile. However if you have a lot of modules this can be rather slow. If you want to update a single module you can use r10k deploy module to update a specific set of modules.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml module icebreaker
cat environments/production/modules/icebreaker/manifests/init.pp

What gets installed?

When r10k installs Puppet modules from Git, it assumes that it should use the latest commit on the 'master' branch. This means that you can make changes to an external Puppet module and push changes to your environment without having to constantly update Git commits, like how Git submodules work. However this should be done for modules that are under development, and modules that are in a final state should be pinned to a commit or tag.

Let's run through how pinning a Git module works.

Tagging a Git module

Before we can pin our icebreaker module, we need a Git ref that we can pin the module to. To make things easier for this demo, we'll create a Git tag.

cd ~/r10k-workshop/src/icebreaker
git tag 0.1.0 HEAD^ -a -m "Initial module release"
git push --tags

In this case we tagged the commit 'HEAD^', which is the second latest commit. We're doing this so that the master branch and the 0.1.0 tag point to different commits.

Updating the Puppetfile with the tag

cd ~/r10k-workshop/src/environments
cat > Puppetfile <<EOD
mod "icebreaker", :git => "${PWD}/../../git/tessier-icebreaker.git", :ref => '0.1.0'
EOD
git add Puppetfile
git commit -m "Update Puppetfile for icebreaker 0.1.0"
git push

Deploy the tagged module

Since we made a change to the Puppetfile, we have to update both the environment and the Puppet module.

cd ~/r10k-workshop/puppet
r10k deploy -c r10k.yaml environment production --puppetfile
cat environments/production/modules/icebreaker/manifests/init.pp

And now the icebreaker module has gone from master to the 0.1.0 tag.

We can run puppet apply to make sure that the expected module version is used.

puppet apply ~/r10k-workshop/puppet/environments/production/site.pp