Master Ansible: Why It’s Special, What It Does, and How It Works with Practical Examples

Introduction

Ansible is a powerful yet simple tool that revolutionizes system management for IT teams. Its user-friendly YAML playbooks, agentless architecture, and capability to automate repetitive tasks make IT automation both accessible and efficient. By examining what makes Ansible special and unique and how it operates, you can understand why it has become a preferred choice for managing servers and streamlining workflows.

Let’s explore why automated configuration management is needed in organizations with the following example:

Background:

  • Person X is a System Administrator at ABC Company, managing 100 systems for a Hospital Information Management System (HIMS).
  • These systems must be consistently up-to-date and properly configured to ensure smooth operations, especially in the healthcare industry where uptime and security are critical.

The Journey of System Administrator X: The Evolution of Configuration Management

1. Manual Configuration Management:


Tasks: Manually log into each system to apply updates, manage services,
and install software.

Systems: 100 systems (Linux + Windows).

Challenges: Time-consuming, lacks uniformity, prone to human error.

Example: SSH into each server to run commands manually.

2. Introduction to Shell Scripts:

Tasks: Automates repetitive tasks by using shell scripts on Linux systems.

Example: Script for Installing Software such as Nginx Across Multiple Servers.

Challenges: Separate scripts are required for different Linux distributions
(e.g., apt for Ubuntu, yum for CentOS). Windows has no support and is hard
to maintain across growing systems.

3. Introduction to Python Scripts:

Tasks: Improved flexibility in automation for both Linux and Windows, 
along with enhanced error handling.

Example: A Python script for installing Nginx, which is designed to work
with various operating systems.

Challenges: Complex logic across different environments requires regular
updates and maintenance of dependencies, but it still lacks scalability
and idempotency.

4. The Rise of CM Tools (Puppet, Chef, SaltStack):

Tools: Puppet (Ruby), Chef (Ruby), SaltStack (Python).

Capabilities: Use a central configuration server to automate the configuration
process across multiple systems.

Challenges: Programming knowledge specific to each tool is required.
Agents must be installed on every system, adding overhead.

Example: Puppet enforces system states, but it requires a complex setup and
the installation of agents.

5. Ansible: The Preferred Configuration Management Tool:

Agentless: No agents are required for installation on target systems; 
instead, SSH is used for Linux and WinRM for Windows.

Simple YAML Playbooks: User-friendly configuration that is easy to read,
requiring no programming skills.

Idempotent: Guarantees tasks are performed only when required, preventing
unnecessary repetition.

Cross-Platform: Supports Linux, Windows, network devices, and
cloud infrastructure.

Scalable: Effectively manages environments of any size, from small to large.

Extensive Module Library: Ansible includes numerous built-in modules for
various tasks, such as file management and cloud service interaction.

Community and Enterprise Support: Robust community backing and the
Red Hat-supported enterprise version, Ansible Tower, provides
comprehensive solutions.

Example: A YAML playbook to install Nginx on all systems to ensure consistency.

Now, with some practical examples, let’s explore why Ansible is so special, what makes it stand out, and how it works.

1. Why Ansible is Special

  • Unified Automation: Ansible uses one playbook for multiple platforms (e.g., Linux and Windows), simplifying workflows.
  • Agentless Architecture: Unlike scripts, Ansible does not require additional software on target machines; it uses SSH for Linux and WinRM for Windows.
  • Idempotency: Ansible ensures tasks are performed only when necessary, avoiding redundant or repeated actions.
  • Easy Maintenance: YAML syntax is human-readable and simple to update, reducing the complexity of managing automation.

Example — Why Ansible is Better:
You’d need separate logic for each operating system in shell or Python scripts. With Ansible, the same playbook handles all systems:

- name: Install and start Nginx
hosts: all
tasks:
# Task for Debian-based systems
- name: Install Nginx on Debian
apt:
name: nginx
state: present
become: yes
when: ansible_os_family == "Debian"

# Task for RedHat-based systems
- name: Install Nginx on RedHat
yum:
name: nginx
state: present
become: yes
when: ansible_os_family == "RedHat"

# Task for Windows systems
- name: Install Nginx on Windows
win_chocolatey:
name: nginx
state: present
when: ansible_connection == "winrm"

# Start Nginx service on Linux
- name: Start Nginx service on Linux
service:
name: nginx
state: started
become: yes
when: ansible_os_family in ["Debian", "RedHat"]

