Understanding Ansible Playbooks
Playbooks in Ansible are the foundation for automating complex IT tasks. They allow you to define a series of tasks that can be executed on remote systems in a structured, repeatable manner. A well-crafted playbook can significantly reduce manual effort and minimize configuration drift across your infrastructure.
Playbook Syntax Fundamentals
Before diving into complex playbooks, it's crucial to understand the basic syntax rules:
- Indentation: Use two spaces for each level of indentation. Tabs are strictly forbidden in Ansible playbooks.
- Colons: When using a colon (e.g., in a key-value pair), a space must follow it.
- Lists: Use a hyphen (-) to denote list items, followed by a space.
---
- hosts: 172.16.1.41
tasks:
- name: Install a package
yum: name=nginx state=present
- name: Copy a configuration file
copy: src=/path/to/config dest=/etc/nginx/nginx.conf
Executing Playbooks
Once a playbook is written, you can execute it using the ansible-playbook command. It's a good practice to follow a three-step process:
- Syntax Check: Verify the playbook's syntax without executing any tasks. ```
ansible-playbook --syntax-check your_playbook.yml
- Dry Run (Check Mode): Simulate the execution to see what changes would be made. ```
ansible-playbook -C your_playbook.yml
- Execution: Run the playbook to apply the changes. ```
ansible-playbook your_playbook.yml
Inventory Management
The inventory file (/etc/ansible/hosts by default) defines the hosts and groups of hosts upon which commands and playbooks can be executed. Here are several ways to configure it:
1. Grouping Hosts
You can group hosts logically, such as by function or environment.
[web_servers]
web1.example.com
web2.example.com
[data_servers]
data1.example.com
data2.example.com
2. Pattern Matching
Use patterns to match multiple hosts based on IP ranges or hostnames.
[webservers]
192.168.1.[10:20]
[dbservers]
db-[a:z].example.com
3. Custom SSH Parameters
Specify non-standard SSH ports or credentials directly in the inventory.
[special_servers]
host1.example.com ansible_ssh_port=2222
host2.example.com ansible_ssh_user=admin ansible_ssh_pass=secret
4. Nested Groups and Variables
Groups can contain other groups, and you can define variables at the group level.
[production:children]
web
db
[web]
web1.example.com
web2.example.com
[web:vars]
http_port=8080
Advanced Playbook Features
Variables
Variables allow you to customize playbooks for different environments or hosts. They can be defined in several ways:
- Inline in Playbook: ```
vars:
app_version: 1.2.3
db_user: admin
- Command Line: ```
ansible-playbook site.yml --extra-vars "app_version=1.2.3 db_user=admin"
- Inventory File: ```
[web]
web1.example.com app_version=1.2.3 db_user=admin
Variable Precedence: Command-line variables > Playbook variables > Inventory variables.
Conditionals (when)
Use the when clause to execute tasks based on specific conditions.
- name: Install Apache on CentOS
yum: name=httpd state=present
when: ansible_distribution == "CentOS"
- name: Install Apache on Ubuntu
apt: name=apache2 state=present
when: ansible_distribution == "Ubuntu"
Loops
Loops allow you to repeat a task for a list of items.
- name: Create multiple users
user: name={{ item.name }} groups={{ item.groups }} state=present
with_items:
- { name: 'user1', groups: 'developers' }
- { name: 'user2', groups: 'admins' }
- name: Install multiple packages
yum: name={{ item }} state=present
with_items:
- vim
- git
- curl
Handlers
Handlers are tasks that only run when triggered by another task. They are ideal for restarting services after configuration changes.
- name: Copy Apache configuration
copy: src=apache.conf dest=/etc/httpd/conf/httpd.conf
notify: restart apache
handlers:
- name: restart apache
service: name=httpd state=restarted
Tags
Tags allow you to selectively run parts of a playbook.
- name: Install and configure Nginx
yum: name=nginx state=present
tags: install
- name: Start Nginx service
service: name=nginx state=started
tags: start
To run tasks with the install tag:
ansible-playbook site.yml --tags=install
Roles: Organizing Playbooks
Roles provide a structured way to organize playbooks, making them more reusable and maintainable. A role typically contains the following directories:
tasks/: Main list of tasks to be executed.handlers/: Handlers, stored inmain.yml.defaults/: Default variables for the role.vars/: Other variables for the role.files/: Files to be copied to the remote system.templates/: Templates to be rendered and copied to the remote system.meta/: Metadata for the role, e.g., dependencies.
Example Role Structure
roles/
├── webserver/
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ ├── vars/
│ │ └── main.yml
│ └── files/
│ └── index.html
└── database/
├── tasks/
│ └── main.yml
└── ...
Using Roles in a Playbook
You can apply roles to specific hosts or groups within a playbook.
- hosts: webservers
roles:
- webserver
- hosts: dbservers
roles:
- database
Common Pitfalls and Best Practices
- Syntax Errors: Always double-check indentation and colons.
- Module Usage: Prefer specific Ansible modules over
shellorcommandwhen possible. - Single Task per Name: Each
nameshould ideally correspond to a single module call. - Avoid Shell Overuse: Use shell commands sparingly; leverage modules for better idempotency.