Create Multiple Machine Environments With Vagrant

January 11, 2018 Security and Compliance, MOVEit

 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.

Read next Proper Script Management: A Practical Guide