Skip to content

Ansible: architecture and practical techniques

๐Ÿ—๏ธ Ansible architecture

What I like in Ansible is simplicity and agentless architecture:

  • agentless model - uses existing SSH (Linux/Unix) or WinRM (Windows) protocols to communicate with managed hosts
  • modular structure - everything is based on declarative YAML files: playbooks, roles and inventory
  • idempotency - operations can be safely repeated without risk of duplicate changes

Role-based project organization

Example of role based structure:

ansible-project/
โ”œโ”€โ”€ ๐Ÿ“ inventory/
โ”‚   โ”œโ”€โ”€ development.yml      # Dev environment definition
โ”‚   โ””โ”€โ”€ production.yml       # Production environment definition
โ”œโ”€โ”€ ๐Ÿ“ group_vars/
โ”‚   โ”œโ”€โ”€ all.yml              # Variables common to all groups
โ”‚   โ”œโ”€โ”€ webservers.yml       # Variables for webservers group
โ”‚   โ””โ”€โ”€ dbservers.yml        # Variables for dbservers group
โ”œโ”€โ”€ ๐Ÿ“ host_vars/
โ”‚   โ””โ”€โ”€ specific-host.yml    # Variables for specific host
โ”œโ”€โ”€ ๐Ÿ“ roles/
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ common/              # Common role for all servers
โ”‚   โ”‚   โ”œโ”€โ”€ ๐Ÿ“ tasks/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ main.yml     # Main role tasks
โ”‚   โ”‚   โ”œโ”€โ”€ ๐Ÿ“ handlers/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ main.yml     # Handlers
โ”‚   โ”‚   โ”œโ”€โ”€ ๐Ÿ“ templates/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ntp.conf.j2  # Configuration file templates
โ”‚   โ”‚   โ”œโ”€โ”€ ๐Ÿ“ files/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ banner.txt   # Static files
โ”‚   โ”‚   โ”œโ”€โ”€ ๐Ÿ“ vars/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ main.yml     # Internal role variables
โ”‚   โ”‚   โ””โ”€โ”€ ๐Ÿ“ defaults/
โ”‚   โ”‚       โ””โ”€โ”€ main.yml     # Default variable values
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ webserver/           # Role for web servers
โ”‚   โ””โ”€โ”€ ๐Ÿ“ database/            # Role for database servers
โ”œโ”€โ”€ site.yml                 # Main playbook
โ”œโ”€โ”€ webservers.yml           # Playbook for web servers
โ””โ”€โ”€ dbservers.yml            # Playbook for database servers

Practical techniques

Task delegation

Task delegation allows executing specific operations on a different host than the currently processed one:

- name: Register new server in load balancer
    shell: /usr/local/bin/register_node.sh {{ inventory_hostname }}
    delegate_to: load_balancer8
    # This task will execute on the load_balancer8 host

Collections instead of simple playbooks

Don't reinvent the wheel - use ready-made collections from Ansible Galaxy:

ansible-galaxy collection install community.docker

# Usage in playbook
- name: Run PostgreSQL container
    community.docker.docker_container:
        name: db
        image: postgres:13
        ports:
            - "5432:5432"

๐Ÿ” Ansible Vault for sensitive data

# Encrypting password files
ansible-vault encrypt group_vars/all/vault.yml

# Running playbooks with encrypted data
ansible-playbook site.yml --ask-vault-pass

โšก Performance optimization

- hosts: all
    gather_facts: no  # disable fact gathering when unnecessary
    # or
    gather_subset: network  # gather only selected facts

๐Ÿ•ต๏ธ Diff mode

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

Combining --diff with --check allows seeing what changes will be made without actually making them.

๐Ÿ”„ Execution strategies

- hosts: webservers
    strategy: free  # parallel task execution without synchronization
    # alternatives: linear (default), debug (interactive)
    tasks:
        # tasks...

๐Ÿ”„ Error handling and loops

- name: Start services
    service:
        name: "{{ item }}"
        state: started
    loop:
        - nginx
        - redis
        - postgresql
    ignore_errors: yes  # continue despite errors
    register: service_result

- name: Notify about errors
    mail:
        to: "admin@foobar.com"
        subject: "Service startup error"
        body: "There was a problem starting services"
    when: service_result.failed

๐ŸŒŸ Advanced role techniques

๐Ÿ“‹ role dependencies

# roles/webserver/meta/main.yml
dependencies:
    - role: common
    - role: security
        vars:
            security_level: high

๐Ÿงฉ Reusable roles with parameters

# playbook.yml
- hosts: webservers
    roles:
        - role: nginx
            vars:
                nginx_port: 80
                ssl_enabled: true

        - role: nginx
            vars:
                nginx_port: 8080
                server_name: "api.foobar.com"

๐Ÿ” Dynamic inventory

Instead of static host lists, use dynamic inventory for cloud infrastructure:

# AWS EC2
ansible-playbook -i inventory_aws_ec2.yml site.yml

# Azure
ansible-playbook -i inventory_azure_rm.yml site.yml

๐Ÿšฆ Control flow - conditional handling

- name: Install distribution-specific packages
    include_tasks: "{{ ansible_os_family | lower }}.yml"
    # automatically loads debian.yml or redhat.yml depending on system

๐Ÿ“ˆ Monitoring and debugging

๐Ÿ” Variable debugging

- name: Display host information
    debug:
        var: ansible_facts
        verbosity: 1  # displays only with -v or higher level

๐Ÿ“Š Callback plugins

# ansible.cfg
[defaults]
callback_whitelist = profile_tasks, timer

This will enable displaying execution time for individual tasks.

๐Ÿ† Best practices

  1. ๐Ÿ“ฆ maintain small, specialized roles - each role in general should have one specific purpose
  2. ๐Ÿ”„ test roles in isolation - use molecule for role testing
  3. ๐Ÿ“ document variables - use comments in defaults/main.yml files
  4. ๐Ÿ”’ never store credentials in plain text - always use ansible vault or other vault derivative
  5. ๐Ÿ”ง use tags for selective execution - ansible-playbook site.yml --tags "configuration,packages"
  6. ๐Ÿงช check changes before deployment - use --check and --diff

๐Ÿš€ Summary

Ansible enables infrastructure automation without excessive complexity. Role-based approach provides modularity, code reuse, and easier management. With task delegation, collections, and execution strategies, you can create flexible and efficient automation solutions.


๐Ÿ”— Useful resources: