Complete Guide to Ansible

Table of Contents

What is Ansible?

Ansible is an open-source automation platform that simplifies cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs. It uses a simple, human-readable language (YAML) to describe automation jobs.

Key Features

  • Agentless: No need to install agents on managed nodes
  • Simple: Uses SSH for communication and YAML for configuration
  • Powerful: Can manage complex multi-tier deployments
  • Flexible: Works with existing tools and infrastructure
  • Secure: Uses SSH and requires no additional ports or daemons

Key Concepts

Control Node

The machine where Ansible is installed and from which all tasks and playbooks are executed.

Managed Nodes

The network devices and servers you manage with Ansible. Also called "hosts."

Inventory

A list of managed nodes. An inventory file is also sometimes called a "hostfile."

Modules

Units of code Ansible executes. Each module has a particular use, from administering users to managing VLAN interfaces on network devices.

Tasks

Units of action in Ansible. You can execute a single task once with an ad-hoc command.

Playbooks

Ordered lists of tasks, saved so you can run those tasks in that order repeatedly.

Installation

Prerequisites

  • Python 3.8 or newer
  • SSH access to managed nodes
  • Python on managed nodes

Installation Methods

pip install ansible

Using package managers

Ubuntu/Debian:

sudo apt update
sudo apt install ansible

CentOS/RHEL/Fedora:

sudo dnf install ansible
# or
sudo yum install ansible

Verify Installation

ansible --version

Getting Started

Basic Command Structure

ansible <host-pattern> -m <module> -a <arguments>

Simple Ad-hoc Commands

# Check connectivity
ansible all -m ping

# Run shell commands
ansible all -m shell -a "uptime"

# Copy files
ansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts"

# Install packages
ansible all -m apt -a "name=nginx state=present" --become

Inventory Management

Static Inventory

Basic INI Format (/etc/ansible/hosts):

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

[databases]
db1.example.com
db2.example.com

[production:children]
webservers
databases

YAML Format:

all:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
    databases:
      hosts:
        db1.example.com:
        db2.example.com:
    production:
      children:
        webservers:
        databases:

Host Variables

[webservers]
web1.example.com http_port=80 maxRequestsPerChild=808
web2.example.com http_port=303 maxRequestsPerChild=909

Group Variables

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

