Skip to main content

Ansible introduction for beginners

· 5 min read
VoidQuark
Open-source enthusiast

Ansible Logo

This blog post focus on a simple and quick explanation of what Ansible is and what it can do.

What is ansible

Ansible is open-source software used for automation. It is written in Python language. It can orchestrate complex workflow, deploy software, configure systems. The fact that it is an open source is important. Now let’s dive directly into examples for better understanding.

It is possible to achieve complex tasks such as deploying the whole cloud and managing the cloud life cycle ( infrastructure as code ). This sounds cool, right?

Easy tasks like deploying, removing, or configuring virtual network devices ( e.g. switches, routers ), applications ( e.g database cluster, web server), and virtual machines. Still not enough?

Few more examples:

  • extend partitions
  • automate backups
  • change the config files
  • build container
  • build OS cloud images
  • deploy Kubernetes cluster
  • automate tasks on API endpoints
  • update/upgrade application or operating systems

So now you see that you are not limited. This freedom is exactly what we need and what we want to achieve. Keep in mind that these were just examples, in reality, Ansible can do much more.

How does it work

Before running an Ansible playbook, you must install it on a workstation or central VM (e.g. Ansible host). Ansible is completely agentless and by default uses ssh. Sure you also have other options like Kerberos, basic auth ( not recommended ), and much more. After connecting to your nodes Ansible pushes modules that are executed and removed when finished.

Ansible

After a quick overview of what Ansible does, let's jump on the structure.

Ansible basic structure

  • Inventory
  • Playbook

Inventory example

The inventory contains information about hosts and groups. It helps us build a logical separation between multiple hosts/groups.

─── inventory
├── group_vars
│ ├── apache # GROUP NAME
│ │ └── apache_vars.yml
│ └── nginx # GROUP NAME
│ └── nginx_vars.yml
├── hosts
└── host_vars
├── apache1.voidquark.com # HOSTNAME
│ └── host_vars.yml
├── apache2.voidquark.com # HOSTNAME
| └── host_vars.yml
├── nginx1.voidquark.com # HOSTNAME
| └── host_vars.yml
└── nginx2.voidquark.com # HOSTNAME
└── host_vars.yml

Group specific variables:

#CONTENT OF: inventory/group_vars/apache/apache_vars.yml
---
web_server_file: "filename_for_apache"
#CONTENT OF: inventory/group_vars/nginx/nginx_vars.yml
---
web_server_file: "filename_for_nginx"

Host specific variables:

#CONTENT OF: inventory/host_vars/apache1.voidquark.com/host_vars.yml
---
web_host_specific_file: "filename_for_apache1.voidquark.com"
#CONTENT OF: inventory/host_vars/apache2.voidquark.com/host_vars.yml
---
web_host_specific_file: "filename_for_apache2.voidquark.com"
#CONTENT OF: inventory/host_vars/nginx1.voidquark.com/host_vars.yml
---
web_host_specific_file: "filename_for_nginx1.voidquark.com"
#CONTENT OF: inventory/host_vars/nginx2.voidquark.com/host_vars.yml
---
web_host_specific_file: "filename_for_nginx2.voidquark.com"

Inventory hosts file can be written in INI or YAML. Content of inventory/hosts

[nginx]
nginx1.voidquark.com
nginx2.voidquark.com

[apache]
apache1.voidquark.com
apache2.voidquark.com

As shown in the above example there are four different hosts ( nginx1.voidquark.com, nginx1.voidquark.com, apache1.voidquark.com, apache2.voidquark.com ) and two different groups. Each group and host have its own variables. This helps us to run the same code on different groups or hosts with different variable values.

Playbook example

Ansible Playbook is a blueprint that contains automation tasks information. There are a lot of options for what a playbook can contain. For example, it is possible to write a code directly in the playbook or even call roles where the code is located. I do not want to mention this option as it will be too much information for beginners. I tried to use a simple example with the above inventory where code is written in the playbook.

---
# Playbook example
- hosts: all
tasks:
- name: Create empty file on remote server using group variables
ansible.builtin.file:
path: "/tmp/{{ web_server_file }}"
state: "touch"
- name: Create empty file on remote server using host variables
ansible.builtin.file:
path: "/tmp/{{ web_host_specific_file }}"
state: "touch"

Executed playbook with command ansible-playbook -i inventory/hosts playbook.yml

PLAY [all] ************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [nginx1.voidquark.com]
ok: [nginx2.voidquark.com]
ok: [apache1.voidquark.com]
ok: [apache2.voidquark.com]

TASK [Create empty file on remote server using group variables] *****************************************************************************
changed: [nginx1.voidquark.com]
changed: [nginx2.voidquark.com]
changed: [apache1.voidquark.com]
changed: [apache2.voidquark.com]

TASK [Create empty file on remote server using host variables] *****************************************************************************
changed: [nginx1.voidquark.com]
changed: [nginx2.voidquark.com]
changed: [apache1.voidquark.com]
changed: [apache2.voidquark.com]

PLAY RECAP ************************************************************************************************************
nginx1.voidquark.com : ok=1 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nginx2.voidquark.com : ok=1 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
apache1.voidquark.com : ok=1 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
apache2.voidquark.com : ok=1 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Playbook created one file on each host with a different file name.

[[email protected] ~]$ ls /tmp/filename_for_*
/tmp/filename_for_nginx /tmp/filename_for_nginx1.voidquark.com

[[email protected] ~]$ ls /tmp/filename_for_*
/tmp/filename_for_nginx /tmp/filename_for_nginx2.voidquark.com

[[email protected] ~]$ ls /tmp/filename_for_*
/tmp/filename_for_apache /tmp/filename_for_apache1.voidquark.com

[[email protected] ~]$ ls /tmp/filename_for_*
/tmp/filename_for_apache /tmp/filename_for_apache2.voidquark.com

You can notice that Ansible playbook uses YAML. Now you see it was not difficult to create simple Ansible automation.

For simplicity, no roles, vault, or modules have been mentioned. It makes Ansible more complex but more manageable and logical.

If you want to manage Ansible at scale with a few hundred nodes, then is required to develop the correct structure and use some best practices.


Recommended official documentation


Thanks for reading. I'm entering the void. 🛸 ➡️ 🕳️