Today’s sysadmin and devops professionals have to manage, on average, a much larger number of servers hosting a much larger number of applications, than their counterparts from as recently as the 90’s. Blame this on the exponential growth in computing for organizations, coupled with the emergence of new technologies such as virtualization and cloud computing.

Thus tools like Puppet and Ansible are fast becoming essential components for managing a large number of servers, like in a data center. They are commonly called Configuration Management (CM) and Remote Execution (RE) tools, and often overlap with provisioning or orchestration tools. These mega-useful apps allow the admin, for instance, to execute an action on several servers simultaneously, deploy multiple apps with a single click, and generally make it much easier to configure and maintain dozens, hundreds, or even thousands of servers.

Ansible vs Puppet: Overview

Puppet is one of the biggest names in the CM market. It has been around for the longest time, since 2005, which for CM tools is like being around since the dawn of mankind. Several big-name clients run their data centers using Puppet - Google, Reddit, Dell, PayPal, Oracle, Los Alamos Labs, and Stanford University; having such clients on board always lends a certain level of credibility to a product. Puppet also boasts the most mature interface and runs on all the major operating systems – Linux, Windows, Unix and even Mac OS X. Following the model set up by the various Linux versions, it is an open-source app (developed using Ruby), but there is also a large, well-established support and sponsor company called PuppetLabs to offer professional support and a commercial enterprise version of the software. Puppet also offers a simple installation routine and several tools for tasks such as rapid deployment to client servers. There is a Ruby-based CLI in addition to the GUI; actually for most advanced tasks you will most likely have to depend on the CLI, with the GUI being a viewing, management and monitoring interface. This implies that in addition to the sysadmin work, you also have to learn Ruby.

At this point you may be thinking: “All this sounds great! Are there any cons, or can I go purchase Puppet right now?” Well, the buzz in CM discussion forums is that Puppet, like many other software giants, has become a victim of its own success and size. ‘Nimble’ and ‘agile’ aren’t words that can be used to describe Puppet – stuff like reported bugs take too long to fix and ignoring new feature requests. There is also some grumbling about PuppetLabs aggressively pushing its customers towards adopting the commercial version. And lastly, although Puppet supports both pure Ruby as well as its customized DSL on the CLI, the Ruby-only support is being deprecated. This is bad news for those who had only learnt Ruby and not the in-house DSL.

Ansible has leapfrogged Puppet to grab the biggest market share in the configuration management industry, with a leading 26.5% share, followed by old hands MSCCM and Puppet. First released in early 2012, it is also an open-source supported by a parent company – in this case AnsibleWorks. It was developed in Python, not Ruby, which makes it spiritually closer to Salt (another new-ish CM tool) than Puppet. The other advantage of Python is that it is inbuilt into most Unix and Linux deployments nowadays, so getting up and running is quicker. Ansible’s unique selling proposition is its lightweight and quick deployment. In fact it does not even use deployable agents for master-client communication; instead all functions are performed over SSH. For those configurations that don’t support root SSH, Ansible can ‘sudo’ as root. Ansible can be run from the CLI without the use of configuration files for simple tasks, such as making sure a service is running, or to trigger updates and reboots. For more complex tasks, Ansible configuration is handled via YAML syntax in configuration files called playbooks. Ansible commands can be written in almost any programming language and distributed as universal JSON modules, which is clearly a benefit over having to choose a single language.

Ansible has become much more popular due to its fresh approach, and many more companies are deploying Ansible for large data center deployments. Ansible and the enthusiastic community are of course working hard to build on this success – by increasing the number of supported devices, integrating better Windows support, improving the ecosystem, and so on.

Ansible vs Puppet: Setup Differences 

The differences between Ansible or Puppet are apparent right from the moment when you set the tools up. Because the tools follow different architectural paradigms, their setup is different. Ansible has an explicit goal to make setup as simple as possible, and this shows in the user experience. 

To set up Ansible, you will want to designate a single node as your control node. In reality, any of your nodes can be the control node. Install Ansible on this node using the latest Ansible package from your distro’s package repositories. There is no need to set up client software on your other nodes. Create an SSH key pair on your control node, then copy it onto the rest of your nodes. Create an inventory file for your Ansible nodes. Typically, this goes into /etc/ansible/hosts on Linux OSes like Red Hat Linux, Ubuntu, and Debian. As simple as that, you are now ready to use Ansible to run playbooks on both your control node and the rest of your inventory. Ansible will use SSH connections to your controlled nodes to run your configuration management playbooks.