# Start Nginx service on Windows
- name: Ensure Nginx service is running on Windows
win_service:
name: nginx
start_mode: auto
state: started
when: ansible_connection == "winrm"

Why It’s Special:


  • Seamlessly handles different package managers (apt, yum, choco).
  • Automatically skips tasks that are incompatible with the OS (e.g., apt tasks will not run on CentOS).

2. How Ansible Works:

Ansible uses three core components:

  1. Inventory: Defines target systems and groups.
  2. Playbooks: YAML files that define tasks to automate.
  3. Modules: Prebuilt tools that execute specific actions (e.g., installing packages, creating files).

Example: An End-to-End Workflow with a Practical Application.

Here’s how to install and start Nginx using Ansible:

Project Directory Structure:

ansible_project/
├── inventory/
│ ├── inventory.ini # Static inventory file
│ └── aws_ec2.yml # Optional dynamic inventory file (if using AWS dynamic inventory)
├── playbooks/
│ └── install_nginx.yml # Main playbook to install Nginx
├── group_vars/
│ └── linux_servers.yml # Variables for all Linux servers
├── roles/
│ └── nginx/
│ ├── tasks/
│ │ └── main.yml # Tasks for installing Nginx
│ ├── defaults/
│ │ └── main.yml # Default variables for the role
│ └── vars/
│ └── main.yml # Custom variables for the role
├── files/
│ └── linuxkey.pem # Private key file for SSH (ensure permissions are restricted)
├── ansible.cfg # Ansible configuration file
├── requirements.yml # Role dependencies (if any)
└── README.md # Project documentation

  1. Inventory File: Define the target systems.
[web_servers]
Ubuntu-Server ansible_host=34.228.32.234 ansible_user=ubuntu ansible_private_key_file=/home/ubuntu/ansible_project/files/linuxkey.pem ansible_python_interpreter=/usr/bin/python3
RedHat-Server ansible_host=18.208.142.133 ansible_user=ec2-user ansible_private_key_file=/home/ubuntu/ansible_project/files/redhat-key.pem ansible_python_interpreter=/usr/bin/python3

[windows]
Windows-Server ansible_host=44.207.1.149 ansible_user=Administrator ansible_connection=winrm ansible_port=5985 ansible_winrm_transport=basic ansible_password="{{ windows_password }}"

[all:vars]
ansible_python_interpreter=/usr/bin/python3

2. Playbook: Automate the task.

- name: Install and start Nginx
hosts: all
vars_files:
- ../vars/secrets.yml # Include secrets file if using encrypted variables
tasks:
# Task for Debian-based systems
- name: Install Nginx on Debian
apt:
name: nginx
state: present
become: yes
when: ansible_os_family == "Debian"

# Task for RedHat-based systems
- name: Install Nginx on RedHat
yum:
name: nginx
state: present
become: yes
when: ansible_os_family == "RedHat"

# Task for Windows systems
- name: Install Nginx on Windows
win_chocolatey:
name: nginx
state: present
when: ansible_connection == "winrm"

# Start Nginx service on Linux
- name: Start Nginx service on Linux
service:
name: nginx
state: started
become: yes
when: ansible_os_family in ["Debian", "RedHat"]

# Ensure Nginx service is running on Windows
- name: Ensure Nginx service is running on Windows
win_service:
name: nginx
start_mode: auto
state: started
when: ansible_connection == "winrm"

3. Run the Playbook: Execute the playbook using the following command:

ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml --vault-password-file ~/.vault_pass

How It Works:

  • Ansible reads the inventory file to identify the target systems.
  • It uses SSH or WinRM to connect to the machines.
  • The playbook’s tasks are executed based on conditions (e.g., OS family).

We are already well versed in Linux servers, particularly in creating and connecting via SSH. Now, we will look into the Windows part below.

How to Configure WinRM on the Windows Server:

Before establishing a connection, ensure that WinRM is correctly configured on the Windows server.

Execute the following commands in PowerShell with Administrator privileges:

For HTTP (Port 5985):

Enable-PSRemoting -Force

Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true

Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true

Restart-Service WinRM

New-NetFirewallRule -Name "WinRM_HTTP" -DisplayName "Allow WinRM HTTP" -Protocol TCP -LocalPort 5985 -Action Allow

Get-NetFirewallRule | Where-Object { $_.DisplayName -like "Allow WinRM*" }

Get-Service WinRM

Ping Test on Windows:

Run the playbook with the Vault password file:

ansible-playbook -i inventory/inventory.ini playbooks/ping_windows.yml --vault-password-file ~/.vault_pass

