Set up an Ansible lab in 20 minutes

Build an environment to support learning and experimenting with new software.
99 readers like this.
Science lab with beakers

Being able to build and tear down a public cloud environment is very useful, but most of us don’t have easy access to a public cloud. The next best thing would be to have a lab on your local machine, but even running on a local machine brings performance, flexibility, and other challenges. Most of the time, the additional workloads on our local machines interfere with doing our daily job, and they certainly prevent having a readily available environment to play and experiment with new software.

My team and I encountered this challenge a few years ago when we were starting to learn Ansible. We couldn’t find an environment that we could use individually, and our frustration with the situation caused some of us to stop experimenting. We knew we needed to find a solution.

We spent a lot of time researching the options and came up with a set of tools that enable our curiosity to learn in an environment we fully control. We can spin up and tear down the lab environment on our local machines without needing access to on-premises labs or public clouds.

This article will explain how to deploy your own lab environment on your local machine in as little as 20 minutes in a fully automated way.

You can find all the code for this exercise in my GitHub repository.

Tools and software

This solution uses the following tools and software:

  • Ansible is our automation tool of choice because it’s easy to use and flexible enough to handle the lab requirements.
  • Vagrant is easy to use for building and maintaining virtual machines.
  • VirtualBox is a hosted hypervisor that works in Windows and Linux environments.
  • Fedora v30+ is the operating system on my local machine.

You must have the following set up to build the environment:

  • An internet connection
  • Virtualization Technology support enabled in your BIOS (here is the procedure for my Lenovo laptop)
  • Vagrant v2.2.9
  • The latest version of Ansible
  • The latest version of VirtualBox
  • Fedora v30+ host operating system

What’s in the lab environment?

This project aims to deploy an Ansible host with an Ansible engine and multiple Linux nodes along with some pre-loaded and pre-configured applications (httpd and MySQL). It also enables Cockpit so that you can monitor the status of the virtual machines (VMs) during testing. The reason to use a pre-deployed application is for efficiency (so you don’t have to spend time installing those components). This allows you to focus on creating roles and playbooks and testing against the environments deployed by the tools listed above.

We determined that the best scenario for our use case was a multi-machine Vagrant environment. The Vagrantfile creates three CentOS VMs to simulate two target hosts and an Ansible control machine:

  • Host1: No graphical user interface (GUI), with httpd and MySQL installed
  • Host2: No GUI, with httpd and MySQL installed
  • Ansible-host: No GUI, with Ansible engine installed

Enable multiple hypervisors

Some hypervisors may not allow you to bring up VMs if more than one hypervisor is in use. To fix this problem, follow these steps (based on Vagrant’s installation instructions).

First, find out the name of the hypervisor:

$ lsmod | grep kvm
kvm_intel             204800  6
kvm                   593920  1 kvm_intel
irqbypass              16384  1 kvm

The one I’m interested in is kvm_intel, but you might want another (such as kvm_amd).

Run the following as root to blacklist the hypervisor:

$ echo 'blacklist kvm-intel' >> /etc/modprobe.d/blacklist.conf

Restart your machine and try running Vagrant again.

The Vagrant file

cat Vagrantfile 
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
# Define VMs with static private IP addresses, vcpu, memory and vagrant-box.
  boxes = [
    {
      :name => "web1.demo.com", ⇒ Host1 this is one of the target nodes
      :box => "centos/8",	      ⇒ OS version 
      :ram => 1024,		      ⇒ Allocated memory
      :vcpu => 1,               ⇒  Allocated CPU
      :ip => "192.168.29.2"     ⇒ Allocated IP address of the node
    },
    {
      :name => "web2.demo.com", ⇒ Host2 this is one of the target nodes
      :box => "centos/8",
      :ram => 1024,
      :vcpu => 1,
      :ip => "192.168.29.3"
    },
    {
      :name => "ansible-host", ⇒ Ansible Host with Ansible Engine
      :box => "centos/8",
      :ram => 8048,
      :vcpu => 1,
      :ip => "192.168.29.4"
    }
  ]

  # Provision each of the VMs.
  boxes.each do |opts|
    config.vm.define opts[:name] do |config|
#   Only Enable this if you are connecting to Proxy server
#      config.proxy.http    = "http://usernam:password@x.y:80"⇒ Needed if you have a proxy
#      config.proxy.https   = "http://usernam:password@x.y:80"
#      config.proxy.no_proxy = "localhost,127.0.0.1"
      config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
      config.ssh.insert_key = false
      config.vm.box = opts[:box]
      config.vm.hostname = opts[:name]
      config.vm.provider :virtualbox do |v| ⇒  Defines the vagrant provider
        v.memory = opts[:ram]
        v.cpus = opts[:vcpu]
      end
      config.vm.network :private_network, ip: opts[:ip]
      config.vm.provision :file do |file|
         file.source     = './keys/vagrant' ⇒ vagrant keys to allow access to the nodes
         file.destination    = '/tmp/vagrant' ⇒ the location to copy the vagrant key
      end
      config.vm.provision :shell, path: "bootstrap-node.sh" ⇒ script that copy hosts entry
      config.vm.provision :ansible do |ansible| ⇒ declaration to run ansible playbook
        ansible.verbose = "v"
        ansible.playbook = "playbook.yml" ⇒ the playbook used to configure the hosts
      end
        end
  end
end

These are the important files that you need to pay attention to:

  • inventory-test.yaml: The inventory file to connect to the nodes
  • playbook.yaml: The playbook file that Vagrant provisioner calls to configure the nodes
  • Vagrantfile: The file that Vagrant uses to deploy the environment
  • vagrant keys: The Vagrant keys for connecting to the nodes in your lab environment

You can adjust these files based on your needs. Ansible’s flexibility gives you the power to declaratively change your environment as you require.

Deploy your lab environment

First, clone the code from the GitHub repo:

$ git clone https://github.com/mikecali/ansible-labs-101.git
Cloning into 'ansible-labs-101'...
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 15 (delta 2), reused 10 (delta 0), pack-reused 0
Unpacking objects: 100% (15/15), 6.82 KiB | 634.00 KiB/s, done.

Next, change your directory to vagrant-session-2, and view its contents:

$ ls
Bootstrap-node.sh   inventory   keys   playbook.yml   README.md Vagrantfile

You now have all the artifacts and configuration files you need for your lab environment. To deploy your environment, run:

$ vagrant up

With a decent internet connection, it takes only about 20 minutes to get a running environment:

$ vagrant up
Bringing machine 'web1.demo.com' up with 'virtualbox' provider...
Bringing machine 'web2.demo.com' up with 'virtualbox' provider...
Bringing machine 'ansible-host' up with 'virtualbox' provider...
==> web1.demo.com: Importing base box 'centos/8'...
==> web1.demo.com: Matching MAC address for NAT networking...
==> web1.demo.com: Checking if box 'centos/8' version '1905.1' is up to date...
==> web1.demo.com: Setting the name of the VM: ansible-labs_web1democom_1606434176593_70913
==> web1.demo.com: Clearing any previously set network interfaces...
==> web1.demo.com: Preparing network interfaces based on configuration...
    web1.demo.com: Adapter 1: nat
    web1.demo.com: Adapter 2: hostonly
==> web1.demo.com: Forwarding ports...
    web1.demo.com: 22 (guest) => 2222 (host) (adapter 1)
==> web1.demo.com: Running 'pre-boot' VM customizations...
==> web1.demo.com: Booting VM...
==> web1.demo.com: Waiting for machine to boot. This may take a few minutes...
    web1.demo.com: SSH address: 127.0.0.1:2222
    web1.demo.com: SSH username: vagrant
    web1.demo.com: SSH auth method: private key
[...]

Once the playbook execution completes, you will see output like this:

PLAY RECAP *********************************
Ansible-host     : ok=20 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=3

Real 18m14.288s
User 2m26.978s
Sys 0m26.849s

Verify that all VMs are running:

$ vagrant status
Current machine states:

Web1.demo.com    running (virtualbox)
Web2.demo.com    running (virtualbox)
ansible-host     running (virtualbox)
[...]

You can investigate further by logging into one of the VMs. Access the ansible-host:

> vagrant ssh ansible-host
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Thu Nov 26 12:21:23 2020 from 10.0.2.2
[vagrant@ansible-host ~] uptime
16:46:42 up 1:24, 1 user, load average: 0.00, 0.01, 0.04

Finally, you can use the Ansible module to ping the other nodes you created:

[vagrant@ansible-host]$ ansible -i inventory-test.yaml \
webservers -m ping -u vagrant
192.168.29.2 | SUCCESS => {
  "Ansible-facts": {
      "Discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "Changed": false;
    "Ping": "pong"
}
[...]

Clean up

Clean up your environment by running:

$ vagrant destroy [vagrant machine name]

Your output will look like this:

Get creative to learn

Learning software like Ansible on your own time in your own lab is a good habit, but it can be difficult because of constraints that are out of your control.

Sometimes, you need to get creative and find another way. There are many options in the open source community you can choose from; one of the main reasons we picked these tools is because they are commonly used and familiar to many people.

Also, please note that these playbooks are not as optimized as I want. Please feel free to improve them and share your work in the comments.

What to read next

My first day using Ansible

A sysadmin shares information and advice about putting Ansible into real-world use configuring computers on his network.

Tags
ID
Mike Calizo is the Principal Customer Success Manager of Elastic.co focused on government customers and is based in Canberra, Australia. Mike believes that "data is power" and harnessing this power can improve organizations to leverage their own insights to differentiate through innovation and drive efficiencies with cost optimization strategies.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.