Mastering Ansible for Server Management – Part 2

In the previous blog, Understanding Server Configuration Management – Part 1, we explored the fundamental concepts of Server Configuration Management. I trust it offered you a solid grasp of its importance and familiarised you with well-known tools for practical implementation.

What we will cover today

In this blog, our focus shifts to exploring how Ansible can facilitate configuration management and extend its capabilities. We will learn about:

  • Important Ansible concepts
  • How to perform Ansible setup
  • Key Ansible terms: 
    • Inventory 
    • Playbook
    • Roles 
    • Host
    • Group
    • Module
  • An example playbook for pinging a remote host

Prerequisites:

Before delving into Ansible, ensure you have:

 

  • A general understanding of Configuration Management (you can refer to Understanding Server Configuration Management – Part 1)
  • At least two servers: one Linux and the other either Linux or Windows
    • Ansible will be installed on the Linux server and will act as a control node. Other servers (Windows/Linux) will act as a target host, on which configurations need to be implemented.
  • Established network connectivity between the servers
    • Ensure Ansible control node (Linux server) is able to reach the target host successfully. 
      • Linux target host must be reachable on port 22
      • Windows target host must be reachable on WinRM port 5985 and 5986. 
  • Basic familiarity with YAML basics and Linux commands

 

I hope this sets the stage for the exploration of Ansible and its role in effective configuration management. Let’s dive in!

What is Ansible?

Let’s take a closer look at a conversation between Matt H, Lead Engineer and his teammates to understand and set up Ansible for their project. 

Matt: Hey team, considering we’ve got over 60 servers to handle, both on AWS and on-premises, we’ve decided to integrate Open Source Ansible into our project for efficient server management. There are several reasons behind choosing Ansible for our specific use case:

  • Lower Learning Curve: Ansible is incredibly user-friendly. Installation is a breeze, and you can get a simple playbook up and running within minutes, unlike other tools with lengthy installation processes and steeper learning curves. With Ansible utilising YAML, a declarative language, creating and managing new playbooks becomes a straightforward task.
  • Agentless Architecture: An added advantage is that Ansible doesn’t require installing agents on the target hosts. This means we won’t need to touch all 60+ servers to make them Ansible-ready. Simply install Ansible on a single control node, and you’re ready to execute playbooks. All that’s required is a valid user account on the target servers, which Ansible can leverage for server access. Example, for Linux target hosts, this user account could involve a combination of a username and password or authentication through an SSH key.
  • Single Solution: Ansible acts as an “all-in-one” tool, capable of handling all automation steps. Developed in Python, it inherits the language’s general-purpose features. Additionally, you can leverage thousands of existing Python community packages to create custom modules.

We’ll uncover more insights about Ansible as we start building new playbooks.

Sam: Hey Matt, I’m wondering why we need Ansible if each of these 60+ servers is owned by different business teams. Couldn’t we just ask them to make the required changes individually on each server?

Matt: It’s definitely possible to SSH/RDP into each server and make changes manually. However, this approach isn’t sustainable and will become increasingly challenging to manage in the future. While we could write bash/powershell scripts, they would be inefficient and inconsistent given the multiple OS types and different syntaxes we’re dealing with. 

Ansible, on the other hand, provides modules that are platform-agnostic, effectively handling Windows, Linux (Ubuntu, CentOS), and various other operating systems.

Ansible simplifies this process. The YAML syntax allows us to define tasks in a human-readable format, making it much easier to support and maintain in the long run.

Sam: Okay, that makes sense. What do we need to get started?

Matt: Take a day or two to familiarise yourself with Ansible on their official website. Meanwhile, I’ll set up a control node and install Ansible.

After a couple of days:

Sam: Matt, could you please elaborate on how the architecture is structured? Also, after reviewing their website, I’ve familiarised myself with these Ansible terms and now have a foundational understanding of how Ansible operates:

  • Task: Task is perhaps the smallest and most important entity in the Ansible playbook. It is like a small job or instruction that you want to perform on a server/node. These tasks can involve actions such as installing software, creating folders, or updating settings, each represented as an individual task written in YAML format.
  • Playbook: Playbooks are files where Ansible code resides, serving as collections of one or more tasks.
  • Variables: In a variable file, you can define and store variables utilised in your playbooks. Variables act as placeholders for values that may change, and employing a Vars file helps maintain playbook cleanliness and organisation.
  • Role: Roles provide a structured way to organise playbooks and related files. They contribute to modularising Ansible automation tasks, enhancing code reusability and maintainability.
  • Handlers: Handlers, a special type of task, are employed to manage services. Typically used to restart or stop services when system changes require service reloading.
  • Host: Any server, machine, or node managed using Ansible is termed a Host.
  • Inventory: An Inventory file manages details of all in-scope hosts, often in YAML or ini format.
  • Group: Hosts in the inventory file can be logically grouped into one or more groups, such as a Linux server in Melbourne being part of both “Linux” and “Melbourne” groups. Grouping facilitates playbook execution on specific sets of hosts.

Matt: This is an excellent grasp, Sam. I believe you can now explain these concepts to other team members. Regarding the architecture, our initial infrastructure setup would look something like this.


Matt: I’ve set up a Linux EC2 server to function as an Ansible controller node and have successfully installed Ansible on it. 

You can refer to the installation details here.

Sam: I assume we need to start creating playbooks for the required configurations. Is that right?

