DEV Community

Cover image for Advanced Ansible Techniques and Real-World Applications: Day 31 of 50 days DevOps Tools Series
Shiivam Agnihotri
Shiivam Agnihotri

Posted on

Advanced Ansible Techniques and Real-World Applications: Day 31 of 50 days DevOps Tools Series

Welcome to Day 31 of our "50 DevOps Tools in 50 Days" series! In our previous post, we introduced you to Ansible, covering its basic architecture, setup, and some simple playbooks. Today, we’re diving deeper into the world of Ansible, exploring advanced techniques and real-world applications that will elevate your automation skills to the next level. This post will focus on features like Ansible roles, Ansible Vault, conditionals, and loops, providing you with practical examples to solidify your understanding.

Recap: What is Ansible?

Before we delve into advanced concepts, let's quickly recap what Ansible is:

Agentless Automation Tool: Ansible uses SSH to manage nodes without requiring any agent installation.
YAML-Based Playbooks: Ansible’s tasks are defined in human-readable YAML files.
Idempotency: Ensures that the same playbook can be run multiple times without unintended side effects.

Advanced Ansible Concepts

In this section, we will explore some of the advanced features of Ansible that allow for more powerful and flexible automation.

1. Ansible Roles

As your Ansible playbooks grow in complexity, it becomes important to keep them organized and maintainable. Ansible roles allow you to structure your playbooks into reusable components.

Structure of a Role:

An Ansible role has a specific directory structure:

roles/
├── common/
│   ├── tasks/
│   │   └── main.yml
│   ├── handlers/
│   │   └── main.yml
│   ├── templates/
│   ├── files/
│   ├── vars/
│   │   └── main.yml
│   └── defaults/
│       └── main.yml
Enter fullscreen mode Exit fullscreen mode

Each directory serves a specific purpose:

tasks/: Contains the main tasks to be executed.
handlers/: Defines actions that should be triggered by certain tasks (e.g., restarting a service).
templates/: Holds Jinja2 templates that can be dynamically generated.
files/: Stores static files that need to be copied to the managed nodes.
vars/: Contains variables specific to the role.
defaults/: Stores default variables for the role.

Creating and Using a Role:

Let’s create a simple role to set up an Nginx web server.

Create the Role Directory:

mkdir -p roles/nginx/{tasks,handlers,templates,files,vars,defaults}
Enter fullscreen mode Exit fullscreen mode

Define Tasks:

In roles/nginx/tasks/main.yml, add the following:

---
- name: Install Nginx
  apt:
    name: nginx
    state: present

- name: Start Nginx
  service:
    name: nginx
    state: started
    enabled: true
Enter fullscreen mode Exit fullscreen mode

Use the Role in a Playbook:

Create a playbook that uses this role:

---
- name: Apply Nginx role
  hosts: webservers
  roles:
    - nginx
Enter fullscreen mode Exit fullscreen mode

Run the Playbook:

ansible-playbook -i hosts playbook.yml
Enter fullscreen mode Exit fullscreen mode

Using roles helps in breaking down complex playbooks into smaller, reusable components, making your automation scripts easier to manage and scale.

2. Ansible Vault

When managing infrastructure, you often need to handle sensitive information like passwords, API keys, or SSH private keys. Ansible Vault allows you to encrypt these secrets within your playbooks.

Encrypting a File:

To encrypt a file with Ansible Vault:

ansible-vault encrypt secrets.yml
Enter fullscreen mode Exit fullscreen mode

You’ll be prompted to enter a password. This password will be required whenever the playbook is run or the file is decrypted.

Using Encrypted Variables:

In your playbook, you can reference variables stored in an encrypted file:

---
- name: Deploy application with secrets
  hosts: appservers
  vars_files:
    - secrets.yml
  tasks:
    - name: Use secret API key
      shell: echo "{{ api_key }}"

Enter fullscreen mode Exit fullscreen mode

Running the Playbook:

When running a playbook that uses encrypted files, use the --ask-vault-pass option:

ansible-playbook -i hosts playbook.yml --ask-vault-pass
Enter fullscreen mode Exit fullscreen mode

Ansible Vault is a powerful tool that ensures your sensitive data remains secure while automating infrastructure.

3. Conditionals and Loops

Real-world playbooks often need to make decisions based on certain conditions or iterate over lists of items. Ansible provides support for conditionals and loops to handle these scenarios.

Using Conditionals:

Conditionals allow tasks to be executed only when certain conditions are met:

---
- name: Install Apache on Debian-based systems
  apt:
    name: apache2
    state: present
  when: ansible_os_family == "Debian"
Enter fullscreen mode Exit fullscreen mode

Looping Over Items:

Loops are useful when you need to perform the same task on multiple items:

---
- name: Create multiple users
  user:
    name: "{{ item }}"
    state: present
  loop:
    - alice
    - bob
    - charlie
Enter fullscreen mode Exit fullscreen mode

You can also use more complex loops:

---
- name: Install multiple packages
  apt:
    name: "{{ item.name }}"
    state: "{{ item.state }}"
  loop:
    - { name: 'nginx', state: 'present' }
    - { name: 'git', state: 'latest' }
Enter fullscreen mode Exit fullscreen mode

Conditionals and loops give your playbooks the flexibility to adapt to different environments and requirements.

