Ansible Lab setup with Vagrant
Updated:
Introduction
Ansible is an open-source, powerful, and simple tool for client-server and network device automation. Ansible is agent-less, which means nothing to install on a client only Python is installed and SSH is enabled on the remote host.
How Ansible Works:- Ansible will do the following.
- Generate a Python script
- Copy the script to the remote node
- Execute the script on a remote node
- Wait for the script to complete execution on all hosts
- Remove the script from the remote node
Ansible will then move to the next task in the list, and go through these same steps. It’s important to note the following:
- Ansible runs each task in parallel across all hosts.
- Ansible waits until all hosts have completed a task before moving to the next task.
- Ansible runs the tasks in the order that you specify them.
Ansible Installation
In this blog, we will create a lab environment using Vagrant.
Control node requirement
For the control node, you can use any machine with Python 2.7 or Python 3.5 (or higher) installed. The Ansible installation is simple and depends on the OS of your control node, see Ansible document for installation.
Managed node requirement
For managed nodes, Ansible makes a connection over SSH, Python and SSH client is required.
Requirements of this lab
- VMware or Virtual box
- Vagrant
Using Vagrant to set up a testing lab
Vagrant is an excellent open-source tool for managing virtual machines. You can use Vagrant to boot a Linux virtual machine inside your laptop, and you can use that as a test server.
I’m using Vagrant for my lab set-up, the process is simple as below:
-
Go to the Vagrant website, download the vagrant, and install it on your machine. For more details see Introduction to Vagrant and Quick Start Guide.
-
Download Vagrant file.
Create a directory in your machine and copy the vagrant file from the repo. In my case, I, create a directory in Document, named lab (name can be anything). Open Powershell/Bash and navigate to the lab directory and boot the Vagrant.
To boot the vagrant devices
vagrant up
will create and boot the below devices.
- centos01
- ubuntu01
Command after booting to check the status of devices:
╭─$ ~/Desktop/lab
╰─➤ vagrant status
Current machine states:
centos01 running (virtualbox)
ubuntu01 running (virtualbox)
This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
Use vagrant ssh ubuntu01
command to ssh into a device and check ping to the other device.
See Permission Denied guide on StackOverflow to setup ssh connection.
Configuring Ansible Client
I have two Vagrant hosts ubuntu01, centos01 and Ansible control node(my pc). On the control node, edit the host’s file for IP to name resolution.
sudo nano /etc/hosts
After opening the file add below IP and hostname.
192.168.56.10 centos01
192.168.56.11 ubuntu01
Create an SSH key on Ansible control node as below and accept the defaults.
ssh-keygen
list the keys to verify with the ls .ssh command, and copy the key to the client’s machine.
ssh-copy-id -i .ssh/id_rsa.pub vagrant@ubuntu01
ssh-copy-id -i .ssh/id_rsa.pub vagrant@centos01
Now ssh to Ubuntu01, and configure the managed host, so that it doesn’t require a password to get sudo level access.
ssh vagrant@ubuntu01
sudo visudo
Go to the bottom of the file and add this line as below:
vagrant ALL=(ALL) NOPASSWD: ALL
Also, configure centos so that it doesn’t require a password to get root-level access.
ssh vagrant@centos01
su -
sudo visudo
Go to the bottom of the file and add this line as below:
vagrant ALL=(ALL) NOPASSWD: ALL
Ansible installation on Ubuntu
- Create a virtual environment
╭─$ ~
╰─➤ virtualenv ansible2.9
created virtual environment CPython3.8.10.final.0-64 in 2567ms
creator CPython3Posix(dest=/home/syd/ansible2.9, clear=False, no_vcs_ignore=False, global=False)
seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/syd/.local/share/virtualenv)
added seed packages: pip==22.1.2, setuptools==63.1.0, wheel==0.37.1
activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
- Activate the environment.
╭─$ ~
╰─➤ source ansible2.9/bin/activate
(ansible2.9) ╭─$ ~
╰─➤
- Upgrade pip
(ansible2.9) ╭─$ ~
╰─➤ pip list
Package Version
---------- -------
pip 22.1.2
setuptools 63.1.0
wheel 0.37.1
[notice] A new release of pip available: 22.1.2 -> 22.2.2
[notice] To update, run: pip install --upgrade pip
(ansible2.9) ╭─$ ~
╰─➤ pip install --upgrade pip
Requirement already satisfied: pip in ./ansible2.9/lib/python3.8/site-packages (22.1.2)
Collecting pip
Using cached pip-22.2.2-py3-none-any.whl (2.0 MB)
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 22.1.2
Uninstalling pip-22.1.2:
Successfully uninstalled pip-22.1.2
Successfully installed pip-22.2.2
(ansible2.9) ╭─$ ~
╰─➤ pip list
Package Version
---------- -------
pip 22.2.2
setuptools 63.1.0
wheel 0.37.1
- Install Ansible.
(ansible2.9) ╭─$ ~
╰─➤ pip install ansible==2.9.9
Collecting ansible==2.9.9
Downloading ansible-2.9.9.tar.gz (14.2 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.2/14.2 MB 374.5 kB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Collecting jinja2
Downloading Jinja2-3.1.2-py3-none-any.whl (133 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.1/133.1 kB 69.9 kB/s eta 0:00:00
Collecting PyYAML
Downloading PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (701 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 701.2/701.2 kB 194.6 kB/s eta 0:00:00
Collecting cryptography
Downloading cryptography-37.0.4-cp36-abi3-manylinux_2_24_x86_64.whl (4.1 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.1/4.1 MB 215.1 kB/s eta 0:00:00
Collecting cffi>=1.12
Downloading cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (442 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 442.7/442.7 kB 253.7 kB/s eta 0:00:00
Collecting MarkupSafe>=2.0
Downloading MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB)
Collecting pycparser
Downloading pycparser-2.21-py2.py3-none-any.whl (118 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 118.7/118.7 kB 143.3 kB/s eta 0:00:00
Building wheels for collected packages: ansible
Building wheel for ansible (setup.py) ... done
Created wheel for ansible: filename=ansible-2.9.9-py3-none-any.whl size=16168980 sha256=95256af318d09dbee7bbe604a228af5f82ff2e14d4172b62bdb90d2b78407a0f
Stored in directory: /home/syd/.cache/pip/wheels/50/cb/af/4945f05738b88f4d5c273e7e2690e832e1fa9edb8461c2b53c
Successfully built ansible
Installing collected packages: PyYAML, pycparser, MarkupSafe, jinja2, cffi, cryptography, ansible
Successfully installed MarkupSafe-2.1.1 PyYAML-6.0 ansible-2.9.9 cffi-1.15.1 cryptography-37.0.4 jinja2-3.1.2 pycparser-2.21
(ansible2.9) ╭─$ ~
╰─➤ ansible --version
ansible 2.9.9
config file = None
configured module search path = ['/home/syd/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/syd/ansible2.9/lib/python3.8/site-packages/ansible
executable location = /home/syd/ansible2.9/bin/ansible
python version = 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0]
To test Ansible installation, run the below command:
$ ansible localhost -m ping
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
Ansible Configuration Set-Up
Ansible configuration/inventory files define setting/managed nodes that ad-hoc commands/playbooks can be run against. I’m creating ansible.cfg/hosts files in the ansible default location (/etc/ansible).
sudo mkdir /etc/ansible
sudo nano /etc/ansible/ansible.cfg
In ansible.cfg we define the location of the inventory file which will be used for this project as follows.
[defaults]
inventory = ./hosts
Create groups and add hosts to the group.
[ubuntu]
ubuntu01
[centos]
centos01
[linux:children]
ubuntu
centos
[linux:vars]
ansible_usr=vagrant
The lab setup is now completed.
Introduction to ad hoc commands
An Ansible ad hoc command is a command-line tool to automate a single task on one or more managed nodes. Ad hoc commands are quick and easy, but they are not reusable. Ad hoc commands demonstrate the simplicity and power of Ansible. Ad-hoc system interaction is a powerful and useful tool but some limitations exist.
$ ansible -m ping all
centos01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ubuntu01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
$ ansible all -a 'whoami'
centos01 | CHANGED | rc=0 >>
vagrant
ubuntu01 | CHANGED | rc=0 >>
vagrant
Elevate to root with -b for become. Why? Because Ansible doesn’t elevate the sudo privilege by default.
ansible all -b -a 'whoami'
ubuntu01 | CHANGED | rc=0 >>
root
centos01 | CHANGED | rc=0 >>
root
Some examples of ad-hoc commands are below:
- ansible all -a “uptime”
- ansible all -a “whoami”
- ansible all -b -a “whoami”
If you do not specify the -m (module), the default command module will run.
ansible all -m command -a 'echo Ansible is fun with Vagrant'
centos01 | CHANGED | rc=0 >>
Ansible is fun with Vagrant
ubuntu01 | CHANGED | rc=0 >>
Ansible is fun with Vagrant
It’s a basic command, but a little to explain, the command does the following:
• First, we specify all, so the command will be run across all the inventory we list.
• The -m option is then provided to allow us to specify a module we can use.
• Finally, we specify the -a option allows us to provide arguments to the shell module, we are simply running an echo command to print the output “Ansible is fun”
If I, remove the -m command from the above ad-hoc command it will also work because ansible uses the command module by default.
Playbook Examples
---
- name: PLAYBOOK-1
hosts: linux
tasks:
- name: A UNAME???
shell: uname -a > /home/vagrant/res.txt
- name: B WHOAMI???
shell: whoami >> /home/vagrant/res.txt
$ ansible-playbook playbook-1.yaml
PLAY [PLAYBOOK-1] ***************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [centos01]
ok: [ubuntu01]
TASK [A UNAME???] ***************************************************************************************************
changed: [centos01]
changed: [ubuntu01]
TASK [B WHOAMI???] **************************************************************************************************
changed: [ubuntu01]
changed: [centos01]
PLAY RECAP **********************************************************************************************************
centos01 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ubuntu01 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Running Multiple Plays
A playbook can have multiple plays and each play can in turn contains multiple tasks.
---
- name: Play-book to install packages
hosts: ubuntu
become: true
tasks:
- name: Install git on ubuntu
apt:
name: git
state: present
- name: Play-2....
hosts: centos
become: true
tasks:
- name: Install git on centos
yum:
name: git
state: present
ansible-playbook playbook-4.yml
PLAY [Play-1... ubuntu] *********************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [ubuntu01]
TASK [Install git on ubuntu] ****************************************************************************************
ok: [ubuntu01]
PLAY [Play-2... centos] *********************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [centos01]
TASK [Install git on centos] ****************************************************************************************
changed: [centos01]
PLAY RECAP **********************************************************************************************************
centos01 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ubuntu01 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Thanks, for reading.
Comments