Wednesday, December 24, 2014

Book Review: Puppet Essentials

This blog post is my review of Felix Frank's Puppet Essentials (Packt Publishing, 2014). The subtitle of this book is, "Get up and running quickly using the power of Puppet to manage your IT infrastructure," and it consists of 8 chapters spanning just over 200 substantive pages.


The Preface of a Packt book tends to be a good first place to look when trying to decide whether the books suits the potential reader. As with other Packt books I've reviewed, Puppet Essentials's Preface provides short summaries of its eight chapters and explains what's needed to run the examples ("two or more virtual machine instances" with the "virtualization guests [having] a connection to the Internet and with each other"). The first chapter also tells us that all examples in the book use "the 3.6.2 release from Puppet Labs' repository."

The "Who this book is for" section of Packt Prefaces us perhaps the most important to a potential reader. This one states:

This book assumes that you have no prior Puppet knowledge. You should have a sound technical background. Experience with the GNU/Linux command line is required. Existing programming skills are recommended. This book is also suitable for beginners or intermediate Puppet users who wish to expand their knowledge about the software.
Chapter 1: Writing Your First Manifests

The initial chapter of Puppet Essentials provides some brief historical facts about Puppet and then explains how to download and install Puppet. The chapter then explains that Puppet manifests are "the equivalent of scripts or programs" and are "written in Puppet's domain-specific language (DSL)."

Chapter 1 differentiates parameters and properties in Puppet and then explains and demonstrates use of the -e option (pass in-lined manifest via shell command) and use of the --noop option ("dry run" what command would do without actually causing that effect or change).

This first chapter provides an introduction to Puppet syntax including conditional statements (if/elsif/else, case, and selectors [ternary]), using variables (which are immutable) and variable types (strings, arrays, and hashes). The first chapter also has a nice explanation of how Puppet manifests are declarative rather than imperative (or procedural). The author writes that "manifests should always describe what you expect to be the end result. The specifics of what actions need to be taken to get there are decided by Puppet."

Because Puppet manifest files are declarative, it is important to explicitly specify order of the results prescribed in the manifest file. The first chapter demonstrates use of -> syntax (order chaining arrow) to establish these explicit dependencies. It also explains and demonstrates application of the before and require metaparameters for explicitly specifying dependencies.

I liked that, in the section on avoiding circular dependencies, the author shows the error that will be printed to the console indicating a circular dependency error and discusses how to see the cyclic path using the --graph option. Use of -graph generates .dot files that can be viewed as graphics with OmniGraffle, Graphwiz, or dotty.

Chapter 1's introduction to Puppet also covers communication between resources via events/signals. I like how the use of notify and subscribe are shown to be analogous to use of before and require. This section also introduces the notification chaining arrow (~>).

The first chapter wraps up with a discussion on "examining the most notable resource types" and specifically looks at the file, package, service, user, group, exec (with a warning to beware abusing this), cron, and mount. The chapter's summary provides some useful reminders including that Puppet manifests "resemble scripts," but "they should not be considered as such" because "they consist of resources instead of commands" and these "resources are generally not evaluated in the order in which they have been written."

Chapter 2: The Master and Its Agents

The second chapter of Puppet Essentials moves the focus from simple Puppet manifests used on single hosts to master/agent use. This chapter introduces puppet-master and explains how to specify agent-specific configuration in node designations in the site manifest on the master.

I liked that Chapter 2 mentions use of --configprint to print out configuration settings Puppet is using. The chapter also covers setting up the agents and getting them to communicate properly with certificates. The discussion covers creating a certificate, revoking a certificate, and renewing a certificate. Another part of the chapter discusses using cron to manage agent lifecycle.

Chapter 2 includes a warning about not using Puppet's built-in WEBrick in a production environment. It then describes in detail how to configure Ruby-based Phusion Passenger with Apache server and with Nginx.

