Thomas Venturini
Vagrant - Provisioning

Vagrant - Provisioning

Provisioning is the part of your setup where you arrange all elements of your environment to match your needs. Everything we are going to cover in this article will happen on your guest machine.

We have already covered the basic usage of the vagrant command and we have talked about the different types of Vagrantfiles that make up the configuration. Now we are going to talk about provisioning.

If you don't have read the other articles about vagrant you could lack behind so make sure to check them out before proceeding with this article.

Provisioning

The vagrant up command merges all Vagrantfiles which make up your configuration, but it is also provisioning your guest system. To use provisioning makes the setup of your environment repeatable through your team or any host system. It is a good practice to do all your configurations and software installations through your provisioning, so you can vagrant destroy and vagrant up your environment and be ready to go.

vagrant up will look for provisioning information in your projects Vagrantfile. As we have seen in the last article of this series this could look like the following.

config.vm.provision "shell", inline: <<-SHELL
  apt-get update
  apt-get install -y apache2
SHELL

Or if you are using a more complex setup for your environment, what is more likely, you will be using a dedicated provisioning script like so.

config.vm.provision "shell", path: "script.sh"

Provisioning your Environment

Provisioning is usually done through the first vagrant up, but provisioning can also happen during other events.

To execute the provisioning on a running environment you can use vagrant provision.

The vagrant reload command gives you another option to provision your environment. vagrant reload is short for vagrant halt && vagrant up but you can also use the --provision flag to do your provisioning again.

You can also use vagrant up --no-provision to not run provisioning on your environment.

Provisioners

Let's get more concrete now. In this article we are only going to show the shell provisioner but there are others. Also there can be more than one provisioner, so it comes in handy that you can name them.

Naming a provisioner is done through a slightly different version of the config.vm.provision method. The following example will name the provisioner as default.

config.vm.provision "default", type: "shell", path: "script.sh"

Since we know that we can use multiple provisioners, we need a way to run them on their own. Fortunately vagrant gives us a way to do so. Use the following to bring up your machine with a specific provisioner.

vagrant up --provision-with default

default is the name we gave our provisioner in the last step.

In rare cases you need to run provisioners everytime you bring up your machine. You can do so by adding run: "always" to your provision method call like so.

config.vm.provision "shell", inline: "echo hello", run: "always"

In other rare cases you don't want to run a provisioner during any normal events and only call it with the --provision-with flag. In that case you will need to set run to "never".

config.vm.provision "shell", inline: "echo hello", run: "never"

Provisioners are run in the order in your Vagrantfile but you now know how to control this.

Now that we have covered the usage of provisioners we are going to take a look at the most important ones.

File

The file provisioner can be used to upload files such as configurations from your host to your guest system. This can be extremely useful so remember this one.

config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"

# or for folders

config.vm.provision "file", source: "~/path/to/host/folder", destination: "$HOME/remote/newfolder"

Remember that uploaded files and folders are not synchronized between your host and guest system. But thats good, because you can adapt each one as you need it.

Shell

With the shell provisioner you have two options. You can use the inline or path option. We will take a look at both.

Inline

Within the inline option you have also various options on how you do this. The documentation shows you the following options.

Vagrant.configure("2") do |config|
  config.vm.provision "shell",
    inline: "echo Hello, World"
end
$script = <<-SCRIPT
echo "I am provisioning..."
date > /etc/vagrant_provisioned_at
SCRIPT

Vagrant.configure("2") do |config|
  config.vm.provision "shell", inline: $script
end

But there is another one. As the default Vagrantfile created by vagrant init shows us, you can also use the following variant.

config.vm.provision "shell", inline: <<-SHELL
  apt-get update
  apt-get install -y apache2
SHELL

External Script

The shell provisioner also accepts a path to an external script. The file will be uploaded to the guest system and executed. Relative paths, will be relative to the project root. This could look like so.

config.vm.provision "shell", path: "script.sh"

If you want to execute a script, thats already on the guest system, you can do so with the following code.

config.vm.provision "shell", inline: "/bin/sh /path/to/the/script/already/on/the/guest.sh"

Script Arguments

You can also use arguments in your shell provisioner. I will only show you the array variant, because I don't want you to worry about escaping.

config.vm.provision "shell" do |s|
    s.inline = "echo $1"
    s.args   = ["hello, world!"]
end

For a file based shell provisioner this could look like so.

config.vm.provision "shell" do |s|
    s.path = "script.sh"
    s.args = ["one", "two"]
end

And this would be the external script that shows us the arguments.

echo $1 # one
echo $2 # two

Thats all for this provisioner. The shell provisioner is the best way for beginners so we will only cover this one. If you take a look at the documentation you will find other provisioners that may suit your needs.

Some of the available provisioners are very powerful tools and you should take a look at them, but for now we have covered the basics of provisioning. You should be ready to go now 🙂