Ansible Configuration
Introduction
Ansible configuration is the foundation of effective automation. Before you can start managing servers and automating tasks with Ansible, you need to understand how to configure it properly. This guide will walk you through the essential configuration components of Ansible, from the main configuration file to inventory management and variables.
Ansible uses a simple, human-readable configuration approach that makes it accessible for beginners while providing powerful capabilities for advanced users. By the end of this guide, you'll understand how to set up Ansible to fit your specific automation needs.
The ansible.cfg File
The ansible.cfg
file is the heart of Ansible configuration. It defines global settings that affect how Ansible operates.
Default Locations
Ansible looks for configuration files in the following order:
ANSIBLE_CONFIG
environment variable (if set)ansible.cfg
in the current directory~/.ansible.cfg
(user home directory)/etc/ansible/ansible.cfg
(system-wide)
Creating Your First ansible.cfg
Let's create a basic ansible.cfg
file:
[defaults]
inventory = ./inventory
remote_user = ubuntu
host_key_checking = False
timeout = 30
This configuration:
- Sets the inventory file location to
./inventory
in the current directory - Defines
ubuntu
as the default user for SSH connections - Disables host key checking (useful for testing, but consider enabling it in production)
- Sets a connection timeout of 30 seconds
Common Configuration Settings
Here are some commonly used settings you can add to your ansible.cfg
file:
[defaults]
# Inventory settings
inventory = ./inventory
inventory_ignore_extensions = .pyc, .pyo, .swp, .bak, ~
# Connection settings
remote_user = ansible
timeout = 60
host_key_checking = True
# Performance settings
forks = 10
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_fact_cache
fact_caching_timeout = 86400
# Output settings
log_path = ./ansible.log
stdout_callback = yaml
bin_ansible_callbacks = True
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
Inventory Management
Inventory files define the hosts and groups that Ansible manages. They can be in INI or YAML format.
Basic INI Inventory
Here's a simple inventory file in INI format:
# Simple hosts
web1.example.com
web2.example.com
# Groups
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com
db2.example.com
# Group of groups
[datacenter:children]
webservers
dbservers
YAML Inventory Format
The same inventory can be defined in YAML format:
all:
hosts:
web1.example.com:
web2.example.com:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
dbservers:
hosts:
db1.example.com:
db2.example.com:
datacenter:
children:
webservers:
dbservers:
Adding Host Variables
You can add variables to specific hosts in your inventory:
[webservers]
web1.example.com http_port=80 max_connections=100
web2.example.com http_port=8080 max_connections=200
[webservers:vars]
ansible_user=webadmin
ansible_ssh_private_key_file=/path/to/webadmin_key
Dynamic Inventory
For environments with changing infrastructure, you can use dynamic inventory scripts. For example, a simple script that outputs JSON in the expected format:
#!/usr/bin/env python3
import json
inventory = {
'webservers': {
'hosts': ['web1.example.com', 'web2.example.com'],
'vars': {
'http_port': 80
}
},
'dbservers': {
'hosts': ['db1.example.com', 'db2.example.com'],
'vars': {
'db_port': 5432
}
},
'_meta': {
'hostvars': {
'web1.example.com': {
'ansible_host': '192.168.1.101'
},
'web2.example.com': {
'ansible_host': '192.168.1.102'
}
}
}
}
print(json.dumps(inventory))
To use this script, you would configure your ansible.cfg
:
[defaults]
inventory = ./inventory_script.py
Variables and Precedence
Ansible uses variables from multiple sources with a defined precedence order. Understanding this helps when troubleshooting configuration issues.
Common Variable Locations
- Command-line variables (
-e
or--extra-vars
) - Play variables (defined in playbooks)
- Host and group variables (in inventory or in separate files)
- Role defaults (lowest precedence)
Variable Files Organization
A recommended structure for organizing variable files:
inventory/
├── group_vars/
│ ├── all.yml # Variables for all hosts
│ ├── webservers.yml # Variables for webservers group
│ └── dbservers.yml # Variables for dbservers group
├── host_vars/
│ ├── web1.example.com.yml # Variables for web1
│ └── db1.example.com.yml # Variables for db1
└── inventory # Main inventory file
Example content for group_vars/webservers.yml
:
---
http_port: 80
deploy_user: www-data
enable_ssl: true
apache_settings:
document_root: /var/www/html
error_log: /var/log/apache2/error.log
max_clients: 150
Configuring Ansible for Different Environments
It's common to have different configurations for development, testing, and production environments.
Environment-Specific Inventory
Create separate inventory files for different environments:
inventory/
├── development
├── testing
└── production
Then specify which one to use with the -i
flag:
ansible-playbook -i inventory/development site.yml
Environment-Specific Variables
Use group_vars to define environment-specific variables:
inventory/
├── group_vars/
│ ├── development/
│ │ ├── vars.yml
│ │ └── vault.yml # encrypted sensitive variables
│ ├── testing/
│ │ ├── vars.yml
│ │ └── vault.yml
│ └── production/
│ ├── vars.yml
│ └── vault.yml
├── development
├── testing
└── production
Connection Settings
Ansible connects to managed nodes primarily via SSH, but you can configure different connection types.
SSH Configuration
Basic SSH settings in the inventory:
[webservers]
web1.example.com ansible_user=admin ansible_port=2222
Or in group variables:
---
ansible_user: admin
ansible_port: 2222
ansible_ssh_private_key_file: ~/.ssh/custom_key
Using SSH Connection Options
Add SSH options to ansible.cfg
:
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
pipelining = True
control_path = /tmp/ansible-ssh-%%h-%%p-%%r
Local Connections
For managing the localhost:
[local]
localhost ansible_connection=local
Practical Example: Complete Setup
Let's put everything together with a real-world example of a complete Ansible configuration setup:
Project Structure
ansible-project/
├── ansible.cfg
├── inventory/
│ ├── group_vars/
│ │ ├── all.yml
│ │ ├── webservers.yml
│ │ └── dbservers.yml
│ ├── host_vars/
│ │ ├── web1.example.com.yml
│ │ └── db1.example.com.yml
│ └── hosts
├── playbooks/
│ ├── site.yml
│ ├── webservers.yml
│ └── dbservers.yml
└── roles/
├── common/
├── webserver/
└── database/
ansible.cfg
[defaults]
inventory = ./inventory/hosts
roles_path = ./roles
log_path = ./ansible.log
host_key_checking = False
retry_files_enabled = False
interpreter_python = auto_silent
nocows = 1 # Disable cowsay for cleaner output
stdout_callback = yaml
bin_ansible_callbacks = True
[ssh_connection]
pipelining = True
[colors]
highlight = white
verbose = blue
warn = bright purple
error = red
debug = dark gray
deprecate = purple
skip = cyan
unreachable = red
ok = green
changed = yellow
Inventory File (inventory/hosts)
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com
[production:children]
webservers
dbservers
Group Variables (inventory/group_vars/webservers.yml)
---
# Web server configuration
http_port: 80
https_port: 443
document_root: /var/www/html
# Firewall settings
firewall_allowed_tcp_ports:
- 22
- 80
- 443
# Apache settings
apache_version: 2.4
apache_mods_enabled:
- rewrite
- ssl
- headers
Running a Playbook with this Configuration
With this setup, you can now run playbooks that use your configuration:
ansible-playbook playbooks/site.yml
The output will look something like:
PLAY [Configure all servers] ***************************************************
TASK [Gathering Facts] *********************************************************
ok: [web1.example.com]
ok: [web2.example.com]
ok: [db1.example.com]
TASK [common : Install required packages] **************************************
changed: [web1.example.com]
changed: [web2.example.com]
changed: [db1.example.com]
PLAY [Configure webservers] ****************************************************
TASK [Gathering Facts] *********************************************************
ok: [web1.example.com]
ok: [web2.example.com]
TASK [webserver : Install Apache] **********************************************
changed: [web1.example.com]
changed: [web2.example.com]
PLAY RECAP *********************************************************************
db1.example.com : ok=2 changed=1 unreachable=0 failed=0
web1.example.com : ok=4 changed=2 unreachable=0 failed=0
web2.example.com : ok=4 changed=2 unreachable=0 failed=0
Configuration Visualization
Let's visualize the Ansible configuration flow:
Best Practices for Ansible Configuration
-
Keep inventory files version-controlled: Store your inventory files in version control to track changes over time.
-
Use vault for sensitive data: Encrypt sensitive variables using
ansible-vault
:bashansible-vault create vault.yml
ansible-vault edit vault.yml -
Organize variables logically:
- Use
group_vars/all
for truly global variables - Place environment-specific variables in appropriate group files
- Use host_vars sparingly for truly host-specific settings
- Use
-
Use multiple inventories for different environments:
- Keep separate inventories for dev, test, staging, and production
- Use the same playbooks against different inventories
-
Tune performance settings:
- Increase
forks
for parallel execution - Use
gathering = smart
to cache facts - Enable fact caching for faster playbook runs
- Increase
-
Document your configurations:
- Add comments to your ansible.cfg and inventory files
- Keep a README.md that explains the structure and use of your Ansible setup
Troubleshooting Configuration Issues
When running into configuration problems, follow these steps:
-
Check configuration precedence:
bashansible --version
This shows which configuration file Ansible is using.
-
Validate inventory:
bashansible-inventory --list -i inventory
This lists all hosts and variables in your inventory.
-
Test connectivity:
bashansible all -m ping
Confirms Ansible can connect to all hosts.
-
Debug variables:
bashansible webservers -m debug -a "var=hostvars[inventory_hostname]"
Shows all variables defined for hosts in the webservers group.
-
Increase verbosity:
bashansible-playbook site.yml -vvv
Provides detailed information about what Ansible is doing.
Summary
In this guide, we've covered:
- The
ansible.cfg
file and its configuration options - Inventory management with static and dynamic inventories
- Variable precedence and organization
- Environment-specific configurations
- Connection settings for different scenarios
- A practical, real-world setup example
- Best practices for Ansible configuration
- Troubleshooting techniques
Proper configuration is essential for an effective Ansible deployment. By understanding these concepts, you'll be able to create an Ansible environment that's organized, maintainable, and suited to your specific automation needs.
Exercises
- Create a basic
ansible.cfg
file and inventory for two servers you have access to. - Set up group and host variables for your inventory.
- Configure different SSH connection options for two different server groups.
- Create a dynamic inventory script that reads hosts from a CSV file.
- Set up separate inventory files for development and production environments.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)