4. Dynamic Inventory Management

In cloud environments, your infrastructure can change frequently, with instances being spun up or down regularly. Managing a static inventory file becomes impractical. Dynamic inventory scripts allow Ansible to query your cloud provider and automatically discover and manage your infrastructure.

Example: Using AWS EC2 Dynamic Inventory

Ansible provides a dynamic inventory script for AWS EC2, which you can use to discover your EC2 instances automatically.

Install the Required Python Packages:

pip install boto boto3
Enter fullscreen mode Exit fullscreen mode

Download the EC2 Dynamic Inventory Script:

Ansible provides an EC2 inventory script that you can download and place in your project:

curl -o ec2.py https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/ec2.py
chmod +x ec2.py
Enter fullscreen mode Exit fullscreen mode

Configure the Script:

You may need to configure the script to specify your AWS region and credentials. The configuration file (ec2.ini) can be customized as needed.

Run a Playbook with the Dynamic Inventory:

ansible-playbook -i ec2.py playbook.yml
Enter fullscreen mode Exit fullscreen mode

This approach ensures that Ansible always has an up-to-date view of your infrastructure, making it ideal for managing dynamic cloud environments.

5. Handling Complex Dependencies with Ansible Playbook Blocks

In some cases, you might need to ensure that a series of tasks either all succeed or all fail together. Ansible Playbook Blocks allow you to group tasks and apply common attributes or error handling across them.

Example: Grouping Tasks with a Block
Suppose you’re setting up a complex service where each task depends on the success of the previous one:

---
- hosts: appservers
  tasks:
    - block:
        - name: Install required packages
          apt:
            name: "{{ item }}"
            state: present
          loop:
            - nginx
            - postgresql
            - redis

        - name: Start services
          service:
            name: "{{ item }}"
            state: started
          loop:
            - nginx
            - postgresql
            - redis

      rescue:
        - name: Rollback in case of failure
          shell: |
            systemctl stop nginx
            systemctl stop postgresql
            systemctl stop redis
Enter fullscreen mode Exit fullscreen mode

In this example, if any task within the block fails, the tasks in the rescue section will be executed, allowing you to implement custom error handling and rollback mechanisms.

6. Orchestrating Complex Workflows with Ansible Playbooks

When dealing with multi-step processes, such as deploying a microservices architecture or setting up a continuous integration/continuous deployment (CI/CD) pipeline, you need to orchestrate multiple playbooks to run in a specific sequence.

Example: Orchestrating a Microservices Deployment

Imagine you have three microservices that need to be deployed in a specific order:

Prepare the Environment: Install Docker and Kubernetes.
Deploy the Database Service: This service needs to be up before the others.
Deploy the Backend Service: Depends on the database service.
Deploy the Frontend Service: Depends on the backend service.

Playbook Structure:

---
- import_playbook: prepare_environment.yml

- import_playbook: deploy_database.yml

- import_playbook: deploy_backend.yml

- import_playbook: deploy_frontend.yml
Enter fullscreen mode Exit fullscreen mode

Running the Orchestrated Playbook:

ansible-playbook site.yml
Enter fullscreen mode Exit fullscreen mode

This orchestration ensures that each service is deployed in the correct order, with dependencies properly managed.

Real-Life Scenario: Deploying a Multi-Tier Application

Let’s consider a scenario where you need to deploy a multi-tier web application consisting of a front-end server, a back-end server, and a database server. You want to ensure that the database is set up before the back-end server, and the back-end server before the front-end.

Step 1: Define the Inventory

Create an inventory file hosts:

[frontend]
192.168.1.10

[backend]
192.168.1.11

[database]
192.168.1.12
Enter fullscreen mode Exit fullscreen mode

Step 2: Write the Playbook

Here’s a simplified playbook for deploying the application:

---
- name: Deploy Database
  hosts: database
  tasks:
    - name: Install MySQL
      apt:
        name: mysql-server
        state: present

- name: Deploy Backend
  hosts: backend
  tasks:
    - name: Install Python dependencies
      pip:
        name:
          - flask
          - sqlalchemy
        state: present
  when: ansible_os_family == "Debian"

- name: Deploy Frontend
  hosts: frontend
  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present
Enter fullscreen mode Exit fullscreen mode

Step 3: Execute the Playbook

Run the playbook to deploy the application:

ansible-playbook -i hosts deploy.yml
Enter fullscreen mode Exit fullscreen mode

This playbook ensures that the database is set up before the backend, and the backend before the frontend. You can add more tasks and roles as needed to configure the application fully.

Conclusion

In today’s post, we've delved deep into advanced Ansible features, showcasing how you can structure your playbooks using roles, secure sensitive information with Ansible Vault, and manage dynamic infrastructure with dynamic inventories. We also explored how to handle complex workflows using playbook blocks, leverage community roles from Ansible Galaxy, and integrate Ansible for container orchestration .

Ansible’s versatility makes it a critical tool for DevOps engineers, enabling you to automate complex tasks, ensure consistency across environments, and speed up deployment processes.

Tomorrow, we'll dive into a new DevOps Tool. Stay tuned!

👉 Make sure to follow me on LinkedIn for the latest updates: Shiivam Agnihotri

Top comments (1)

Collapse
 
little_twinkle_0ae2b15172 profile image
little twinkle

Well said