Matt: Yes, absolutely. However, before we dive into that, let’s first understand how we plan to structure our project. The code will be managed using a GitHub repository. Here’s an overview of what our basic project looks like:

You’ve covered quite a bit of terminology already, but let me break down what you’ll find in each file:

Inventory File:

Variables File:

As this server is part of the “ubuntu” group, all the variables defined in group_vars/ubuntu.yml will be inherited by this server. The following variables will be applied to all hosts belonging to the “ubuntu” group.

Additionally, we can create another variable file named “group_vars/server1.yml” to specify variables that exclusively belong to this server.

Playbook:

The provided playbook example involves pinging the server and displaying all available variables that can be referenced within this playbook.

The output for server1 looks like this:

Here, -i is used to pass the inventory file name, and -e is used to pass extra variables. Notably, we haven’t hardcoded the hostname in our playbook. Instead, {{ target_host }} is specified, and its value can be provided during execution.

Now, we can update the inventory file with more servers (assuming they are in the same network and allow ICMP and SSH ports from the Ansible control node). The playbook can then be executed by passing the server name via the command line.

The output for a server that is not accessible from the Ansible control node would appear as follows:

Sam: Does this mean we can add all the servers in the inventory file and simply pass “all” in the target_host variable to determine if the server is reachable or not?

Matt: Yes, it is as simple as that.

Sam: It was easier than I anticipated. Could you please provide an example of a playbook that incorporates roles, handlers, and other elements?

Matt: Certainly! Let’s take a look at a playbook example that demonstrates the use of roles and handlers. The project structure would look like as below:

Let’s take an example of the config login banner playbook example. The updated playbook code will look like:

  • As in the previous example, we are accepting the target_host variable.
  • The playbook applies the config_banner role, which is designed to handle login banner configurations.
  • The actual role tasks are defined in the roles/config_banner/tasks/main.yml file. When you specify a role in the playbook, it automatically looks for the role’s tasks in the roles/role_name/tasks/main.yml file. This convention makes the playbook cleaner and more readable.

Now let’s have a look at the roles directory.

  • files: This directory contains files that will be copied to the target hosts. In this case, login.warn and motd are the files for the login banner configuration.
  • handlers: The main.yml file within the handlers directory includes tasks that define handlers. Handlers are actions that get triggered by other tasks and can be used, for example, to restart services. In this case, the main.yml file contains a handler to reload the sshd service.
 

 

– name: Restart SSH service
service:
  name: sshd
  state: restarted

  • tasks: The main.yml file in the tasks directory specifies the main tasks for the role. These are the tasks that will be executed when the role is applied. It includes steps to copy files, update configurations, and perform other necessary actions.
 

– name: Copy login.warn file to /etc/login.warn
copy:
  src: files/login.warn
  dest: /etc/login.warn
  backup: yes
  mode: 0644

– name: Copy motd file to /etc/motd
copy:
  src: files/motd
  dest: /etc/motd
  backup: yes
  mode: 0644

– name: Update sshd_config
lineinfile:
  path: /etc/ssh/sshd_config
  regexp: ‘^#?Banner’
  line: ‘Banner /etc/login.warn’
  state: present
notify: Restart SSH service

– name: Check Login Banner
shell: cat /etc/login.warn
register: banner_output
ignore_errors: true

– name: Check Message of the Day
shell: cat /etc/motd
register: motd_output
ignore_errors: true

– name: Display Results
debug:
  msg: |
    Login Banner:
    {{ banner_output.stdout | default(‘Banner not configured.’) }}

    Message of the Day:
    {{ motd_output.stdout | default(‘Message of the Day not configured.’) }}

Sam: Thanks for the detailed explanation, it’s exactly what I was looking for. 

Matt: You’re very welcome, Sam! I’m glad I could provide the detailed explanation you were seeking. If you have any more questions or if there’s anything else you’d like assistance with, feel free to ask. Happy coding!

Sam: Have you already made the code available in the GitHub repository?

Matt: Yes, it is available here.

Sam: I’ve heard there’s a paid version of Ansible available in the market. Could you please provide more details? Should we consider using it, or is the Open Source Ansible sufficient for our needs?

Matt: Yes, RedHat offers a paid solution called Ansible Automation Platform. While Open Source Ansible remains a powerful and widely used tool, Ansible Automation Platform is designed to meet the demands of larger enterprises with additional features and support tailored for complex automation needs.

In the next blog, we’ll take a closer look at Ansible Automation Platform, exploring its intricacies.

Conclusion

In this blog, we explored Ansible, a super handy tool for making server tasks easy. We learned its salient features like being easy to use, not needing any agents, and how it’s awesome for getting stuff done on different systems. Starting from the basics, we looked at playbooks, terms, and how to organise projects smartly for production grade. Ansible’s flexibility really stood out when we played around with variables and roles.

In the next blog, we will delve into Ansible Automation Platform, exploring its intricacies, benefits, and how it complements the capabilities of Open Source Ansible. As we continue our journey, the choice between Open Source Ansible and Ansible Automation Platform will be tailored to the specific needs and scale of the organisation.

Whether you are navigating the terrain of Open Source Ansible or exploring the advanced features of Ansible Automation Platform, the goal remains the same – to streamline and elevate the efficiency of automation processes in your infrastructure.

Enjoyed this blog?

Share it with your network!

Move faster with confidence