We will now implement the install_nginx playbook.

Before running the install_nginx playbook:

Command to Run the Playbook

Run the playbook while supplying the Vault password needed to decrypt the `windows_password` variable:

ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml --vault-password-file ~/.vault_pass

After running the install_nginx playbook without any errors:

The playbook’s tasks are executed based on conditions (e.g., OS family).


3. What Makes Ansible Unique

  • Cross-Platform: It can manage Linux, Windows, and even network devices, all with the same tool.
  • Simplified Logic: There’s no need to write conditionals for operating system differences manually — Ansible handles that for you.
  • Reusable Roles: Ansible lets you organize tasks into roles, which makes them reusable across different projects.
  • Community Modules: Thousands of prebuilt modules make it easier to manage complex tasks, such as handling users, services, and cloud instances.

Example — Modularization with Roles:
To avoid the need to write tasks repeatedly, create a reusable role for installing Nginx.

Step-by-Step Guide to Create a Role:

i) Create the Role Directory Structure

Run the following command to generate the required role structure:

ansible-galaxy init roles/nginx

This will create a directory structure like this:

roles/nginx/
├── tasks
│ └── main.yml # Contains tasks for installing and starting Nginx
├── handlers
│ └── main.yml # Contains handlers for restarting Nginx
├── defaults
│ └── main.yml # Contains default variables
├── vars
│ └── main.yml # Contains role-specific variables (optional)
├── files
├── templates
├── meta
│ └── main.yml # Metadata for the role (dependencies, etc.)
├── tests
│ ├── inventory # Test inventory
│ └── test.yml # Test playbook

ii) Define Tasks in the Role

Edit the roles/nginx/tasks/main.yml file and add the tasks for installing and starting Nginx:

# roles/nginx/tasks/main.yml
---
# Install Nginx on Debian-based systems
- name: Install Nginx on Debian
apt:
name: nginx
state: present
become: yes
when: ansible_os_family == "Debian"
# Install Nginx on RedHat-based systems
- name: Install Nginx on RedHat
yum:
name: nginx
state: present
become: yes
when: ansible_os_family == "RedHat"
# Install Nginx on Windows (via Chocolatey)
- name: Install Nginx on Windows
win_chocolatey:
name: nginx
state: present
when: ansible_connection == "winrm"
# Start Nginx service on Linux
- name: Start Nginx service on Linux
service:
name: nginx
state: started
become: yes
when: ansible_os_family in ["Debian", "RedHat"]
# Start Nginx service on Windows
- name: Ensure Nginx service is running on Windows
win_service:
name: nginx
start_mode: auto
state: started
when: ansible_connection == "winrm"

iii) Create a Playbook to Use the Role

Now that the role is defined create a playbook to use it. For example, create install_nginx.yml in the playbooks/ directory:

# playbooks/install_nginx.yml
---
name: Install and configure Nginx
hosts: all
roles:
- nginx

iv) Update Your Inventory

Make sure your inventory.ini is still valid for both Linux and Windows hosts.

v) Run the Playbook

Run the playbook that uses the role:

ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml

What Makes It Unique:

  • One role for all operating systems.
  • Easily reused across multiple projects.

Why Ansible Stands Out

  1. Unified Configuration: Say goodbye to writing multiple scripts for different operating systems.
  2. Agentless Architecture: Setup is minimal — just use SSH or WinRM.
  3. Scalability: Easily manage thousands of systems using the same playbook.
  4. Idempotency: Prevent redundant actions; Ansible makes changes only when necessary.

Tips for Ensuring Smooth Execution of Ansible Playbooks

To execute Ansible playbooks effectively, follow these essential steps:

  1. Maintain a Clean and Accurate Inventory:
  • Keep your inventory file well-structured with the correct IPs, usernames, and connection variables. Use groups and variables to simplify.

Example: Ensure the inventory file contains correct entries for all hosts:

[web_servers]
Ubuntu-Server ansible_host=<Ubuntu_IP> ansible_user=ubuntu ansible_private_key_file=<Path-to-Ubuntu-Private-Key-on-Control-Node> ansible_python_interpreter=/usr/bin/python3

[redhat]
RedHat-Server ansible_host=<RedHat_IP> ansible_user=ec2-user ansible_private_key_file=<Path-to-RedHat-Private-Key-on-Control-Node> ansible_python_interpreter=/usr/bin/python3

