2017-09-27 19:34:38 +03:00
---
2017-06-09 15:05:58 +03:00
category: tool
2017-06-09 15:07:58 +03:00
tool: ansible
2017-06-09 15:05:58 +03:00
contributors:
- ["Jakub Muszynski" , "http://github.com/sirkubax"]
2018-11-16 00:49:18 +03:00
- ["Pat Myron" , "https://github.com/patmyron"]
2018-11-17 20:51:39 +03:00
- ["Divay Prakash", "https://github.com/divayprakash"]
2017-06-09 15:05:58 +03:00
filename: LearnAnsible.txt
---
2018-11-17 20:51:39 +03:00
## Introduction
2018-10-30 23:04:56 +03:00
```yaml
2017-09-22 23:21:42 +03:00
---
2018-05-15 13:03:43 +03:00
"{{ Ansible }}" is an orchestration tool written in Python.
2018-11-17 20:51:39 +03:00
...
2017-09-22 23:21:42 +03:00
```
2017-08-15 22:55:44 +03:00
2018-11-17 20:51:39 +03:00
Ansible is (one of many) orchestration tools. It allows you to control your
environment (infrastructure and code) and automate the manual tasks.
Ansible has great integration with multiple operating systems (even Windows)
and some hardware (switches, Firewalls, etc). It has multiple tools that
integrate with the cloud providers. Almost every noteworthy cloud provider is
present in the ecosystem (AWS, Azure, Google, DigitalOcean, OVH, etc...).
2018-11-17 22:38:50 +03:00
But ansible is way more! It provides execution plans, an API, library, and callbacks.
2018-11-17 20:51:39 +03:00
### Main pros and cons
#### Pros
2019-11-20 17:31:29 +03:00
* It is an agent-less tool. In most scenarios, it uses ssh as a transport layer.
2018-11-17 20:51:39 +03:00
In some way you can use it as 'bash on steroids'.
2019-11-20 17:31:29 +03:00
* It is very easy to start. If you are familiar with the concept of ssh - you already
2018-11-17 20:51:39 +03:00
know Ansible (ALMOST).
* It executes 'as is' - other tools (salt, puppet, chef - might execute in
different scenario than you would expect)
* Documentation is at the world-class standard!
* Writing your own modules and extensions is fairly easy.
* Ansible AWX is the open source version of Ansible Tower we have been waiting
for, which provides an excellent UI.
#### Cons
* It is an agent-less tool - every agent consumes up to 16MB ram - in some
2022-12-10 18:05:34 +03:00
environments, it may be noticeable amount.
2018-11-17 20:51:39 +03:00
* It is agent-less - you have to verify your environment consistency
'on-demand' - there is no built-in mechanism that would warn you about some
change automatically (this can be achieved with reasonable effort)
2018-11-17 22:38:50 +03:00
* Official GUI - Ansible Tower - is great but expensive.
2019-07-15 22:34:46 +03:00
* There is no 'small enterprise' payment plan, however Ansible AWX is the free
2018-11-17 20:51:39 +03:00
open source version we were all waiting for.
#### Neutral
Migration - Ansible < - > Salt is fairly easy - so if you would need an
event-driven agent environment - it would be a good choice to start quick with
Ansible, and convert to Salt when needed.
#### Some concepts
Ansible uses ssh or paramiko as a transport layer. In a way you can imagine
that you are using a ssh with API to perform your action. The simplest way is
to execute remote command in more controlled way (still using ssh).
On the other hand - in advanced scope - you can wrap Ansible (use python Ansible
2018-11-17 22:38:50 +03:00
code as a library) with your own Python scripts! It would act a
2018-11-17 20:51:39 +03:00
bit like Fabric then.
2018-05-15 13:03:43 +03:00
## Example
2018-11-17 20:51:39 +03:00
2018-05-15 13:03:43 +03:00
An example playbook to install apache and configure log level
2018-11-17 20:51:39 +03:00
2018-10-30 23:04:56 +03:00
```yaml
2018-05-15 13:03:43 +03:00
---
- hosts: apache
vars:
apache2_log_level: "warn"
handlers:
- name: restart apache
2018-11-17 20:51:39 +03:00
service:
2018-05-15 13:03:43 +03:00
name: apache2
state: restarted
enabled: True
2018-11-17 20:51:39 +03:00
notify:
2018-05-15 13:03:43 +03:00
- Wait for instances to listen on port 80
become: True
- name: reload apache
2018-11-17 20:51:39 +03:00
service:
2018-05-15 13:03:43 +03:00
name: apache2
state: reloaded
2018-11-17 20:51:39 +03:00
notify:
2018-05-15 13:03:43 +03:00
- Wait for instances to listen on port 80
become: True
- name: Wait for instances to listen on port 80
2018-11-17 20:51:39 +03:00
wait_for:
state: started
host: localhost
port: 80
timeout: 15
2018-05-15 13:03:43 +03:00
delay: 5
tasks:
2018-11-17 20:51:39 +03:00
- name: Update cache
apt:
update_cache: yes
2018-05-15 13:03:43 +03:00
cache_valid_time: 7200
become: True
- name: Install packages
2018-11-17 20:51:39 +03:00
apt:
2018-05-15 13:03:43 +03:00
name={{ item }}
with_items:
- apache2
- logrotate
notify:
- restart apache
become: True
- name: Configure apache2 log level
2018-11-17 20:51:39 +03:00
lineinfile:
2018-05-15 13:03:43 +03:00
dest: /etc/apache2/apache2.conf
line: "LogLevel {{ apache2_log_level }}"
regexp: "^LogLevel"
notify:
- reload apache
become: True
2018-11-17 20:51:39 +03:00
...
2018-05-15 13:03:43 +03:00
```
2018-01-02 00:21:33 +03:00
2017-09-22 23:21:42 +03:00
## Installation
2018-11-17 20:51:39 +03:00
2017-09-22 23:21:42 +03:00
```bash
# Universal way
$ pip install ansible
2017-06-09 15:05:58 +03:00
2017-09-22 23:21:42 +03:00
# Debian, Ubuntu
$ apt-get install ansible
```
2018-11-17 20:51:39 +03:00
2018-01-01 23:58:35 +03:00
* [Appendix A - How do I install ansible ](#infrastructure-as-a-code )
2017-09-22 23:27:32 +03:00
* [Additional Reading. ](http://docs.ansible.com/ansible/latest/intro_installation.html )
2017-09-22 23:21:42 +03:00
2017-09-22 23:48:55 +03:00
### Your first ansible command (shell execution)
2018-11-17 20:51:39 +03:00
2017-09-22 23:21:42 +03:00
```bash
2018-11-17 20:51:39 +03:00
# Command pings localhost (defined in default inventory: /etc/ansible/hosts)
2017-09-22 23:21:42 +03:00
$ ansible -m ping localhost
2018-11-17 20:51:39 +03:00
# You should see this output
2017-09-22 23:27:32 +03:00
localhost | SUCCESS => {
2018-11-17 20:51:39 +03:00
"changed": false,
2017-09-22 23:21:42 +03:00
"ping": "pong"
2017-09-22 23:27:32 +03:00
}
2017-09-22 23:21:42 +03:00
```
2018-11-17 20:51:39 +03:00
2017-09-22 23:48:55 +03:00
### Shell Commands
2018-11-17 20:51:39 +03:00
2017-09-07 00:40:18 +03:00
There are few commands you should know about
2017-09-22 23:29:12 +03:00
* `ansible` (to run modules in CLI)
* `ansible-playbook` (to run playbooks)
* `ansible-vault` (to manage secrets)
* `ansible-galaxy` (to install roles from github/galaxy)
2017-09-22 23:30:27 +03:00
2017-09-22 23:48:55 +03:00
### Module
2017-09-22 23:42:43 +03:00
2018-11-17 20:51:39 +03:00
A program (usually python) that executes, does some work and returns proper
JSON output. This program performs specialized task/action (like manage
instances in the cloud, execute shell command). The simplest module is called
`ping` - it just returns a JSON with `pong` message.
2017-09-22 23:41:27 +03:00
Example of modules:
2018-11-17 22:38:50 +03:00
2018-11-15 03:00:54 +03:00
* Module: `ping` - the simplest module that is useful to verify host connectivity
2019-11-20 17:31:29 +03:00
* Module: `shell` - a module that executes a shell command on a specified host(s).
2017-09-22 23:41:27 +03:00
2017-06-09 15:05:58 +03:00
2017-09-22 23:21:42 +03:00
```bash
2017-09-27 18:00:23 +03:00
$ ansible -m ping all
2017-09-22 23:21:42 +03:00
$ ansible -m shell -a 'date; whoami' localhost #hostname_or_a_group_name
```
2018-11-17 20:51:39 +03:00
* Module: `command` - executes a single command that will not be processed
through the shell, so variables like `$HOME` or operands like ``|` `;` ` will not
work. The command module is more secure, because it will not be affected by the
user’ s environment. For more complex commands - use shell module.
2017-09-22 23:21:42 +03:00
```bash
$ ansible -m command -a 'date; whoami' # FAILURE
2017-09-27 18:00:23 +03:00
$ ansible -m command -a 'date' all
$ ansible -m command -a 'whoami' all
2017-09-22 23:21:42 +03:00
```
2018-11-17 20:51:39 +03:00
* Module: `file` - performs file operations (stat, link, dir, ...)
* Module: `raw` - executes a low-down and dirty SSH command, not going through
the module subsystem (useful to install python2.7)
2017-09-22 23:21:42 +03:00
2017-09-27 17:47:10 +03:00
### Task
2017-08-15 22:44:20 +03:00
2018-11-17 20:51:39 +03:00
Execution of a single Ansible **module** is called a **task** . The simplest
module is called `ping` as you could see above.
2017-08-15 22:44:20 +03:00
2019-11-20 17:31:29 +03:00
Another example of the module that allows you to execute a command remotely on
2018-11-17 20:51:39 +03:00
multiple resources is called `shell` . See above how you were using them already.
2017-08-15 22:44:20 +03:00
2017-09-27 17:47:10 +03:00
### Playbook
2018-11-17 20:51:39 +03:00
2017-09-27 18:06:17 +03:00
**Execution plan** written in a form of script file(s) is called **playbook** .
2019-11-20 17:31:29 +03:00
Playbooks consist of multiple elements -
2017-09-22 23:21:42 +03:00
* a list (or group) of hosts that 'the play' is executed against
* `task(s)` or `role(s)` that are going to be executed
* multiple optional settings (like default variables, and way more)
2017-09-27 18:06:17 +03:00
2018-11-17 20:51:39 +03:00
Playbook script language is YAML. You can think that playbook is very advanced
CLI script that you are executing.
2017-09-07 00:20:52 +03:00
2018-11-17 20:51:39 +03:00
#### Example of the playbook
2017-09-22 23:21:42 +03:00
2018-11-17 20:51:39 +03:00
This example-playbook would execute (on all hosts defined in inventory) two tasks:
2017-09-27 18:00:23 +03:00
* `ping` that would return message *pong*
2017-09-22 23:21:42 +03:00
* `shell` that execute three commands and return the output to our terminal
2017-08-15 22:44:20 +03:00
2018-10-30 23:04:56 +03:00
```yaml
2017-10-21 00:45:03 +03:00
- hosts: all
2018-11-17 20:51:39 +03:00
2017-10-21 00:45:03 +03:00
tasks:
- name: "ping all"
ping:
2018-11-17 20:51:39 +03:00
2017-10-21 00:45:03 +03:00
- name: "execute a shell command"
shell: "date; whoami; df -h;"
2017-09-07 00:20:52 +03:00
```
2018-01-01 22:54:32 +03:00
Run the playbook with the command:
2018-11-17 20:51:39 +03:00
2017-09-07 00:20:52 +03:00
```bash
$ ansible-playbook path/name_of_the_playbook.yml
2017-08-15 22:44:20 +03:00
```
2018-11-17 20:51:39 +03:00
Note: Example playbook is explained in the next chapter: 'Roles'
2017-09-27 18:52:48 +03:00
### More on ansible concept
2017-06-09 15:05:58 +03:00
2017-09-28 01:02:01 +03:00
### Inventory
2019-11-20 17:31:29 +03:00
An inventory is a set of objects or hosts, against which we are executing our
2018-11-17 20:51:39 +03:00
playbooks or single tasks via shell commands. For these few minutes, let's
assume that we are using the default ansible inventory (which in Debian based
system is placed in `/etc/ansible/hosts` ).
2017-09-28 01:02:01 +03:00
```
localhost
[some_group]
hostA.mydomain.com
hostB.localdomain
2018-01-01 22:54:32 +03:00
1.2.3.4
2017-09-28 01:02:01 +03:00
[a_group_of_a_groups:children]
some_group
some_other_group
```
2018-11-17 20:51:39 +03:00
2017-09-28 01:02:01 +03:00
* [Additional Reading. ](http://docs.ansible.com/ansible/latest/intro_inventory.html )
2018-11-17 20:51:39 +03:00
2017-09-28 01:05:12 +03:00
### ansible-roles (a 'template-playbooks' with right structure)
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
You already know that the tasks (modules) can be run via CLI. You also know the
playbooks - the execution plans of multiple tasks (with variables and logic).
2017-08-15 22:46:45 +03:00
2018-11-17 20:51:39 +03:00
A concept called `role` was introduced for parts of the code (playbooks) that
should be reusable.
2017-08-15 22:55:44 +03:00
2018-11-17 20:51:39 +03:00
**Role** is a structured way to manage your set of tasks, variables, handlers,
default settings, and way more (meta, files, templates). Roles allow reusing
the same parts of code in multiple playbooks (you can parametrize the role
'further' during its execution). Its a great way to introduce `object oriented`
management for your applications.
2017-08-15 22:55:44 +03:00
2017-09-27 18:52:48 +03:00
Role can be included in your playbook (executed via your playbook).
2017-08-15 22:55:44 +03:00
2018-10-30 23:04:56 +03:00
```yaml
2017-10-21 00:45:03 +03:00
- hosts: all
tasks:
- name: "ping all"
ping:
- name: "execute a shell command"
shell: "date; whoami; df -h;"
2018-11-17 20:51:39 +03:00
roles:
2017-10-21 00:45:03 +03:00
- some_role
- { role: another_role, some_variable: 'learnxiny', tags: ['my_tag'] }
2018-11-17 20:51:39 +03:00
2017-10-21 00:45:03 +03:00
pre_tasks:
- name: some pre-task
shell: echo 'this task is the last, but would be executed before roles, and before tasks'
2017-09-07 00:20:52 +03:00
```
2017-10-21 00:32:41 +03:00
#### For remaining examples we would use additional repository
2020-01-24 17:52:50 +03:00
This example installs ansible in `virtualenv` so it is independent from the system.
2019-11-20 17:31:29 +03:00
You need to initialize it into your shell-context with the `source environment.sh`
2018-11-17 20:51:39 +03:00
command.
2018-01-01 22:54:32 +03:00
2019-10-25 12:33:09 +03:00
We are going to use this repository with examples: [https://github.com/sirkubax/ansible-for-learnXinYminutes ](https://github.com/sirkubax/ansible-for-learnXinYminutes )
2017-10-21 00:29:13 +03:00
2017-09-27 18:52:48 +03:00
```bash
2018-11-17 20:51:39 +03:00
$ # The following example contains a shell-prompt to indicate the venv and relative path
2018-01-01 22:57:43 +03:00
$ git clone git@github.com:sirkubax/ansible-for-learnXinYminutes.git
2017-10-21 00:29:13 +03:00
user@host:~/$ cd ansible-for-learnXinYminutes
user@host:~/ansible-for-learnXinYminutes$ source environment.sh
2017-10-21 00:24:45 +03:00
$
2017-10-21 00:26:03 +03:00
$ # First lets execute the simple_playbook.yml
2017-10-27 15:42:44 +03:00
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_playbook.yml
2017-10-21 00:24:45 +03:00
```
2017-10-20 23:31:58 +03:00
2018-01-01 23:03:34 +03:00
Run the playbook with roles example
2018-11-17 20:51:39 +03:00
2017-10-21 00:24:45 +03:00
```bash
$ source environment.sh
2017-10-21 00:26:03 +03:00
$ # Now we would run the above playbook with roles
2017-10-27 15:42:44 +03:00
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_role.yml
2017-09-27 18:52:48 +03:00
```
2018-11-17 20:51:39 +03:00
#### Role directory structure
2017-09-07 00:20:52 +03:00
```
roles/
some_role/
2017-09-27 19:11:20 +03:00
defaults/ # contains default variables
files/ # for static files
templates/ # for jinja templates
tasks/ # tasks
handlers/ # handlers
vars/ # more variables (higher priority)
meta/ # meta - package (role) info
2017-09-07 00:20:52 +03:00
```
#### Role Handlers
2018-11-17 20:51:39 +03:00
Handlers are tasks that can be triggered (notified) during execution of a
playbook, but they execute at the very end of a playbook. It is the best way to
restart a service, check if the application port is active (successful
deployment criteria), etc.
2017-08-15 22:46:45 +03:00
2018-11-16 00:49:18 +03:00
Get familiar with how you can use roles in the simple_apache_role example
2018-11-17 20:51:39 +03:00
2017-10-27 15:42:44 +03:00
```
playbooks/roles/simple_apache_role/
├── tasks
│ └── main.yml
└── templates
└── main.yml
```
2017-06-09 15:05:58 +03:00
### ansible - variables
2017-09-27 19:11:20 +03:00
2018-11-17 20:51:39 +03:00
Ansible is flexible - it has 21 levels of variable precedence.
2018-01-01 23:03:34 +03:00
[read more ](http://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable )
For now you should know that CLI variables have the top priority.
2017-09-27 19:11:20 +03:00
You should also know, that a nice way to pool some data is a **lookup**
2017-09-28 01:05:12 +03:00
### Lookups
2018-11-17 20:51:39 +03:00
Awesome tool to query data from various sources!!! Awesome!
2018-01-01 23:05:16 +03:00
query from:
2018-05-15 13:03:43 +03:00
* pipe (load shell command output into variable!)
2017-09-27 19:11:20 +03:00
* file
* stream
* etcd
2018-05-15 13:03:43 +03:00
* password management tools
* url
2017-09-27 19:11:20 +03:00
2017-10-27 15:42:44 +03:00
```bash
# read playbooks/lookup.yml
2018-01-01 23:21:39 +03:00
# then run
2017-10-27 15:42:44 +03:00
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/lookup.yml
```
2017-09-27 19:11:20 +03:00
You can use them in CLI too
2018-11-17 20:51:39 +03:00
2017-09-23 12:43:25 +03:00
```yaml
2017-10-21 01:01:29 +03:00
ansible -m shell -a 'echo "{{ my_variable }}"' -e 'my_variable="{{ lookup("pipe", "date") }}"' localhost
ansible -m shell -a 'echo "{{ my_variable }}"' -e 'my_variable="{{ lookup("pipe", "hostname") }}"' all
2017-09-27 19:11:20 +03:00
2017-10-27 15:42:44 +03:00
# Or use in playbook
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/lookup.yml
```
2018-11-17 20:51:39 +03:00
### Register and Conditional
2017-10-27 15:55:16 +03:00
#### Register
2018-11-17 20:51:39 +03:00
2018-11-16 00:49:18 +03:00
Another way to dynamically generate the variable content is the `register` command.
2018-11-17 20:51:39 +03:00
`Register` is also useful to store an output of a task and use its value
2018-11-16 00:49:18 +03:00
for executing further tasks.
2018-11-17 20:51:39 +03:00
2017-10-27 15:42:44 +03:00
```
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/register_and_when.yml
2017-09-23 12:43:25 +03:00
```
2017-06-09 15:05:58 +03:00
2017-10-27 15:55:16 +03:00
```yaml
---
- hosts: localhost
tasks:
- name: check the system capacity
shell: df -h /
register: root_size
- name: debug root_size
debug:
msg: "{{ root_size }}"
2018-11-17 20:51:39 +03:00
2017-10-27 15:55:16 +03:00
- name: debug root_size return code
debug:
msg: "{{ root_size.rc }}"
2018-11-17 20:51:39 +03:00
# when: example
2017-10-27 15:57:54 +03:00
2017-10-27 15:55:16 +03:00
- name: Print this message when return code of 'check the system capacity' was ok
debug:
msg: "{{ root_size.rc }}"
when: root_size.rc == 0
2018-11-17 20:51:39 +03:00
...
2017-10-27 15:55:16 +03:00
```
2018-11-17 20:51:39 +03:00
2017-10-27 15:58:23 +03:00
#### Conditionals - when:
2017-10-27 15:55:16 +03:00
2018-11-17 20:51:39 +03:00
You can define complex logic with Ansible and Jinja functions. Most common is
usage of `when:` , with some variable (often dynamically generated in previous
playbook steps with `register` or `lookup` )
2017-10-27 15:55:16 +03:00
2018-01-01 23:21:39 +03:00
```yaml
---
- hosts: localhost
tasks:
- name: check the system capacity
shell: df -h /
when: some_variable in 'a string'
roles:
- { role: mid_nagios_probe, when: allow_nagios_probes }
2018-11-17 20:51:39 +03:00
...
2018-01-01 23:21:39 +03:00
```
2017-10-27 15:55:16 +03:00
2017-10-27 16:00:25 +03:00
### ansible - tags, limit
2017-10-27 15:55:16 +03:00
You should know about a way to increase efficiency by this simple functionality
#### TAGS
2017-10-27 15:59:23 +03:00
2018-11-17 20:51:39 +03:00
You can tag a task, role (and its tasks), include, etc, and then run only the
tagged resources
2017-10-27 15:55:16 +03:00
2018-11-17 20:51:39 +03:00
```
ansible-playbook playbooks/simple_playbook.yml --tags=tagA,tag_other
ansible-playbook playbooks/simple_playbook.yml -t tagA,tag_other
There are special tags:
always
--skip-tags can be used to exclude a block of code
--list-tags to list available tags
```
2017-10-27 15:55:16 +03:00
2018-01-01 23:31:22 +03:00
[Read more ](http://docs.ansible.com/ansible/latest/playbooks_tags.html )
2017-10-27 16:00:25 +03:00
#### LIMIT
2017-10-27 15:59:51 +03:00
2018-11-17 20:51:39 +03:00
You can limit an execution of your tasks to defined hosts
2017-10-27 16:05:56 +03:00
2018-11-17 20:51:39 +03:00
```
ansible-playbook playbooks/simple_playbook.yml --limit localhost
--limit my_hostname
--limit groupname
--limit some_prefix*
--limit hostname:group #JM
```
2017-10-27 15:55:16 +03:00
2017-09-28 01:05:12 +03:00
### Templates
2017-09-27 19:11:20 +03:00
2018-11-17 20:51:39 +03:00
Templates are a powerful way to deliver some (partially) dynamic content.
Ansible uses **Jinja2** language to describe the template.
2017-09-27 19:11:20 +03:00
2018-11-17 20:51:39 +03:00
```
2017-09-27 19:11:20 +03:00
Some static content
{{ a_variable }}
2018-11-17 20:51:39 +03:00
{% for item in loop_items %}
2017-09-27 19:11:20 +03:00
this line item is {{ item }}
{% endfor %}
```
2018-11-17 20:51:39 +03:00
2018-11-15 03:00:54 +03:00
Jinja may have some limitations, but it is a powerful tool that you might like.
2017-09-22 23:21:42 +03:00
2018-11-17 20:51:39 +03:00
Please examine this simple example that installs apache2 and generates
index.html from the template
2018-01-01 23:39:09 +03:00
"playbooks/roles/simple_apache_role/templates/index.html"
```bash
$ source environment.sh
$ # Now we would run the above playbook with roles
(venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_role.yml --tags apache2
```
2018-01-01 22:54:32 +03:00
#### Jinja2 CLI
2018-11-17 20:51:39 +03:00
2017-09-27 19:34:38 +03:00
You can use the jinja in the CLI too
2018-11-17 20:51:39 +03:00
2017-09-27 19:34:38 +03:00
```bash
2019-10-25 12:35:24 +03:00
ansible -m shell -a 'echo {{ my_variable }}' -e 'my_variable=something, playbook_parameter=twentytwo' localhost
2017-09-27 19:34:38 +03:00
```
2018-11-17 20:51:39 +03:00
2018-01-01 23:31:22 +03:00
In fact - jinja is used to template parts of the playbooks too
2018-11-17 20:51:39 +03:00
2018-10-30 23:04:56 +03:00
```yaml
2018-11-17 20:51:39 +03:00
# check part of this playbook: playbooks/roles/sys_debug/tasks/debug_time.yml
2018-01-01 23:31:22 +03:00
- local_action: shell date +'%F %T'
register: ts
become: False
changed_when: False
- name: Timestamp
debug: msg="{{ ts.stdout }}"
when: ts is defined and ts.stdout is defined
become: False
```
2017-06-09 15:05:58 +03:00
2018-01-01 22:54:32 +03:00
#### Jinja2 filters
2018-11-17 20:51:39 +03:00
2018-11-16 00:49:18 +03:00
Jinja is powerful. It has many built-in useful functions.
2018-11-17 20:51:39 +03:00
```
2017-09-28 00:57:45 +03:00
# get first item of the list
{{ some_list | first() }}
# if variable is undefined - use default value
{{ some_variable | default('default_value') }}
```
2018-11-17 20:51:39 +03:00
2018-01-01 23:40:25 +03:00
[Read More ](http://docs.ansible.com/ansible/latest/playbooks_filters.html )
2017-09-27 19:34:38 +03:00
2017-09-28 01:05:12 +03:00
### ansible-vault
2017-09-27 19:34:38 +03:00
2018-11-17 20:51:39 +03:00
To maintain **infrastructure as code** you need to store secrets. Ansible
provides a way to encrypt confidential files so you can store them in the
repository, yet the files are decrypted on-the-fly during ansible execution.
The best way to use it is to store the secret in some secure location, and
2019-11-20 17:31:29 +03:00
configure ansible to use them during runtime.
2017-09-27 19:34:38 +03:00
```bash
2018-01-01 22:54:32 +03:00
# Try (this would fail)
$ ansible-playbook playbooks/vault_example.yml
2017-09-27 19:34:38 +03:00
$ echo some_very_very_long_secret > ~/.ssh/secure_located_file
2018-01-01 22:54:32 +03:00
# in ansible.cfg set the path to your secret file
2017-09-27 19:34:38 +03:00
$ vi ansible.cfg
ansible_vault_password_file = ~/.ssh/secure_located_file
2018-01-01 22:54:32 +03:00
#or use env
$ export ANSIBLE_VAULT_PASSWORD_FILE=~/.ssh/secure_located_file
2017-09-27 19:34:38 +03:00
$ ansible-playbook playbooks/vault_example.yml
2018-01-01 23:47:54 +03:00
# encrypt the file
2017-09-27 19:34:38 +03:00
$ ansible-vault encrypt path/somefile
# view the file
$ ansible-vault view path/somefile
# check the file content:
$ cat path/somefile
# decrypt the file
$ ansible-vault decrypt path/somefile
```
2017-09-28 01:05:12 +03:00
### dynamic inventory
2017-09-27 19:34:38 +03:00
2018-11-17 20:51:39 +03:00
You might like to know, that you can build your inventory dynamically.
(For Ansible) inventory is just JSON with proper structure - if you can
deliver that to ansible - anything is possible.
2017-09-27 19:34:38 +03:00
2018-11-17 20:51:39 +03:00
You do not need to reinvent the wheel - there are plenty of ready to use
2019-11-20 17:31:29 +03:00
inventory scripts for the most popular Cloud providers and a lot of in-house
2018-11-17 20:51:39 +03:00
popular usecases.
2017-09-27 19:34:38 +03:00
2018-01-01 23:47:54 +03:00
[AWS example ](http://docs.ansible.com/ansible/latest/intro_dynamic_inventory.html#example-aws-ec2-external-inventory-script )
2017-09-27 19:34:38 +03:00
```bash
2018-11-17 20:51:39 +03:00
$ etc/inv/ec2.py --refresh
2017-09-27 19:34:38 +03:00
$ ansible -m ping all -i etc/inv/ec2.py
```
2018-01-01 23:47:54 +03:00
[Read more ](http://docs.ansible.com/ansible/latest/intro_dynamic_inventory.html )
2017-09-28 01:07:12 +03:00
2017-09-28 01:05:12 +03:00
### ansible profiling - callback
2017-09-27 19:34:38 +03:00
2018-11-17 20:51:39 +03:00
Playbook execution takes some time. It is OK. First make it run, then you may
like to speed things up. Since ansible 2.x there is built-in callback for task
execution profiling.
2017-06-09 15:05:58 +03:00
```
2018-11-17 20:51:39 +03:00
vi ansible.cfg
# set this to:
2017-09-28 00:57:45 +03:00
callback_whitelist = profile_tasks
2017-06-09 15:05:58 +03:00
```
2017-09-28 01:05:12 +03:00
### facts-cache and ansible-cmdb
2018-11-17 20:51:39 +03:00
2019-11-20 17:31:29 +03:00
You can pull some information about your environment from another host.
2018-11-17 20:51:39 +03:00
If the information does not change - you may consider using a facts_cache
to speed things up.
2017-06-09 15:05:58 +03:00
```
2017-09-28 00:57:45 +03:00
vi ansible.cfg
2017-06-09 15:05:58 +03:00
2017-09-28 00:57:45 +03:00
# if set to a persistent type (not 'memory', for example 'redis') fact values
# from previous runs in Ansible will be stored. This may be useful when
# wanting to use, for example, IP information from one group of servers
# without having to talk to them in the same playbook run to get their
# current IP information.
fact_caching = jsonfile
fact_caching_connection = ~/facts_cache
fact_caching_timeout = 86400
2017-06-09 15:05:58 +03:00
```
2017-09-28 00:57:45 +03:00
I like to use `jsonfile` as my backend. It allows to use another project
2024-04-19 08:58:53 +03:00
`ansible-cmdb` [(project on GitHub) ](https://github.com/fboender/ansible-cmdb ) that generates a HTML page of your inventory
2018-11-17 20:51:39 +03:00
resources. A nice 'free' addition!
### Debugging ansible [chapter in progress]
2017-06-09 15:05:58 +03:00
2017-09-28 00:57:45 +03:00
When your job fails - it is good to be effective with debugging.
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
1. Increase verbosity by using multiple -v ** [ -vvvvv]**
2. If variable is undefined -
`grep -R path_of_your_inventory -e missing_variable`
3. If variable (dictionary or a list) is undefined -
`grep -R path_of_your_inventory -e missing_variable`
4. Jinja template debug
2018-01-01 23:54:39 +03:00
5. Strange behaviour - try to run the code 'at the destination'
2017-06-09 15:05:58 +03:00
2018-11-16 00:49:18 +03:00
### Infrastructure as code
2018-11-17 20:51:39 +03:00
You already know, that ansible-vault allows you to store your confidential data
2018-11-17 22:38:50 +03:00
along with your code. You can go further - and define your
ansible installation and configuration as code.
2018-11-17 20:51:39 +03:00
See `environment.sh` to learn how to install the ansible itself inside a
`virtualenv` that is not attached to your operating system (can be changed by
non-privileged user), and as additional benefit - upgrading version of ansible
is as easy as installing new version in new virtualenv. What is more, you can
have multiple versions of Ansible present at the same time.
2017-06-09 15:05:58 +03:00
```bash
2018-11-17 20:51:39 +03:00
# recreate ansible 2.x venv
2017-09-28 00:57:45 +03:00
$ rm -rf venv2
$ source environment2.sh
2018-11-17 20:51:39 +03:00
# execute playbook
2017-09-28 00:57:45 +03:00
(venv2)$ ansible-playbook playbooks/ansible1.9_playbook.yml # would fail - deprecated syntax
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
# now lets install ansible 1.9.x next to ansible 2.x
2017-09-28 00:57:45 +03:00
(venv2)$ deactivate
$ source environment.1.9.sh
2018-11-17 20:51:39 +03:00
# execute playbook
2017-09-28 00:57:45 +03:00
(venv1.9)$ ansible-playbook playbooks/ansible1.9_playbook.yml # works!
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
# please note that you have both venv1.9 and venv2 present - you need to (de)activate one - that is all
2017-06-09 15:05:58 +03:00
```
2017-10-20 22:42:16 +03:00
#### become-user, become
2018-11-17 20:51:39 +03:00
In Ansible - to become `sudo` - use the `become` parameter. Use `become_user`
to specify the username.
2018-01-02 00:07:51 +03:00
```
- name: Ensure the httpd service is running
service:
name: httpd
state: started
become: true
```
2018-11-17 20:51:39 +03:00
Note: You may like to execute Ansible with `--ask-sudo-pass` or add the user to
sudoers file in order to allow non-supervised execution if you require 'admin'
2022-12-10 18:05:34 +03:00
privileges.
2018-01-02 00:03:48 +03:00
[Read more ](http://docs.ansible.com/ansible/latest/become.html )
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
## Tips and tricks
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### --check -C
2018-11-17 20:51:39 +03:00
Always make sure that your playbook can execute in 'dry run' mode (--check),
and its execution is not declaring 'Changed' objects.
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### --diff -D
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
Diff is useful to see nice detail of the files changed.
It compare 'in memory' the files like `diff -BbruN fileA fileB` .
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### Execute hosts with 'regex'
2018-11-17 20:51:39 +03:00
2017-06-09 15:05:58 +03:00
```bash
2017-09-28 00:57:45 +03:00
ansible -m ping web*
2017-06-09 15:05:58 +03:00
```
2018-11-17 20:51:39 +03:00
#### Host groups can be joined, negated, etc
2017-06-09 15:05:58 +03:00
```bash
2017-09-28 00:57:45 +03:00
ansible -m ping web*:!backend:monitoring:& allow_change
2017-06-09 15:05:58 +03:00
```
2017-09-28 01:05:12 +03:00
#### Tagging
2018-11-17 20:51:39 +03:00
You should tag some (not all) objects - a task in a playbook, all tasks
included form a role, etc. It allows you to execute the chosen parts of the
playbook.
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### no_logs: True
2018-11-17 20:51:39 +03:00
You may see, that some roles print a lot of output in verbose mode. There is
also a debug module. This is the place where credentials may leak. Use `no_log`
to hide the output.
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### Debug module
2018-11-17 20:51:39 +03:00
2018-01-02 00:10:59 +03:00
allows to print a value to the screen - use it!
2017-06-09 15:05:58 +03:00
2017-09-28 01:05:12 +03:00
#### Register the output of a task
2018-01-02 00:10:59 +03:00
2018-11-17 20:51:39 +03:00
You can register the output (stdout), rc (return code), stderr of a task with
the `register` command.
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
#### Conditionals: when:
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
#### Loop: with, with\_items, with\_dict, with\_together
2017-06-09 15:05:58 +03:00
2018-11-17 20:51:39 +03:00
[Read more ](http://docs.ansible.com/ansible/latest/playbooks_conditionals.html )
2017-06-09 15:05:58 +03:00
2018-10-30 23:04:56 +03:00
## Additional Resources
2017-06-09 15:05:58 +03:00
2018-10-30 23:04:56 +03:00
* [Servers For Hackers: An Ansible Tutorial ](https://serversforhackers.com/c/an-ansible-tutorial )
* [A system administrator's guide to getting started with Ansible - FAST! ](https://www.redhat.com/en/blog/system-administrators-guide-getting-started-ansible-fast )
* [Ansible Tower ](https://www.ansible.com/products/tower ) - Ansible Tower provides a web UI, dashboard and rest interface to ansible.
2018-11-15 03:00:54 +03:00
* [Ansible AWX ](https://github.com/ansible/awx ) - The Open Source version of Ansible Tower.
2022-07-18 14:52:44 +03:00
* [Ansible Tutorial for Beginners: Ultimate Playbook & Examples ](https://spacelift.io/blog/ansible-tutorial )