Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
Learn Ansible

You're reading from   Learn Ansible Automate your cloud infrastructure, security configuration, and application deployment with Ansible

Arrow left icon
Product type Paperback
Published in May 2024
Publisher Packt
ISBN-13 9781835088913
Length 414 pages
Edition 2nd Edition
Tools
Arrow right icon
Author (1):
Arrow left icon
Russ McKendrick Russ McKendrick
Author Profile Icon Russ McKendrick
Russ McKendrick
Arrow right icon
View More author details
Toc

Table of Contents (24) Chapters Close

Preface 1. Part 1: Introducing, Installing, and Running Ansible FREE CHAPTER
2. Chapter 1: Installing and Running Ansible 3. Chapter 2: Exploring Ansible Galaxy 4. Chapter 3: The Ansible Commands 5. Part 2: Deploying Applications
6. Chapter 4: Deploying a LAMP Stack 7. Chapter 5: Deploying WordPress 8. Chapter 6: Targeting Multiple Distributions 9. Chapter 7: Ansible Windows Modules 10. Part 3: Network and Cloud Automation
11. Chapter 8: Ansible Network Modules 12. Chapter 9: Moving to the Cloud 13. Chapter 10: Building Out a Cloud Network 14. Chapter 11: Highly Available Cloud Deployments 15. Chapter 12: Building Out a VMware Deployment 16. Part 4: Ansible Workflows
17. Chapter 13: Scanning Your Ansible Playbooks 18. Chapter 14: Hardening Your Servers Using Ansible 19. Chapter 15: Using Ansible with GitHub Actions and Azure DevOps 20. Chapter 16: Introducing Ansible AWX and Red Hat Ansible Automation Platform 21. Chapter 17: Next Steps with Ansible 22. Index 23. Other Books You May Enjoy

Ansible versus other tools

If you look at the design principles in the first commit compared to the current version, you will notice that while there have been some additions and tweaks, the core principles remain pretty much intact:

  • Agentless: Everything should be managed by the SSH daemon using the WinRM protocol in the case of Windows machines or API calls—there should be no reliance on custom agents or additional ports that need to be opened or interacted with on the target host. The machine running Ansible should need line of sight of the target resource network-wise.
  • Minimal: You should be able to manage new remote machines without installing any new software on the target host; each Linux target host will typically have at least SSH and Python installed as part of a minimal installation, which is all needed to run Ansible.
  • Descriptive: You should be able to describe your infrastructure, stack, or task in a language readable by machines and humans.
  • Simple: The setup processes and the learning curve should be simple and intuitive.
  • Easy to use: It should be the most accessible IT automation system ever.

A few of these principles make Ansible quite different from other tools. Let’s examine the fundamental difference between Ansible and other tools, such as Puppet and Chef.

Declarative versus imperative

When I started using Ansible, I had already implemented Puppet to help manage the stacks on the machines I was managing. As the configuration became increasingly complex, the Puppet code became highly complicated. This was when I started looking at alternatives, and some fixed some of the issues I was facing.

Puppet uses a custom declarative language to describe the configuration. Puppet then packages this configuration as a manifest that the agent running on each server then applies.

Using declarative language means that Puppet, Chef, and other configuration tools, such as CFEngine, all operate using the principle of eventual consistency, meaning that eventually, after a few runs of the agent, your desired configuration would be in place.

On the other hand, Ansible is an imperative language that, rather than just defining the end state of your desired outcome and letting the tool decide how it should get there, you also define the order in which tasks are executed to reach the state you have defined.

The example I use is as follows. We have a configuration where the following states need to be applied to a server:

  1. Create a group called Team.
  2. Create a user Alice and add her to the group Team.
  3. Create a user Bob, and add him to the group Team.
  4. Give the user Alice escalated privileges.

This may seem simple; however, when you execute these tasks using declarative language, you may, for example, find that the following happens:

Figure 1.1 – An overview of what happens with the declarative run

Figure 1.1 – An overview of what happens with the declarative run

So, what has happened here? Our tool has executed the tasks during run 1 in the order of 2, 1, 3, and 4, meaning that the user Alice could not be created when the first task ran because the group Team did not exist.

However, as the group Team was created before the user Bob was created, Bob’s user was created without any errors, and the final task, adding escalated privileges to the user Alice, failed because no user called Alice existed on the system for the escalated privileges to be applied to.

During run 2, the tasks were executed in the same order as run 1, but this time as a group called Team existed, the user Alice was created, and because Alice was present, that user was given escalated privileges.

No changes were needed during run 3 as everything was as expected; that is, consistent.

Each subsequent run would continue until there was either a change to the configuration or on the host itself, for example, if Bob had annoyed Alice and she used her escalated privileges to remove the user Bob from the host. When the agent subsequently runs, Bob will be recreated as that is still our desired configuration, no matter what access Alice thinks Bob should have.

