Ansible

Introduction

  • push-based config management, also supports pull
  • copies a generated script to the managed host via ssh and then executes it
  • simple for small setups, powerful enough for complex situations
  • connects to several hosts in parallel (but largest scale only via pull mode)
  • master node only requires ansible, no other server (HTTP etc)
  • managed nodes need no client, only ssh and python
  • written in python, uses yaml playbooks and Jinja2 templates
  • extensible with modules

Further documentation

Commands

ansible all -m ping                         # test all hosts by invoking ping module
ansible some-host -m setup                  # display all gathered facts (system info)
ansible some-host -a uptime                 # run a given command
ansible some-host -s -a "tail some-file"    # run a given command with sudo
ansible some-host -s -m apt -a name=htop    # install given package using the apt module
ansible-playbook some-playbook.yml          # run a given playbook
ansible-playbook -C -D some-playbook.yml    # run in dry-run mode (--check) and show diff
ansible-playbook --step playbook.yml        # prompt before running each task
ansible-playbook --limit ahost playbook.yml # run playbook only on given host
ansible-playbook --syntax-check file.yml    # check the syntax of a given playbook
ansible-playbook --list-hosts playbook.yml  # list hosts affected by a given playbook
ansible-playbook --list-tasks playbook.yml  # list tasks defined in a given playbook
ansible-playbook --list-tags playbook.yml   # list tags defined in a given playbook
ansible -i someinv all --list-hosts         # list all hosts in given inventory
ansible-inventory -i someinv --list         # list hostnames, groups and variables of inventory
ansible-inventory -i someinv --graph        # show ascii graph of host groups
ansible-config dump                         # show ansible config paramaters and non-default values
ansible-doc -l                              # list ansible commands with a short description
ansible-doc some-module                     # read documentation of a given module
ansible <command> -vvvv                     # run command with verbose output for debugging
export ANSIBLE_KEEP_REMOTE_FILES=1          # don't delete remote script files in ~/.ansible/

Configuration

Minimal setup

inventory:

hostname.example.com

playbook.yml:

- hosts: all
  remote_user: root
  tasks:
  - name: install htop
    apt: name=htop state=present

Command to run playbook

ansible-playbook -i inventory playbook.yml

Typical folder structure

├── ansible.cfg
├── handlers/
├── host_vars/
├── group_vars/
├── inventory
├── roles/
│   └── webserver/
│       ├── defaults/
│       ├── files/
│       ├── handlers/
│       ├── tasks/
│       ├── templates/
│       └── vars/
└── playbook.yml

Variable precedence

-e arg > role > play > host > group > defaults

ansible.cfg

Example ansible.cfg file to configure ansible

[defaults]
hostfile = hosts
sudo_flags = -HE
retry_files_enabled = False
gathering = smart
hash_behaviour = merge

where the hash_behaviour setting enables merging of hash variables for instance from host_vars and group_vars.

In some cases you may want to add force_handlers = true to trigger handlers even if a failure occured on that host.

inventory

Example inventory file

vagrant1 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_user=vagrant ansible_ssh_private_key_file=/path_to_VM/.vagrant/machines/default/virtualbox/private_key

[server]                # group
vagrant1

[web]
vagrant1

[webserver:children]    # group of groups
web
server

Ansible also supports the concept of a dynamic inventory, i.e. an executable script that returns the hosts in JSON format.

Runtime profiling

Ansible offers built-in callbacks to measure the runtime permformance.

  • profile_tasks: show runtime of each tasks and summary with the list of slowest tasks
  • profile_roles: show summary with runtime of the roles
  • timer: show total playbook runtime

Enable the callbacks you need in the [default] section of your ansible.cfg.

[default]

callbacks_enabled = profile_tasks, profile_roles

Enabling the verbose debug output may shed some light on what exactly Ansible is doing that takes so much time.

export ANSIBLE_DEBUG=1

Playbook Debugger

Ansible can enter an interactive debugger shell if a playbook has an error.

export ANSIBLE_ENABLE_TASK_DEBUGGER=True

Debugger commands:

p host                      # print host
p result                    # print task result
p task                      # print task name
p task.args                 # print task arguments
p task_vars                 # print task variables
p task_vars['some_key']     # print given task variable
task_vars['some_key'] = 1   # update value of task variable (similarly args)
u                           # update task after modification
r                           # redo task
c                           # continue
q                           # quit

Retry files

Ansible can generate a .retry file with the hostnames that failed (or where offline) during a playbook run. You can then limit the next run to only those hosts.

export ANSIBLE_RETRY_FILES_ENABLED=1
ansible-playbook playbooks/play.yml
ansible-playbook playbooks/play.yml --limit @playbooks/play.retry