As infrastructure automation becomes critical for DevOps and cloud-native environments, Ansible stands out as a simple yet powerful configuration management and orchestration tool. Recruiters need to identify professionals who can design and maintain idempotent, scalable automation for servers, cloud resources, and CI/CD pipelines.
This resource, "100+ Ansible Interview Questions and Answers," is tailored for recruiters to streamline the evaluation process. It spans core Ansible concepts to advanced real-world implementations, ensuring you can accurately assess a candidate’s automation skills.
Whether hiring for DevOps Engineers, Cloud Engineers, or Site Reliability Engineers (SREs), this guide enables you to assess a candidate’s:
For a streamlined assessment process, consider platforms like WeCP, which allow you to:
✅ Create customized Ansible assessments tailored to your infrastructure stack.
✅ Include hands-on tasks, such as writing playbooks to configure web servers, orchestrating multi-tier applications, or securing secrets with Ansible Vault.
✅ Proctor assessments remotely with AI-based integrity monitoring.
✅ Leverage automated grading to evaluate YAML accuracy, logic, and adherence to automation best practices.
Save time, ensure technical depth, and confidently hire Ansible experts who can deliver reliable, automated infrastructure from day one.
Ansible Interview Questions and Answers
Ansible is an open-source IT automation tool designed to simplify the management and configuration of systems, deployment of applications, and orchestration of tasks across a wide variety of environments. Ansible uses SSH to manage remote nodes (or WinRM for Windows) and does not require any agents to be installed on the target machines, which makes it lightweight and easy to implement.
Ansible is primarily used for:
The major advantages of Ansible include:
Ansible provides several features that make it an ideal choice for system automation and DevOps workflows:
Ansible is composed of several key components that work together to provide automation and orchestration capabilities:
A playbook in Ansible is a YAML file that defines a series of tasks to be executed on managed nodes. Playbooks are the central unit of automation in Ansible and allow users to automate the configuration of systems, deployment of applications, and orchestration of tasks across multiple systems. Each playbook consists of one or more "plays," which define which hosts to target and the tasks to execute on them.
A basic playbook includes:
An example of a simple playbook:
---
- name: Install and start Apache web server
hosts: webservers
become: yes
tasks:
- name: Install Apache
yum:
name: httpd
state: present
- name: Ensure Apache is running
service:
name: httpd
state: started
In this example:
In Ansible, a task is defined as an individual unit of work within a playbook. A task specifies an operation that is to be performed on a managed node using a specific Ansible module. Each task consists of the following key elements:
An example of a task that installs a package:
- name: Install the latest version of Apache
yum:
name: httpd
state: latest
In this example:
The inventory file in Ansible defines the list of hosts (machines or systems) that Ansible will manage. It is essential because it tells Ansible which machines should be included in the automation process and organizes them into groups for easier management.
The inventory file can be static (a simple text file) or dynamic (automatically generated from external sources like cloud providers). In static inventory files, hosts are listed along with their groupings. For example, a typical inventory file might look like this:
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com
In this example:
Ansible uses this inventory to target specific groups of hosts or individual systems when running playbooks or ad-hoc commands.
An inventory file can be created manually as a simple text file (e.g., hosts.ini) or automatically using a dynamic inventory script. The inventory file lists the systems you want Ansible to manage and can group them for easy targeting in playbooks.
An example of a static inventory file (hosts.ini):
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com
To use this inventory file in an Ansible command, you can specify it with the -i option:
ansible -i hosts.ini all -m ping
Alternatively, Ansible supports dynamic inventory, which automatically pulls inventory data from cloud services like AWS, GCP, or Azure using scripts or plugins.
Ad-hoc commands in Ansible are quick, one-off commands that are executed without writing a playbook. They allow you to perform simple tasks, such as gathering information from a host or running a module on a target system, without the need to create a full playbook.
For example, an ad-hoc command to ping all hosts in the inventory would be:
ansible all -m ping
Ad-hoc commands are useful for quick operations like checking if a service is running, gathering system information, or updating packages across a few machines. They provide a convenient way to execute commands across multiple machines without the overhead of writing a playbook.
A role in Ansible is a way to organize and structure playbooks into reusable, modular components. Roles are directories that contain a set of tasks, handlers, templates, files, and variables associated with a particular configuration or function. By organizing automation tasks into roles, you can easily reuse and share common configurations across different playbooks.
For example, a role could be used to configure a web server or deploy a specific application. Roles make it easier to maintain and scale playbooks because they encapsulate a specific functionality and allow it to be reused across multiple projects or teams.
Roles typically include:
Roles are invoked in a playbook like this:
- name: Configure web server
hosts: webservers
roles:
- webserver
The main difference between a playbook and an ad-hoc command is that a playbook is a file containing a set of instructions written in YAML to automate a series of tasks, while an ad-hoc command is a one-time command executed directly from the command line for quick operations.
Example of an ad-hoc command:
ansible all -m ping
Example of a playbook:
- name: Install and configure Apache
hosts: webservers
tasks:
- name: Install Apache
yum:
name: httpd
state: present
- name: Start Apache
service:
name: httpd
state: started
Ansible playbooks are written in YAML (Yet Another Markup Language), which is a human-readable format that allows you to define a series of automation tasks to be performed on one or more managed nodes. The syntax of an Ansible playbook involves several key components:
Play: A play is a part of the playbook and defines the hosts on which the tasks will be executed. It starts with the hosts keyword and is followed by the tasks. Example:
- hosts: webservers
Tasks: Tasks are the individual units of work that define what should be done on the target systems. Each task uses an Ansible module and includes parameters. Example:
tasks:
- name: Install Apache
yum:
name: httpd
state: present
Variables: Variables can be defined within a playbook and used in tasks. They allow you to make your playbooks dynamic and reusable. Example:
vars:
httpd_package: httpd
Handlers: Handlers are special tasks that are only run if they are notified by other tasks. They are commonly used to restart services or perform similar actions after a configuration change. Example:
handlers:
- name: Restart Apache
service:
name: httpd
state: restarted
An example of a complete Ansible playbook:
---
- hosts: webservers
become: yes
tasks:
- name: Install Apache
yum:
name: httpd
state: present
- name: Start Apache service
service:
name: httpd
state: started
handlers:
- name: Restart Apache
service:
name: httpd
state: restarted
To install Ansible, you need to have a system running a supported version of Linux or macOS. The installation process may vary based on the operating system. Below are common methods for installation:
On Ubuntu/Debian:
Update your package index:
sudo apt update
Install Ansible:
sudo apt install ansible
On CentOS/RHEL:
Enable the EPEL repository:
sudo yum install epel-release
Install Ansible:
sudo yum install ansible
On macOS (using Homebrew):
Install Homebrew (if not already installed):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Install Ansible:
brew install ansible
Using Python's pip (for all platforms):
Install Ansible via pip:
pip install ansible
On Windows:
Windows does not natively support Ansible, but you can use the Windows Subsystem for Linux (WSL) to run Ansible, or use Cygwin or Docker.
The ansible-playbook command is used to execute playbooks on target machines (managed nodes). A playbook is a collection of instructions (plays) that define what actions should be taken on the nodes, and the ansible-playbook command processes the playbook, connects to the managed nodes, and executes the defined tasks sequentially.
Basic usage:
ansible-playbook <playbook.yml>
You can specify additional options with the ansible-playbook command:
Example of running a playbook:
ansible-playbook -i hosts.ini deploy_app.yml
This command will run the playbook deploy_app.yml using the inventory file hosts.ini, deploying an application on the target machines.
To run a specific task within a playbook, you can use the --tags option, which allows you to tag specific tasks and then run only those tasks. You can define tags for tasks in the playbook and specify which tasks to execute when running the playbook.
Example:
Tag a task in the playbook:
- hosts: webservers
tasks:
- name: Install Apache
yum:
name: httpd
state: present
tags:
- install
- name: Start Apache service
service:
name: httpd
state: started
tags:
- start
Run the playbook with a specific tag:
ansible-playbook -i hosts.ini deploy.yml --tags "install"
This command will only run the tasks tagged with "install", skipping all others.
Alternatively, you can also use --skip-tags to skip specific tasks:
ansible-playbook -i hosts.ini deploy.yml --skip-tags "start"
This command will run all tasks except the ones tagged with "start".
By default, Ansible connects to managed nodes using SSH (Secure Shell) for Linux/Unix-based systems. This is because SSH is commonly used for remote access to systems and provides a secure, encrypted connection for Ansible to execute tasks on managed nodes.
For Windows systems, Ansible uses WinRM (Windows Remote Management) as the default connection method. WinRM allows Ansible to communicate with Windows machines over HTTP/HTTPS to execute tasks remotely.
You can specify the connection method in your inventory file or on the command line if you need to override the default. For example:
To use SSH:
[webservers]
web1.example.com ansible_connection=ssh
To use WinRM (for Windows nodes):
[windows]
winserver.example.com ansible_connection=winrm
A module in Ansible is a piece of code that performs a specific task on a managed node. Modules are the building blocks of Ansible and define the actions that Ansible can execute, such as installing software, managing files, or configuring services. Ansible modules are idempotent, meaning that they will only make changes if necessary to achieve the desired state.
Some commonly used modules include:
An example of using the yum module to install a package:
- name: Install Apache
yum:
name: httpd
state: present
Ansible also allows users to write custom modules for specific use cases.
The ping module in Ansible is used to test the connectivity between the control node and the managed nodes. It simply checks if Ansible can successfully connect to a node and return a "pong" response.
To use the ping module, you can run the following command:
ansible all -m ping -i hosts.ini
This command will ping all nodes listed in the hosts.ini inventory file. If Ansible can successfully reach the nodes, you will receive a pong response, indicating that the connection is working.
Example output:
web1.example.com | SUCCESS | rc=0 >>
pong
web2.example.com | SUCCESS | rc=0 >>
pong
The ping module is useful for quickly verifying that your inventory is set up correctly and that the managed nodes are reachable.
Facts in Ansible are system information that Ansible automatically collects about the managed nodes. These facts include details like the system's operating system, IP address, CPU, memory, and other hardware/software properties. Ansible gathers these facts during playbook execution, and you can use them within your playbooks to make decisions, set variables, or configure systems dynamically.
For example, the ansible_facts module collects facts like:
You can access facts in your playbook like this:
- name: Check if the system is using RedHat
debug:
msg: "This system is RedHat"
when: ansible_facts['ansible_os_family'] == 'RedHat'
Facts are automatically gathered by Ansible at the beginning of each playbook run, but you can disable this fact-gathering process if it's unnecessary using the gather_facts: no option.
You can view the facts of a node in Ansible by using the setup module. This module gathers all available facts about a node, which you can then display using the debug module.
To view the facts for a node, you can run the following command:
ansible <hostname> -m setup
This will return a detailed list of facts about the specified node.
For example, to see the facts of all nodes:
ansible all -m setup
Alternatively, you can view specific facts. For example, to show only the operating system facts:
ansible <hostname> -m setup -a "filter=ansible_os_family"
This will return only the operating system family of the target node.
In Ansible, the become directive is used to run tasks with elevated privileges (e.g., as root or another specified user). By default, tasks in Ansible run as the user defined in the inventory or command line, but sometimes administrative privileges are required to perform certain tasks, such as installing packages, restarting services, or modifying system configurations.
To enable privilege escalation, you use become: yes in your playbook, and you can specify the user with become_user (default is root). You can also specify the method of escalation (e.g., sudo, su, etc.) using become_method.
Example:
- hosts: webservers
become: yes
tasks:
- name: Install Apache
yum:
name: httpd
state: present
In this example, the become: yes directive ensures that the task to install Apache will be executed with elevated privileges. If you need to use a different user, you can specify it with become_user:
- hosts: webservers
become: yes
become_user: root
tasks:
- name: Install Apache
yum:
name: httpd
state: present
In Ansible, you can specify the user for SSH connections using the -u option when running the ansible or ansible-playbook command. Alternatively, you can specify the user in the inventory file or within the playbook.
1. Specifying the user on the command line:
ansible all -i hosts.ini -u username -m ping
In this example, username is the SSH user you want Ansible to use for connecting to the nodes listed in the hosts.ini inventory.
2. Specifying the user in the inventory file:
In your inventory file (hosts.ini), you can specify the SSH user for a specific host or group using the ansible_user variable:
[webservers]
web1.example.com ansible_user=username
web2.example.com ansible_user=username
3. Specifying the user in the playbook:
In the playbook, you can define the ansible_user variable for the entire play:
- hosts: webservers
become: yes
ansible_user: username
tasks:
- name: Install Apache
yum:
name: httpd
state: present
Idempotency in Ansible refers to the ability of an operation to be safely repeated multiple times without changing the result after the first execution. If a task is idempotent, it will only make changes to the system if the desired state is not already achieved. If the system is already in the desired state, running the task again will have no effect.
For example, in the following task, the state of the httpd package will only change if it is not already installed:
- name: Install Apache
yum:
name: httpd
state: present
If the httpd package is already installed, the task will not reinstall it. If it's not installed, Ansible will install it. This ensures that the task can be safely rerun without causing unnecessary changes.
Variables in Ansible are used to store values that can be reused throughout your playbook. You can define variables in several places and at different levels in the Ansible system:
In the playbook:
You can define variables in the vars section of a playbook:
- hosts: webservers
vars:
httpd_package: httpd
tasks:
- name: Install Apache
yum:
name: "{{ httpd_package }}"
state: present
In the inventory file:
You can define variables for specific hosts or groups in the inventory file:
[webservers]
web1.example.com httpd_package=httpd
In external variable files (YAML or JSON):
You can also store variables in external files and include them in your playbooks:
# vars.yml
httpd_package: httpd
And then include it in your playbook:
- hosts: webservers
vars_files:
- vars.yml
tasks:
- name: Install Apache
yum:
name: "{{ httpd_package }}"
state: present
On the command line:
You can override variables on the command line using --extra-vars:
ansible-playbook playbook.yml --extra-vars "httpd_package=httpd"
A template in Ansible is a file that contains placeholders (variables) which can be dynamically replaced during playbook execution. These placeholders are processed using Jinja2 templating. Templates allow you to create configuration files that are customized for each host or environment.
The most common use of templates is in configuration files, where the values can vary depending on the host or group of hosts.
Steps to use a template:
Create a template file with Jinja2 syntax (e.g., config.j2):
# config.j2
server_name {{ ansible_hostname }}
document_root {{ web_root }}
Use the template module in the playbook to process the template and copy it to the target machine:
- name: Copy Apache config file
template:
src: config.j2
dest: /etc/httpd/conf.d/{{ ansible_hostname }}.conf
In Ansible, both vars and defaults are used to define variables, but they have different precedence and use cases:
Example:
vars:
httpd_package: httpd
Example (defaults/main.yml):
httpd_package: httpd
Precedence of variable values:
Handlers in Ansible are special tasks that only run when notified by other tasks. Handlers are typically used for operations like restarting a service after a configuration file has changed, but they can be used for any task that should only run when a specific change occurs.
Example:
tasks:
- name: Install Apache
yum:
name: httpd
state: present
notify:
- restart apache
handlers:
- name: restart apache
service:
name: httpd
state: restarted
In this example, the restart apache handler is triggered if the httpd package is installed or updated. The handler will only run once, regardless of how many tasks notify it.
In Ansible, loops allow you to iterate over a list of items, performing the same task on each item. You can use the loop keyword to define a loop.
Example using loop:
- name: Install multiple packages
yum:
name: "{{ item }}"
state: present
loop:
- httpd
- git
- curl
In this example, Ansible will install the packages httpd, git, and curl one by one on the target hosts.
Alternatively, you can use other looping constructs like with_items, though loop is the preferred method in newer versions of Ansible.
The when statement in Ansible is used to conditionally execute tasks based on a specific condition. It allows you to run a task only if a certain condition is true, enabling more dynamic and flexible automation.
The when condition can use facts, variables, or expressions.
Example:
- name: Install Apache on RedHat-based systems
yum:
name: httpd
state: present
when: ansible_facts['ansible_os_family'] == 'RedHat'
In this example, the task will only run if the managed node’s OS family is RedHat.
You can also combine multiple conditions using and, or, etc.:
- name: Install package if needed
yum:
name: "{{ item }}"
state: present
loop:
- httpd
- git
when: ansible_facts['ansible_memory_mb']['total'] > 1024
To execute tasks only when a condition is met in Ansible, you can use the when keyword. This allows you to define a condition, and if the condition evaluates to true, the task will be executed. If the condition is false, the task is skipped.
Example:
- name: Install Apache if the system is RedHat
yum:
name: httpd
state: present
when: ansible_facts['ansible_os_family'] == 'RedHat'
In this example, the task will only execute on RedHat-based systems.
Ansible Galaxy is a community-driven repository of pre-built Ansible roles, collections, and playbooks that you can use to simplify your automation tasks. It allows you to find reusable content created by other Ansible users and contribute your own.
You can search for roles, collections, and playbooks on Ansible Galaxy. To use content from Galaxy, you can install it using the ansible-galaxy command.
Example of installing a role from Ansible Galaxy:
ansible-galaxy install geerlingguy.apache
This command installs the apache role by geerlingguy from Ansible Galaxy. You can then include the role in your playbook:
- hosts: webservers
roles:
- geerlingguy.apache
Ansible Galaxy allows for faster automation development by leveraging existing solutions and provides an easy way to share your own automation content with the community.
You can install roles from Ansible Galaxy using the ansible-galaxy command-line tool. Ansible Galaxy hosts a large collection of pre-built roles and collections that you can easily reuse in your playbooks. To install a role, use the following command:
To install a role:
ansible-galaxy install <role_name>
For example, to install the geerlingguy.apache role from Galaxy:
ansible-galaxy install geerlingguy.apache
This will download and install the role into the default Ansible role directory (~/.ansible/roles/), or a directory specified in your ansible.cfg configuration file.
To install a specific version of a role:
You can specify the version (or a specific version number) of a role using the -v or --version option:
ansible-galaxy install geerlingguy.apache,2.0.0
To install roles from a requirements file:
If you have a requirements.yml file with a list of roles you want to install, you can install all roles in the file with the following command:
ansible-galaxy install -r requirements.yml
Here’s an example of a requirements.yml file:
---
- name: geerlingguy.apache
version: 2.0.0
- name: geerlingguy.mysql
Ansible Vault is a feature of Ansible that allows you to securely store sensitive data, such as passwords, API keys, or configuration files, within your playbooks and roles. It uses encryption to protect data, ensuring that sensitive information is not exposed in plain text.
Why use Ansible Vault?
How to use Ansible Vault:
Create an encrypted file:You can create a new encrypted file using the ansible-vault create command:
ansible-vault create secrets.yml
Edit an encrypted file:If you need to modify an encrypted file, use the ansible-vault edit command:
ansible-vault edit secrets.yml
Encrypt an existing file:To encrypt a file that is not already encrypted, use the ansible-vault encrypt command:
ansible-vault encrypt plaintext.yml
Decrypt an encrypted file:To decrypt a file, you can use the ansible-vault decrypt command:
ansible-vault decrypt secrets.yml
Using Ansible Vault in a playbook:In your playbook, you can reference encrypted variables in the same way you would use regular variables. For example:
- hosts: webservers
vars_files:
- secrets.yml
tasks:
- name: Print the password
debug:
msg: "{{ db_password }}"
To run a playbook with Vault-encrypted data, you'll need to specify the Vault password either interactively or from a file:
ansible-playbook playbook.yml --ask-vault-pass
The debug statement in Ansible is used to print information to the console during playbook execution. This can be helpful for troubleshooting, printing variable values, or displaying messages that provide insight into the playbook's execution flow.
The debug module allows you to output a message or a variable's value to the terminal.
Example of using debug:
- name: Display the value of a variable
debug:
msg: "The value of my_variable is {{ my_variable }}"
This will print:
The value of my_variable is value_of_variable
Example of using debug with a condition:
- name: Check if the system is running RedHat
debug:
msg: "This is a RedHat system."
when: ansible_facts['ansible_os_family'] == 'RedHat'
You can also use var to output variables directly:
- name: Display facts
debug:
var: ansible_facts
In Ansible, notify is used to trigger handlers to run when a task has made a change. A handler is a special task that is only executed when notified by other tasks. Handlers typically perform actions like restarting a service or reloading a configuration after a change.
Example:
tasks:
- name: Install Apache
yum:
name: httpd
state: present
notify:
- restart apache
handlers:
- name: restart apache
service:
name: httpd
state: restarted
In this example:
Handlers are only executed once, even if multiple tasks notify the same handler.
Ansible automatically runs tasks in parallel on multiple hosts (managed nodes). The default behavior is to run tasks on all hosts in parallel unless you specify otherwise.
To control the level of parallelism, you can adjust the forks option.
1. Using the command line:
You can use the -f or --forks option to specify the number of parallel tasks:
ansible-playbook -i hosts.ini playbook.yml -f 10
This command will run up to 10 tasks in parallel.
2. Using ansible.cfg:
You can set the default number of parallel tasks in your ansible.cfg file under the defaults section:
[defaults]
forks = 10
This will apply to all playbooks unless overridden.
To limit the number of parallel tasks (hosts) that Ansible runs at the same time, you can use the -f or --forks option, or configure the forks setting in your ansible.cfg file.
Using the -f option (on the command line):
ansible-playbook -i hosts.ini playbook.yml -f 5
Using the ansible.cfg file: You can set the forks value in your ansible.cfg to limit the number of parallel tasks globally:
[defaults]
forks = 5
This ensures that Ansible will run a maximum of 5 tasks in parallel across all hosts.
Managing multiple environments in Ansible typically involves using different inventory files for each environment (e.g., dev, staging, prod) and using variable files to manage environment-specific configurations.
1. Using different inventory files:
You can create separate inventory files for each environment:
Then specify the environment when running the playbook:
ansible-playbook -i inventory-dev.ini playbook.yml
2. Using variable files for each environment:
Create environment-specific variable files:
Then include these files in your playbook:
- hosts: all
vars_files:
- vars/{{ env }}.yml
tasks:
- name: Do something specific
debug:
msg: "This is the {{ env }} environment"
You can pass the environment variable (env) when running the playbook:
ansible-playbook playbook.yml --extra-vars "env=dev"
3. Ansible Vault for sensitive data:
If you have sensitive data for each environment (e.g., different database passwords), use Ansible Vault to encrypt environment-specific data files.
Tags in Ansible allow you to run only specific parts of a playbook. Tags are useful when you want to run a subset of tasks, such as when debugging or testing individual parts of your playbook without executing everything.
How to use tags:
Define tags for tasks:
tasks:
- name: Install Apache
yum:
name: httpd
state: present
tags:
- install
- name: Start Apache
service:
name: httpd
state: started
tags:
- start
Run playbook with specific tags:You can run only the tasks associated with certain tags:
ansible-playbook playbook.yml --tags "install"
Skip tasks with specific tags:If you want to run all tasks except those with a specific tag, use the --skip-tags option:
ansible-playbook playbook.yml --skip-tags "start"
Ansible provides several methods for handling errors in playbooks:
Using ignore_errors: yes:You can use ignore_errors: yes to continue executing tasks even if a particular task fails:
- name: Install Apache (ignore errors if it fails)
yum:
name: httpd
state: present
ignore_errors: yes
Using block and rescue:The block and rescue constructs allow you to define error handling logic:
tasks:
- block:
- name: Install Apache
yum:
name: httpd
state: present
rescue:
- name: Handle failure
debug:
msg: "Apache installation failed"
Using failed_when:You can specify a custom failure condition with failed_when:
- name: Ensure apache is installed
yum:
name: httpd
state: present
failed_when: ansible_facts['yum']['installed'] == 0
To check the status of a playbook execution, you can use:
Verbose output (-v, -vv, -vvv):You can run a playbook with different levels of verbosity to get detailed information about its execution:
ansible-playbook playbook.yml -vvv
Check exit status:After running a playbook, you can check the exit status ($? on Unix-based systems) to determine if the playbook ran successfully. A 0 exit status means success, while a non-zero exit status indicates failure.
ansible-playbook playbook.yml
echo $?
In Ansible, both include and import are used to load external playbooks, tasks, or files, but they have different behaviors and use cases.
Example:
tasks:
- include: tasks_to_include.yml
Example:
tasks:
- import_tasks: tasks_to_import.yml
Key Differences:
Debugging an Ansible playbook is essential to troubleshoot and identify issues with tasks. There are several methods for debugging:
Example:
- name: Display variable value
debug:
msg: "The value of my_variable is {{ my_variable }}"
You can increase the verbosity of your playbook execution using the -v, -vv, or -vvv flags. The more vs you add, the more detailed the output will be, helping with identifying errors.
ansible-playbook playbook.yml -vvv
Ansible commands return an exit code (0 for success, 1 for failure). You can check this exit code to see if any tasks failed.
ansible-playbook playbook.yml
echo $?
The --check option allows you to simulate a playbook run without making any changes. This is useful for testing playbooks before they execute.
ansible-playbook playbook.yml --check
In Ansible, notify and listen are used together to trigger handlers, but they have different roles in the process:
Example:
tasks:
- name: Install httpd
yum:
name: httpd
state: present
notify:
- restart apache
Example:
handlers:
- name: restart apache
service:
name: httpd
state: restarted
listen: "restart apache"
Key Differences:
Ansible facts are system information gathered by Ansible about the target hosts during playbook execution. These facts include details about the system's operating system, network interfaces, hardware, memory, and other environment variables.
Example of enabling facts gathering:
- hosts: all
gather_facts: yes # this is the default behavior
tasks:
- name: Show OS information
debug:
msg: "The OS is {{ ansible_facts['ansible_distribution'] }}"
Using the setup module: You can also manually collect facts using the setup module:
- hosts: all
tasks:
- name: Collect facts
setup:
To create a custom Ansible module, you can write a Python script that follows the Ansible module guidelines and communicates with Ansible through JSON. Here are the steps:
Example of a simple custom module:
# my_module.py
from ansible.module_utils.basic import AnsibleModule
def run_module():
module = AnsibleModule(
argument_spec=dict(
name=dict(required=True, type='str')
)
)
name = module.params['name']
# Simulate some logic
result = {'changed': False, 'message': f"Hello, {name}"}
module.exit_json(**result)
if __name__ == '__main__':
run_module()
- name: Use custom module
my_module:
name: "John Doe"
An Ansible collection is a distribution format for Ansible content (roles, modules, plugins, and documentation). It is designed to package and distribute reusable automation content in a standardized way. Collections allow for easier sharing and distribution of Ansible content.
How to use a collection:
ansible-galaxy collection install community.general
Once installed, you can reference it in your playbook:
- name: Use module from a collection
community.general.some_module:
param1: value
To specify dependencies for a role in Ansible, you use the dependencies keyword in the role’s meta/main.yml file. This allows you to specify other roles that should be executed before the current role is applied.
Example (meta/main.yml):
dependencies:
- role: common
- role: apache
In this case, the common and apache roles will be executed before the current role.
Using Ansible for multi-tier application deployment involves defining different groups of hosts (e.g., web servers, application servers, database servers) in your inventory and creating separate playbooks or tasks for each tier.
Steps:
Define different groups in your inventory file:ini
[webservers]
web1.example.com
web2.example.com
[appservers]
app1.example.com
app2.example.com
[dbservers]
db1.example.com
Example:
- hosts: webservers
tasks:
- name: Install nginx
yum:
name: nginx
state: present
- hosts: appservers
tasks:
- name: Install application code
git:
repo: https://github.com/myapp.git
dest: /var/www/myapp
- hosts: dbservers
tasks:
- name: Install MySQL
yum:
name: mysql-server
state: present
A dynamic inventory is an inventory that is generated dynamical
ly at runtime rather than being statically defined in an ini or yaml file. It is useful for environments where the inventory changes frequently, such as cloud environments (AWS, Azure, GCP).
How to configure a dynamic inventory:
Install dependencies:
pip install boto boto3
Example (inventory file):
plugin: aws_ec2
regions:
- us-east-1
Ansible can manage Windows systems through WinRM (Windows Remote Management). To manage Windows systems, you need to set up WinRM on the target machine and ensure that the Ansible control machine can communicate with Windows hosts over WinRM.
Steps:
Configure WinRM on Windows: Use PowerShell to configure WinRM on the Windows machine:
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' # Trust all hosts
Install pywinrm to allow Ansible to communicate with Windows systems:
pip install pywinrm
Example (inventory.ini):
[windows]
winserver1 ansible_host=192.168.1.100 ansible_user=Administrator ansible_password=Password123 ansible_connection=winrm
Example:
- name: Install IIS on Windows
hosts: windows
tasks:
- name: Install IIS feature
win_feature:
name: Web-Server
state: present
This will install IIS on the Windows machine using Ansible.
Ansible tags are used to group tasks or plays in a playbook, allowing you to selectively run or skip certain parts of the playbook during execution. They help to organize complex playbooks into manageable parts, and facilitate testing, debugging, and running specific tasks only when necessary.
Use cases for tags:
Example:
---
- hosts: all
tasks:
- name: Install Nginx
yum:
name: nginx
state: present
tags:
- install
- name: Start Nginx
service:
name: nginx
state: started
tags:
- start
To run only the tasks tagged as install:
ansible-playbook playbook.yml --tags "install"
To skip tasks with the start tag:
ansible-playbook playbook.yml --skip-tags "start"
Ansible filters allow you to manipulate or transform data within playbooks. Filters are used to modify the values of variables, lists, dictionaries, or strings during execution, making them more flexible and dynamic.
Examples of commonly used filters:
default: Provides a default value if the variable is undefined.
{{ my_variable | default('default_value') }}
join: Joins a list into a single string with a separator.
{{ ['apple', 'banana', 'cherry'] | join(', ') }}
# Output: apple, banana, cherry
length: Returns the length of a list, string, or dictionary.
{{ ['apple', 'banana', 'cherry'] | length }}
# Output: 3
to_json: Converts a variable or object to JSON format.
{{ my_variable | to_json }}
regex_replace: Replaces a pattern in a string using a regular expression.
{{ "hello world" | regex_replace("world", "Ansible") }}
# Output: hello Ansible
Filters are often used in conjunction with vars or debug modules to manipulate or display data.
Ansible provides several ways to handle errors and control the behavior when a task fails.
tasks:
- name: Install a package
yum:
name: non_existent_package
state: present
ignore_errors: yes
tasks:
- name: Ensure apache is installed
yum:
name: httpd
state: present
failed_when: ansible_facts['yum']['installed'] == 0
tasks:
- block:
- name: Install Apache
yum:
name: httpd
state: present
rescue:
- name: Handle failure
debug:
msg: "Apache installation failed"
tasks:
- name: Install Apache on RedHat
yum:
name: httpd
state: present
when: ansible_facts['ansible_os_family'] == 'RedHat'
In Ansible, the state parameter in many modules (such as yum, package, service, etc.) defines the desired state of a resource (such as a package, service, file, etc.).
Example:
- name: Ensure nginx is installed
yum:
name: nginx
state: present
Example:
- name: Ensure nginx is removed
yum:
name: nginx
state: absent
The state=present is used when you want to ensure the resource exists, while state=absent is used to ensure the resource is removed.
To set up Ansible to manage AWS EC2 instances, you need to install the necessary dependencies and configure the aws_ec2 dynamic inventory plugin.
Steps:
Install the boto and boto3 Python libraries, which allow Ansible to interact with AWS APIs.
pip install boto boto3
Example:
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
region = us-east-1
Example configuration (inventory.yml):
plugin: aws_ec2
regions:
- us-east-1
filters:
instance_type: t2.micro
ansible -i inventory.yml all -m ping
Both the command and shell modules are used to execute commands on remote systems, but they have key differences:
Example:
- name: Run a command without shell
command: /bin/echo Hello World
Example:
- name: Run a shell command
shell: "echo Hello World > /tmp/hello.txt"
Key Difference:
Ansible provides the ability to run tasks asynchronously, allowing them to continue running in the background while the playbook moves on to the next task. This is useful for long-running tasks like large software installations or network operations.
Example:
- name: Run a long task asynchronously
command: /usr/bin/some_long_running_task
async: 600 # run for up to 600 seconds
poll: 0 # do not wait for the task to finish, move to the next task immediately
- name: Check async task status
async_status:
jid: "{{ long_running_task.job_id }}"
register: job_result
until: job_result.finished
retries: 5
delay: 10
A task block in Ansible is a group of tasks that can be treated as a single unit. A task block allows you to group multiple tasks together and apply certain logic (like when, notify, rescue, and always) to the entire block.
Example:
tasks:
- block:
- name: Install nginx
yum:
name: nginx
state: present
- name: Start nginx service
service:
name: nginx
state: started
rescue:
- name: Handle error
debug:
msg: "Error installing nginx"
always:
- name: Clean up
file:
path: /tmp/nginx_tmp
state: absent
You can restrict tasks to specific hosts in several ways:
- hosts: webservers
tasks:
- name: Install nginx
yum:
name: nginx
state: present
- hosts: all
tasks:
- name: Install nginx on web servers
yum:
name: nginx
state: present
when: ansible_facts['ansible_hostname'] == 'webserver1'
The wait_for module is used to wait for a specific condition to be met before continuing with the playbook. It can be used to wait for a port to become open, a file to appear, or even a condition to be true.
Common use cases:
Example 1 (wait for port):
- name: Wait for HTTP port to be open
wait_for:
port: 80
host: "{{ ansible_host }}"
state: started
timeout: 300 # Timeout after 5 minutes
Example 2 (wait for file):
- name: Wait for file to appear
wait_for:
path: /tmp/myfile.txt
state: present
timeout: 60
The wait_for module is useful when you need to wait for an external system or process to become ready before continuing.
You can pass variables to Ansible playbooks at runtime using the -e or --extra-vars option. This allows you to override or define variables directly from the command line when running the playbook.
Usage examples:
Passing a single variable:
ansible-playbook playbook.yml -e "my_var=value"
Passing multiple variables:
ansible-playbook playbook.yml -e "var1=value1 var2=value2"
Passing a JSON or YAML file with variables: If you have a file with variable definitions, you can pass it like this:
ansible-playbook playbook.yml -e "@vars.json"
Or in YAML format:
ansible-playbook playbook.yml -e "@vars.yml"
Passing a dictionary as an extra variable: You can pass dictionaries or complex structures using JSON syntax.
ansible-playbook playbook.yml -e '{"users": ["alice", "bob"]}'
This approach gives you flexibility to inject environment-specific data into your playbooks without modifying the playbook itself.
The with_items loop in Ansible allows you to iterate over a list of items and perform the same task for each item. This is commonly used to apply the same operation to multiple items, such as installing multiple packages, creating multiple users, or managing multiple files.
Example:
- name: Install multiple packages
yum:
name: "{{ item }}"
state: present
with_items:
- httpd
- nginx
- mysql
In this example, Ansible will loop through the list of packages (httpd, nginx, mysql) and install each one.
In newer versions of Ansible, it's recommended to use the loop keyword instead of with_items, which has a more flexible syntax and supports additional features like looping through dictionaries.
Ansible Tower, part of Red Hat Ansible Automation Platform, provides Role-Based Access Control (RBAC) to manage access to resources like playbooks, inventories, and job templates. This allows you to assign specific permissions to users or groups, ensuring that individuals can only perform actions they are authorized to do.
Steps to Implement RBAC in Ansible Tower:
Example: To restrict a user to just viewing jobs in a specific project, you would assign the "Viewer" role to the team for that project.
The gather_facts directive in Ansible determines whether Ansible will collect information (facts) about the managed nodes at the beginning of a playbook run. These facts are automatically gathered by Ansible and provide information about the system, such as the operating system, IP addresses, memory, and disk space. This information is stored in the ansible_facts variable and can be used throughout the playbook to make decisions.
By default, fact gathering is enabled (gather_facts: yes), but it can be turned off if the playbook does not require system information.
Example:
- hosts: webservers
gather_facts: yes
tasks:
- name: Show OS information
debug:
msg: "The OS is {{ ansible_facts['os_family'] }}"
When to disable: If you're only performing simple tasks that don't require facts, disabling fact gathering can speed up the execution of the playbook.
- hosts: webservers
gather_facts: no
tasks:
- name: Install nginx
yum:
name: nginx
state: present
Ansible Tower is a web-based interface and dashboard that sits on top of Ansible and is part of the Red Hat Ansible Automation Platform. It provides a more enterprise-friendly way to manage and automate your Ansible playbooks and tasks, offering features such as job scheduling, logging, role-based access control (RBAC), and integration with other systems.
Benefits of Ansible Tower:
Example: A system administrator can use Ansible Tower to launch an inventory synchronization job, track the job’s progress, and receive alerts if something goes wrong.
In Ansible, you can include external files, such as tasks, variables, or templates, in your playbook to keep things modular and organized. There are several directives for including files:
include: This directive includes tasks from another file.
- name: Include tasks file
include: tasks.yml
import: Similar to include, but the included content is processed at the time the playbook is parsed (before execution).
- import_tasks: tasks.yml
include_tasks: Used for including task files dynamically within the playbook.
- include_tasks: "tasks/{{ ansible_hostname }}.yml"
Roles: The most common way to include reusable content in Ansible is using roles. Roles are directories containing predefined task files, templates, handlers, and other components, which can be easily reused across different playbooks.
- name: Include role
hosts: all
roles:
- common
Using roles and includes makes your playbooks modular and easier to maintain.
A play in Ansible is a set of tasks that are executed on a group of hosts. A play defines the set of actions that should be performed on each target machine and organizes them into a sequential series of steps. Each play in a playbook targets a specific group of hosts, and within each play, you can specify tasks, variables, handlers, and roles.
Structure of a Play:
Example:
- name: Install Apache on web servers
hosts: webservers
gather_facts: yes
tasks:
- name: Install Apache package
yum:
name: httpd
state: present
- name: Start Apache service
service:
name: httpd
state: started
In this example, the play installs and starts Apache on the webservers group, with gather_facts enabled.
An Ansible callback plugin is a plugin that allows you to capture and process events during playbook execution. Callback plugins provide ways to customize the behavior of Ansible, such as modifying output formats, integrating with external systems, or sending notifications. These plugins are part of Ansible’s plugin architecture.
Use cases for callback plugins:
Example: To change the output format to JSON, you can use a callback plugin like this:
ansible-playbook playbook.yml --stdout=json
Idempotence is the property of a system where performing an operation multiple times will always produce the same result. In Ansible, this means that running a playbook multiple times will not change the system after the first successful run, as long as the system is already in the desired state.
Ansible achieves idempotence by checking the current state of the system before making any changes. For example, if a task installs a package, Ansible checks whether the package is already installed. If it is, Ansible will not install it again, ensuring no redundant changes are made.
Example:
- name: Install nginx
yum:
name: nginx
state: present
If nginx is already installed, running this task again will have no effect, ensuring idempotence.
The loop keyword in Ansible is used to iterate over a list or a dictionary and execute the same task multiple times with different items. The loop keyword is more flexible than older looping constructs like with_items and is used to iterate over data structures passed as variables.
Usage example with a list:
- name: Install multiple packages
yum:
name: "{{ item }}"
state: present
loop:
- httpd
- nginx
- mysql
In this case, Ansible will install each package in the list, one at a time.
Usage example with a dictionary:
- name: Configure services
service:
name: "{{ item.key }}"
state: "{{ item.value }}"
loop:
- { key: 'nginx', value: 'started' }
- { key: 'mysql', value: 'stopped' }
Here, Ansible will configure both services (nginx and mysql) based on the dictionary values.
Ansible Vault is a tool within Ansible to encrypt sensitive data, such as passwords, API keys, or other secrets, ensuring that they are not stored in plaintext within your playbooks or inventories. Vault provides a way to securely manage sensitive information while still allowing it to be used in your automation tasks.
Steps to handle secrets management with Ansible Vault:
Create an encrypted file: You can create a new file and encrypt it using the ansible-vault create command.
ansible-vault create secrets.yml
Edit an encrypted file: To modify an encrypted file, you can use the ansible-vault edit command.
ansible-vault edit secrets.yml
Encrypt an existing file: If you have a plain text file containing sensitive data, you can encrypt it with:
ansible-vault encrypt my_file.yml
Decrypt an encrypted file: To read or modify an encrypted file directly, you can decrypt it with:
ansible-vault decrypt secrets.yml
Use Vault variables in playbooks: Encrypted files can be referenced in your playbook as variables:
- name: Use encrypted variables
hosts: all
vars_files:
- secrets.yml
tasks:
- name: Print password
debug:
msg: "The password is {{ secret_password }}"
Provide Vault password: To execute playbooks with encrypted files, provide the vault password either interactively using --ask-vault-pass or through a file with --vault-password-file:
ansible-playbook playbook.yml --ask-vault-pass
or
ansible-playbook playbook.yml --vault-password-file .vault_pass.txt
Example:
[defaults]
inventory = ./inventory
remote_user = ansible
retries = 3
Example (INI format):
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com
db2.example.com
While the ansible.cfg configures Ansible's execution environment, the inventory file defines the specific targets for the playbooks.
Ansible can be used to provision cloud resources on platforms such as AWS, Azure, Google Cloud, and others by using specific Ansible modules designed for each cloud provider. These modules allow you to create, configure, and manage cloud resources such as virtual machines, security groups, networks, and more.
Example: Provisioning an EC2 instance in AWS:
Set AWS credentials: Configure your AWS credentials either through environment variables, the AWS CLI, or directly in ansible.cfg.
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
Use Ansible to create an EC2 instance:
- name: Provision EC2 instance in AWS
hosts: localhost
tasks:
- name: Launch EC2 instance
amazon.aws.ec2_instance:
name: MyInstance
key_name: MyKey
instance_type: t2.micro
image_id: ami-0c55b159cbfafe1f0
region: us-east-1
state: present
wait: yes
security_groups:
- sg-12345678
subnet_id: subnet-abcdefg
tags:
Name: MyInstance
You can use similar modules for other cloud platforms, such as azure_rm_virtualmachine for Azure or gce_instance for Google Cloud.
Ansible does not have an explicit "rollback" feature, but rollback can be managed by structuring tasks and playbooks in a way that they can undo changes if something goes wrong. Here are several strategies for handling deployment rollback:
- name: Update configuration file
copy:
src: config.conf
dest: /etc/myapp/config.conf
notify:
- restart service
handlers:
- name: restart service
service:
name: myapp
state: restarted
- name: Backup important file
copy:
src: /etc/myapp/config.conf
dest: /etc/myapp/config.conf.bak
remote_src: yes
- name: Modify configuration file
copy:
src: new_config.conf
dest: /etc/myapp/config.conf
- name: Restore configuration if necessary
copy:
src: /etc/myapp/config.conf.bak
dest: /etc/myapp/config.conf
when: rollback_needed
The terms create and overwrite typically describe the behavior of modules that deal with creating or updating resources.
create: This term indicates that the module will create a resource if it does not exist, but it will not modify an existing resource.Example: In the file module, create would ensure that a file is created only if it doesn't already exist.
- name: Create a new file
file:
path: /tmp/myfile.txt
state: touch
overwrite: This indicates that the module will overwrite or replace an existing resource with a new one. It will apply changes even if the resource already exists, potentially replacing or modifying its contents.Example: When using the copy module, if the destination file already exists, it will be overwritten.
- name: Overwrite a file with new content
copy:
src: new_file.txt
dest: /tmp/existing_file.txt
Ansible provides several modules specifically designed for configuring network devices such as routers, switches, firewalls, and load balancers. These modules are available for various network vendors, including Cisco, Juniper, Arista, and others.
Install the required collections: Ansible has different collections for various vendors, such as cisco.ios, juniper.junos, etc. You can install these collections via Ansible Galaxy.
ansible-galaxy collection install cisco.ios
Example for Cisco IOS device:
- name: Configure Cisco IOS Router
hosts: routers
gather_facts: no
tasks:
- name: Configure interface
cisco.ios.ios_interface:
name: GigabitEthernet0/0
description: "Main Interface"
enabled: true
mtu: 1500
In this example, Ansible configures an interface on a Cisco router. You can similarly configure other network settings like VLANs, routing protocols, ACLs, etc.
Ansible is cross-platform and can manage both Linux and Windows systems. It abstracts away many OS-specific differences using modules that detect the underlying OS type and execute commands accordingly.
Ansible automatically detects the target operating system and uses the appropriate modules to perform tasks.
- name: Install package on Linux
package:
name: httpd
state: present
when: ansible_facts['os_family'] == 'RedHat'
- name: Install package on Windows
win_chocolatey:
name: googlechrome
state: present
when: ansible_facts['os_family'] == 'Windows'
Ansible does not have built-in notification mechanisms, but you can implement notifications using handlers, callback plugins, or external systems via custom tasks.
Using Handlers: Trigger notifications when specific conditions occur. For example, send a Slack notification when a task completes.
- name: Send notification
slack:
token: "your-slack-token"
channel: "#notifications"
msg: "Ansible playbook completed successfully!"
when: notify_on_success
Ansible integrates well with Jenkins for automating CI/CD pipelines. Jenkins can trigger Ansible playbooks as part of the build and deployment process.
Triggering Ansible Playbooks from Jenkins: In a Jenkins pipeline, you can use the Ansible plugin to run playbooks directly or trigger a shell command to run Ansible commands.groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
ansiblePlaybook playbook: 'deploy.yml'
}
}
}
}
Using Ansible CLI in Jenkins: You can also invoke Ansible via a shell script in Jenkins.
ansible-playbook -i inventory deploy.yml
This allows for automated deployment processes as part of the continuous delivery pipeline.
When a playbook fails on remote hosts, there are several steps you can take to troubleshoot the issue:
Use Verbose Mode: Use the -v, -vv, or -vvv flag with the ansible-playbook command to increase the verbosity level. This will give you more detailed output, showing exactly where the failure occurred and providing additional context.
ansible-playbook playbook.yml -vvv
Check Connectivity: Ensure that Ansible can reach the target hosts. Test connectivity using the ping module:
ansible all -m ping -i inventory.ini
Run Tasks Individually: You can use the --start-at-task option to run the playbook from the specific task where it failed. This allows you to isolate the problem and test it independently.
ansible-playbook playbook.yml --start-at-task="Task name"
To make an Ansible playbook reusable across multiple environments (dev, staging, prod), follow these strategies:
Use Environment-Specific Variables: Store environment-specific variables in separate files. You can create a directory structure like this:
├── playbook.yml
├── inventories/
│ ├── dev.ini
│ ├── staging.ini
│ └── prod.ini
└── group_vars/
├── dev.yml
├── staging.yml
└── prod.yml
Use Group Variables: In your group_vars/ directory, define environment-specific settings (such as database URLs, usernames, passwords, etc.) for each environment. These files will contain the variable values for each group (dev, staging, prod).
# group_vars/dev.yml
db_host: dev-db.example.com
db_user: devuser
Use Inventory Files for Environment-Specific Hosts: Create separate inventory files for each environment, which will define the target hosts for each environment.
# inventories/dev.ini
[web]
dev-web1.example.com
dev-web2.example.com
[db]
dev-db.example.com
Use Playbook Variables: You can pass environment-specific variables to the playbook at runtime using the -e option, allowing you to dynamically specify variables during execution.
ansible-playbook playbook.yml -e "env=dev"
Conditionally Define Variables: In the playbook, use conditionals to apply different tasks based on the environment.
- name: Deploy application
hosts: "{{ env }}"
tasks:
- name: Install dependencies
yum:
name: "{{ item }}"
state: present
loop: "{{ dependencies }}"
Include Environment-Specific Files: Use vars_files to include the environment-specific variables file within the playbook.
- name: Deploy to dev
hosts: dev
vars_files:
- "group_vars/dev.yml"
tasks:
- name: Install Dev Application
yum:
name: dev-app
state: present
This modular approach allows you to maintain separate configurations for different environments while using a single playbook.
Managing large inventories in Ansible requires a combination of strategies to ensure scalability, performance, and ease of maintenance:
Example of AWS dynamic inventory:
ansible-playbook -i aws_ec2.yml playbook.yml
Organize Inventory by Groups: Organize hosts into groups based on roles, environments, or other criteria (e.g., web, db, app, dev, prod). This makes it easier to target specific subsets of hosts in your playbook.
[web]
web1.example.com
web2.example.com
[db]
db1.example.com
db2.example.com
Split Large Inventories into Multiple Files: For large inventories, split them into multiple files and include them in a master inventory file.
# master_inventory.ini
[web]
include=web_inventory.ini
[db]
include=db_inventory.ini
Use Host Vars: For managing host-specific variables, you can create individual files for each host under the host_vars/ directory. This approach keeps the inventory organized.
└── host_vars/
├── web1.yml
├── web2.yml
├── db1.yml
Limit the Scope of Playbooks: Use --limit to restrict the execution to a subset of hosts in large inventories, making playbooks more manageable.
ansible-playbook playbook.yml --limit "web"
Ansible Tower provides several advanced features that make it more beneficial than using command-line Ansible, especially in large, enterprise environments:
To implement high availability (HA) in an infrastructure using Ansible, you would need to ensure that multiple instances of critical services (e.g., databases, web servers, etc.) are set up in a redundant configuration, and that they can failover if one instance becomes unavailable.
Steps for HA implementation:
Install and Configure Load Balancers: Use Ansible to install and configure load balancers (e.g., HAProxy, NGINX) to distribute traffic between multiple backend servers.
- name: Install HAProxy
apt:
name: haproxy
state: present
- name: Configure HAProxy for load balancing
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
Install and Configure Redundant Services: Ensure that your services (e.g., databases, web servers) are installed and configured on multiple nodes. Use Ansible to deploy these services across multiple servers and ensure they are in sync.Example: Setting up a multi-node MySQL cluster.
- name: Install MySQL
yum:
name: mysql-server
state: present
- name: Configure MySQL replication
mysql_replication:
mode: master
master_host: "{{ master_ip }}"
master_user: "replication_user"
master_password: "{{ replication_password }}"
Ansible plays a key role in automating the deployment, configuration, and orchestration of microservices in a cloud-native environment. It can help:
Example:
- name: Deploy a Dockerized microservice
docker_container:
name: my_service
image: my_service_image:latest
state: started
ports:
- "8080:8080"
In a multi-cloud environment, Ansible can be used to manage resources across different cloud providers (e.g., AWS, Azure, Google Cloud) using dynamic inventories and cloud modules.
Example:
- name: Create EC2 instance in AWS
ec2_instance:
key_name: mykey
region: us-east-1
image: ami-123456
instance_type: t2.micro
when: cloud_provider == "aws"
Callback plugins in Ansible are used to hook into the execution of playbooks and perform actions or log output based on specific events, such as when a task starts, when it finishes, or when it fails.
Example of using a callback plugin to send notifications to Slack:
- name: Notify Slack on failure
slack:
token: "your-slack-token"
channel: "#alerts"
msg: "Playbook execution failed!"
when: result.failed
To create custom inventory sources, you can write a dynamic inventory script in Python, which interacts with external systems (e.g., cloud providers, databases) to generate the list of hosts dynamically.
Write a Dynamic Inventory Script: Create a script that outputs JSON data containing the list of hosts and their associated variables.Example Python script:
# my_inventory.py
import json
import sys
def get_inventory():
inventory = {
"all": {
"hosts": ["host1.example.com", "host2.example.com"],
"vars": {
"ansible_user": "admin"
}
}
}
print(json.dumps(inventory))
if __name__ == '__main__':
get_inventory()
Use the Script as an Inventory Source:
ansible-playbook -i my_inventory.py playbook.yml
Example:
ansible-galaxy install geerlingguy.apache
Example:
pip install ansible
ansible-galaxy is specific to managing Ansible content (roles, collections), while ansible-pip is used to install or manage Ansible as a Python package.
Canary Deployments: Canary deployments involve rolling out changes to a small subset of servers (the "canary" group) before gradually expanding the deployment to the rest of the servers. Ansible can be used to automate this process by targeting a small group of servers first and then scaling the deployment to the larger group.
Steps:
[canary]
canary-server1
canary-server2
[production]
server1
server2
server3
Deploy to the canary group first:
- name: Deploy to Canary servers
hosts: canary
tasks:
- name: Deploy new version of the app
shell: deploy_new_version.sh
Expand deployment to production: Once the canary servers ar
e validated, deploy the same version to the production group.
- name: Deploy to production servers
hosts: production
tasks:
- name: Deploy new version of the app
shell: deploy_new_version.sh
Blue-Green Deployments: Blue-Green deployments involve maintaining two environments: a "blue" environment (current production) and a "green" environment (new version). You switch traffic from blue to green after validating the new environment.
Steps:
[blue]
server1
server2
[green]
server3
server4
Deploy to the green environment: Deploy the new version to the green group while the blue environment continues to serve traffic.
- name: Deploy to Green environment
hosts: green
tasks:
- name: Deploy new version of the app
shell: deploy_new_version.sh
Delegation in Ansible is the process of running a task on a host other than the one currently being targeted by the playbook. You delegate tasks when you want a task to be executed on a different host, even if that host is not part of the current play's target group.
Use cases for delegation:
Example:
- name: Delegating a task to another host
hosts: web_servers
tasks:
- name: Fetch configuration from control machine
copy:
src: /path/to/local/file
dest: /path/to/remote/file
delegate_to: localhost
In this example, the copy task is executed on localhost, even though the playbook is running against web_servers.
Rolling updates involve updating services or applications on a subset of machines at a time to ensure availability during the update process. In Ansible, you can achieve rolling updates by updating a few nodes at a time, then validating and proceeding to the next set of nodes.
Steps:
Define a group of servers to be updated: Create a group in the inventory (e.g., web_servers).
[web_servers]
server1
server2
server3
server4
Update in batches: Use Ansible’s serial keyword to specify the number of hosts to update at a time. For example, if you want to update 2 servers at a time:
- name: Rolling update for web servers
hosts: web_servers
serial: 2
tasks:
- name: Deploy new version
shell: deploy_new_version.sh
To optimize Ansible playbook performance:
Use async and poll for long-running tasks: For tasks that take a long time, use asynchronous execution to prevent them from blocking the entire playbook.Example:
- name: Start long-running task
command: /path/to/long_running_task
async: 600
poll: 0
Parallel Execution: Use forks to run tasks in parallel. This can be configured globally in the ansible.cfg file or through the ansible-playbook command.
[defaults]
forks = 10
Optimize Fact Gathering: If you don't need facts, disable fact gathering to speed up playbook execution.
- name: Disable fact gathering
gather_facts: no
Managing secrets and sensitive data securely in Ansible can be done using the following strategies:
Ansible Vault: Ansible Vault allows you to encrypt sensitive variables, files, and data in your playbooks, making them accessible only to authorized users.Example of encrypting a variable file:
ansible-vault create secrets.yml
You can then reference the encrypted file in your playbook:
- name: Deploy with secrets
vars_files:
- secrets.yml
tasks:
- name: Deploy application
shell: deploy.sh
Automating patch management with Ansible involves regularly checking for updates and applying patches to servers. The process can be automated using the following steps:
Define the patching task: Use package management modules (apt, yum, dnf, etc.) to install or update packages across servers.Example:
- name: Update all packages on Ubuntu
apt:
upgrade: dist
update_cache: yes
Ansible can integrate with external systems like ServiceNow, JIRA, or Slack using their APIs, either via custom modules or Ansible's uri module.
ServiceNow: Integrate with ServiceNow to automate incident creation or update processes.Example using the uri module:
- name: Create an incident in ServiceNow
uri:
url: "https://your_instance.service-now.com/api/now/table/incident"
method: POST
user: "{{ service_now_user }}"
password: "{{ service_now_password }}"
body:
short_description: "Issue with server"
description: "Server is down"
headers:
Content-Type: "application/json"
delegate_to: localhost
JIRA: Use JIRA's REST API to create, update, or transition issues.Example using uri:
- name: Create a JIRA issue
uri:
url: "https://your_instance.atlassian.net/rest/api/2/issue"
method: POST
user: "{{ jira_user }}"
password: "{{ jira_password }}"
body:
fields:
project:
key: "PROJECT_KEY"
summary: "New issue"
description: "Description of the issue"
issuetype:
name: "Bug"
headers:
Content-Type: "application/json"
delegate_to: localhost
Directory Structure: Follow the best practice directory structure for Ansible roles:
roles/
├── common/
│ ├── tasks/
│ ├── handlers/
│ ├── templates/
│ └── vars/
├── webserver/
└── database/
Ansible integrates with container orchestration tools like Kubernetes and Docker through specific Ansible modules designed for managing containers and orchestrating containerized workloads. This integration allows you to automate the deployment, scaling, and management of containerized applications.
Docker Integration: Ansible provides the docker_container, docker_image, and docker_volume modules for managing Docker containers, images, and volumes. With these modules, you can automate tasks such as building images, starting containers, or removing containers.Example of managing Docker containers:
- name: Manage Docker container
docker_container:
name: my_container
image: nginx:latest
state: started
restart_policy: always
Kubernetes Integration: Ansible also provides modules for managing Kubernetes resources, such as k8s, k8s_facts, and k8s_raw. These modules allow you to automate tasks like creating/deleting pods, services, deployments, and managing namespaces.Example of managing a Kubernetes deployment:
- name: Deploy application to Kubernetes
k8s:
state: present
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: myapp:latest
ports:
- containerPort: 8080
This integration makes Ansible an effective tool for managing both containerized applications (with Docker) and large-scale containerized environments (with Kubernetes), providing infrastructure automation in containerized and cloud-native architectures.
In a hybrid cloud environment, where you have workloads spread across on-premises data centers and public/private cloud providers (e.g., AWS, Azure, Google Cloud), there are several challenges when using Ansible:
Solution:
Ansible can manage the full lifecycle of Kubernetes clusters from initial setup to scaling and upgrades. You can use Ansible to automate the deployment, configuration, and management of Kubernetes clusters across multiple cloud providers or on-premise data centers.
Cluster Installation: Use Ansible to install and configure the control plane (masters) and worker nodes, as well as set up networking (e.g., Calico, Weave) and persistent storage solutions.Example:
- name: Set up Kubernetes control plane
k8s_cluster:
state: present
name: my-k8s-cluster
master: true
nodes: ["node1", "node2", "node3"]
Cluster Scaling: Use Ansible to scale your Kubernetes cluster by adding or removing nodes.Example:
- name: Scale Kubernetes deployment
k8s:
state: present
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 5 # Scaling to 5 replicas
Managing large-scale, distributed systems with Ansible involves breaking down the configuration tasks into manageable pieces and ensuring efficient and scalable execution across thousands of nodes.
Inventory Management: Use dynamic inventory to automatically generate and manage large inventories. For example, use dynamic inventory scripts to pull host information from cloud environments like AWS, Azure, or GCP.Example:
ansible-playbook -i aws_ec2.py playbook.yml
Parallel Execution: Increase the number of parallel tasks using forks in the ansible.cfg or ansible-playbook command. This speeds up playbook execution when dealing with large numbers of hosts.Example:
[defaults]
forks = 50 # Run 50 tasks concurrently
To enforce security compliance in an enterprise setting, you can use Ansible to automate the application of security policies, perform audits, and maintain a consistent security posture across all systems.
Automated Security Policies: Use Ansible to enforce security settings on servers, such as hardening the OS, configuring firewalls, disabling unused services, and ensuring that patches are applied.Example: Hardening SSH settings:
- name: Ensure SSH is secured
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#PermitRootLogin'
line: 'PermitRootLogin no'
notify:
- restart sshd
Compliance Auditing: Use Ansible to run security audits or compliance checks (e.g., CIS Benchmarks, DISA STIG) on servers and generate reports. Tools like OpenSCAP can be integrated into Ansible to check security compliance.Example:
- name: Run OpenSCAP compliance check
command: oscap oval eval --results /tmp/report.xml --profile xccdf_org.ssgproject.content_profile_pci-dss /etc/openscap/scap-yum-rhel7.xml
Yes, Ansible can integrate with monitoring tools like Prometheus, Nagios, and Zabbix to automate the configuration and management of monitoring systems and ensure infrastructure health.
Prometheus: Ansible can configure Prometheus servers, deploy exporters, and set up alerting rules. You can use Ansible's prometheus module (or simply uri to interact with Prometheus’ API) to automate scraping configurations or deploy Prometheus itself.Example:
- name: Install Prometheus
apt:
name: prometheus
state: present
Nagios: Use Ansible to deploy Nagios, configure checks, and add new hosts or services to the Nagios configuration files. Ansible has Nagios modules to integrate with Nagios and automate configuration.Example:
- name: Add host to Nagios configuration
nagios_host:
host_name: myserver
alias: "My Web Server"
address: 192.168.1.100
Zabbix: Ansible can also automate the configuration of Zabbix agents, servers, and host configurations to monitor servers and services.Example:
- name: Install Zabbix agent
apt:
name: zabbix-agent
state: present
By automating the deployment and configuration of these monitoring tools with Ansible, you can ensure that your infrastructure is consistently monitored and managed.
Managing application updates and rollbacks with Ansible involves automating the process of upgrading applications and ensuring that if issues arise, you can quickly roll back to a stable version.
Blue-Green Deployment: Use Ansible to manage a blue-green deployment, where you maintain two identical environments (blue and green) and switch traffic between them after a successful update.Example:
- name: Deploy new application version (Green)
docker_container:
name: myapp-green
image: myapp:latest
state: started
Rolling Updates: For a rolling update, Ansible can update applications one instance at a time, ensuring that there’s no downtime.Example:
- name: Update application
docker_container:
name: myapp
image: myapp:latest
state: restarted
update: true
Rollback: If an update fails, you can use Ansible to roll back to a previous version by pulling the previous image or restoring the previous configuration.Example:
- name: Rollback to previous version
docker_container:
name: myapp
image: myapp:old-version
state: started
An Ansible dynamic inventory plugin allows you to create inventories dynamically, fetching host information from external sources such as cloud providers, CMDB systems, or custom scripts.
AWS EC2 inventory:
ansible-playbook -i ec2.py playbook.yml
To implement continuous integration (CI) with Ansible for infrastructure provisioning, integrate Ansible playbooks with a CI tool like Jenkins, GitLab CI, or CircleCI to automatically provision infrastructure on commit.
Jenkins Example: Configure Jenkins to trigger an Ansible playbook whenever there is a change in the repository. Jenkins can run playbooks to provision servers, deploy applications, or configure infrastructure.Example:
ansible-playbook -i inventory/dev playbook.yml
Ansible can play a crucial role in disaster recovery by automating the backup and recovery processes for systems and services.
Backup Automation: Use Ansible to create scheduled backups of important data (e.g., databases, configuration files, application data) and store them in safe locations (e.g., remote servers, cloud storage).Example:
- name: Backup database
command: pg_dump mydb > /backups/mydb_backup.sql
Disaster Recovery Playbooks: Create playbooks to rebuild infrastructure and services in the event of a disaster. This includes reinstalling servers, configuring services, restoring backups, and ensuring that applications are running correctly.Example:
- name: Recover application data
command: restore /backups/mydb_backup.sql
Yes, Ansible can be used to provision and configure a Kubernetes cluster. Using Ansible, you can automate the installation, configuration, and management of Kubernetes clusters across multiple nodes in both cloud environments and on-premise data centers.
Playbook Example: Here's an example playbook to install Kubernetes on a set of nodes:
- name: Install Kubernetes
hosts: k8s_nodes
become: true
tasks:
- name: Install Kubernetes packages
apt:
name:
- kubelet
- kubeadm
- kubectl
state: present
- name: Initialize the Kubernetes master
command: kubeadm init --pod-network-cidr=192.168.0.0/16
when: inventory_hostname == "k8s_master"
- name: Set up kubeconfig for user
command: mkdir -p ~/.kube && cp /etc/kubernetes/admin.conf ~/.kube/config
when: inventory_hostname == "k8s_master"
- name: Apply Calico network plugin
command: kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
when: inventory_hostname == "k8s_master"
This example installs the necessary packages (kubeadm, kubelet, kubectl), initializes the master node, and applies the Calico network plugin. Ansible can then be used to manage Kubernetes resources (pods, services, deployments) through the k8s module.
Zero-downtime deployments are crucial for ensuring that applications remain available during updates or changes. Ansible can be used to orchestrate deployment strategies that minimize downtime, such as blue-green deployments, rolling updates, and canary deployments.
Rolling Updates: Ansible can deploy updates to one node at a time, ensuring that at least part of the application is always available. You can achieve this using Kubernetes or Docker containers and Ansible’s playbook management.Example:
- name: Rolling update for web app
docker_container:
name: myapp
image: myapp:latest
state: restarted
update: true
Blue-Green Deployments: In a blue-green deployment, two environments (blue and green) are maintained. Ansible can switch traffic from the old environment (blue) to the new one (green) without downtime.Example:
- name: Switch to green environment
shell: mv /etc/nginx/sites-enabled/green /etc/nginx/sites-enabled/default
Ansible plays a critical role in Infrastructure as Code (IaC) by automating the provisioning, configuration, and management of infrastructure in a declarative and repeatable manner. IaC allows infrastructure to be managed with code, ensuring consistency, version control, and easier scalability.
Declarative Automation: With Ansible, you define desired states for infrastructure. For example, you describe that a web server should be installed and configured, and Ansible ensures that the server meets this configuration.Example:
- name: Install Apache Web Server
apt:
name: apache2
state: present
Ansible can automate backup and recovery operations for various systems and services, such as databases, file systems, and application data. Here's how to set up an automated solution:
Backup: Use Ansible to automate backups of critical data to a secure location, such as a remote server or cloud storage (e.g., AWS S3).Example (Backup MySQL Database):
- name: Backup MySQL database
command: mysqldump -u root -p{{ mysql_password }} {{ db_name }} > /backups/{{ db_name }}.sql
Recovery: Automate the restoration of data from backup to ensure quick recovery after failures.Example (Restore MySQL Database):
- name: Restore MySQL database
command: mysql -u root -p{{ mysql_password }} {{ db_name }} < /backups/{{ db_name }}.sql
Ansible is inherently idempotent, meaning that you can run the same playbook multiple times, and it will only make changes if necessary. To ensure idempotency in dynamic environments (where infrastructure is constantly changing), you should follow these best practices:
- name: Ensure Apache is installed
apt:
name: apache2
state: present
Scaling applications in the cloud using Ansible involves automating the provisioning and management of additional resources (e.g., instances, containers) to meet increased demand. Here’s how you can handle scaling:
Horizontal Scaling (Auto-scaling): In cloud environments like AWS, Azure, or GCP, you can use Ansible to automatically increase or decrease the number of instances in response to changes in load. For example, using AWS’s EC2 Auto Scaling with Ansible.Example (AWS Auto Scaling Group):
- name: Create Auto Scaling Group in AWS
ec2_asg:
name: myapp-asg
launch_config_name: myapp-launch-config
min_size: 1
max_size: 10
desired_capacity: 2
vpc_zone_identifier: subnet-xyz
Load Balancer Configuration: Ansible can automate the configuration of cloud load balancers (e.g., AWS ELB, Azure Load Balancer) to distribute traffic across scaled instances.Example (AWS ELB):
- name: Create Elastic Load Balancer (ELB)
ec2_elb_lb:
name: myapp-lb
security_group: sg-abc123
subnets: subnet-abc123,subnet-def456
state: present
Vertical Scaling (Resizing Instances): Ansible can be used to modify instance types for vertical scaling, increasing CPU, memory, or disk resources for cloud instances.Example (AWS EC2 Instance Resize):
- name: Resize EC2 instance
ec2_instance:
instance_id: i-abc123
instance_type: t2.large
To manage a fleet of containers using Ansible, you would use Ansible's container-related modules (e.g., docker_container, docker_image) to automate the management of containerized applications, such as starting, stopping, updating, or scaling containers.
Deploy Containers: Use Ansible playbooks to deploy and manage containers across multiple hosts.
Example (Start a Docker container):
- name: Start web application container
docker_container:
name: webapp
image: myapp:latest
state: started
ports:
- "80:80"
Scale Containers: You can scale the number of container instances running on a node or across nodes, based on the workload.Example (Scale container instances):
- name: Scale web application containers
docker_container:
name: webapp
image: myapp:latest
state: started
replicas: 5
Update Containers: Update or roll back container versions.Example (Update Docker container):
- name: Update myapp container
docker_container:
name: myapp
image: myapp:v2
state: started
Ansible has built-in cloud modules for integrating with cloud APIs like AWS, GCP, and Azure. These modules allow you to automate the provisioning and management of cloud resources.
AWS: Use Ansible’s ec2 modules to manage AWS resources, such as EC2 instances, VPCs, security groups, and S3 buckets. Example:
- name: Create an EC2 instance
ec2_instance:
name: myinstance
key_name: mykey
instance_type: t2.micro
image_id: ami-12345678
region: us-west-2
GCP: Use gcp_compute_instance to manage Google Cloud instances, networks, and storage.
Example:
- name: Create a GCP VM
gcp_compute_instance:
name: my-vm
machine_type: n1-standard-1
image: projects/debian-cloud/global/images/family/debian-9
zone: us-central1-a
Azure: Use the azure_rm modules to manage Azure resources. Example:
- name: Create an Azure VM
azure_rm_virtualmachine:
resource_group: myresourcegroup
name: myvm
vm_size: Standard_B1s
image: UbuntuLTS
admin_username: azureuser
admin_password: "{{ azure_password }}"