[windows]
Windows-Server ansible_host=<Windows_IP> ansible_user=Administrator ansible_connection=winrm ansible_port=5985 ansible_winrm_transport=basic ansible_password="{{ windows_password }}"

[all:vars]
ansible_python_interpreter=/usr/bin/python3

2. Secure Private Key Files:

  • Ensure strict permissions (chmod 400) for private key files and reference the correct paths in your inventory.
chmod 400 /path/to/private_key.pem

Key Notes:
i) .pem files are only necessary for the initial access to set up SSH keys.
ii) Once the public SSH key (`id_rsa.pub`) is added to the managed node’s `authorized_keys` file, the `.pem` file is no longer required since passwordless authentication is enabled.
iii) Use the `authorized_key` Ansible module in playbooks to automate the distribution of SSH keys for multiple nodes.

3. Test Connectivity Before Execution:

  • Use the ping module to verify connectivity with all managed nodes, ensuring SSH or WinRM connections are properly configured.

Example:

ansible web_servers -i inventory/inventory.ini -m ping
ansible-playbook -i inventory/inventory.ini ./playbooks/ping_windows.yml --vault-password-file ~/.vault_pass

4. Set Up and Verify Host Requirements:

  • Ensure Python is installed on Linux hosts and verify that WinRM is correctly configured on Windows hosts.

Example: Ensure WinRM is configured properly on the Windows server:

  • The following commands configure and enable WinRM on the Windows system, allow unencrypted and Basic authentication, and ensure that firewall rules permit traffic over port 5985 (HTTP).
  • These steps are essential for establishing a WinRM connection from the Ansible control node to the managed Windows system.
# 1. Enable PowerShell Remoting on the Windows system (required for Ansible to connect).
Enable-PSRemoting -Force

# 2. Allow Basic authentication for WinRM (needed for Ansible WinRM connection using basic authentication).
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true

# 3. Allow unencrypted communication for WinRM (Ansible typically uses this for simple setups without SSL).
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true

# 4. Restart the WinRM service to apply the changes made to its configuration.
Restart-Service WinRM

# 5. Create a new firewall rule to allow inbound traffic on port 5985 (default HTTP port for WinRM).
New-NetFirewallRule -Name "WinRM_HTTP" -DisplayName "Allow WinRM HTTP" -Protocol TCP -LocalPort 5985 -Action Allow

# 6. Verify that the firewall rule for WinRM is applied and active.
Get-NetFirewallRule | Where-Object { $_.DisplayName -like "Allow WinRM*" }

# 7. Check the status of the WinRM service to ensure it is running and ready to accept connections.
Get-Service WinRM

5. Use Ansible Vault for Sensitive Data:

  • Encrypt sensitive variables like passwords with Ansible Vault and include them securely in your playbooks.

Example:

# Store sensitive variables like windows_password in a Vault-encrypted file:
ansible-vault create vars/secrets.yml

# Add variables like:
windows_password: "your-windows-password"

# Reference the Vault file in your playbooks:
vars_files:
- ../vars/secrets.yml

# Use the Vault password file to run playbooks:
ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml --vault-password-file ~/.vault_pass

6. Implement Role-Based and Modular Playbooks:

  • Organize your playbooks into reusable roles and tasks, using conditionals to target specific systems.

7. Run in Check Mode First:

  • Validate playbooks with ` — check` mode to preview changes before applying them.

Example:

ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml --check --vault-password-file ~/.vault_pass

8. Enable Verbose Logging:

  • Use verbose mode (`-vvv`) for detailed insights during execution.

Example:

ansible-playbook -i inventory/inventory.ini playbooks/install_nginx.yml --check --vault-password-file ~/.vault_pass -vvv

9. Follow Best Practices for Playbook Design:

  • Ensure tasks are idempotent and use clear formatting and names for clarity.

10. Test and Validate Your Setup Regularly:

  • Periodically verify your inventory, playbooks, and connections to maintain functionality.

Conclusion

Ansible simplifies IT automation by effectively balancing power and ease of use. Its agentless architecture, idempotent tasks, and human-readable playbooks make managing systems easy, whether you are overseeing a few servers or thousands. Ansible’s simplicity and effectiveness establish it as an essential tool for modern IT operations.

What are your thoughts on this article? Feel free to share your opinions in the comments below — or above, depending on your device! If you enjoyed the story, please consider supporting me by clapping, leaving a comment, and highlighting your favorite parts.

Visit subbutechops.com to explore the fascinating world of technology and data. Get ready for more exciting content. Thank you, and happy learning!

Leave a Comment