[webservers:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

Dynamic Inventory

Ansible can work with dynamic inventory sources like AWS EC2, Google Cloud, Azure, etc.

# Using AWS EC2 plugin
ansible-inventory -i inventory_aws_ec2.yml --list

Playbooks

Basic Playbook Structure

---
- name: Configure web servers
  hosts: webservers
  become: yes
  vars:
    http_port: 80
    max_clients: 200
  
  tasks:
    - name: Install Apache
      apt:
        name: apache2
        state: present
    
    - name: Start Apache service
      service:
        name: apache2
        state: started
        enabled: yes
    
    - name: Copy configuration file
      template:
        src: httpd.conf.j2
        dest: /etc/apache2/apache2.conf
      notify: restart apache
  
  handlers:
    - name: restart apache
      service:
        name: apache2
        state: restarted

Running Playbooks

# Run a playbook
ansible-playbook playbook.yml

# Run with specific inventory
ansible-playbook -i inventory.ini playbook.yml

# Run with extra variables
ansible-playbook playbook.yml --extra-vars "version=1.23.45 other_variable=foo"

# Dry run (check mode)
ansible-playbook playbook.yml --check

# Run with increased verbosity
ansible-playbook playbook.yml -v

Modules

Common Modules

System Modules

# File operations
- name: Create a directory
  file:
    path: /opt/myapp
    state: directory
    mode: '0755'

# Copy files
- name: Copy configuration
  copy:
    src: app.conf
    dest: /etc/myapp/app.conf
    backup: yes

# Template files
- name: Generate configuration from template
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf

Package Management

# APT (Debian/Ubuntu)
- name: Install packages
  apt:
    name: ['nginx', 'mysql-server', 'php']
    state: present
    update_cache: yes

# YUM/DNF (RHEL/CentOS/Fedora)
- name: Install packages
  yum:
    name: ['httpd', 'mariadb-server']
    state: present

Service Management

- name: Start and enable service
  service:
    name: nginx
    state: started
    enabled: yes

User Management

- name: Create user
  user:
    name: myuser
    group: mygroup
    shell: /bin/bash
    home: /home/myuser
    create_home: yes

Variables and Facts

Defining Variables

In Playbooks:

---
- hosts: webservers
  vars:
    http_port: 80
    server_name: web.example.com

In Separate Files:

# vars/main.yml
http_port: 80
server_name: web.example.com

Using Variable Files:

---
- hosts: webservers
  vars_files:
    - vars/main.yml

Variable Precedence (Highest to Lowest)

  1. Extra vars (-e in command line)
  2. Task vars
  3. Block vars
  4. Role and include vars
  5. Play vars_files
  6. Play vars_prompt
  7. Play vars
  8. Host facts
  9. Playbook host_vars
  10. Playbook group_vars
  11. Inventory host_vars
  12. Inventory group_vars
  13. Inventory vars
  14. Role defaults

Using Variables

- name: Install {{ package_name }}
  apt:
    name: "{{ package_name }}"
    state: present

- name: Print variable
  debug:
    msg: "The value is {{ my_variable }}"

Facts

Ansible automatically gathers facts about managed hosts:

- name: Display facts
  debug:
    var: ansible_facts

- name: Use specific fact
  debug:
    msg: "OS family is {{ ansible_os_family }}"

Handlers

Handlers are tasks that run only when notified by other tasks:

tasks:
  - name: Copy configuration
    copy:
      src: nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted

Roles

Roles provide a way to group related tasks, variables, files, templates, and handlers.

Role Directory Structure

roles/
    webserver/
        tasks/
            main.yml
        handlers/
            main.yml
        templates/
            nginx.conf.j2
        files/
            index.html
        vars/
            main.yml
        defaults/
            main.yml
        meta/
            main.yml

Creating a Role

ansible-galaxy init webserver

Using Roles in Playbooks

---
- hosts: webservers
  roles:
    - webserver
    - database
    - monitoring

Role with Parameters

---
- hosts: webservers
  roles:
    - role: webserver
      http_port: 8080
      server_name: custom.example.com

Best Practices

1. Directory Organization

project/
├── ansible.cfg
├── inventories/
│   ├── production/
│   │   ├── hosts.yml
│   │   └── group_vars/
│   └── staging/
│       ├── hosts.yml
│       └── group_vars/
├── playbooks/
├── roles/
└── vars/

2. Use Version Control

Always keep your Ansible code in version control (Git).

3. Name Tasks Descriptively

# Good
- name: Install and start Apache web server
  apt:
    name: apache2
    state: present

# Bad
- apt:
    name: apache2
    state: present

4. Use Tags

- name: Install packages
  apt:
    name: "{{ item }}"
    state: present
  loop: "{{ packages }}"
  tags: ['packages', 'setup']

Run specific tags:

ansible-playbook playbook.yml --tags "packages"

5. Use Vault for Sensitive Data

# Create encrypted file
ansible-vault create secrets.yml

# Edit encrypted file
ansible-vault edit secrets.yml

# Run playbook with vault
ansible-playbook playbook.yml --ask-vault-pass

6. Use Check Mode

ansible-playbook playbook.yml --check --diff

7. Handle Failures Gracefully

- name: Start service
  service:
    name: myservice
    state: started
  ignore_errors: yes

- name: Alternative approach
  service:
    name: myservice
    state: started
  failed_when: false

Common Use Cases

1. Web Server Setup

---
- name: Configure web servers
  hosts: webservers
  become: yes
  
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
    
    - name: Start nginx
      service:
        name: nginx
        state: started
        enabled: yes
    
    - name: Copy website files
      copy:
        src: website/
        dest: /var/www/html/
        mode: '0644'

2. Database Configuration

---
- name: Configure MySQL
  hosts: databases
  become: yes
  
  tasks:
    - name: Install MySQL
      apt:
        name: mysql-server
        state: present
    
    - name: Start MySQL
      service:
        name: mysql
        state: started
        enabled: yes
    
    - name: Create database
      mysql_db:
        name: myapp
        state: present

3. User Management

---
- name: Manage users
  hosts: all
  become: yes
  
  tasks:
    - name: Create users
      user:
        name: "{{ item }}"
        state: present
        groups: sudo
        shell: /bin/bash
      loop:
        - alice
        - bob
        - charlie

4. System Updates

---
- name: Update systems
  hosts: all
  become: yes
  
  tasks:
    - name: Update package cache
      apt:
        update_cache: yes
      when: ansible_os_family == "Debian"
    
    - name: Upgrade packages
      apt:
        upgrade: dist
      when: ansible_os_family == "Debian"

Troubleshooting

Common Issues and Solutions

1. SSH Connection Issues

# Test SSH connectivity
ansible all -m ping

# Use specific SSH key
ansible all -m ping --private-key=/path/to/key

# Skip host key checking (not recommended for production)
export ANSIBLE_HOST_KEY_CHECKING=False

2. Permission Issues

# Use become (sudo)
ansible all -m shell -a "whoami" --become

# Specify become user
ansible all -m shell -a "whoami" --become --become-user=root

3. Debug Information

- name: Debug variable
  debug:
    var: my_variable

- name: Debug with message
  debug:
    msg: "Variable value is {{ my_variable }}"

4. Verbose Output

# Different levels of verbosity
ansible-playbook playbook.yml -v    # verbose
ansible-playbook playbook.yml -vv   # more verbose
ansible-playbook playbook.yml -vvv  # very verbose
ansible-playbook playbook.yml -vvvv # extremely verbose

5. Ansible Configuration

# ansible.cfg
[defaults]
inventory = inventory.ini
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = memory

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

Useful Commands

# List all hosts
ansible all --list-hosts

# Check syntax
ansible-playbook playbook.yml --syntax-check

# List tasks
ansible-playbook playbook.yml --list-tasks

# List tags
ansible-playbook playbook.yml --list-tags

# Start at specific task
ansible-playbook playbook.yml --start-at-task="Install packages"

# Limit to specific hosts
ansible-playbook playbook.yml --limit webservers

Conclusion

Ansible is a powerful automation tool that can significantly simplify infrastructure management, application deployment, and configuration management. Its agentless architecture and human-readable YAML syntax make it accessible to both developers and system administrators.

Key takeaways:

  • Start simple with ad-hoc commands
  • Use playbooks for repeatable automation
  • Organize code with roles for reusability
  • Follow best practices for maintainable automation
  • Use version control and testing
  • Leverage the extensive module ecosystem

For more information, refer to the official Ansible documentation.