paulgorman.org/technical

Ansible

Ansible is an IT automation package. Its big competitor is SaltStack.

Overview:

Installation & Getting Started

Ansible works over ssh, so we don’t need to install anything on clients. The control machine must have Python (2.6+ or 3.5+).

# apt-get install ansible

Even on the control machine, there’s no database, no running daemon, just commands to run as needed.

http://docs.ansible.com/ansible/latest/intro_installation.html

Ansible uses any settings it finds in ~/.ssh/config (e.g., jump host). By default, it uses SFTP but can be configured to use SCP. Ansible assumes the use of SSH keys, but can be given the --ask-pass or --ask-become-pass option.

Ansible doesn’t just have to connect remotely over SSH. The transports are pluggable, and there are options for managing things locally, as well as managing chroot, lxc, and jail containers. A mode called ‘ansible-pull’ can also invert the system and have systems ‘phone home’ via scheduled git checkouts to pull configuration directives from a central repository.

http://docs.ansible.com/ansible/latest/intro_getting_started.html

Basic definitions:

Ansible looks for its configuration in this order:

  1. ANSIBLE_CONFIG environment variable
  2. $PWD/ansible.cfg
  3. $HOME/ansible.cfg
  4. /etc/ansible/ansible.cfg

The config file defines the location of the hosts inventory:

inventory      = /etc/ansible/hosts

Inventory

Ansible acts on multiple machines from the inventory. A dynamic inventory is possible (LDAP, Cobbler, etc.), but the file /etc/ansible/hosts is the default inventory (or specify with the -i flag):

# Ex 1: Ungrouped hosts, specify before any group headers.
bigby.example.com
192.168.100.22
www[1:26].example.com
[dbservers]
everest.example.com
db-[a:f].example.com
[kvm]
mizzen.example.com
zol.example.com
tiger.example.com

For hosts with non-22 SSH ports, specify them like foo.example.com:22000. The inventory can contain variable definitions, per-host or per-group, for later use in playbooks:

firefly.example.com http_port=8080
[flint]
super_secret=true

Make groups-of-groups using the :children suffix:

[north_america:children]
michigan
illinois
newyork

Two implicit groups exist: all and ungrouped.

Have Ansible scan the hosts file to list all hosts it recognizes or all hosts from a particular group:

$ ansible all --list-hosts
$ ansible webservers --list-hosts

Check which of the hosts in the inventory respond to pings:

$ansible all -m ping
firefly.example.com | SUCCESS => {
	"changed": false,
	"ping": "pong"
}
tiger.example.com | SUCCESS => {
	"changed": false,
	"ping": "pong"
}
kosmokrator.example.com | SUCCESS => {
	"changed": false,
	"ping": "pong"
}
mizzen.example.com | SUCCESS => {
	"changed": false,
	"ping": "pong"
}
nostromo.example.com | SUCCESS => {
	"changed": false,
	"ping": "pong"
}

Ad-Hoc Commands

Ad-hoc commands are things too quick, simple, or single-use to write as a playbook.

http://docs.ansible.com/ansible/latest/intro_adhoc.html

Ping all the hosts:

$ ansible all -m ping

We have a [kvm] group of hypervisors specified in /etc/ansible/hosts. What guests are on each?

$ ansible kvm --ask-become-pass --become -a "virsh list --all"

For commands that require shell features (even ones as basic as pipes) use the “shell” module:

$ ansible detroit -m shell -a 'echo $TERM'

(The default module is command.)

The -f flag sets the number of parallel processes (default 5).

$ ansible kvm -f 10 -m shell -a 'cat /etc/group | tac'

So far we’ve been demoing simple command execution, but most Ansible modules are not simple imperative scripts. Instead, they use a declarative model, calculating and executing the actions required to reach a specified final state. Furthermore, they achieve a form of idempotence by checking the current state before they begin, and if the current state matches the specified final state, doing nothing. However, we also recognize that running arbitrary commands can be valuable, so Ansible easily supports both.

Transfer a file directly to many servers:

$ ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"

Change file ownership or permissions with the file module:

$ ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"

Delete directories (recursively) and delete files:

$ ansible webservers -m file -a "dest=/path/to/c state=absent"

Add or remove users:

$ ansible all -m user -a "name=foo password=<crypted password here>"
$ ansible all -m user -a "name=foo state=absent"

Trigger a Git pull:

$ ansible webservers -m git -a "repo=https://foo.example.org/repo.git dest=/srv/myapp version=HEAD"

Make sure a service is started, restarted, or stopped:

$ ansible webservers -m service -a "name=httpd state=started"
$ ansible webservers -m service -a "name=httpd state=restarted"
$ ansible webservers -m service -a "name=httpd state=stopped

Long-running operations can run in the background, with optional timeout and status polling:

$ ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"
$ ansible web1.example.com -m async_status -a "jid=488359678239.2844"
$ ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"

Report “facts” — discovered variables about the client(s):

$ ansible all -m setup

Playbooks

Playbooks are Ansible’s configuration, deployment, and orchestration language.

http://docs.ansible.com/ansible/latest/playbooks.html

Write playbooks in YAML. http://docs.ansible.com/ansible/latest/YAMLSyntax.html

Each playbook lists one or more “plays”. A “play” links hosts to tasks. Tasks are calls to Ansible modules.

---
- hosts: webservers
  vars:
	http_port: 80
	max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
	yum: name=httpd state=latest
  - name: write the apache config file
	template: src=/srv/httpd.j2 dest=/etc/httpd.conf
	notify:
	- restart apache
  - name: ensure apache is running (and enable it at boot)
	service: name=httpd state=started enabled=yes
  handlers:
	- name: restart apache
	  service: name=httpd state=restarted

Run a playbook:

$ ansible-playbook myplaybook.yml

Check the playbook syntax:

$ ansible-playbook --check myplaybook.yml

Walk through a playbook step-by-step:

$ ansible-playbook --step myplaybook.yml

Make a playbook executable and head it with this shebang like to run it like a shell script:

#!/usr/bin/ansible-playbook

A playbooks can contain {{ variables }}. Register the results of shell commands as variables like:

tasks:
  - shell: /usr/bin/foo
    register: foo_result
    ignore_errors: True

Modules

http://docs.ansible.com/ansible/latest/modules.html

Show available modules:

$ ansible-doc -l

Ansible offers many modules from the very basic and universal to the esoteric.

Interesting modules include: apt, at, copy, cron, dnf, docker*, git, group, hostname, htpasswd, include, ipnetns (v2.5+), iptables, letsencrypt, lvol (lvm), mail, mount, mysql, nmcli, package, sysctl, systemd, user, virt (libvirt), vyos_, win_*, yum.

Mon Nov 20 17:07:08 EST 2017