Skip to main content

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:

  1. ANSIBLE_CONFIG environment variable (if set)
  2. ansible.cfg in the current directory
  3. ~/.ansible.cfg (user home directory)
  4. /etc/ansible/ansible.cfg (system-wide)

Creating Your First ansible.cfg

Let's create a basic ansible.cfg file:

ini
[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:

ini
[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:

ini
# 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:

yaml
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:

ini
[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:

python
#!/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:

ini
[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

  1. Command-line variables (-e or --extra-vars)
  2. Play variables (defined in playbooks)
  3. Host and group variables (in inventory or in separate files)
  4. 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:

yaml
---
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:

bash
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:

ini
[webservers]
web1.example.com ansible_user=admin ansible_port=2222

Or in group variables:

yaml
---
ansible_user: admin
ansible_port: 2222
ansible_ssh_private_key_file: ~/.ssh/custom_key

Using SSH Connection Options

Add SSH options to ansible.cfg:

ini
[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:

ini
[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

ini
[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)

ini
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

[production:children]
webservers
dbservers

Group Variables (inventory/group_vars/webservers.yml)

yaml
---
# 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:

bash
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

  1. Keep inventory files version-controlled: Store your inventory files in version control to track changes over time.

  2. Use vault for sensitive data: Encrypt sensitive variables using ansible-vault:

    bash
    ansible-vault create vault.yml
    ansible-vault edit vault.yml
  3. 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
  4. Use multiple inventories for different environments:

    • Keep separate inventories for dev, test, staging, and production
    • Use the same playbooks against different inventories
  5. Tune performance settings:

    • Increase forks for parallel execution
    • Use gathering = smart to cache facts
    • Enable fact caching for faster playbook runs
  6. 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:

  1. Check configuration precedence:

    bash
    ansible --version

    This shows which configuration file Ansible is using.

  2. Validate inventory:

    bash
    ansible-inventory --list -i inventory

    This lists all hosts and variables in your inventory.

  3. Test connectivity:

    bash
    ansible all -m ping

    Confirms Ansible can connect to all hosts.

  4. Debug variables:

    bash
    ansible webservers -m debug -a "var=hostvars[inventory_hostname]"

    Shows all variables defined for hosts in the webservers group.

  5. Increase verbosity:

    bash
    ansible-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

  1. Create a basic ansible.cfg file and inventory for two servers you have access to.
  2. Set up group and host variables for your inventory.
  3. Configure different SSH connection options for two different server groups.
  4. Create a dynamic inventory script that reads hosts from a CSV file.
  5. 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! :)