Deploying With Vagrant, Provisioning With Ansible

As I mentioned in a previous post I’m preparing for the RedHat’s ex294 exam in order to get the RHCE certification before my RHCSA expires. I bought a book about ansible, and did all of the exercises, now it’s time to face the exam simulation, but for that, I need several vms.

I used several VirtualBox VMs to do the exercises, I created one and made a couple of linked copies but, the second copied generated a new snapshot, despite there were no changes on the original machine between both copies.

Then I remembered a tool I used on the FreeIPA Workshop which allowed me to deploy the base servers for the workshop with a single command:

vagrant up

I searched about and found the Vagrant’s project page by Hashicorp. vagrantup.com screenshot It’s simple but clear, and that was what I wanted, deploying development environments in a easy way.

Getting Started

The next step was clear: going to the Get Started tutorial.

The tutorial was composed of 12 parts and a about 20 minutes long. That was an estimation based on word count, it took me a bit more, but I wasn’t following it step by step, but adapting it to my goal.

I’m not going to reproduce every step of the tutorial here, if you are interested, click the aforementioned link, but after issuing the vagrant init command, I got a Vagrantfile initialized with almost every line commented out.

Next step was to change the base image, so I went to the box search page and searched for a CentOS 8 image, as that was the requirement for the sample exam. I found one called centos/8, but it wasn’t an official image, but the user tair pointed to the official CentOS repo so I used the official image’s url, please note that Hashicorp is not checking the images or the users' claims of being the official providers.

config.vm.box = "official-centos-8"
config.vm.box_url = "https://cloud.centos.org/centos/8/vagrant/x86_64/images/CentOS-8-Vagrant-8.3.2011-20201204.2.x86_64.vagrant-virtualbox.box"

Then, as my goal was to set up several vms, I searched for how to do it, and the solution was quite simple: a loop. Fortunately, looping is well explained on vagrant documentation, also the variable inheritance.

(1..4).each do |i|
    config.vm.define "node#{i}" do |node|

I also wanted the VMs to be part of the internal network which I had my control node connected to, a special directive on the network section allowed me to specify its name:

node.vm.network "private_network", ip: "10.200.200.10#{i}",
    virtualbox__intnet: "ansiblenet"

At this point I had my new machines connected to the old one, great!

There were another settings available, like the allocated memory and virtual cpus or the hostname. The complete Vagrantfile is posted below.

Provisioning

One of the requirements for the sample exam was having the nodes accesible by SSH, using the root user and without being prompted for a password. It was time for a provisioning script.

At first I was tempted to use a bash script to create root’s authorized_keys file, but one of the provisioners available was ansible, and the goal of this deployment is to practice with ansible, so I grasped the opportunity and wrote a very simple playbook.

---
- name: Vagrant provisioning
  hosts: all
  become: true
  become_method: sudo
  tasks:
   - name: setup roots ssh key
     authorized_key:
       user: root
       key: "{{ lookup('file', './keys/root-id_rsa.pub') }}"

And put it on a folder with the public key in order to keep all things clear:

provisioning/
├── keys
│   └── root-id_rsa.pub
└── provisioning.yml

1 directory, 2 files

Then I had all I needed for the test exam, I ran out of excuses, it was time to face it.

The complete Vagrant file

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

Vagrant.configure("2") do |config|
  # An alias for the image and the image's url.
  config.vm.box = "official-centos-8"
  config.vm.box_url = "https://cloud.centos.org/centos/8/vagrant/x86_64/images/CentOS-8-Vagrant-8.3.2011-20201204.2.x86_64.vagrant-virtualbox.box"

  # Specifying the provisioner
  config.vm.provision :ansible do |ansible|
    ansible.playbook = "provisioning/provisioning.yml"
  end

  (1..4).each do |i|
    config.vm.define "node#{i}" do |node|
      # Configuring the network, the virtualbox__intnet specifies
      # the internal network name
      node.vm.network "private_network", ip: "10.200.200.10#{i}",
        virtualbox__intnet: "ansiblenet"

      node.vm.provider "virtualbox" do |vb|
        # Use linked images instead of copying the base for
        # each vm
        vb.linked_clone = true

        # Display the VirtualBox GUI when booting the machine
        #vb.gui = true

        # Set up the VM's name
        vb.name = "vagrant_node#{i}"

        # Don't check for guest additions
        vb.check_guest_additions = false
    
        # Customize the amount of memory on the VM:
        vb.memory = "2048"
        # Customize the amount of vcpus
        vb.cpus = "2"
      end
    end
  end
end