Ansible for Managing Configurations...
Tags: ansible, automation, ubuntu, multipass
Published: 2022-03-18 15:27:02

### So, What is Ansible?
Ansible is simply an Automation Tool, which handles automation of your IT infrastructure, like:
- [Configuration management](https://www.ansible.com/use-cases/configuration-management)
- [Multi-node orchestration](https://www.ansible.com/use-cases/orchestration)
- [Application deployment](https://www.ansible.com/use-cases/application-deployment)
- [Ad-hoc task execution](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html)
- [Network automation](https://www.ansible.com/integrations/networks)
- [Provisioning](https://www.ansible.com/use-cases/provisioning)

Few reasons that make Ansible my first choice:
1. Ansible is a **Push-based** configuration management tool that makes it more powerful and different from other configuration management tools. It requires to setup a control node only, and you are good to push your configurations or deployments to any (or self) node configured in your inventory. sounds cleaner way to set up a node :)
2. It is **open source** and free to use.
3. CentOS and Ubuntu Linux is one of the choices for application deployments, and by default, Ansible is packaged to support a number of modules that are commonly used for managing the virtual machines.
4. Ansible is backed by a strong developer community, so no need to worry if you are stuck, you will get help easily.
5. Ansible offers a very high and seamless integration with leading cloud providers (AWS, Azure, GCP), different automation tools (like StackStorm), and various 3rd Party services.
6. It is highly customizable based on your workflow requirements, with the ability to easily create new modules/sub-modules and plugins.

### How to Setup?

Ansible is an agentless automation tool that you install on a control node. From the control node, Ansible manages machines and other devices remotely (by default, over the SSH protocol).

![Ansible flow of Execution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z8x53o1ksqsdw30ywj4c.png)

Ansible is supported on the majority of general-purpose Operating systems. A few of them are Linux (RHEL, CentOS, Fedora, Ubuntu, Debian, Arch), macOS, Windows...

There are several ways to install Ansible on your control node. If your OS supports a rich package manager that comes with Ansible binaries, go for it. If not, Ansible and its required binaries can be easily installed using python's widely used package management tool, `pip`.

1. Install pip on your control node (https://pip.pypa.io/en/stable/installation/)
2. Install Ansible using pip
```{shell}
$ python -m pip install --user ansible
```

### How Ansible Works?
Ansible works by connecting your control node to managed nodes and pushing out small programs, called "Ansible Modules" to them. Ansible then executes these modules (over SSH by default) and removes them when finished. The configuration of all the managed nodes can be done in the inventory file. Ansible even supports Jinja2 templating to enable dynamic expressions and access to variables and facts.

So How do we tell Ansible to execute these modules?
1. Executing an ad-hoc command

2. Write the flow of your configurations in an Ansible playbook. Ansible Playbook is a YAML file, in which you write ordered instructions for pushing your configurations; these instructions are nothing but writing the modules, which will be executed on the remote hosts.

### Let's see an example in action:
Presumably, you have already installed Ansible on your control node, we will go through the process of running the Ansible playbooks step by step.
1. Verify Ansible setup on Control Node
2. Create the Managed node and configure the SSH keys
3. Setup the standard Ansible directory on control Node
4. Write a playbook
5. Running your playbook

### 1. Verify Ansible setup on Control Node
The Ansible 'ping' module is a simple but useful tool for testing connectivity with a remote host. The module will attempt to connect to the remote, validate a usable 'python', and return 'pong' if successful.
```{shell}
~ ➜ ansible localhost -m ping
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
```

###2. Create a managed node and set up the SSH keys
We will bootstrap a minimal Ubuntu virtual machine, where we will setup the configurations using ansible. Additionally, we will setup the SSH keys to allow access to the managed node from your control node.

####2.A Install multipass
Multipass is a lightweight VM manager, and we can launch Ubuntu instances using the multipass cli.
**Installation Instructions**: https://multipass.run

####2.B Launching Multipass instance
```{shell}
~ ➜ #List available multipass instances
~ ➜ multipass find
Image                       Aliases           Version          Description
18.04                       bionic            20220310         Ubuntu 18.04 LTS
20.04                       focal,lts         20220308         Ubuntu 20.04 LTS
21.10                       impish            20220309         Ubuntu 21.10

~ ➜ #Launch bionic instance with default configurations
~ ➜ multipass launch --name ubuntu-bionic bionic
Launched: ubuntu-bionic
```
####2.C Copy SSH keys to ubuntu VM
```{shell}
~ ➜ #Generating SSH key pair
~ ➜ ssh-keygen -t rsa -N '' -f /tmp/ansiblekey <<< y
Generating public/private rsa key pair.
Your identification has been saved in /tmp/ansiblekey
Your public key has been saved in /tmp/ansiblekey.pub
The key fingerprint is:
SHA256: <random-chars> manojsh@192.168.54.24

~ ➜ #Copying public key to multipass instance
~ ➜ cat /tmp/ansiblekey.pub | multipass exec ubuntu-bionic -- tee -a .ssh/authorized_keys
```
####2.D Verify SSH to multipass instance
```{shell}
~ ➜ #List Multipass instances
➜  Installs multipass ls
Name                    State             IPv4             Image
ubuntu-bionic           Running           192.168.215.15    Ubuntu 18.04 LTS

~ ➜ #SSH into multipass instance
➜  ssh -i /tmp/ansiblekey ubuntu@192.168.215.15
The authenticity of host '192.168.215.15 (192.168.215.15)' can not be established.
ED25519 key fingerprint is <random-chars>.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@ubuntu-bionic:~$ 
```

###3. Setup the standard Ansible directory on control Node
####3.A Create an `AnsibleWorkspace` directory
```{shell}
~ ➜ #Create a directory where you can keep your playbooks, inventory and other required files.
~ ➜ mkdir AnsibleWorkspace
~ ➜ cd AnsibleWorkspace
AnsibleWorkspace ➜ ls -a
.  ..
AnsibleWorkspace ➜ 
```

####3.B Create `ansible.cfg` file
'ansible.cfg' is a main configuration file that governs the behavior of all interactions performed by the control node.

```{shell}
~ ➜ #Generating default ansible config file with all properties disabled
AnsibleWorkspace ➜ ansible-config init --disabled > ansible.cfg
```

####3.B Create inventory file
Ansible works against managed hosts that are configured in your inventory file as a list or group of lists. The default location for inventory is `/etc/ansible/hosts`, but we can override this by updating path value of `inventory` field in `ansible.cfg` file. Let's first create an inventory file for our multipass ubuntu instance.

```{shell}
AnsibleWorkspace ➜ cat > ./inventory << EOL
[webservers]
nginxserver ansible_host=192.168.215.15 ansible_user=ubuntu
EOL
```
`ansible_host` and `ansible_user` values are nothing but the IPAddress and username of your configured multipass instance; using this info ansible will connect to the multipass instance via SSH.

Please read this official [link](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html) to learn more about inventory file creation.

####3.C Update inventory and ssh-key file path in 'ansible.cfg' file
Open the ansible.cfg file and set the following values under defaults section
```{ini}
[defaults]
inventory=./inventory
private_key_file=/tmp/ansiblekey
```

####3.D Verify the Ansible Configuration
Since we have already configured inventory and private key path, we are good to verify connectivity with our multipass instance 'nginxserver'.
```{shell}
➜  AnsibleWorkspace ansible nginxserver -m ping                                            
nginxserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
```

###4. Write a playbook
Playbooks are the language by which Ansible orchestrates, configures, administers, or deploys systems. 
Let's write a playbook to setup an Nginx server.
Create `nginx-setup.yml` file in your `AnsibleWorkspace` directory with tasks to install and start an Nginx server.
```{yaml}
---
- hosts: nginxserver
  become: yes
  tasks:
    - name: Install nginx latest version on host
      apt: 
        name: nginx 
        state: latest
    
    - name: Start nginx service
      service:
          name: nginx
          state: started
```

Let's take a look at each and every part of your playbook file:

**hosts:** The name of the node or node-group configured in your inventory.
**become:** The become flag instructs ansible to connect as a root user.
**tasks:** tasks is a list of modules that we wish to run on the managed node in a specific order. Every task will include a 'name' field as well as a'module' with configurable arguments.
**apt** The [apt](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html) module will install the newest version of Nginx using the standard Ubuntu apt package manager.
**service** [service](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html) module controls services on managed node.

###5. Running your playbook
Ansible is packaged with a set of binaries, We can run an ansible playbook using the `ansible-playbook` command.

```{shell}
AnsibleWorkspace ➜ ansible-playbook nginx-setup.yaml                                                        

PLAY [nginxserver] **************************************************************

TASK [Gathering Facts] **************************************************************
ok: [nginxserver]

TASK [Install nginx latest version on host] **************************************************************
changed: [nginxserver]

TASK [Start nginx service] **************************************************************
changed: [nginxserver]

PLAY RECAP **************************************************************
nginxserver                : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```
Playbook executed without any error, and we can see it has installed and started nginx service. Now, let's verify the output, go to http://192.168.215.15 (multipass instance ip, default port 80) in your browser.

![Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4full8bidibalepgzuu.png)

###Final Words
Ansible is a straightforward yet powerful automation solution for automating your IT infrastructure. It can manage modest to large-scale systems. We can use ad-hoc commands to meet simple demands or construct complicated playbooks to set up a multi-node orchestration.
Resources to learn more about ansible:
- https://www.ansible.com/overview/how-ansible-works
- https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html
- https://youtu.be/ZAdJ7CdN7DY
- https://spacelift.io/blog/ansible-tutorial