Vagrant - Provisioning 2/2
Vagrant provides an easy and powerful way to deploy local machines for development and testing. You can use Ansible or Podman and Docker to provision complete use cases on the machines, too.
Vagrant provides an easy and powerful way to deploy local machines for development and testing. You can add provisioners via Shell and file, as discussed in the "Vagrant - Provisioning 1/2" article. Furthermore, you can use Ansible or Podman and Docker to provision complete use cases on the machines.
Provisioning
In addition to the spin-up of VMs, you can define provisioning tasks and scripts in Vagrant. This is especially helpful, if you want to add packages to a machine or configure services. A simple command vagrant up
will trigger the provisioners by default. In case you want to run it again, you can use the command vagrant provision
.
For Ansible and container development, you can also use the feature to test your code and test it properly. In the below sections, I will explain how you can add Ansible Playbooks or container deployments to your Vagrantfile.
Ansible
If you develop Ansible Playbooks, Roles or Collections, you may want to test them properly. Much stuff can be done in containers, but sometimes you want to test virtualization, kernel parameters, certain security and firewall settings and just need some "real" machine.
Vagrant can help to spin up a machine and deploy your code on different Operating Systems and you can do much more, than in Docker or Podman containers.
You can also consider Ansible, if you are using it anyway, to deploy and configure your infrastructure. Same tool for production and develop is my preferred way.
If you don't know Ansible, I strongly recommend reading some articles about it.
Ansible Provisioner
The Ansible Provisioner is very useful, if you are having Ansible installed on your machine anyway. You can use different Ansible Version in a "virtualenv" and run everything as, if the Vagrant Box is just another remote machine (stack).
Let's see how this works. First, we need to create a small project and some files.
# Create project directory
$ mkdir vagrant-ansible
$ cd vagrant-ansible
# Create files
$ touch playbook.yml
$ touch Vagrantfile
Let's write a simple playbook, that will install a basic web server. Edit the "playbook.yml" file and fill in some content like below.
As you can see, we want to copy a custom index.html, too. Let's create this.
# Create directory
$ mkdir files
# Create file
$ touch files/index.html
The ansible.builtin.copy module will look in the "files" directory on its own, and you don't need to specify the full path. Some content for the website may look like the below example.
The last part, we need to add content for the Vagrantfile. The below example should be sufficient. Edit the Vagrantfile with the editor of your choice.
As you can see, we will spin-up a Fedora 34 machine. In addition, you can see a new section "config.vm.provision", which will trigger the Ansible provisioning. Vagrant will create an inventory automatically and run the "ansible-playbook" command, so the new inventory is used.
Just run vagrant up
to start the VM and run the provisioner. Afterwards, you can test the deployment or change the playbook and run the provisioner again.
# Start the machine and provision
$ vagrant up
# Check for machine IP
$ vagrant ssh-config
# Check the deployed website
$ curl http://IP_ADDRESS
# Run the provisioner again
$ vagrant provision
Ansible Local Provisioner
If you don't have Ansible on your machine, you can consider using the Ansible Local provisioner. Vagrant will try to install Ansible in the Vagrant machine and apply the provided playbook afterwards.
During this process, Vagrant will sync the working directory in the Vagrant machine. It will be available in the "/vagrant" directory. To get a better understanding of this sync feature, please have a look at the documentation.
We can easily tune the previous example. Just edit the Vagrantfile as described below.
You can spin up a fresh VM or re-apply the playbook with the below commands.
# Start the machine and provision
$ vagrant up
# Check for machine IP
$ vagrant ssh-config
# Check the deployed website
$ curl http://IP_ADDRESS
# Run the provisioner again
$ vagrant provision
Podman / Docker
The development of containers can be a problem, too. If you have an application, that must be shipped as a container, or if you just want to spin-up a third party container, Vagrant can be helpful. This way, you don't need to define Networks, Secrets or download images, which are idling around until you clean them up.
You will also be able to verify if containers can run on different platforms. Since the Podman and Docker provisioner are working very similar and are having basically the same syntax, I will focus on Podman for this section. The examples are easy to apply to Docker, too.
If you don't know anything about Podman and Docker, I recommend reading the articles here.
Hint: Unfortunately, the Podman installation on Fedora fails. Therefore, I am using the CentOS 8 Stream Vagrant box.
Pull/Run Image
You can use Vagrant to run a container from an existing image. I will stick to a simple example again. Let's create the project directory and some needed files first.
# Create project directory
$ mkdir vagrant-podman
$ cd vagrant-podman
# Create files
$ touch Vagrantfile
Edit the Vagrantfile and add the Podman provisioner.
After starting the Vagrant machine, we can test if the server is reachable.
# Start vagrant machine
$ vagrant up
# Get IP address
$ vagrant ssh-config
Host centos
HostName 192.168.122.4
...
# Test if httpd is really running
$ curl 192.168.122.4
<html><body><h1>It works!</h1></body></html>
So, running a prepared image (or multiple images) is easy.
Build Image
Since I want to use the provisioner to test new images and Dockerfiles/Containerfiles, let's have a look at the "build image" feature.
First, we need to create a simple Dockerfile. Unfortunately, Vagrant does not support the general Containerfile and we need to name it "Dockerfile".
# Create Dockerfile
$ touch Dockerfile
Edit the file and fill in the below content.
This file should create a container image, based on Fedora Linux, with the Apache httpd web server in it.
The Vagrantfile to build the image and run it afterwards will look like the below example.
Spin up the machine and test if everything works.
# Create the machine and run the provisoner
$ vagrant up
# Check IP address
$ vagrant ssh-config
Host centos
HostName 192.168.122.190
# Check the website
$ curl 192.168.122.190
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Test Page for the HTTP Server on Fedora</title>
...
Vagrant is doing this by syncing the complete working directory into "/vagrant" on the target machine. To get a better understanding of the Vagrant sync feature, please have a look at the official documentation.
Code
I have uploaded a bunch of examples, which you can use to build your own provisioners. These also include some examples from the "Vagrant - Getting Started" and "Vagrant - Provisioning 1/2" articles, and the repository is under active maintenance.
Docs & Links
Vagrant provides additional documentation for the provisioners. Please have a look at these, too.
Conclusion
Hint: Unfortunately, the Podman installation on Fedora fails. Therefore, I am using the CentOS 8 Stream Vagrant box.