This is an Ansible Playbook tutorial where we will learn to write an ansible playbook from scratch with an example. Ansible requires two most important files, which are known as playbook and inventory file.
Before we start with our Ansible Playbook Tutorial, I hope you already have an environment with Ansible installed, let us understand about YAML file architecture with some examples:
What is YAML?
- YAML Ain’t Markup Language (YAML) is often called a data serialization language.
- It was intended to be human-readable and organize data into a structured format.
- Programming languages can understand the content of YAML files (which usually have a
.yml
or.yaml
extension) and map them to built-in data types. - For example, when you consume a
.yaml
file in your Python script, it will automatically convert the content into either a dictionary{}
or list[]
, so you can work and iterate over it. - YAML rules help to construct a readable file so it's important to understand them in order to write a valid and well formatted YAML file.
YAML file formatting
There're a few rules to follow while developing YAML files. YAML uses indentation (like Python), which builds the relationship of items with one another:
Key value Pair in YAML File
Below we take data in the simplest form such as key value pair in the YAML format where Key and value are separated by a colon. It is important that you give a whitespace followed y colon differentiating the Key and Value
Fruit: Apple Vegetable: Carrot Liquid: Water Meat: Chicken
Here Keys are Fruit, Vegetable, Liquid, Meat while the respective Values are Apple, Carrot, Water and Chicken
Array or Lists in YAML File
Here we list some fruits and vegetables. So Fruits and Vegetables followed by a colon here represent array while all the elements of the array would start with a dash (-) so Orange, Apple and Banana are the elements of Fruits array while Carrot, Cauliflower and Tomato are the elements of Vegetables array
Fruits: - Orange - Apple - Banana Vegetables: - Carrot - Cauliflower - Tomato
Dictionary or Map in YAML File
It is a set of properties group together under an item. Here we try to represent nutrition information of two fruits
Calories, Fat and Carbs are different for each item. You must have equal number of whitespaces before the properties of single item so they are all aligned together
Banana: Calories: 105 Fat: 0.4 g Carbs: 27 g Grapes: Calories: 62 Fat: 0.3 g Carbs: 16g
Spaces and Indentation in YAML File
Correct indentation is very important for YAML data. It's recommended to use an advanced text editor such as, Sublime Text or Notepad++, as they have options that convert the tabs to a specific number of whitespaces. Here we have dictionary representing nutrition information about Banana. We are giving same number spaces for individual properties that indicates these key value pairs fall within Banana. But what if we gave extra spaces for Fat and Carbs like below
Banana: Calories: 105 Fat: 0.4 g Carbs: 27 g
Now with this Fat and Carbs will fall under Calories and thus they will become properties of Calories which does not make any sense and thus will lead to syntax error. The error will tell you that mapping values are npot allowed here because calories already have a value set i.e. 105. You can either set a direct value or hashmapo but you cannot have both.
So the number of spaces before each property is the key in YAML. The indentation is not important i.e. you can give 5 spaces or 6 spaces but make sure the gaps are consistent.
Key Value or Dictionary or Lists in YAML File
You can have Lists containing dictionary further containing list. In this case we have list of Fruits and the elements of the Lists are Banana and Grape but each of these element are further dictionaries containing nutrition information
Fruits: - Banana: Calories: 105 Fat: 0.4 g Carbs: 27 g - Grape: Calories: 62 Fat: 0.3 g Carbs: 16g
Dictionary vs List vs List of Dictionaries
It is important to understand that all the data structures such as XML, JSON or YAML is used to represent data. The data can be about an organization and all of it's employees and their personal details or it could be data about school and all of it's students and their grades
Let's take an example of a car, A car is a single object and it has properties such as Color, Model, Transition and price. To store different information or properties of a single object we use Dictionary.
Here, we create a simple dictionary by using a key value format.
Color: Blue Model: Corvette Transition: Manual Price: $20,000
Now we may also split the Model further into "Model Name" and "Year", so we can use a dictionary within another dictionary
Color: Blue Model: Name: Corvette Year: 1995 Transition: Manual Price: $20,000
Let's say we want to store the name of 6 different cars. To store this we will use a List or Array as it is multiple item of same type or object. Since we are only storing a name we have a simple list of strings
- Blue Corvette - Grey Corvette - Red Corvette - Green Corvette
Now what if we would like to store all information about each car such as Color, Model, Transition and price. So we will modify our "List of Strings" to "List of Dictionaries"
- Color: Blue Model: Name: Corvette Year: 1995 Transition: Manual Price: $20,000 - Color: Grey Model: Name: Corvette Year: 1995 Transition: Manual Price: $20,000 - Color: Red Model: Name: Corvette Year: 1995 Transition: Manual Price: $22,000 - Color: Green Model: Name: Corvette Year: 1995 Transition: Manual Price: $23,000
Dictionary is an un-ordered collection where List is an ordered collection
For example here we have two dictionary.
In the first example Fat is defined before Carbs in the properties
Banana: Calories: 105 Fat: 0.4 g Carbs: 27 g
While in this example Carbs is define before Fat but that doesn't really matter. The properties can be defined in any order but the two dictionaries will still be the same as long as the value of each properties match. This is the not the same for list or arrays. Arrays are ordered collection so the order of item matters.
Banana: Calories: 105 Fat: 0.4 g Carbs: 27 g
In this example we have defined lists in an order Orange → Apple → Banana
Fruits: - Orange - Apple - Banana
but if we write the same Array/List in below order both arrays are not the same. This is something you should keep in mind while working with data structures
Fruits: - Orange - Banana - Apple
Now let us continue our Ansible Playbook tutorial with the basic question, what are ansible playbooks?
What are Ansible Playbooks?
- Ansible playbooks are text files or configuration files that are written in particular format called YAML.
- These are expressed in the YAML format and have a minimum of syntax, which is not to be a programming language or script, but rather a model of a configuration.
- Each playbook includes one or more "
plays
" in a list. - The goal of a play is to map a group of hosts to some well-defined roles and tasks.
- A task is nothing but a call or operation, which applies on group of hosts.
The following is the syntax of the Playbook.yaml
file:
--- - hosts: webserver sudo: yes remote_user: ec2-user tasks: - name: Updating System yum: name=* state=latest
In this playbook, two directives are important, first is hosts and second is tasks. Task will be applied on the hosts.
Ansible Playbook Tutorial
Ansible Playbooks are Ansible orchestration language, it is in playbooks where we define what we want Ansible to do. It is a set of instructions you provide Ansible to work it's magic.
Now since we know that all playbooks are written in YAML format. Below example breaks down the YAML file.
Playbook - A single YAML file Play - Defines a set of activities (tasks) to be run on a single or group of hosts Task - An action to be performed on the host, below are some examples: Execute command Run a script Install a package Shutdown/restart
Simple Ansible Playbook Example
For example it can be as simple as running a series of commands in different servers in a sequence and restarting those servers in a particular order. Below is a simple ansible playbook example:
# Simple Ansible Playbook Example - Run command1 on server1 - Run command2 on server2 - Run command3 on server3 - Run command4 on server4 - Run command5 on server5 - Run command6 on server6 - Run command7 on server7 - restarting server1 - restarting server2 - restarting server3 - restarting server4 - restarting server5 - restarting server6 - restarting server7
Complex Ansible Playbook Example
Now below is one little more complex Ansible playbook example:
# Complex Ansible playbook Example - Deploy 50 VMs on Public Cloud - Deploy 50 VMs on Private Cloud - Provision Storage to all VMs - Setup Network Configuration on Private VMs - Setup Cluster configuration - Configure Web server on 20 Public VMs - Configure DB server on 20 private VMs - Setup LoadBalancing between web server VMs - Setup Monitoring components - Install and Configure backup clients on VMs - Update CMDB database with new VM information
Sample Ansible Playbook to install Apache
I have already created my Ansible environment so I will not explain those parts here.
Here we have a simple playbook install_httpd.yml
which contains single play i.e. "Play 1". The goal of this play is to run set of activities one after the other on one of the managed host server2.example.com
.
# Simple Ansible Playbook.yml --- - name: Play 1 # Here the host is defined at the play level. This can be anything from your inventory file. hosts: server2.example.com # All tasks under this will be executed on all nodes mentioned under "hosts" which here is "localhost" tasks: - name: Execute command 'date' # Execute date command command: date - name: Execute script on server # Execute test_script.sh, this must exist in your project directory script: test_script.sh # Install httpd service - name: Install httpd service # Using yum yum: name: httpd state: present - name: Start web server # Start the httpd service using service module service: name: httpd state: started
So the playbook is a list of dictionary and has a set of properties called name, hosts and tasks. Since these are items of dictionaries so the order does not matter however this is not value of tasks.
As you see tasks is a list as denoted by the dash so the position of entries matters.
# Sample Inventory File localhost server1.example.com server2.example.com
Next we execute the playbook
[ansible@controller base]$ ansible-playbook install_httpd.yml PLAY [Play 1] *************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** ok: [server2.example.com] TASK [Execute command 'date'] *********************************************************************************** changed: [server2.example.com] TASK [Execute script on server] ********************************************************************************* changed: [server2.example.com] TASK [Install httpd service] ************************************************************************************ changed: [server2.example.com] TASK [Start web server] ***************************************************************************************** changed: [server2.example.com] PLAY RECAP ****************************************************************************************************** server2.example.com : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Lastly I hope this article on ansible playbook tutorial and steps to write a playbook with example on Linux was helpful. So, let me know your suggestions and feedback using the comment section.
References:
Hands-On Enterprise Automation with Python
AWS Automation Cookbook
Related Searches: Ansible Playbook Tutorial. Sample Ansible playbook to install Apache. Ansible playbook example. YAML tutorial for beginners. Define playbook. Create simple ansible playbook.