Puppet Tutorial for Beginners: Basics & DSL
โก Smart Summary
Puppet is an open-source configuration management platform that automates how servers are provisioned, configured, and kept consistent. It applies infrastructure as code through a declarative domain specific language, replacing repetitive manual administration across large server fleets.

Puppet is an open-source configuration management tool that lets you define infrastructure as code and keep large fleets of servers in a consistent, repeatable state. Before we learn Puppet, let us first understand configuration management.
What is Configuration Management?
Configuration management is the process of maintaining software and computer systems โ such as servers, storage, and networks โ in a known, desired, and consistent state. It also provides access to an accurate historical record of system state for project management and audit purposes.
System administrators mostly perform repetitive tasks, such as installing servers and configuring them. These professionals can automate this work by writing scripts.
However, this becomes a difficult job when they work on a massive infrastructure. Configuration management tools such as Puppet were introduced to resolve these issues.
What is Puppet?
Puppet is a system management tool for centralizing and automating the configuration management process. Puppet is also used as a software deployment tool.
It is open-source configuration management software, widely used for server configuration, management, deployment, and the orchestration of various applications and services across the whole infrastructure of an organization.
Puppet is specially designed to manage the configuration of Linux and Windows systems. It is written in Ruby and uses its unique Domain Specific Language (DSL) to describe system configuration.
What are the Puppet versions?
Puppet comes in two versions:
- Open Source Puppet: It is a basic version of the Puppet configuration management tool, also known as Open Source Puppet. It is available directly from Puppet’s website and is licensed under the Apache 2.0 system.
- Puppet Enterprise: A commercial version that offers features such as compliance reporting, orchestration, role-based access control, a GUI, an API, and command-line tools for the effective management of nodes.
What Puppet can do?
For example, suppose you have an infrastructure with about 100 servers. As a system administrator, it is your role to ensure that all these servers are always up to date and running with full functionality.

To do this, you can use Puppet, which lets you write simple code that can be deployed automatically on these servers. This reduces human effort and makes the development process fast and effective.

Puppet performs the following functions:
- Puppet allows you to define distinct configurations for every host.
- The tool allows you to continuously monitor servers to confirm whether the required configuration exists and has not been altered. If the configuration is changed, Puppet reverts to the pre-defined configuration on the host.
- It also provides control over every configured system, so a centralized change is automatically effected everywhere.
- It is also used as a deployment tool, because it automatically deploys software to the system. It implements infrastructure as code, because policies and configurations are written as code.
Puppet DSL and Programming Paradigms
Before we learn the Puppet DSL, let us understand programming paradigms. A programming paradigm is a style that you use in computer programming.
Four types of paradigms are:
- Imperative.
- Declarative.
- Functional (which is considered a subset of the declarative paradigm).
- Object-oriented.
We will focus on the imperative and declarative paradigms.
Imperative Paradigms
This programming paradigm expresses the logic of a computation (what to do) and also describes its control flow (how to do it).
Example:
Assume you are going to your office. You book a cab and start giving step-by-step directions to the driver until you reach the office. Specifying what to do and how to do it is an imperative style.
Declarative Paradigms
This programming paradigm expresses the logic of a computation (what to do) without describing its control flow (how to do it).
Example:
Assume you are going to your office. You book an Uber cab and specify only the final destination (the office). Specifying what to do, but not how to do it, is a declarative style.
| Paradigm | What to do | How to do |
|---|---|---|
| Imperative | Yes | Yes |
| Declarative | Yes | No |
Puppet uses a declarative programming paradigm
Puppet uses a declarative programming approach.
Example: Create a user on the system.
It can be done using an imperative programming pattern with a shell script. Here, we specify how to create the user and what commands to use on the operating system.
However, it can also be done using a declarative programming pattern with only a few lines of Puppet code and the Puppet domain specific language (DSL), and still achieve the same result.
Deployment models of configuration management tools
There are two deployment models for configuration management tools:
- Push-based deployment model: initiated by a master node.
- Pull-based deployment model: initiated by agents.
Push-based deployment model
In this deployment model, the master server pushes the configurations and software to the individual agents. After verifying a secure connection, the master runs commands remotely on the agents. For example, Ansible and Salt Stack.
Pull-based deployment model
In this deployment model, individual servers contact a master server, verify and establish a secure connection, download their configurations and software, and then configure themselves accordingly โ for example, Puppet and Chef.
How Puppet works?
Puppet is based on a pull deployment model, where the agent nodes check in regularly โ after every 1800 seconds โ with the master node to see if anything needs to be updated on the agent. If an update is required, the agent pulls the necessary Puppet code from the master and performs the required actions.
Let us explain this with an example of a master-agent setup.
The Master
This is a Linux-based machine with the Puppet master software installed on it. It is responsible for maintaining configurations in the form of Puppet code. The master node can only be Linux.
The Agents
These are the target machines managed by Puppet, with the Puppet agent software installed on them.
The agent can be configured on any supported operating system, such as Linux, Windows, Solaris, or Mac OS.
The communication between the master and the agent is established through secure certificates.

