Managing configurations of multiple servers and environments is a big benefit of using Ansible. But what should we do when configuration files vary from server to server? Before creating a separate configuration for each server or environment, lets take a look at Ansible templates.
What is an Ansible Template?
Sometimes we need to transfer text files to remote hosts. Those text files are usually configuration files. When we are working with a single server, the configuration file may contain information specific to that server like hostname, IP address, etc. Since we’re working with a single server, we could create the file on the Ansible controller and then use the copy module in a playbook to copy it to the server.
But what if we have multiple web servers each needing that same configuration file but each with their own specific values? We can’t just copy the configuration file to all machines; it’s only built for a single server with a specific hostname, IP address, etc. So we need an Ansible template.
Ansible templates allow you to define text files with variables instead of static values and then replace those variables at playbook runtime.
Ansible Template files
An Ansible template is a text file built with the Jinja2 templating language with a j2 file extension. A Jinja2 template looks exactly like the text file you’d like to get onto a remote host. The only difference is that instead of static values, the file contains variables.
For demonstration, lets install web server on both centos and ubuntu in our lab environment and make sure everything is going fine :
[user1@controller demo-temp]$ ansible ubuntu -b -m apt -a "name=apache2 state=present"
[user1@controller demo-temp]$ ansible centos -b -m yum -a "name=httpd state=present"
Next create a template for web server default page (index.html.j2):
<html>
<center>
<h1> This machine's hostname is {{ ansible_hostname }}</h1>
<h2> os family is {{ ansible_os_family }}</h2>
<small>file version is {{ file_version }}</small>
{# This is comment, it will not appear in final output #}
</center>
</html>
and related playpook to use this template:
---
#sample playbook using template for web server- template-playbook.yaml
- hosts: all
become: yes
vars:
file_version: 1.0
tasks:
- name: install default web page
template:
src: index.html.j2
dest: /var/www/html/index.html
mode: 0777
We can change file permissions with the template module.
Next we will put index.html on each server and check the results:
root@ubuntu:~# cat /var/www/html/index.html
<html>
<center>
<h1> This machine's hostname is ubuntu</h1>
<h2> os family is Debian</h2>
<small>file version is 1.0</small>
</center>
</html>
[root@centos ~]# cat /var/www/html/index.html
<html>
<center>
<h1> This machine's hostname is centos</h1>
<h2> os family is RedHat</h2>
<small>file version is 1.0</small>
</center>
</html>
To add multiple files on a remote host use loops to template multiple files.
How ansible templates work ?
All templating happens on the Ansible controller before the task is sent and executed on the target machine. This approach minimizes the package requirements on the target (jinja2 is only required on the controller). It also limits the amount of data Ansible passes to the target machine. Ansible parses templates on the controller and passes only the information needed for each task to the target machine, instead of passing all the data on the controller and parsing it on the target.
include statement
include plays and tasks
Using include statements is our trick to split a large playbook into smaller pieces. We can also move task to a separate file and use include statement to include tasks from:
Like any other programming or scripting language we can start writing huge play books with hundreds of lines, but it is against the simplicity. Also writing long playbooks make them useful just for a specific use case and no other one can use it!
In programming languages, we try to modularize our code into packages, modules, classes and functions. That way our code becomes more organized, readable and we can share it with others.
Obviously we don't have any programs or classes or functions in Ansible, what we do have are just inventory files, variables and playbooks. What should we do? When most system administrators use ansible they use roles as the way to organize various plays and playbooks.
Previously we learned how to include files, it could be confusing, what kind of file are you including? is it a task file? is it a playfile? How it's included? where it's included? The idea of roles give us a folder structure to storing those files and it also automatically include files that are named and placed in a proper place.
Roles is a new way to organize things. This is very common that people share roles. Usually the file extention on roles is going to be .yml on the YAML files instead of .yaml . That is because the lent of extention is not important in linux, but when you are sharing roles with other people it is important.
So roles provide a mechanism to break a complicated playbook into multiple reusable components. Each component offers a small function that can be used independently within the playbook. So rather than creating one complex playbook, you can create many roles and simply drop them into your playbooks.