Ansible - let's try
- Tutorial
Ansible is a relatively young configuration management system with a history of just over three years. But despite this, he quickly and quickly burst into the world of configuration management systems, crowding out Chef, Puppet and SaltStack.
Let's look at him carefully to understand why he is so loved by techies.
So what is ansbile good for:
You can start using ansible in a couple of minutes. Suppose you are using OSX.
Now create a file
Go:
What have we done? For all hosts (parameter
If the module (key
In addition to the ansible utility, there is also the ansible-playbook utility, which you will use most often.
For further examples, I started the t2.micro machine on aws with Ubuntu 14.04 and registered it in hosts.
Also, in order not to enter parameters every time in the command line, I created a file in the project directory
After that, create our first script (playbook in ansible terminology)
We run our first script, which updates the apt cache, and then puts two packages: nginx and postgresql.
In fact, we called the apt module twice , only with different parameters. The script file itself is a Yaml file interspersed with the Jinja2 template engine .
Indeed, in order to control the machine, Python must be installed on it (and it is installed by default on all modern linux systems) and there must be ssh access. Compare this with other systems where you need to put a client who needs certain versions of different languages and libraries. This fact, by the way, makes starting with ansible much easier than for other systems.
The module can be written in any language, it should be able to accept input parameters and issue json in response. But why write a new module if there are already 242 modules for all occasions (in version 1.8.4). In case you are really missing something, there is a good description of how to write your module .
I would not want to make a huge sheet of the script, so let's split the script into parts using the role mechanism.
For those who are too lazy to write something themselves, there are already thousands of ready-made roles on the ansible galaxy website , and they are of quite decent quality to use them in battle.
We will create a pure role.
Let's modify the file
Pay attention to the key
And in the file
Using roles, you can reuse code (although whether Yaml is code is a philosophical question). Of course, the example is intentionally simplified, but from it it becomes clear how to organize projects on ansible with a large number of components.
Ansible has a built-in module
The setup module collects various data for the node, this is an analog of ohai in chef (by the way, ansible can also use ohai to collect information). All this data can then be used in scripts and templates. For example, the default ip address can be obtained by accessing the variable
Ansible has templates that use the Jinja2 template engine. Let's make 2 patterns.
Pay attention to the variables in double curly brackets (for example
In order to work out some actions asynchronously, ansible has handlers (handlers) that can be called from tasks. Create your own handler that reloads nginx.
We will now refine the task file for the nginx role.
As is clear from the description, this task sets nginx, starts it, deletes the nginx configuration file by default, creates a configuration file from the template
So, run the resulting script.
As you can see, at the end nginx reloaded the configuration. Take a look at the browser.
Voila! We installed and started nginx with the configuration file we needed, generated a page with data from ansible for it, and reloaded nginx.
And so you do not think that ansible is an ideal product that has nowhere to develop, I will talk about its shortcomings.
Let's look at him carefully to understand why he is so loved by techies.
So what is ansbile good for:
- low entry threshold;
- declarative configuration description language;
- Managed nodes do not need to install any additional software;
- just write an add-on module.
Low entry threshold
You can start using ansible in a couple of minutes. Suppose you are using OSX.
$ brew install ansible
$ ansible --version
ansible 1.8.4
configured module search path = None
Now create a file
hosts
:[test]
localhost ansible_connection=local
Go:
$ ansible -i hosts -m ping all
localhost | success >> {
"changed": false,
"ping": "pong"
}
What have we done? For all hosts (parameter
all
) from the hosts file, execute the ping module. Let's see something else.ansible -i hosts -a 'ls -lah' all
$ ansible -i hosts -a "ls -lah" all
localhost | success | rc=0 >>
total 12K
drwxr-xr-x 5 brun staff 170 Apr 1 11:50 .
drwxr-xr-x 91 brun staff 3.1K Apr 1 11:37 ..
-rw-r--r-- 1 brun staff 230 Apr 1 12:07 export.sh
-rw-r--r-- 1 brun staff 42 Apr 3 14:48 hosts
-rw-r--r-- 1 brun staff 376 Apr 1 12:49 playbook.yml
If the module (key
-m
) is not specified, then the command module is used . In fact, ansible can be used not only as a configuration management system, but also as a framework for distributed execution of commands.Declarative configuration description language
In addition to the ansible utility, there is also the ansible-playbook utility, which you will use most often.
For further examples, I started the t2.micro machine on aws with Ubuntu 14.04 and registered it in hosts.
# hosts
[web]
111.111.111.111
Also, in order not to enter parameters every time in the command line, I created a file in the project directory
ansible.cfg
.# ansible.cfg
[defaults]
hostfile = hosts
After that, create our first script (playbook in ansible terminology)
web.yml
.web.yml
# web.yml
---
- hosts: all
user: ubuntu
tasks:
- name: Update apt cache
apt: update_cache=yes
sudo: yes
- name: Install required packages
apt: name={{ item }}
sudo: yes
with_items:
- nginx
- postgresql
We run our first script, which updates the apt cache, and then puts two packages: nginx and postgresql.
ansible-playbook web.yml
$ ansible-playbook web.yml
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [111.111.111.111]
TASK: [Update apt cache] ******************************************************
ok: [111.111.111.111]
TASK: [Install required packages] *********************************************
changed: [111.111.111.111] => (item=nginx,postgresql)
PLAY RECAP ********************************************************************
111.111.111.111 : ok=3 changed=1 unreachable=0 failed=0
In fact, we called the apt module twice , only with different parameters. The script file itself is a Yaml file interspersed with the Jinja2 template engine .
No additional software needs to be installed on managed nodes
Indeed, in order to control the machine, Python must be installed on it (and it is installed by default on all modern linux systems) and there must be ssh access. Compare this with other systems where you need to put a client who needs certain versions of different languages and libraries. This fact, by the way, makes starting with ansible much easier than for other systems.
Just write an add-on module
The module can be written in any language, it should be able to accept input parameters and issue json in response. But why write a new module if there are already 242 modules for all occasions (in version 1.8.4). In case you are really missing something, there is a good description of how to write your module .
Something serious
I would not want to make a huge sheet of the script, so let's split the script into parts using the role mechanism.
For those who are too lazy to write something themselves, there are already thousands of ready-made roles on the ansible galaxy website , and they are of quite decent quality to use them in battle.
We will create a pure role.
ansible-galaxy init nginx -p roles
$ ansible-galaxy init nginx -p roles
- nginx was created successfully
$ tree
├── roles
│ └── nginx
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ └── vars
│ └── main.yml
Let's modify the file
web.yml
.web.yml
---
- hosts: all
user: ubuntu
sudo: yes
roles:
- nginx
Pay attention to the key
sudo: yes
. It allows you not to write this line in every task. Most administrative tasks should still be performed with rights root
, so it makes sense to leave it here. And in the file
roles/nginx/tasks/main.yml
we write the following:roles / nginx / tasks / main.yml
---
- name: Update apt cache
apt: update_cache=yes
- name: Install required packages
apt: name=nginx
Using roles, you can reuse code (although whether Yaml is code is a philosophical question). Of course, the example is intentionally simplified, but from it it becomes clear how to organize projects on ansible with a large number of components.
Facts
Ansible has a built-in module
setup
that runs first for all managed nodes. Let's see what he does.ansible -m setup all -u ubuntu
$ ansible -m setup all -u ubuntu
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"172.31.7.80"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "12/03/2014",
"ansible_bios_version": "4.2.amazon",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-3.13.0-44-generic",
"console": "ttyS0",
"ro": true,
"root": "UUID=fd803688-5c41-4188-8a06-382a65a520bf"
},
"ansible_default_ipv4": {
"address": "172.31.7.80",
"alias": "eth0",
"gateway": "172.31.0.1",
"interface": "eth0",
"macaddress": "06:a8:07:41:47:a5",
"mtu": 9001,
"netmask": "255.255.240.0",
"network": "172.31.0.0",
"type": "ether"
}
... и так далее
The setup module collects various data for the node, this is an analog of ohai in chef (by the way, ansible can also use ohai to collect information). All this data can then be used in scripts and templates. For example, the default ip address can be obtained by accessing the variable
ansible_default_ipv4
.# web.yml
tasks:
- debug: msg={{ansible_default_ipv4}}
ansible-playbook web.yml
$ ansible-playbook web.yml
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [111.111.111.111]
TASK: [debug msg="{{ansible_default_ipv4}}"] **********************************
ok: [111.111.111.111] => {
"msg": "{u'macaddress': u'06:a8:07:41:47:a5', u'network': u'172.31.0.0', u'mtu': 9001, u'alias': u'eth0', u'netmask': u'255.255.240.0', u'address': u'172.31.7.80', u'interface': u'eth0', u'type': u'ether', u'gateway': u'172.31.0.1'}"
}
Patterns
Ansible has templates that use the Jinja2 template engine. Let's make 2 patterns.
# roles/nginx/templates/ansible.conf.j2
server {
listen 80 default_server;
root /usr/share/nginx/html;
index index.html index.htm;
}
# roles/nginx/templates/index.html.j2
{{ ansible_default_ipv4 }}
{{ ansible_env }}
Pay attention to the variables in double curly brackets (for example
{{ ansible_env }}
) - these are ansible variables that we collected using the module we already know setup
.Handlers
In order to work out some actions asynchronously, ansible has handlers (handlers) that can be called from tasks. Create your own handler that reloads nginx.
# roles/nginx/handlers/main.yml
---
# handlers file for nginx
- name: reload nginx
service: name=nginx state=reloaded
We will now refine the task file for the nginx role.
roles / nginx / tasks / main.yml
# roles/nginx/tasks/main.yml
---
- name: Update apt cache
apt: update_cache=yes
- name: Install required packages
apt: name=nginx
- name: Start nginx service
service: name=nginx state=started
- name: Delete default nginx site
file: path=/etc/nginx/sites-enabled/default state=absent
notify: reload nginx
- name: Create default nginx site
template: src=ansible.conf.j2 dest=/etc/nginx/sites-enabled/ansible owner=www-data group=www-data
notify: reload nginx
- name: Create index.html file
template: src=index.html.j2 dest=/usr/share/nginx/html/index.html owner=www-data group=www-data
As is clear from the description, this task sets nginx, starts it, deletes the nginx configuration file by default, creates a configuration file from the template
ansible.conf.j2
that we wrote above, and generates a file index.html
from the template that we described above. Please note that some tasks send a notification notify: reload nginx
. Moreover, in this case 2 notifications should be sent to reboot nginx, but, in fact, they will merge into one, as will be seen below. Notifications are needed to restart nginx (or any other service) only if the template (or something else) has changed, so as not to do this every time ansible starts. So, run the resulting script.
ansible-playbook web.yml
$ ansible-playbook web.yml
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [111.111.111.111]
TASK: [nginx | Update apt cache] **********************************************
ok: [111.111.111.111]
TASK: [nginx | Install required packages] *************************************
ok: [111.111.111.111]
TASK: [nginx | Start nginx service] *******************************************
ok: [111.111.111.111]
TASK: [nginx | Delete default nginx site] *************************************
changed: [111.111.111.111]
TASK: [nginx | Create default nginx site] *************************************
changed: [111.111.111.111]
TASK: [nginx | Create index.html file] ****************************************
changed: [111.111.111.111]
TASK: [debug msg="{{ansible_default_ipv4}}"] **********************************
ok: [111.111.111.111] => {
"msg": "{u'macaddress': u'06:a8:07:41:47:a5', u'network': u'172.31.0.0', u'mtu': 9001, u'alias': u'eth0', u'netmask': u'255.255.240.0', u'address': u'172.31.7.80', u'interface': u'eth0', u'type': u'ether', u'gateway': u'172.31.0.1'}"
}
NOTIFIED: [nginx | reload nginx] **********************************************
changed: [111.111.111.111]
PLAY RECAP ********************************************************************
111.111.111.111 : ok=9 changed=4 unreachable=0 failed=0
As you can see, at the end nginx reloaded the configuration. Take a look at the browser.
Voila! We installed and started nginx with the configuration file we needed, generated a page with data from ansible for it, and reloaded nginx.
disadvantages
And so you do not think that ansible is an ideal product that has nowhere to develop, I will talk about its shortcomings.
- Lack of dependency manager. Now all roles can be stored in the repository, but there is no clear answer to how to work with dependencies and update roles. Everyone uses this approach (it was the same with Chef, for example, 3 years ago), but when the project grows, the disadvantages of this approach are obvious. UPDATE There is some kind of dependency manager , it’s not clear why it is written about this “in small print below”.
- Incomplete documentation. The answers to some obvious questions have to google, and often they are in private blogs and tickets on github.
- Ansible-pull mode for large installations will require serious “file refinement”.
- Inconvenient debug. Even when calling with the key, it is
-vvvv
not always clear which command was executed on the server and what prevented it from executing. - Fast development. Of course, this drawback has a downside - ansible really is developing rapidly. But I came across a bug when version 1.8.1 worked, and 1.8.4 - broke.