This is the third part of the guide on sandboxing Ansible. It focuses on using the sample vagrant file to bring up the dev environment.
What is Vagrant?
Vagrant is a way of automating VM provisioning, OS provisioning, network provisioning, and so much more. According to the Vagrant folks,”Vagrant is a tool for building complete development environments. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases development/production parity, and makes the ‘works on my machine’ excuse a relic of the past.”
This guide utilizes Vagrant to provide the means to automate the sandbox in a repeatable fashion to reduce inconsistencies and save time. We are also using Vagrant to provide folder syncing so that we can use the tools on our host machine for authoring and editing Ansible playbooks.
Lastly it makes the sandbox ‘disposable’. The Vagrantfile describes the sandbox and uses ‘vagrant up’ to bring it into existence. But just as easily, typing ‘vagrant destroy’ destroys the infrastructure.
Verify the Setup
First, you will want to make sure things are working before going any further. Make sure each of these items are complete:
- VirtualBox installed
- Vagrant Installed
- A compatible SSH and Rsync client is installed (ideally the Cygwin packages)
- Git is installed
- Downloaded the .gitignore and sample Vagrantfile
- Setup a Git repository
Even if you have completed those installs, run a couple of quick commands to at least test if they have been added to your path by opening PowerShell and typing each of the following:
rsync ssh vagrant git
If none of those throw errors related to an unknown command, then you are in decent shape. Generally the only issues people run into on Windows are related to Vagrant (specifically SSH and folder syncing). Again, I do have a script that sets it all up which you can find here. For additionally troubleshooting, read my post here .
Inspecting the Vagrantfile
If you were starting from scratch, meaning you are not using a sample Vagrantfile, the very first thing that you would do is a ‘vagrant init’ command. This creates a sample Vagrantfile — the file which is key to understanding Vagrant.
This is not going to be a comprehensive guide on Vagrantfiles, but we’ll get into the basics.
Let’s just see what the default Vagrantfile looks like.
Now open the ‘Vagrantfile’ in a code editor, change the language to Ruby and you will see a pile of commented-out code
You will also notice in Explorer that there are new files
These will eventually house nearly all information regarding those VMs. This is not information you want to track in source control. That’s why the .gitignore file you downloaded earlier excludes everything in the .vagrant folder.
There are a whole lot of things you can configure in a Vagrantfile. To see all of the options, just head to the Vagrant website.
Let’s look at our sample Vagrantfile to see how it’s used to provision our Ansible control server
I’ll go line-by-line:
7. This starts the stanza which defines a new VM. The VM can be referenced by Vagrant by the name “control”. This is not the hostname.
8. Specifies the Vagrant ‘Box’ which we’ll be using. This is more or less the image that will be used for the VM. The boxes can be stored/created locally (by Packer) or pulled from the Vagrant Box repository.
9. Specifies the hostname of the VM
10. Folders can be synced between the host and the guest. This allows you to use dev tools on your host to interact with the guest VMs. This works great for editing code that will live on the guest. The format is: “source”, “destination”. It can use relative paths on the host system, which is what I’m doing here. I use ‘\\’ because of character escape and Windows using the ‘\’ for paths. Documentation on folder syncing can be found here.
11. This is the network configuration. In order to be isolated but still let my host talk to the VMs, I used a “private network”. In VirtualBox this is called a host-only adapter. In addition to the host, all the devices utilizing that host-only adapter will be able to talk to each other. This is perfect for an Ansible setup. You can either use DHCP or assign addresses statically. I used static addresses. More documentation can be found here.
12-16. This is called provisioning. These are the post OS deployment steps. In can be used for adding new user accounts, installing software, creating folders, changing permissions, etc… “Shell” is provisioner which I chose for simplicity. There are many different options, such as Chef, Puppet, Ansible, etc… Meaning if you have existing configuration management utilities, you can probably use them for this. This simply adds the epel repository (required to install Ansible), installs Ansible, and then tree (not required, but it’s nice).
17-19. This configures the provider (the underlying Hypervisor) itself. I simply specify the provider, the amount of memory, and that I do not want to see the VirtualBox console window when it starts.
Let’s get to the fun stuff. Go to the folder with the Vagrantfile and .gitignore file which you downloaded in Part 2. It provisions four different nodes. As long as you are in a directory with a Vagrantfile, Vagrant will have something to work off of. So let’s start by running the command ‘vagrant status’
Vagrant will parse the file and see that there are four VMs to create. Let’s go ahead and just provision one of the nodes. Type
vagrant up control
It will take a little while the first time you run the command because it will need to download the CentOS Box from the repository. It will be significantly faster going forward. However, once it downloads the box, it will import it and then fail immediately.
This is because the Vagrantfile is parsed and sees that the Vagrantfile specifies a folder to sync to the guest, but the folder does not exist on the host. Go ahead and make the directory (you will use it later) and type ‘vagrant up control’ again
This time it worked. It imports the box, sets up all of the networking, inserts an SSH key, and begins to provision the node. This will do a few things, including installing the software we specified in the provisioning stanza of the Vagrantfile. If you get to this point, you are in great shape
Let’s check the status of Vagrant now by doing ‘vagrant status’
Now let’s try to actually interact with the VM by typing
vagrant ssh control
And if you poke around a bit
We could start playing around with Ansible at this point, but let’s not get ahead of ourselves
Now type ‘exit’ to quit the SSH session and go back to PowerShell. This VM should be reachable from our host box, which is a benefit of doing a host-only adapter. However, when I tried to ping the node, it timed out. So what gives?
I double-checked the Vagranfile and everything looked right. So I used ‘vagrant ssh control’ to get back into the node. (this works because it is not SSHing into that 192.168.33.5 address, but rather 127.0.0.1 with port forwarding rules, which you can see if you look at the initial ‘vagrant up’).
I checked out the interfaces with ‘ip addr’
Ignore eth0, eth1 is the interface which should have the IP address which you assign. Unfortunately it didn’t get any IP.
You can tell Vagrant to re-run through the Vagrantfile to make sure it was correctly provisioned. That’s what we’ll do in this case
vagrant reload control
And let’s try again
Looks like that fixed it. Let’s ping it just to make sure everything is in working order
As mentioned a few times in this guide, Vagrant makes it very easy to sync multiple folders across hosts and guests. Earlier we had to create the folder to sync to the guest. Let’s see how this actually works.
We’ll create a new file on our Windows host box. I’ll use VS Code to create a file within the ‘ansible_data’ called ‘inventory’
This will obviously show up in Windows Explorer
But what does it look like in the Ansible VM? Let’s check it out with vi.
No surprises there. The syncing is nearly instantaneous and works in both directions. Let’s add a line in vi
and then view it on our host
More Vagrant Up
Alright, so we have the Ansible control server. That wasn’t bad, but now we have to still bring up all of the others *sigh*
Yes, but it’s incredibly easy. Remember why the first ‘vagrant up’ failed? The web server nodes also have a synced folder. Add that directory in root of this repository — it’s called ‘web_data’.
Now rather than running ‘vagrant up ‘, just type
This will bring up all of the nodes at once. Let that run for a few minutes and they should all complete.
Type ‘vagrant status’ to verify
And there you have it — four virtual machines all on the same network as each other.
Now, to pause all of the VMs, type
Or type ‘vagrant suspend <name>’ to pause a single VM like so
As it mentions, ‘vagrant up’ will resume the VM(s).
As mentioned in the requirements, I do not want to care about the infrastructure I create for a sandbox. Vagrant caters to that sentiment very well.
vagrant destroy -f
to destroy all VMs defined in the Vagrantfile (the -f forces it without asking for confirmation).
Alternatively you can call out the specific VM like so
Both Ansible files and the Vagrantfile are written in declarative languages. They are just text files. As such, they can be added to Git. This means the modification to your infrastructure is documented, tracked, mobile, and easily reversible.
And with folder syncing, you can develop infrastructure by writing Ansible config files from your host box using your tools. These changes will be reflected immediately on the Ansible control server, and can be deployed to your nodes in an instant.
Not only that, but it becomes very easy to test your configuration management. Pull down the Git repository and your Vagrantfile, and you have it all right there; you have an automated test environment that can easily resemble your production environment and you have your Ansible playbooks (we’ll get to that in part 4) ready to test configurations against that infrastructure.
This gets very powerful — very fast.
Up Next – Part 4: Ansible
In Part 4, we’ll finally get to Ansible. It will cover folder structure, inventories, variables, playbooks, and roles.