If we were to run the same tasks using an imperative language, then the following should happen:

Figure 1.2 – An overview of what happens with the imperative run

Figure 1.2 – An overview of what happens with the imperative run

The tasks are executed in the order we defined them, meaning that the Team group is created, the Alice and Bob users are added, and the escalated privileges to the Alice user are applied.

As you can see, both ways get to our final configuration and enforce our desired state. With the tools that use declarative language, it is possible to declare dependencies, meaning we can engineer the issue we encountered when running the tasks.

However, this example only has four steps; what happens when you have a few hundred steps that are launching servers in public cloud platforms and then installing software that needs several prerequisites?

This is the position I found myself in before I started to use Ansible. Puppet was great at enforcing my desired end configuration; however, to get there, I had to worry about building so much logic into my manifests to arrive at my desired state. In Puppet, this logic was using a function that allowed me as the end user to define my dependencies.

In the example we used, I would have had to define that users could only be created once the block of code that created the group had been run and the resource was present.

The more complex my code got, the more I fought the way the declarative tools wanted to run and the longer each execution would take because the tool had to consider my logic, which was a little hit and miss.

This became more annoying, as each successful run was getting close to taking about 40 minutes to complete. If I had dependency issues, I had to start from scratch with each failure and change to ensure that I was fixing the problem and not because things were starting to become consistent, so that typically meant having to redeploy a resource rather than running subsequent runs of my code. This made development very time-consuming, especially when it came to debugging the code, which sometimes involved trial and error.

This is not a great position to find yourself in when you are on the clock and must meet customer deadlines.

Configuration versus orchestration

Another critical difference between Ansible and the other tools it is commonly compared to is that most of these tools have their origins as systems designed to deploy and police a configuration state.

They typically require an agent to be installed on each host; that agent discovers some information about the host it is installed on, then calls back to a central server saying, “Hi, I am server XYZ. Could I please have my configuration?” The server then decides what the configuration for the server looks like and sends it across to the agent, which then applies it. Typically, this exchange takes place every 15 to 30 minutes—this is great if you need to enforce a configuration on a server.

However, the way that Ansible has been designed to run allows it to act as an orchestration tool; for example, you can run it to launch a server in your VMware environment, and once the server has been launched, it can then connect to your newly launched machine and install a LAMP stack. Then, it never has to connect to that host again, meaning that all we are left with is the server, the LAMP stack, and nothing else, other than maybe a few comments in files to say that Ansible added some lines of configuration, which should be the only sign that Ansible was used to configure the host.

Looking at some code

Before we finish this part of the chapter and move on to installing Ansible, let’s quickly look at examples of some actual code. The following bash script installs several RPMs using the yum package manager:

#!/bin/sh
LIST_OF_APPS="dstat lsof mailx rsync tree vim-enhanced git whois"
yum install -y $LIST_OF_APPS

The following is a Puppet class that does the same task as the previous bash script:

class common::apps {
  package {
    [
      'dstat',
      'lsof',
      'mailx',
      'rsync',
      'tree',
      'vim-enhanced',
      'git',
      'whois',
    ]:
    ensure => installed,
  }
}

Next up, we have the same task using SaltStack:

common.packages:
  pkg.installed:
    - pkgs:
      - dstat
      - lsof
      - mailx
      - rsync
      - tree
      - vim-enhanced
      - git
      - whois

Finally, we have the same task again, this time using Ansible:

- name: "Install packages we need"
  ansible.builtin.yum:
    name:
      - "dstat"
      - "lsof"
      - "mailx"
      - "rsync"
      - "tree"
      - "vim-enhanced"
      - "git"
      - "whois"
      - "iptables-services"
    state: "present"

Even without going into any detail, you should be able to get the general gist of what each of the three examples is doing. While not strictly infrastructure, all three are valid examples of infrastructure as code.

This is where you manage the code that manages your infrastructure in precisely the same way as a developer would manage the source code for their application. You use source control, store it in a centrally available repository where you can collaborate with your peers, branch and use pull requests to check in your changes, and, where possible, write and execute unit tests to ensure that changes to your infrastructure are successful and error-free before deploying to production. This should be as automated as possible. Any manual intervention in the tasks mentioned could be a point of failure, and you should work to automate the task.

This approach to infrastructure management has a few advantages, one being that you, as system administrators, are using the same processes and tooling as your developer colleagues, meaning that any procedures that apply to them also apply to you. This makes for a more consistent working experience and exposes you to tools you may have yet to be exposed to or use.

Secondly, and more importantly, it allows you to share your work. Before this approach, this type of work seemed to others a dark art performed only by system administrators. Doing this work in the open allows you to have your peers review and comment on your configuration and do the same yourself to theirs. Also, you can share your work so that others can incorporate elements into their projects.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image