Communication between the Master and the Agent
Step 1) Once the connectivity is established between the agent and the master, the Puppet agent sends data about its state to the Puppet master server. These are called Facts, and this information includes the hostname, kernel details, IP address, file name details, and so on.

Step 2) The Puppet master uses this data and compiles a list of the configuration to be applied to the agent. This list of configuration to be performed on an agent is known as a catalog. It could include package installation, upgrades or removals, file system creation, user creation or deletion, server reboot, IP configuration changes, and so on.
Step 3) The agent uses this list of configuration to apply any required configuration changes on the node.
If there are no drifts in the configuration, the agent does not perform any configuration changes and leaves the node running with the same configuration.

Step 4) Once it is done, the node reports back to the Puppet master, indicating that the configuration has been applied and completed.
Puppet Blocks
Puppet provides the flexibility to integrate reports with third-party tools using Puppet APIs.
Four types of Puppet building blocks are:
- Resources
- Classes
- Manifest
- Modules
Puppet Resources
Puppet resources are the building blocks of Puppet.
Resources are the inbuilt functions that run at the back end to perform the required operations in Puppet.
Puppet Classes
A combination of different resources can be grouped together into a single unit called a class.
Puppet Manifest
A manifest is a directory containing Puppet DSL files. These files have a .pp extension, which stands for Puppet program. The Puppet code consists of definitions or declarations of Puppet classes.
Puppet Modules
Modules are a collection of files and directories, such as manifests and class definitions. They are the re-usable and sharable units in Puppet.
For example, the MySQL module installs and configures MySQL, and the Jenkins module manages Jenkins.