For Puppet, setup is a bit more involved, but there’s plenty of documentation online that will help in case you get stuck. You will need to configure your master and agent nodes to all have the same time and timezone. As root, log into the master server and install the Puppet server software. Configure the Puppet master’s /etc/hosts file to resolve all your managed clients. Start the PuppetServer service, and enable it to receive client connections on port 8140. Since Puppet relies on an agent software running on each minion, you will need to install the Puppet Agent software on each client. You will also need to add the master’s IP address in /etc/hosts to ensure that the client can connect to your master. Start and enable the Puppet agent service on each client. In order for minions to communicate with the master, you will need to generate SSL certificates since Puppet relies on HTTPS for master-client communication.

With both setups, you will want to perform proper server hardening to ensure that unauthorized connections are not permitted.

Ansible vs Puppet: Scalability and Transport Mechanisms 

Both Ansible and Puppet can scale really well, but they use different transport mechanisms to accomplish this goal. In reality, whether you need to manage a few hundred or up to tens of thousands of nodes, there are tweaks and strategies you can use on each platform to scale to that level comfortably.

Ansible uses a transport mechanism default of “smart,” which is typically resolved to SSH. Ansible will first parse your playbooks and determine the inventory that’s affected. It will then open an SSH connection and create a temporary directory. After closing that connection, Ansible opens a second connection for copying over the Ansible module code and Ansible boilerplate code to be executed. Ansible will close this connection before opening a third, final connection for executing the code. This setup will serve most purposes, but it can be customized as you scale your inventory. 

The first feature Ansible can use is called ControlPersist, and it relies on persistent sockets to reduce the time and handshaking required with multiple connections. Ansible also supports “pipelining,” a configuration which cuts down the number of connections required from three to one. Finally, Ansible can be configured to process a greater number of inventory nodes at a time by tweaking the forks variable in Ansible’s configuration. By default, this is set to 5, but you can set it higher to get faster processing. 

Puppet’s transport mechanism is HTTPS which is managed through SSL certificates. A single Puppet server will handle configuration requests from your inventory of Puppet clients. Each client sends Puppet facts to the master and submits a request for a Puppet catalog. The master will then send a catalog in response. The client then processes the catalog, checking each resource against the desired configuration state specified in the catalog. If a resource is not in the desired state, the Puppet client will update the resource on that client machine to conform to the specified desired state. After completing the updates, the client then sends a report back to the Puppet server.

Notably, Puppet’s processing model allocates a JRuby thread from a threadpool to handle each incoming client connection. As your number of nodes grows to large sizes, you can tune Puppet to scale better by expanding the number of JRuby threads available in the pool. You can do this by setting the value of Puppet’s “max-active-instances” configuration setting to a figure higher than the default, which is 1. You can set it, generally, to be as high as the number of CPU cores on the machine, however, be aware that this will use more CPU RAM. As a general rule, you will also need to set a higher “max heap size” for your Puppet server’s JVM to ensure your additional JRuby threads can be allocated without causing an “out of memory” Java virtual machine error. Be careful when performing this tuning as you can stumble into various potential performance pitfalls.  

Ansible CM Code Example 

For day to day configuration work, writing Ansible code is surprisingly simple, thanks to a combination of two factors: using YAML format for its playbooks, and a declarative configuration management style that abstracts away the thorny details. This will be important for getting your devops teams quickly productive, and keeping your code manageable, even for complex configuration tasks.

Ansible code is idempotent. What this means is that you can safely run the playbooks against your inventory over and over again without messing up your servers. Ansible will only change resource states on servers where those states are outside the desired state. For example, if your playbook requires a package to be installed, and a specific configuration file to be created on disk, Ansible will only install this package and create the configuration file you specified the first time the playbook is run on a node. Subsequent runs of the playbooks will leave the package untouched, automatically, until some change occurs that removes or changes the specified file or package configuration. This keeps your nodes in a highly predictable, deterministic state with little to no chance of configuration drift.

Below is a code example of an Ansible playbook that installs the Tomcat web server on your nodes. This is an Ansible example from the official Ansible examples repository, which you can browse to get more familiar with idiomatic Ansible:

- name: Install Java 1.7
yum: name=java-1.7.0-openjdk state=present

- name: add group "tomcat"
group: name=tomcat

- name: add user "tomcat"
user: name=tomcat group=tomcat home=/usr/share/tomcat createhome=no
become: True
become_method: sudo

- name: Download Tomcat
get_url: url= dest=/opt/apache-tomcat-7.0.61.tar.gz

- name: Extract archive
command: chdir=/usr/share /bin/tar xvf /opt/apache-tomcat-7.0.61.tar.gz -C /opt/ creates=/opt/apache-tomcat-7.0.61

- name: Symlink install directory
file: src=/opt/apache-tomcat-7.0.61 path=/usr/share/tomcat state=link

