- Installation
- Documentation
- Inventory
- How to connect to your controlled node?
- Configuration
- Pinging your machines
- Idempotence
- Style guide
- A simple playbook
- Troubleshooting
- Variables
- Storing secrets with vaults
- Facts
- Loops and conditionals
- Handlers
- Running a non-idempotent script
- Fail on purpose
- Rescue blocks
- Tags
- Jinja2 templates
- Timestamps
- Rolling upgrades
- Limits
- Performances
- Roles
- Delegating jobs
- Interacting with APIs
- In Memory Inventory
- Overriding the changed result
- Does Ansible has an API?
- Galaxy
- Tooling
- Zen of Python
- Write module
Link to installation document: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
CentOS/RHEL: yum install ansible
Note: to enable repositories (EPEL or RHEL), check above documentation for reference.
Fedora: dnf install ansible
Link to online documentation tree: https://docs.ansible.com
From CLI after install Ansible:
-
Module list:
ansible-doc -l
-
Module consultation:
ansible-doc <module name>
-
Example:
ansible-doc service
Inventory can take an INI or YAML format.
An example for a static inventory file
INI format
node9
[group1]
node1
node2
[group2]
node3 http_port=80
[group3]
node[10:20]
[prod]
group1
group3
[group1:vars]
var1=value1
YAML format
all:
hosts:
node9:
children:
group1:
hosts:
node1:
node2:
vars:
var1: value1
group2:
hosts:
node3:
http_port: 80
group3:
hosts:
node[10:20]:
prod:
children:
group1:
group3:
To ensure proper configuration and outcome, followings can be used:
-
json inventory output:
ansible-inventory --list
-
list inventory output:
ansible-inventory --graph
Dynamic inventories: https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html
No additional agent needed on controlled nodes. It’s SSH or WinRM.
-
Username and password.
-
SSH key pairs.
-
…
Depends on your existing SSHD configuration.
Apply least privilege approach!
-
/etc/ansible/ansible.cfg
-
~/.ansible.cfg
-
./ansible.cfg
See which configuration file is used with ansible --version
.
[defaults]
inventory = ./inventory
remote_user = user
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
You can use become: true
at the playbook or task level.
You can also use -b
at the command line.
-
Use modules as much as possible!
-
Resort to using
shell
orcommand
only when a module is not available.
Being idempotent allows the defined task to run one time or a thousand times without having an adverse effect on the target system, only ever making the change once. In other words, if a change is required to get the system into its desired state, the change is made; and if the device is already in its desired state, no change is made. This is unlike most traditional custom scripts and the copy and pasting of CLI commands into a terminal window. When the same command or script is executed repeatedly on the same system, errors are (sometimes) raised.
Network Automation with Ansible
Old deprecated way:
- name: http service state
service: name=httpd state=started enabled=yes
The good way:
- name: http service state
service:
name: httpd
state: started
enabled: yes
Example:
-
register
module: store the output of a task to use/investigate laster -
debug
module: display the content of a var -
-v
or-vv
up to-vvvv
: to be used withansible-playbook
-
--syntax-check
: syntax checking -
--check
: "dry-run" or "noop" mode -
--step
: take a pause at every task -
--start-at-task="start httpd service"
: start from a specific task of the playbook
Variable precedence from least to greatest (the last listed variables winning prioritization):
-
command line values (eg “-u user”)
-
role defaults
-
inventory file or script group vars
-
inventory group_vars/all
-
playbook group_vars/all
-
inventory group_vars/*
-
playbook group_vars/*
-
inventory file or script host vars
-
inventory host_vars/*
-
playbook host_vars/*
-
host facts / cached set_facts
-
play vars
-
play vars_prompt
-
play vars_files
-
role vars (defined in role/vars/main.yml)
-
block vars (only for tasks in block)
-
task vars (only for the task)
-
include_vars
-
set_facts / registered vars
-
role (and include_role) params
-
include params
-
extra vars (always win precedence)
playbook-with-var.yml
Using variables: "{{ variable_key }}"
Careful! You might need to surround the variable between quotes.
- name: install package
yum:
name: "{{ package_name }}"
state: latest
- name: install Python library
yum:
name: python3_{{ library_name }}
state: latest
This is OK too:
- name: install Python library
yum:
name: "python3_{{ library_name }}"
state: latest
Never store secrets in plain text!
ansible-vault create secret.yml
password: super_secret
ansible-playbook playbook-vault.yml --ask-vault-pass
gather_facts: true
(default is true)
"ansible_facts": {
"_facts_gathered": true,
"all_ipv4_addresses": [
"192.168.122.132"
],
"all_ipv6_addresses": [
"fe80::6392:81c2:92fd:af3e"
],
[...]
playbook-facts.yml
Note
|
setup module gather facts about remote host: https://docs.ansible.com/ansible/latest/modules/setup_module.html
|
Local facts
/etc/ansible/facts.d/preferences.fact
[general]
org=ibm
type=small
ansible -i inventory all -m setup -a "filter=ansible_local"
playbook-local-fact.yml
playbook-loop.yml
: loop over a list
playbook-loop-advanced.yml
: loops over a dictionary stored in a variable
playbook-facts.yml
: demonstrating the usage of the when
conditional
Handlers are triggered when a task changes something (appears yellow).
Run playbook-handler.yml
once, then run again and notice the difference.
Important
|
Make sure the MOTD is in a different state then expected prior to running the first time, to see expected result. |
playbook-tags.yml
ansible-playbook playbook-tags.yml -t red
ansible-playbook playbook-tags.yml -t hat
ansible-playbook playbook-tags.yml -t "red","hat"
playbook-rolling.yml
Now change the serial
value from 1
to 3
.
When you’re doing rolling upgrades of a cluster, you might want to use any_errors_fatal: True
.
By default, Ansible runs each task on all hosts affected by a play before starting the next task on any host, using 5 forks.
forks: 5
in ansible.cfg
Under the roles
directory (to create if needed):
ansible-galaxy init my_new_role
playbook-role.yml
By default, playbooks are run against an inventory
hosts: all
playbook-delegated.yml
Add a host (and alternatively a group) to the ansible-playbook in-memory inventory
Typically useful when working with OpenStack, etc.
changed_when: "output.rc != 2"
python -m this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
You can write your own modules!