Types of Puppet resources
In general, a system consists of files, users, services, processes, packages, and so on. In Puppet, these are called resources, and they are the fundamental building blocks of Puppet.
All the operations on Puppet agents are performed with the help of Puppet resources.
Puppet resources are the readymade tools used to perform various tasks and operations on any supported platform. We can use a single Puppet resource to perform a specific task, or we can use multiple Puppet resources together to perform complex application configuration deployments.
Resources can have different types. Puppet uses resources and resource types in order to describe a system’s configuration.
There are three kinds of resource types:
- Puppet core or built-in resource types.
- Puppet defined resource types.
- Puppet custom resource types.
Puppet core or built-in resource types
Core or built-in resource types are the pre-built Puppet resource types shipped with the Puppet software. All of the core or built-in Puppet resource types are written and maintained by the Puppet team.
Puppet defined resource types
Defined resource types are lightweight resource types written in the Puppet declarative language using a combination of existing resource types.
Puppet custom resource types
Custom resource types are completely customized resource types written in Ruby.
Let us explore Puppet resource types further.
In the terminal, type the following command to display a list of Puppet-related subcommands:
Puppet --help
In our case, we are interested in the subcommand “resource“, which we will use to find information about the inbuilt Puppet resource types.
In the terminal, type any of the following commands to display a list of actions associated with the Puppet subcommand “resource“:
Puppet help resource Puppet resource --help
In this case, we have resource as the subcommand and –types as the action.
Puppet has 49 inbuilt core resource types.
In the terminal, type the following command to display a list of the available inbuilt Puppet resource types:
puppet resource โtypes
Each type supports a list of attributes. These attributes provide a detailed description that Puppet uses to manage the resource.
To find out all the attributes associated with a Puppet resource type, use the following command:
puppet describe <resource type name>
The parameters will list all the available attributes for that resource type.
puppet describe package
It is hard for a new person to understand and relate many unmanaged Puppet code files. This is where we need some grouping to tie operations together. The aim is to solve a single problem, such as all the operations required to configure SSH on a server, an NTP service, or a complete web server or database server from scratch.
What are Puppet Classes?
Puppet classes are collections of Puppet resources bundled together as a single unit.
Puppet introduced classes to make the structure re-usable and organized.
First, we need to define a class using the class definition syntax. Classes must be unique and can be declared only once with the same name:
class <class-name> {
<Resource declarations>
}
Example:
class ntpconfig {
file {
"/etc/ntp.conf":
ensure=> "present", content=> "server 0.centos.pool.ntp.org iburst\n",
}
}
So far, we have only defined the class; we have not used it anywhere. This means the code we have written will never be executed unless we declare this class elsewhere.
Class Declaration
To use a defined class in your code, use the include keyword.
class ntpconfig {
file {
"/etc/ntp.conf":
ensure=> "present",
content=> "server 0.centos.pool.ntp.org iburst\n",
}
}
include ntpconfig
Let us understand this with a real-world scenario.
Demo install NTP
First, make sure the NTP package is not already present on the server. The following command will return nothing if the NTP package is not present on the server:
rpm -qa | grep -i ntp
As we can see, the NTP package is already present on the server. Let us remove the existing NTP package:
yum remove ntp
After removing the package, ensure that the ntp.conf file no longer exists:
ls -lrt /etc/ntp.conf
Verify that the ntp service does not exist by running the following command:
systemctl status ntp
Create a new .pp file to save the code. From the command line:
vi demontp.pp
Change to insert mode by pressing i on the keyboard.
Type the following code to create a new file:
# Class Definition
class ntpconfig {
# Installing NTP Package
package {"ntp":
ensure=> "present",
}
# Configuring NTP configuration file
file {"/etc/ntp.conf":
ensure=> "present",
content=> "server 0.centos.pool.ntp.org iburst\n",
}
# Starting NTP services
service {"ntpd":
ensure=> "running",
}
}
After you are done editing, press esc.
To save the file, press :wq!
The next step is to check whether the code has any syntax errors. Execute the following command:
puppet parser validate demontp.pp
Make sure that you have switched to the root user to be able to complete the test without any error, by executing the command:
su root
Test is the next step in the code creation process. Execute the following command to perform a smoke test:
Puppet applies demontp.pp --noop
The last step is to run Puppet in real mode and verify the output.
puppet apply demontp.pp
Puppet did not perform anything because the demo class was just defined but not declared.
So, until you declare the Puppet class, the code will not get applied.
Let us declare the demo class inside the same code using include class name at the end of the code:
# Class Definition
class ntpconfig {
# Installing NTP Package
package {"ntp":
ensure=> "present",
}
# Configuring NTP configuration file
file {"/etc/ntp.conf":
ensure=> "present",
content=> "server 0.centos.pool.ntp.org iburst\n",
}
# Starting NTP services
service {"ntpd":
ensure=> "running",
}
}
# Class Declaration
include ntpconfig
Again, check whether the code has any syntax errors. Execute the following command:
puppet parser validate demontp.pp
Make sure that you have switched to the root user to be able to complete the test without any error, by executing the command:
su root
Testing is the next step in the code creation process. Execute the following command to perform a smoke test:
Puppet apply demontp.pp --noop
The last step is to run Puppet in real mode and verify the output.
puppet apply demontp.pp
This time, the code gets applied because the class was defined and then declared.
Ensure that ntp.conf now exists:
ls -lrt /etc/ntp.conf
Verify that the ntp service has been started by running the following command:
systemctl status ntpd











