DEV Community

Maksym
Maksym

Posted on

Complete Ansible Guide

What is Ansible?

Ansible is an open-source automation platform that simplifies configuration management, application deployment, task automation, and orchestration. It uses a simple, human-readable language (YAML) and operates over SSH without requiring agents on target machines.

Key Benefits

  • Agentless: No need to install software on target machines
  • Simple: Uses YAML syntax that's easy to read and write
  • Powerful: Can manage complex multi-tier deployments
  • Idempotent: Safe to run multiple times without side effects
  • Secure: Uses SSH and doesn't leave software installed on targets

Core Concepts

Inventory

A list of managed nodes (servers, network devices, etc.) that Ansible controls. Can be static files or dynamic sources.

Playbooks

YAML files containing a series of tasks to execute on target hosts. Think of them as automation scripts.

Tasks

Individual units of work that Ansible executes, like installing packages or copying files.

Modules

Reusable units of code that Ansible executes. Examples: yum, copy, service, user.

Roles

Way to organize playbooks and reuse code. Roles group related tasks, variables, files, and templates.

Variables

Data that can change how playbooks behave. Can be defined in multiple places with different precedence levels.

Installation

On Control Node (where you run Ansible)

Using pip:

pip install ansible
Enter fullscreen mode Exit fullscreen mode

Using package managers:

# Ubuntu/Debian
sudo apt update
sudo apt install ansible

# CentOS/RHEL/Fedora
sudo dnf install ansible
# or
sudo yum install ansible

# macOS
brew install ansible
Enter fullscreen mode Exit fullscreen mode

Basic Configuration

Ansible Configuration File

Create /etc/ansible/ansible.cfg or ~/.ansible.cfg:

[defaults]
inventory = ./inventory
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
Enter fullscreen mode Exit fullscreen mode

Inventory Management

Static Inventory

Basic inventory file (inventory or hosts):

# Individual hosts
web1.example.com
web2.example.com

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

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

# Groups of groups
[production:children]
webservers
databases

# Variables
[webservers:vars]
http_port=80
nginx_version=1.18
Enter fullscreen mode Exit fullscreen mode

YAML inventory format:

all:
  hosts:
    web1.example.com:
    web2.example.com:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
      vars:
        http_port: 80
    databases:
      hosts:
        db1.example.com:
        db2.example.com:
Enter fullscreen mode Exit fullscreen mode

Dynamic Inventory

For cloud environments, you can use dynamic inventory scripts or plugins that query cloud APIs.

Ad-hoc Commands

Run single tasks without playbooks:

# Ping all hosts
ansible all -m ping

# Check uptime
ansible webservers -m command -a "uptime"

# Install package
ansible webservers -m yum -a "name=nginx state=present" --become

# Copy file
ansible webservers -m copy -a "src=/local/file dest=/remote/file"

# Start service
ansible webservers -m service -a "name=nginx state=started enabled=yes" --become
Enter fullscreen mode Exit fullscreen mode

Playbooks

Basic Playbook Structure

---
- name: Web server setup
  hosts: webservers
  become: yes
  vars:
    http_port: 80

  tasks:
    - name: Install nginx
      yum:
        name: nginx
        state: present

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

    - name: Open firewall for HTTP
      firewalld:
        port: "{{ http_port }}/tcp"
        permanent: yes
        state: enabled
        immediate: yes
Enter fullscreen mode Exit fullscreen mode

Advanced Playbook Features

Handlers (run when notified):

tasks:
  - name: Update nginx config
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted
Enter fullscreen mode Exit fullscreen mode

Conditionals:

tasks:
  - name: Install Apache (RedHat family)
    yum:
      name: httpd
      state: present
    when: ansible_os_family == "RedHat"

  - name: Install Apache (Debian family)
    apt:
      name: apache2
      state: present
    when: ansible_os_family == "Debian"
Enter fullscreen mode Exit fullscreen mode

Loops:

tasks:
  - name: Create users
    user:
      name: "{{ item.name }}"
      group: "{{ item.group }}"
      shell: "{{ item.shell | default('/bin/bash') }}"
    loop:
      - { name: alice, group: admin }
      - { name: bob, group: users }
      - { name: charlie, group: users, shell: /bin/zsh }
Enter fullscreen mode Exit fullscreen mode

Error handling:

tasks:
  - name: Attempt risky operation
    command: /bin/false
    ignore_errors: yes
    register: result

  - name: Handle failure
    debug:
      msg: "Previous task failed, but continuing"
    when: result is failed
Enter fullscreen mode Exit fullscreen mode

Variables and Templates

Variable Precedence (highest to lowest)

  1. Command line values (-e)
  2. Role defaults
  3. Inventory file variables
  4. Host facts
  5. Play variables
  6. Role variables
  7. Block variables
  8. Task variables

Using Templates (Jinja2)

Template file (templates/nginx.conf.j2):