- name: Change ownership of Tomcat installation
file: path=/usr/share/tomcat/ owner=tomcat group=tomcat state=directory recurse=yes

- name: Configure Tomcat server
template: src=server.xml dest=/usr/share/tomcat/conf/
notify: restart tomcat

- name: Configure Tomcat users
template: src=tomcat-users.xml dest=/usr/share/tomcat/conf/
notify: restart tomcat

- name: Install Tomcat init script
copy: dest=/etc/init.d/tomcat mode=0755

- name: Start Tomcat
service: name=tomcat state=started enabled=yes

- name: deploy iptables rules
template: src=iptables-save dest=/etc/sysconfig/iptables
when: "ansible_os_family == 'RedHat' and ansible_distribution_major_version == '6'"
notify: restart iptables

- name: insert firewalld rule for tomcat http port
firewalld: port={{ http_port }}/tcp permanent=true state=enabled immediate=yes
when: "ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7'"

- name: insert firewalld rule for tomcat https port
firewalld: port={{ https_port }}/tcp permanent=true state=enabled immediate=yes
when: "ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7'"

- name: wait for tomcat to start
wait_for: port={{http_port}}

This particular Ansible task downloads and installs Apache Tomcat along with its dependency, the Java JDK 1.7. It then configures, starts and secures the Tomcat installation. As you can see, files managed by Ansible can contain Jinja templates, which makes computing values easier, and makes your configuration more flexible. The YAML code is easy to read and write for both system administrators and developers. It results in making Ansible an approachable configuration management system for both advanced and beginner users alike. 

Puppet CM Code Example 

Puppet’s domain specific language is rooted in Ruby, but the syntax is much closer to C-style imperative languages like Perl, Java, and C++. This approach is a middle ground between developers familiar with Ruby and those who may be unfamiliar with the language. As a result, you don’t need to know any Ruby at all to learn the Puppet DSL and become highly productive with it. 

This sample Puppet manifest from the PuppetLabs MySQL Puppet module repository installs the MySQL client package and configures it:

# @summary
#     Installs and configures the MySQL client.
# @example Install the MySQL client
#     class {'::mysql::client':
#         package_name => 'mysql-client',
#         package_ensure => 'present',
#         bindings_enable => true,
#     }
# @param bindings_enable
#     Whether to automatically install all bindings. Valid values are `true`, `false`. Default to `false`.
# @param install_options
#     Array of install options for managed package resources. You must pass the appropriate options for the package manager.
# @param package_ensure
#     Whether the MySQL package should be present, absent, or a specific version. Valid values are 'present', 'absent', or 'x.y.z'.
# @param package_manage
#     Whether to manage the MySQL client package. Defaults to `true`.
# @param package_name
#     The name of the MySQL client package to install.
class mysql::client (
    $bindings_enable = $mysql::params::bindings_enable,
    $install_options = undef,
    $package_ensure = $mysql::params::client_package_ensure,
    $package_manage = $mysql::params::client_package_manage,
    $package_name = $mysql::params::client_package_name,
)  inherits mysql::params {
    include '::mysql::client::install'

    if $bindings_enable {
        class { 'mysql::bindings':
            java_enable => true,
            perl_enable => true,
            php_enable => true,
            python_enable => true,
            ruby_enable => true,

# Anchor pattern workaround to avoid resources of mysql::client::install to
# "float off" outside mysql::client
anchor { 'mysql::client::start': }
-> Class['mysql::client::install']
-> anchor { 'mysql::client::end': }

An important advantage here in Puppet’s approach is that, unlike those imperative programming languages listed above, the Puppet DSL is declarative, in a way similar to XML as well as the YAML code from the Ansible code example above. The declarative approach of both Puppet and Ansible really shines in both code examples. From a coding perspective, they are similar and closer together than tools such as Chef. That said, the declarative language Puppet uses also provides Ruby-like constructs such as conditionals and iteration, again in a middle of the road style that won’t alienate Ruby users and non-users alike.

Ansible vs Puppet: Ease of Use 

Ease of use should be part of any devops team’s criteria for assessing configuration management tools. Given that Ansible focuses on simplicity of use explicitly as its biggest driving value, this is an area where it performs extraordinarily well. Not just set up, but decisions such as code style and node management all show a thematic approach that presents a simple interface to the devops engineers, whether coming from a developer or sys admin background. 

This is not to say that Puppet is hard to use, not exactly. Puppet packs plenty of power and its opinionated approach to configuration management makes most things obvious as long as you follow the Puppet way to automate your infrastructure. On this front, Puppet helps immensely by modelling each resource explicitly and providing modules that have standard behaviours you can use in your manifests.

From the point of view of learning curve, both platforms are easy to use, but Ansible has a slight edge. The declarative YAML style is easy to get into and Ansible code never gets too complex. Puppet, in the meantime, has come to recognize some of the challenges associated with combining data and code in the same source files. This has propelled the rise of Puppet Hiera, a data storage solution that uses YAML format to store key-value pairs of configuration data. Hiera goes a long way to simplifying and optimizing the Puppet devops experience. The YAML format has proven popular for configuration management use cases, with Salt by Saltstack also using the format.  

Puppet and Ansible both have capabilities for checking and testing your configuration management, all the way from syntax checks to integration your infrastructure-as-code code.

Ansible vs Puppet: Licencing and Enterprise Costs 

As open source tools, Ansible and Puppet have plenty in common where licensing is concerned. 

For a start, the open source release of Ansible is available completely free of charge. For enterprises that require more in the way of security assurances, stability, and reliability, you can upgrade to Ansible Engine, which is a supported, hardened, enterprise-grade release that is provided by Red Hat. Licensing costs for Ansible Engine run generally between $47.50 and $70 per year per node, and vary based on your preferred setup. 

It’s certainly worth it to get the enterprise version when you consider the availability of paid support and how this can help you troubleshoot problems and get them resolved much faster. Ansible Tower, an enterprise management tool, is also available as a service package, and gives your team more capabilities around knowledge, control, and job scheduling from a GUI dashboard.

Just like Ansible, Puppet’s open source release is available for free. For more enterprise features and support, organizations can upgrade to Puppet Enterprise, which costs around $112 to $199 per year per node. Puppet Enterprise offers a package of multiple enterprise level Puppet tools in one installation, along with enterprise grade reporting and monitoring tools, among other advantages over the open source version.   

Ansible vs Puppet: Community 

Puppet, launched in 2005, is the older of these two devops tools, and so has had more time to build its community and user base. However, Ansible, launched in 2012, due to its novel approach, has been able to attract an even bigger audience and create a very vibrant user and contributor community in that time. Puppet users include companies like Uber, Salesforce, and Paypal. The Ansible community, on the other hand, includes companies like Digital Ocean, 9GAG, and TypeForm.

The Ansible community on Github, as measured by contributors, an important indicator in the open source community, is now bigger than that of Ansible, with over 4,800 contributors to Puppet’s 527. The momentum of Ansible over the last several years has been very fast and groundbreaking. It’s reflected in the breakneck pace at which the number of user share Ansible roles on Ansible’s community repository of shared Ansible code, Ansible Galaxy, has exploded. This indicates that the Ansible community has embraced the tool and is eager to share their code and contribute back to the community.

Meanwhile, Puppet’s community, while slower-moving and more stable, has built up the infra-structure to make it easy to find solutions to your Puppet needs from the rest of the community. Puppet Forge provides community contributed modules for accomplishing common configuration management tasks for the Puppet community.

Both of these tools have first class command line tools that enable precise control over the entire lifecycle of a configuration management project. Both integrate well with other widely used devops systems such as Docker, Kubernetes, and Jenkins, or cloud computing platforms like AWS and Azure.    

Is Ansible or Puppet better?

Which of these two tools is best for you is a question only you can determine. The declarative style of both Ansible and Puppet means that these tools have more in common than they have with a bunch of other configuration management tools. However, to make the best selection for your team, you need to pay special attention to how your needs mesh with the tool’s design and strengths.

Ansible should be a better fit for teams that have some interest in YAML-style configuration, and that are in sync with Ansible’s philosophy. This philosophy prioritizes being very simple and having a minimal learning curve, while aiming for managing machines very quickly and in parallel. In addition, this approach is agentless and aims to use existing SSH features instead of building custom agents.

Puppet, on the other hand, should be a better fit for teams that want a DSL that models system resources in a consistent, repeatable manner. This is what the Puppet DSL accomplishes, along with an entire ecosystem of tools to make working with large teams predictable and easy.

Which of those two descriptions better fits your team, only you can tell. If so, your pick should be easy.  


So should you choose Ansible or Puppet? There is no easy answer for this – it depends on your needs. 

  Pros Cons
  • Mature solution
  • Good GUI
  • Support for all major OS’s
  • Easy install
  • Slow-ish to respond and address customer concerns
  • Ruby-based, performance questionable compared to Python-based CM tools
  • Soon all customers must learn the Puppet DSL
  • Excellent performance, agentless install and deploy
  • Low overhead, playbook based
  • Based on ubiquitous Python language
  • CLI accepts commands in almost any language
  • Still very new; not yet tried and tested by many
  • No support for Windows
  • GUI a work in progress

Ready to see
UpGuard in action?