Skip to content

Ansible

What Is It?

Ansible is an agentless configuration management and IT automation tool. It uses SSH to connect to managed hosts and YAML playbooks to declare desired system states. Key concepts include inventory, playbooks, roles, modules, and variables.

Installation

dnf install ansible

Key Files and Directories

Path Purpose
inventory/hosts Managed host inventory
playbook.yml Main playbook
roles//tasks/main.yml Role task definitions
roles//handlers/main.yml Event-driven handlers
roles//templates/ Jinja2 templates

Configuration

Ansible uses a specific directory structure to organise automation code:

ansible/
├── inventory/
│   └── hosts              # Managed host inventory
├── roles/
│   ├── etais/
│   │   └── tasks/main.yml
│   ├── dns/
│   │   ├── tasks/main.yml
│   │   ├── templates/     # Jinja2 templates (.j2)
│   │   ├── files/         # Static files to copy
│   │   └── handlers/main.yml
│   └── web/
│       └── tasks/main.yml
└── playbook.yml           # Main playbook

Minimal Working Configuration

Inventory (inventory/hosts) — defines which hosts to manage:

[vm]
localhost
# Or for remote execution:
# 172.17.64.X

Playbook (playbook.yml) — the main entry point:

---
- hosts: all
  user: centos
  become: yes
  become_user: root
  vars:
    hostname: example
    domain_name: sysadm.ee

  roles:
  - { role: etais, tags: etais }
  - { role: dns, tags: dns }
  - { role: web, tags: web }

Key playbook directives:

  • hosts: all — target all hosts in inventory
  • become: yes — escalate to root via sudo
  • vars: — define variables usable in tasks and templates
  • roles: — list of roles to apply (executed before tasks:)

Role tasks (roles/etais/tasks/main.yml):

- name: Add user scoring
  user:
    name: scoring

- name: Create .ssh directory
  file:
    path: /home/scoring/.ssh
    state: directory
    owner: scoring
    group: scoring
    mode: '0700'

- name: Download scoring public key
  get_url:
    url: https://scoring.sysadm.ee/files/id_rsa.pub
    dest: /home/scoring/.ssh/authorized_keys
    owner: scoring
    group: scoring
    mode: '0600'

- name: Create sudoers file for scoring
  lineinfile:
    dest: /etc/sudoers.d/scoring
    line: "scoring ALL=(ALL) NOPASSWD: ALL"
    state: present
    create: yes

Important Directives

Modules — each task uses a module to perform an action:

Module Purpose Example
user Manage user accounts user: name=scoring
file Create files/directories, set permissions file: path=/dir state=directory mode='0700'
copy Copy static files from controller to host copy: src=file.conf dest=/etc/file.conf
template Copy files with Jinja2 variable substitution template: src=hosts.j2 dest=/etc/hosts
dnf Install/remove packages dnf: name=httpd state=present
systemd Manage services systemd: name=httpd state=restarted enabled=yes
lineinfile Ensure a line exists in a file lineinfile: dest=/etc/file line="key=value"
get_url Download files from URLs get_url: url=https://... dest=/path
seboolean Set SELinux booleans seboolean: name=httpd_can_network_connect state=yes
sefcontext Set SELinux file contexts sefcontext: target='/var/www(/.*)?' setype=httpd_sys_rw_content_t

Templates use Jinja2 syntax for variable substitution:

# templates/hostname.j2
{{ hostname }}.{{ domain_name }}

Handlers — tasks triggered only when a notifying task reports changed:

# roles/web/handlers/main.yml
- name: restart httpd
  systemd:
    name: httpd
    state: restarted

Reference a handler from a task with notify: restart httpd.

Idempotency — a core Ansible concept. Tasks should only report changed on the first run. Subsequent runs should report ok with no changes, meaning the system is already in the desired state.

Common Commands

# Run the full playbook
ansible-playbook playbook.yml -i inventory/hosts

# Run only tasks tagged 'dns'
ansible-playbook playbook.yml -i inventory/hosts --tags=dns

# Dry run (check mode) — show what would change
ansible-playbook playbook.yml -i inventory/hosts --check

# Ad-hoc command — ping all hosts
ansible -m ping all -i inventory/hosts

# Ad-hoc command — run a shell command
ansible all -m shell -a "uptime" -i inventory/hosts

# View gathered facts about a host
ansible -m setup localhost

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

# List tasks that would run
ansible-playbook playbook.yml --list-tasks

Logging and Debugging

  • Verbose output: Add -v, -vv, -vvv, or -vvvv to increase verbosity.
  • debug module: Print variable values during execution:
    - name: Show hostname
      debug: msg="Hello from {{ ansible_hostname }}"
    
  • register: Capture task output for later use:
    - name: Check service status
      command: systemctl status httpd
      register: httpd_status
    - debug: var=httpd_status.stdout
    
  • Task states: ok (no change needed), changed (action taken), failed (error), skipped (condition not met).

Security Considerations

  • No secrets in playbooks: Never hardcode passwords or keys in YAML files committed to Git. Use Ansible Vault (ansible-vault encrypt) for sensitive data.
  • SSH key authentication: Ansible connects via SSH. Use key-based authentication rather than passwords.
  • Least privilege: Run tasks as the minimum required user. Only use become: yes when root access is genuinely needed.
  • lineinfile vs template: For complex configuration files, prefer template (full file replacement) over lineinfile (single-line edits). Templates are more predictable and auditable.
  • Test before applying: Use --check mode and --diff to review changes before applying them to production systems.
  • Commit regularly: Store your Ansible repository in Git and push after every lab. This provides backup, history, and exam preparation.

Further Reading

  • Concepts: Configuration Management, Version Control
  • SOPs: Ansible Operations