Ansible
Ansible is a configuration management system written in Python (Private) and maintained by Red Hat.
Concepts
- Inventory describes the systems we want to manage and groups them for easier management.
- Static inventory, as an INI file (Private). Servers are grouped using headings, with nested groups denoted using colons (
:
) in section headings. Groups can be members of other groups. - Dynamic inventory, using configuration stores like Cobbler.
- Static inventory, as an INI file (Private). Servers are grouped using headings, with nested groups denoted using colons (
- Tasks perform one-off operations, useful for exploration and quick configuration changes.
- Modules perform actions, generally idempotently.
- Tasks are instances of Modules, with a configuration.
- Playbooks are user-configured sets of Tasks.
- Facts provide data to be used for targeting.
Components
- Galaxy is a package manager for Ansible modules.
- Tower provides a compliance/reporting dashboard.
Design
Ansible is agent-less by default, using SSH to administrate systems remotely.
Installation
For Linux systems, Ansible is distributed as a single ansible
package.
Configuration
Ansible searches for its con figuration file in this order:
- The
ANSIBLE_CONFIG
environment variable overrides the search behaviour. ./ansible.cfg
in the current working directory.~/.ansible.cfg
in your home directory.- As a last resort,
/etc/ansible/ansible.cfg
.
By default, the configuration is structured as follows:
/etc/ansible/
:ansible.cfg
:[defaults]
inventory
remote_user
remote_ports
ask_pass
[privilege_escalation]
become
become_user
become_method
become_ask_pass
Usage
Inventory
When expressing inventory as a static file, the inventory file looks something like this:
[us-east-1:compute]
app[0:99].compute.us-east-1.example.com
[us-east-1]
us-east-1:compute
ansible-inventory
can be used to examine the inventory's content.
Dynamic
Dynamic inventory is provided by inventory scripts, executable programs which generate the inventory contents automatically. They might be used together with a CMDB or asset register. They can be written in any programming language, and just need to be marked as executable and able to output a JSON structure like the following:
{
"all": {
"children": ["x"]
}
}
Running ad hoc tasks
Execute ad hoc tasks:
ansible host-pattern -m module [-a args] [-i inventory]
Common modules
Common modules (list more with ansible-doc -l
):
copy
copies a local file to the managed host.file
sets content and properties of files.lineinfile
ensures a specific line exists within a file.ping
performs a basic connectivity test.synchronize
copies files and directories usingrsync
.
Templating
The template
module allows templating files using the Jinja template engine (Private):
- name: Generate the nginx server {}
template:
src: nginx.server.j2
dest: /etc/nginx/conf.d/server.conf
owner: root
group: root
mode: "0600"
Useful variables:
Lookup plugins allow templating using data from outside of Ansible. There are two functions for interacting with them:
lookup(plugin, object)
yields a comma-delimited string of items; andquery(plugin, object)
yields a list of items.
Some common lookup plugins:
file
reads file content.lines
gets content of a file as a list of lines.template
renders a template and yields output.url
fetches content of a web page or API query.
Details of others are available in the documentation:
ansible-doc -t lookup
Host patterns
Host patterns denote which systems upon which a task should be executed.
all
specifies all hosts.- Host and group names.
Playbooks
Playbooks define automated tasks for Ansible to execute. They describe the desired state of the environment using YAML (*.yml
). Ordering is top to bottom, in the definition order.
They're made up of the following files:
ansible.cfg
configures Ansible.inventory
defines the hosts and groups.group_vars/
all/
vars.yml
defines variables applied to all deployments.
<environment>/
vars.yml
defines variables applied to just the<environment>
environment.
host_vars/
requirements.yml
lists dependent rolessite.yml
defines the primary Playbook
The structure:
---
- name: The name of the Playbook
hosts: webservers
vars:
key: value
vars_files:
- vars/webservers.yaml
tasks:
- name: The name of the job
<thing>:
property: value
Playbooks can be executed as follows:
ansible-playbook some-playbook
To perform a dry-run, specify the -C
(--check
) switch.
Variables
Variables can be declared at multiple scopes, with those at the bottom taking precedence:
- CLI arguments
- Role defaults
- Inventory file or script group variables
- Inventory
group_vars/all
- Playbook
group_vars/all
- Inventory
group_vars/*
- Playbook
group_vars/*
- Inventory file or script host variables
- Inventory
host_vars/*
- Playbook
host_vars/*
- Host facts (including cached
set_facts
) - Play
vars
- Play
vars_prompt
- Play
vars_files
- Role variables (defined in role's
/vars/main.yml
) - Block variables
- Task variables
include_vars
set_facts
and register variables- Role (and
include_role
) parameters include_*
parameters- CLI
--extra-vars
Vault
Vault encrypts secrets stored in Playbooks for safe storage in source code management systems. It's managed using the ansible-vault
CLI:
create
view
edit
encrypt
decrypt
rekey
to change a key.
Encryption keys are specified using the --vault-id
parameter, and are named in the form label@source
. prompt
is a commonly used source, causing Ansible to prompt the user for the encryption passphrase.
In task definitions, include_vars
can be used to load variables.
Loops
Loops allow reducing duplication, and altering the structure of a playbook based upon variable contents.
- name: loops
hosts: all
tasks:
- name: list
debug:
msg: "{{ item }}"
loop:
- a
- b
- name: dict
debug:
msg: "({{ item.x }}, {{ item.y }})"
with_dict:
- { x: 1, y: 1 }
- { x: 2, y: 2 }
- name: list from variable
debug:
msg: "{{ item }}"
loop: "{{ some_variable }}"
Registers
Tasks can include a register
key, making its execution result available as a variable for later conditional evaluation.
Conditionals
Conditionals can be used to constrain execution of a module based on variables. They're specified using the when
key on a task. Conditions:
bool_value
andnot bool_value
var is defined
andvar is not defined
x == y
andx != y
x < y
,x <= y
,x >= y
,x > y
value in set
and
andor
can be used to combine conditions
When when
is specified as a list, all conditions in the list must evaluate to true
(they're grouped by and
). Parentheses can be used for grouping conditions.
ansible_facts
is a dictionary of values about the host which may be useful here:
distribution
contains the Linux distribution (Private) name.
Handlers
Handlers provide a publisher-subscriber model for delaying or re-applying modules based on changes happening elsewhere. A notifying task can specify a notify
key, which will cause all tasks with the same value in their listen
key to re-run.
Note that handlers will run most once after all notifications to the handler in the Play have completed.
Blocks
Blocks allow grouping logically related tasks together, and allow for a try-except-finally approach to error handling:
tasks:
- name: Do a bunch of things
block:
- name: Step one
debug:
msg: Step one
- name: Step two
debug:
msg: Step two
rescue:
- name: Rescue
debug:
msg: Failed
always:
- name: Always
debug:
msg: Complete
Roles
Roles package tasks in a form allowing reuse with a different set of variables, allowing Playbooks to scale to larger projects through composition of smaller, focused modules.
ansible-galaxy init some-role
creates a structure like the following:
some-role/
is the root of the role.defaults/
contains default values, intended to be overridden in Plays.main.yml
files/
handlers/
main.yml
meta/
contains authorship, licensing and dependency metadata about the role.main.yml
README.md
tasks/
is similar to thetasks
section of a Play.main.yml
templates/
tests/
inventory
test.yml
vars/
contains values not intended for overriding in Plays.main.yml
Roles are consumed in the roles
section of a Playbook:
---
- name: Some Playbook
hosts: all
roles:
- some-role
Backlinks