An Ansible playbook is a YAML file that defines a set of tasks to be executed on a group of hosts. Playbooks are designed to be human-readable and allow you to manage configurations, deployments, and other tasks in an automated and repeatable manner. Here’s an in-depth look at each aspect of an Ansible playbook:
Ansible Playbook Structure
Ansible playbooks are written in YAML and contain one or more plays. Each play specifies a set of tasks to be executed on a group of hosts.
Breakdown of Playbook Components
YAML Syntax:
- Ansible playbooks are written in YAML, a human-readable data serialization format.
Document Start:
---
Play:
- A play is a collection of tasks that are run on a set of hosts. Each play can have different hosts, tasks, variables, and handlers.
Play Name:
- name: Ensure Apache is installed and running
A descriptive name for the play. This helps in understanding what the play does when reading logs and outputs.
Hosts:
hosts: webservers
Specifies the target hosts or group of hosts on which the play will run. The group webservers
would be defined in the inventory file.
Become:
become: yes
Enables privilege escalation (sudo). Tasks in this play will be run with elevated privileges.
Tasks:
tasks:
A list of tasks to be executed on the target hosts. Each task is executed sequentially.
Task Components
Task Name:
- name: Install Apache
A descriptive name for the task. This helps in understanding what each task does when reading logs and outputs.
Module:
ansible.builtin.apt:
Specifies the Ansible module to be used for the task. In this case, the apt
module is used to manage packages on Debian-based systems.
Module Arguments:
name: apache2
state: present
Arguments for the module. Here, the apt
module installs the apache2
package and ensures it is present.
Playbook Example
Here is the playbook for local machine
---
- name: Update web servers
hosts: localhost
tasks:
- name: Install Apache httpd (state=present is optional)
ansible.builtin.apt:
name: apache2
state: present
- name: Copy file with owner and permissions
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Start service httpd, if not started
ansible.builtin.service:
name: apache2
state: started
Explanation of the Playbook
Playbook Header:
---
Indicates the beginning of a YAML document.
Play Definition:
- name: Update web servers
hosts: localhost
tasks:
- name: A descriptive name for the play.
- hosts: Specifies the target hosts for the play. Here,
localhost
is used. - tasks: A list of tasks to be executed on the specified hosts.
Task 1: Install Apache httpd
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
- name: Install Apache httpd (state=present is optional)
ansible.builtin.apt:
name: apache2
state: present
- name: A descriptive name for the task.
- ansible.builtin.apt: The Ansible module used to install packages via
apt
. - name: The package to be installed (
apache2
). - state: Ensures the package is present. This is optional as
present
is the default state.
Task 2: Copy index.html
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html
- name: Copy file with owner and permissions
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: A descriptive name for the task.
- ansible.builtin.copy: The Ansible module used to copy files.
- src: Source file path (
index.html
). - dest: Destination file path (
/var/www/html/index.html
).
Task 3: Start Apache Service
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html
- name: Start service httpd, if not started
ansible.builtin.service:
name: apache2
state: started
- name: A descriptive name for the task.
- ansible.builtin.service: The Ansible module used to manage services.
- name: The name of the service (
apache2
). - state: Ensures the service is started.
Example Usage with Groups
To target a group of hosts defined in an inventory file, you can modify the hosts
parameter in the playbook.
Inventory File (inventory
):
[web]
18.208.198.47
172.22.240.232
[db]
18.208.198.4
172.22.240.2d
Modified Playbook:
---
- name: Update web servers
hosts: web
tasks:
- name: Install Apache httpd (state=present is optional)
ansible.builtin.apt:
name: apache2
state: present
- name: Copy file with owner and permissions
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Start service httpd, if not started
ansible.builtin.service:
name: apache2
state: started
Running the Playbook:
ansible-playbook -i inventory playbook.yml -u ubuntu -k
This command runs the playbook against the hosts in the web
group, using the ubuntu
user and prompting for the SSH password.
Ansible Playbook Command
Basic Command:
ansible-playbook web.yaml
- ansible-playbook: The command to run Ansible playbooks.
- web.yaml: The playbook file to execute.
Options Explained
Basic Playbook Execution:
ansible-playbook web.yaml
- Runs the specified playbook
web.yaml
on the hosts defined within the playbook or the inventory file specified in the playbook.
Check Mode (Dry Run):
ansible-playbook -C web.yaml
- -C or –check: Runs the playbook in check mode. This simulates the changes that would be made by the playbook without actually applying them. It’s useful for testing what changes would be made without affecting the system.
Check Mode with Verbosity:
ansible-playbook -C web.yaml -vvvvvv
-vvvvvv: Adds verbosity to the output. More v
characters increase the level of verbosity, providing more detailed output about what Ansible is doing. This is useful for debugging and getting more insight into the playbook execution.
Specify Inventory, Remote User, and Privilege Escalation:
ansible-playbook -i inventory web.yaml -u ubuntu -k -b
- -i inventory: Specifies the inventory file to use. The inventory file contains the list of hosts to target.
- -u ubuntu: Specifies the remote user to use for connecting to the hosts. In this case,
ubuntu
. - -k: Prompts for the SSH password of the remote user.
- -b: Uses privilege escalation (sudo) to run the tasks with elevated privileges.
Summary of Options
- -i: Specifies the inventory file.
- -u: Specifies the remote user.
- -k: Prompts for the SSH password.
- -b: Uses privilege escalation (sudo).
- -C: Runs in check mode (dry run).
- -v, -vv, -vvv, -vvvv, -vvvvv, -vvvvvv: Sets the verbosity level of the output.
Additional Ansible Playbook Options
–syntax-check
- Checks the syntax of the playbook without executing it.
ansible-playbook web.yaml --syntax-check
–list-tasks
- Lists all tasks that would be executed by the playbook without running them.
ansible-playbook web.yaml --list-tasks
–list-hosts
- Lists all hosts that the playbook would run against without executing any tasks.
ansible-playbook web.yaml --list-hosts
–step
- Prompts the user for confirmation before running each task.
ansible-playbook web.yaml --step
–start-at-task
- Starts the playbook run at the task matching the given name.
ansible-playbook web.yaml --start-at-task="Install Apache"
–tags and –skip-tags
- Runs only tasks with the specified tags or skips tasks with the specified tags.
ansible-playbook web.yaml --tags "install,config"
ansible-playbook web.yaml --skip-tags "debug"
–limit
- Limits the execution to the specified hosts or groups.
ansible-playbook web.yaml --limit web
ansible-playbook web.yaml --limit "web:&prod"
–diff
- Shows differences when files are changed by Ansible.
ansible-playbook web.yaml --diff
–vault-id and –ask-vault-pass
- Used for encrypting and decrypting secrets with Ansible Vault.
ansible-playbook web.yaml --vault-id @prompt
ansible-playbook web.yaml --ask-vault-pass
–extra-vars
- Passes additional variables to the playbook.
ansible-playbook web.yaml --extra-vars "var1=value1 var2=value2"
Live Practical
Create inventory
[web]
51.8.106.65
51.8.106.109
Create web.yaml file
---
- name: Update web servers
hosts: web
tasks:
- name: Install Apache httpd (state=present is optional)
ansible.builtin.apt:
name: apache2
state: present
- name: Copy file with owner and permissions
ansible.builtin.copy:
src: /home/jami/index.html
dest: /var/www/html/index.html
- name: Start service httpd, if not started
ansible.builtin.service:
name: apache2
state: started
~
Run the ansible playbook
ansible-playbook -i inventory web.yaml -u jami -k -b
if getting below error
TASK [Install Apache httpd (state=present is optional)] ****************************************************************************************************************
fatal: [51.8.106.65]: FAILED! => {"cache_update_time": 1717269140, "cache_updated": false, "changed": false, "msg": "'/usr/bin/apt-get -y -o \"Dpkg::Options::=--force-confdef\" -o \"Dpkg::Options::=--force-confold\" install 'apache2=2.4.41-4ubuntu3.17'' failed: E: Unable to correct problems, you have held broken packages.\n", "rc": 100, "stderr": "E: Unable to correct problems, you have held broken packages.\n", "stderr_lines": ["E: Unable to correct problems, you have held broken packages."], "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nSome packages could not be installed. This may mean that you have\nrequested an impossible situation or if you are using the unstable\ndistribution that some required packages have not yet been created\nor been moved out of Incoming.\nThe following information may help to resolve the situation:\n\nThe following packages have unmet dependencies:\n apache2 : Depends: apache2-bin (= 2.4.41-4ubuntu3.17) but it is not going to be installed\n Depends: apache2-utils (= 2.4.41-4ubuntu3.17) but it is not going to be installed\n Recommends: ssl-cert but it is not installable\n", "stdout_lines": ["Reading package lists...", "Building dependency tree...", "Reading state information...", "Some packages could not be installed. This may mean that you have", "requested an impossible situation or if you are using the unstable", "distribution that some required packages have not yet been created", "or been moved out of Incoming.", "The following information may help to resolve the situation:", "", "The following packages have unmet dependencies:", " apache2 : Depends: apache2-bin (= 2.4.41-4ubuntu3.17) but it is not going to be installed", " Depends: apache2-utils (= 2.4.41-4ubuntu3.17) but it is not going to be installed", " Recommends: ssl-cert but it is not installable"]}
fatal: [51.8.106.109]: FAILED! => {"cache_update_time": 1717269139, "cache_updated": false, "changed": false, "msg": "'/usr/bin/apt-get -y -o \"Dpkg::Options::=--force-confdef\" -o \"Dpkg::Options::=--force-confold\" install 'apache2=2.4.41-4ubuntu3.17'' failed: E: Unable to correct problems, you have held broken packages.\n", "rc": 100, "stderr": "E: Unable to correct problems, you have held broken packages.\n", "stderr_lines": ["E: Unable to correct problems, you have held broken packages."], "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nSome packages could not be installed. This may mean that you have\nrequested an impossible situation or if you are using the unstable\ndistribution that some required packages have not yet been created\nor been moved out of Incoming.\nThe following information may help to resolve the situation:\n\nThe following packages have unmet dependencies:\n apache2 : Depends: apache2-bin (= 2.4.41-4ubuntu3.17) but it is not going to be installed\n Depends: apache2-utils (= 2.4.41-4ubuntu3.17) but it is not going to be installed\n Recommends: ssl-cert but it is not installable\n", "stdout_lines": ["Reading package lists...", "Building dependency tree...", "Reading state information...", "Some packages could not be installed. This may mean that you have", "requested an impossible situation or if you are using the unstable", "distribution that some required packages have not yet been created", "or been moved out of Incoming.", "The following information may help to resolve the situation:", "", "The following packages have unmet dependencies:", " apache2 : Depends: apache2-bin (= 2.4.41-4ubuntu3.17) but it is not going to be installed", " Depends: apache2-utils (= 2.4.41-4ubuntu3.17) but it is not going to be installed", " Recommends: ssl-cert but it is not installable"]}
solution:
If the playbook still fails, you can manually connect to the remote machines and perform the following steps to identify and resolve the issues.
Update Package List:
sudo apt update
Upgrade Installed Packages:
sudo apt upgrade
Fix Broken Packages:
sudo apt --fix-broken install
Run again