server {
    listen {{ http_port }};
    server_name {{ ansible_hostname }};

    location / {
        root /var/www/html;
        index index.html;
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the template:

- name: Deploy nginx config
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/conf.d/default.conf
  notify: restart nginx
Enter fullscreen mode Exit fullscreen mode

Roles

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
Enter fullscreen mode Exit fullscreen mode

Using Roles in Playbooks

---
- name: Configure web servers
  hosts: webservers
  roles:
    - common
    - webserver
    - { role: monitoring, when: monitoring_enabled }
Enter fullscreen mode Exit fullscreen mode

Creating Roles with Ansible Galaxy

# Create role structure
ansible-galaxy init webserver

# Install role from Galaxy
ansible-galaxy install geerlingguy.nginx

# Install from requirements file
ansible-galaxy install -r requirements.yml
Enter fullscreen mode Exit fullscreen mode

Common Modules

System Modules

  • yum/apt - Package management
  • service/systemd - Service management
  • user/group - User management
  • cron - Crontab management
  • mount - Filesystem mounting

File Modules

  • copy - Copy files to remote hosts
  • template - Process Jinja2 templates
  • file - Set file attributes
  • lineinfile - Ensure line in file
  • replace - Replace text in files

Command Modules

  • command - Run commands
  • shell - Run shell commands
  • script - Run local script on remote hosts
  • raw - Run raw SSH commands

Cloud Modules

  • ec2 - AWS EC2 management
  • azure_rm_* - Azure resource management
  • gcp_* - Google Cloud Platform

Best Practices

Playbook Organization

  • Use descriptive names for plays and tasks
  • Keep playbooks focused and modular
  • Use roles for reusable code
  • Group related functionality together

Variable Management

  • Use group_vars and host_vars directories
  • Keep sensitive data in Ansible Vault
  • Use meaningful variable names
  • Document variable purposes

Security

  • Use Ansible Vault for sensitive data
  • Limit sudo usage with become_user
  • Use SSH key authentication
  • Regularly update Ansible

Testing

  • Use --check mode for dry runs
  • Test on non-production first
  • Use ansible-lint for syntax checking
  • Version control your playbooks

Ansible Vault

Encrypting Files

# Create encrypted file
ansible-vault create secret.yml

# Encrypt existing file
ansible-vault encrypt secret.yml

# Edit encrypted file
ansible-vault edit secret.yml

# View encrypted file
ansible-vault view secret.yml

# Decrypt file
ansible-vault decrypt secret.yml
Enter fullscreen mode Exit fullscreen mode

Using Vaulted Variables

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

# Use password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Enter fullscreen mode Exit fullscreen mode

Running Playbooks

Basic Execution

# Run playbook
ansible-playbook site.yml

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

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

# Use different inventory
ansible-playbook site.yml -i production

# Override variables
ansible-playbook site.yml -e "http_port=8080"

# Increase verbosity
ansible-playbook site.yml -vvv
Enter fullscreen mode Exit fullscreen mode

Tags

tasks:
  - name: Install packages
    yum:
      name: "{{ item }}"
      state: present
    loop: "{{ packages }}"
    tags: packages

  - name: Configure service
    template:
      src: config.j2
      dest: /etc/service/config
    tags: config
Enter fullscreen mode Exit fullscreen mode
# Run only tagged tasks
ansible-playbook site.yml --tags packages

# Skip tagged tasks
ansible-playbook site.yml --skip-tags config
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Common Issues

  • SSH connectivity problems
  • Permission errors (use --become)
  • Python interpreter issues
  • Module not found errors
  • YAML syntax errors

Debugging Commands

# Verbose output
ansible-playbook site.yml -vvv

# Debug specific host
ansible hostname -m setup

# Check inventory
ansible-inventory --list

# Syntax check
ansible-playbook site.yml --syntax-check

# List tasks
ansible-playbook site.yml --list-tasks
Enter fullscreen mode Exit fullscreen mode

Example: Complete Web Server Deployment

---
- name: Deploy web application
  hosts: webservers
  become: yes
  vars:
    app_name: myapp
    app_port: 8080

  tasks:
    - name: Update system packages
      yum:
        name: "*"
        state: latest
      tags: system

    - name: Install required packages
      yum:
        name:
          - nginx
          - python3
          - git
        state: present
      tags: packages

    - name: Create application user
      user:
        name: "{{ app_name }}"
        system: yes
        shell: /bin/false
        home: "/opt/{{ app_name }}"
        create_home: yes
      tags: users

    - name: Clone application repository
      git:
        repo: https://github.com/company/myapp.git
        dest: "/opt/{{ app_name }}/app"
        version: main
      become_user: "{{ app_name }}"
      tags: deploy

    - name: Install application dependencies
      pip:
        requirements: "/opt/{{ app_name }}/app/requirements.txt"
        virtualenv: "/opt/{{ app_name }}/venv"
      become_user: "{{ app_name }}"
      tags: deploy

    - name: Configure nginx
      template:
        src: nginx-app.conf.j2
        dest: "/etc/nginx/conf.d/{{ app_name }}.conf"
      notify: restart nginx
      tags: config

    - name: Configure systemd service
      template:
        src: app.service.j2
        dest: "/etc/systemd/system/{{ app_name }}.service"
      notify:
        - reload systemd
        - restart app
      tags: config

    - name: Start and enable services
      service:
        name: "{{ item }}"
        state: started
        enabled: yes
      loop:
        - nginx
        - "{{ app_name }}"
      tags: services

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

    - name: reload systemd
      systemd:
        daemon_reload: yes

    - name: restart app
      service:
        name: "{{ app_name }}"
        state: restarted
Enter fullscreen mode Exit fullscreen mode

This guide covers the fundamentals of Ansible. Start with simple playbooks and gradually incorporate more advanced features as you become comfortable with the basics.

Top comments (0)