The second chapter discusses tuning Puppet by monitoring and configuring the Passenger Pool Size when using Phusion Passenger instead of WEBrick. There is also a section in this chapter on troubleshooting SSL issues.

Chapter 3: A Peek Under the Hood – Facts, Types, and Providers

Puppet Essentials's third chapter begins with an explanation for why Facter is a valuable "secondary system" in Puppet. The author describes Facter as being "a layer of abstraction over the characteristics of both hardware and software." This feature especially intrigued me as Facter supplies "facts" about each agent that are essentially characteristics of each particular host identified by well-known names. Some of the built-in "facts" that are referenced include processorcount, ipaddress, operatingsystem, operatingsystemrelease, osfamily, and macaddress. The chapter then moves onto developing custom facts with Ruby code and discusses approaches for specifying when facts only apply to certain operating systems or hardware. I also appreciate the author addressing external facts that can be written without Ruby as static (YAML or JSON format) files or even scripts.

Chapter 3 also provides more in-depth discussion of types and providers in Puppet.

Chapter 4: Modularizing Manifests with Classes and Defined Types

Chapter 4 of Puppet Essentials introduces Puppet classes and Puppet defined types and then compares and contrasts them and describes the situations in which each is preferred. Nesting classes is also explained and demonstrated as an approach for composite classes.

Sections in Chapter 4 explain how to use defined types as resource wrappers, as resource multiplexers, as macros, and to process array values. This very detailed chapter also discusses limitations of Puppet classes and some work-arounds for those limitations.

Chapter 5: Extending Your Puppet Infrastructure with Modules

Chapter 5 of Puppet Essentials is about Puppet modules, which the PuppetForge website describes as "reusable, sharable units of Puppet code." The chapter describes the types of things that can be part of a module and explains that modules are in root directories with names matching the module's name. Manifests are stored under that module-named root directory in the manifests subdirectory. The author explains that manifests/init.pp "can be thought of as a default manifest location, because it is looked up for any definition from the module in question." The author also uses text explanation and indented text hierarchical representation of the module's directory/file structure to illustrate structuring of a module in the file system. This chapter also explains how to configure various environments for Puppet.

Another section of Chapter 5 covers downloading and installing modules created by others. This section references PuppetForge as one source of modules and introduces the command puppet module install to download and install a Puppet module. The author recommends that "the stdlib module should be considered mandatory" because "it adds a large number of useful functions to the Puppet language."

The "Modules' Best Practices" section of Chapter 5 "provides details on how to organize your manifests" and "advises some design practices and strategies in order to test changes to modules." Along the way, the author references Puppet taking advantage of an infrastructure as code paradigm. This chapter also explains how to create one's own module without publishing it to PuppetForge. An interesting example working with Cacti illustrates various points being made, including that there are times when it's best to write a wrapper script when a series of complex commands needs to be run and call that wrapper script from Puppet.

A relatively lengthy section of the fifth chapter discusses "enhancing the agent through plugins" such as custom facts, parser functions, types, and providers. The portion of custom facts states that "native Ruby facts ... are more portable than external facts." The chapter concludes with a brief overview of how to find modules matching one's needs on PuppetForge.

Chapter 6: Leveraging the Full Toolset of the Language

Puppet Essentials's sixth chapter covers "some techniques that you are not going to need every day" that "can make difficult scenarios much easier." In the section on templating configuration files, the author points out that Puppet uses ERB as its template language and that this is similar to PHP or JSP, but with Ruby code inside the tags. This section on templating introduces basic ERB syntax, describes how to apply templates, and describes how to mitigate performance issues with templates.

The section of Chapter 6 on creating virtual resources with the @ prefix provides concrete discussion on how these virtual resources make it much easier to use common resources across Puppet modules. This section uses text and code listings to explain realizing virtual resources with the realize function and with a collector.

Chapter 6 also introduces exported resources and demonstrates use of @@ prefix to declare these. It also provides an example of collecting exported resources.

The brief "Exporting SSH host keys" section of Chapter 6 introduces Puppet's sshkey service. The chapter also includes two other brief sections on "managing hosts files locally" and "automating custom configuration items." There are much more detailed sections on overriding resource parameters, Puppet class inheritance, and using resource defaults. Chapter 6 concludes with warnings about using the defined function or stdlib's ensure_resource and a discussion about why these should be avoided.

Chapter 7: Separating Data from Code Using Hiera

Chapter 7 of Puppet Essentials talks about the maintenance issues associated with Puppet manifests that mix data and logic and introduces use of Hiera to support an "external database that holds all individual and shared values." The chapter describes Hiera built into Puppet and demonstrates how to configure Hiera via the hiera.yaml file. The chapter briefly compares and contrasts the three back-ends for Hiera (YAML, JSON, and Puppet Manifest Files), mentions that custom Ruby back-ends can be written, and then focuses on YAML files. It provides detailed explanations and examples of using Hiera and briefly discusses considerations when "choosing between manifest and Hiera designs."

A particularly useful section of Chapter 7 is the section "Debugging Hiera lookups" which introduces the command-line tool hiera that can be used to help "determine where the respective [data] values are retrieved from for any given agent node."

Chapter 8: Configuring Your Cloud Application with Puppet

The final chapter of Puppet Essentials talks about using Puppet in the cloud. Before discussing Puppet and the cloud, however, the chapter first looks at some of Puppet's most common deployment environments (Debian and Red Hat Linux and with Vagrant). This eighth chapter also describes Craig Dunn's Roles and Profiles pattern.

The discussion on "Taking Puppet to the cloud" approaches this subject based on the "Infrastructure as a Service (IaaS) paradigm," but later provides an explanation of how to implement a Platform as a Service (PaaS) implementation on top of the IaaS implementation. Sections in this chapter cover "initializing agents in the cloud," "using Puppet's cloud-provisioner module," "building Manifests for the cloud," "composing arbitrary configuration files," and "handling instance deletions."

A major section in this final chapter is on "preparing for autoscaling" so commonly associated with deployments to the cloud. Several items are discussed in this section, including the need to test manifests regularly.

The final chapter's Summary summarizes the chapter and includes a couple of paragraphs that provide an overall book conclusion.

General Observations
  • Puppet Essentials serves as both an introductory text on use of Puppet and as a reference on more intermediate and advanced uses of Puppet.
  • I like that Puppet Essentials talks about things that have changed in Puppet or are likely to change in the future. It's difficult for a technical book to avoid being overcome by events or becoming obsolete, but these references to changes help.
  • Puppet Essentials is written as though expecting an audience familiar with Ruby or Perl for most of their scripting tasks. This assumption is manifest (no pun intended) by many references to those languages when introducing Puppet concepts and syntax.
  • Puppet Essentials references things that are outside the scope of the book such as Puppet 4, Stages, scaling a master with load balancing, using "openssl command-line tool ... for analyzing the certificates and related files", generating HTML documentation with puppet-doc (which apparently has been used to create much of the impressive Puppet online documentation), writing Ruby back-ends for Hiera, publishing modules, and "exploiting PuppetDB."
  • The "Summary" sections of each chapter did a nice job of thoroughly and relatively concisely reviewing the highlights covered earlier in each chapter.
  • The numerous code listings in this book are black font on white background with no color syntax and no line numbers. There are some instances where portions of code most relevant to the discussion are highlighted in bold.
  • Although the text of Puppet Essentials is generally highly readable, there are some typos. For example, there are at least a couple references to "boxen" instead of "boxes."
  • Other reviews of Puppet Essentials might help provide a more complete picture of the book:

I recommend Puppet Essentials for developers or operations personnel (or "DevOps" personnel) who want a good introductory text on Puppet that also provides enough in-depth information and observations to be useful as a reference. As the author states in the book, the online Puppet documentation seems well maintained and highly approachable, but it's nice to have a book to tie it altogether and to provide some in-depth asides.

No comments: