Vagrant provides a solution for creating disposable and consistent environments, all within a single configuration file.
In the context of IT operations, Vagrant provides a solution for creating disposable environments that maintain consistency between platforms and virtual environments. One of the great features of Vagrant is the ability to configure entire environments in code within a single configuration file (Vagrantfile). This means that with one command, “vagrant up”, you can bring multiple virtual machines up at once, and even with their own private networking.
In this article, I will take you through the process of using configurations in Vagrant to create and deploy a small Puppet test environment, similar to my previous article. Ironically, you can actually use Puppet (or other configuration management solutions) to apply configurations to your Vagrant environment instead of writing your code in Vagrant, which is a more common use case. For the scope of this article, I will be using shell scripts instead.
Getting VMs Started
In this environment, we have the Puppet master and two Puppet agents, so three virtual machines altogether. I will use host files within each VM instead of DNS so that they can find each other via hostname.
Hostname | Role | IP Address |
puppet | Puppet master | 192.168.10.21 |
puppetagent-1 | Puppet agent | 192.168.10.22 |
puppetagent-2 | Puppet agent | 192.168.10.23 |
Creating the Vagrantfile
So I have created a Vagrant project named “puppet”, which is just a directory on my file system. I create a Vagrantfile and will insert my code.
Dans-MacBook-Pro:puppet dan$ pwd
/Users/dan/puppet
Dans-MacBook-Pro:puppet dan$ touch Vagrantfile
In my Vagrantfile, I specify a configuration for each of my three VMs. First, let’s look at the Puppet Master config (named “puppet”):
config.vm.define "puppet" do |puppet|
puppet.vm.box = "bento/centos-7.2"
puppet.vm.network "private_network", ip: "192.168.10.21"
puppet.vm.hostname = "puppet"
puppet.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "4096"]
vb.customize ["modifyvm", :id, "--cpus", "2"]
end
puppet.vm.provision "shell", inline: <<-SHELL
sudo echo "192.168.10.22 puppetagent-1" | sudo tee -a /etc/hosts
sudo echo "192.168.10.23 puppetagent-2" | sudo tee -a /etc/hosts
sudo systemctl enable firewalld
sudo systemctl start firewalld
sudo firewall-cmd --permanent --zone=public --add-port=8140/tcp
sudo yum -y install ntp
sudo timedatectl set-timezone America/New_York
sudo systemctl start ntpd
sudo firewall-cmd --add-service=ntp --permanent
sudo rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
sudo yum -y install puppetserver
sudo touch /etc/puppetlabs/puppet/autosign.conf
sudo echo "*" | sudo tee -a /etc/puppetlabs/puppet/autosign.conf
sudo firewall-cmd --reload
sudo systemctl enable puppetserver
sudo systemctl start puppetserver
SHELL
end
First, we specify that the Vagrant box will be “bento/centos-7.2” (which is the same for the other virtual machines as well). Next, we specify we want a private network NIC and an IP of 192.168.10.21. The private network is important because that allows the virtual machines to communicate with each other. Since I am using Virtualbox as my provider, I specify to change the CPU and memory. This is actually necessary for the Puppet Master to operate by default. Lastly, I set that when the VM is provisioned (runs for the first time or with –provision) it will run a shell script. The shell script does the following:
- Set the hosts file so that the Puppet Master can find the other nodes by name
- Enables the firewall for port 8140
- Installs and configures NTP to EST
- Installs Puppet server and allows any node to have its certificate signed automatically
The other two virtual machines, puppetagent-1 and puppetagent-2, have almost the same configuration; the only difference is that their hostname and IP address is different, for obvious reasons:
config.vm.define "puppetagent-1" do |puppetagent1|
puppetagent1.vm.box = "bento/centos-7.2"
puppetagent1.vm.network "private_network", ip: "192.168.10.22"
puppetagent1.vm.hostname = "puppetagent-1"
puppetagent1.vm.provision "shell", inline: <<-SHELL
sudo echo "192.168.10.21 puppet" | sudo tee -a /etc/hosts
sudo timedatectl set-timezone America/New_York
sudo rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
sudo yum -y install puppet-agent
sudo /opt/puppetlabs/bin/puppet agent --test
SHELL
end
config.vm.define "puppetagent-2" do |puppetagent2|
puppetagent2.vm.box = "bento/centos-7.2"
puppetagent2.vm.network "private_network", ip: "192.168.10.23"
puppetagent2.vm.hostname = "puppetagent-2"
puppetagent2.vm.provision "shell", inline: <<-SHELL
sudo echo "192.168.10.21 puppet" | sudo tee -a /etc/hosts
sudo timedatectl set-timezone America/New_York
sudo rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
sudo yum -y install puppet-agent
sudo /opt/puppetlabs/bin/puppet agent --test
SHELL
end
Both nodes also run the same shell script which does the following:
- Adds “puppet” to its hosts file
- Sets the time zone to EST
- Installs Puppet agent
- Runs the “puppet agent –test” command which officially makes it a Puppet node
Pretty simple, right? While Vagrant is written in Ruby, it is certainly not necessary to know that language in order to use it, as it is very intuitive. To get the complete Vagrantfile used in this article, click here.
Read: Installing Your First Vagrant Box
Vagrant up
Now it is time to bring up our Puppet test environment for the first time. Keep in mind that unless you have the bentos/centos-7.2 box already on your local computer, Vagrant will download it first and then bring up the virtual machines. Depending on your Internet connection speed, this may take a little while. With my bentos/centos-7.2 box already installed, my Macbook takes about 3-4 minutes to get this environment up.
Dans-MacBook-Pro:puppet dan$ vagrant up
Bringing machine 'puppet' up with 'virtualbox' provider...
Bringing machine 'puppetagent-1' up with 'virtualbox' provider...
Bringing machine 'puppetagent-2' up with 'virtualbox' provider...
==> puppet: Importing base box 'bento/centos-7.2'...
I will not show the entire output because it is quite long, but click here to view it.
Managing multiple machines
When you have multiple machines in one Vagrant project, you do have to use the CLI a bit differently. For instance, to gracefully shut down puppetagent-1 I would run:
Dans-MacBook-Pro:puppet dan$ vagrant halt puppetagent-1
This is slightly different than using just one virtual machine in a project. In the case of using only one machine, you can just run vagrant halt without specifying the name. When using multiple machines, vagrant halt would shut down all virtual machines if no name is specified. The same applies to the rest of the standard commands such as vagrant up, status, destroy etc.
Conclusion
While bringing up a Puppet test environment in Vagrant is actually pretty simple, you can see how Vagrant is great for bringing up applications in a test environment as well. In addition, Vagrant plugs right into configuration management solutions like Ansible and Chef, so you can actually leverage the same configuration code you use in production.
Dan Franciscus
Dan Franciscus is a systems engineer and VMware Certified Professional (VCP) specializing in VMware, PowerShell, and other Microsoft-based technologies. You can reach Dan at his blog (http://www.winsysblog.com/) or Twitter at @dan_franciscus.