Quick startup with Vagrant

Overview:

Vagrant - is an open-source software developed by HashiCorp which enables you to easily create and automate the provisioning process of virtual machines in your local development environments.

Vagrant acts as a wrapper on virtual machines, communicating with them via API providers (hypervisors). You can also code your own API provider. Default provider for Vagrant is - VirtualBox

Vagrant components:

vagrant.drawio.png

Installation:

To install Vagrant check out the following article: "How to set up Vagrant with Docker on Ubuntu 18.04"

Boxes:

  1. Box - is a golden image used to boot up the virtual machine
  2. Bentoo boxes are generalized simple bare-bone boxes that are made in a consistent way
  3. All available boxes can be found here
  4. To pull the box image on your system use:
    vagrant box add [box_name]
    

Vagrantfile:

  1. Vagrantfile describes the overall configuration and provisioning of the environment
  2. To create Vagrantfile use:
    vagrant init
    
    After running the command you should see the following Vagrantfile in your directory:
    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    # All Vagrant configuration is done below. The "2" in Vagrant.configure
    # configures the configuration version (we support older styles for
    # backwards compatibility). Please don't change it unless you know what
    # you're doing.
    Vagrant.configure("2") do |config|
    # The most common configuration options are documented and commented below.
    # For a complete reference, please see the online documentation at
    # https://docs.vagrantup.com.
    # Every Vagrant development environment requires a box. You can search for
    # boxes at https://vagrantcloud.com/search.
    config.vm.box = "base"
    # Disable automatic box update checking. If you disable this, then
    # boxes will only be checked for updates when the user runs
    # `vagrant box outdated`. This is not recommended.
    # config.vm.box_check_update = false
    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine. In the example below,
    # accessing "localhost:8080" will access port 80 on the guest machine.
    # NOTE: This will enable public access to the opened port
    # config.vm.network "forwarded_port", guest: 80, host: 8080
    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine and only allow access
    # via 127.0.0.1 to disable public access
    # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
    # Create a private network, which allows host-only access to the machine
    # using a specific IP.
    # config.vm.network "private_network", ip: "192.168.33.10"
    # Create a public network, which generally matched to bridged network.
    # Bridged networks make the machine appear as another physical device on
    # your network.
    # config.vm.network "public_network"
    # Share an additional folder to the guest VM. The first argument is
    # the path on the host to the actual folder. The second argument is
    # the path on the guest to mount the folder. And the optional third
    # argument is a set of non-required options.
    # config.vm.synced_folder "../data", "/vagrant_data"
    # Provider-specific configuration so you can fine-tune various
    # backing providers for Vagrant. These expose provider-specific options.
    # Example for VirtualBox:
    #
    # config.vm.provider "virtualbox" do |vb|
    #   # Display the VirtualBox GUI when booting the machine
    #   vb.gui = true
    #
    #   # Customize the amount of memory on the VM:
    #   vb.memory = "1024"
    # end
    #
    # View the documentation for the provider you are using for more
    # information on available options.
    # Enable provisioning with a shell script. Additional provisioners such as
    # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
    # documentation for more information about their specific syntax and use.
    # config.vm.provision "shell", inline: <<-SHELL
    #   apt-get update
    #   apt-get install -y apache2
    # SHELL
    end
    
  3. To set the box in Vagrantfile edit the following line:
    config.vm.box = "[box_name]"
    
  4. To validate the Vagrantfile use:
    vagrant validate
    

Vagrant up:

  1. To deploy the Vagranfile use:
    vagrant up
    
  2. When we run vagrant up command:
    • First, it tries to look for the Vagrantfile in the existing directory where the command was run
    • If we run vagrant up command in the directory without the actual Vagrantfile, the command will look up the directory tree until it will find the file
  3. When we run vagrant up command it loads a number of other Vagrantfiles to load and merge:
    • Box Vagrantfile
    • User Vagrantfile - specified inside the config directory at ~/.vagrant.d
    • Project Vagrantfile
    • Multi-machine
    • Provider

Example deployment of Ubuntu server:

  1. Create folder to store your Vagrantfile and other config files:
    mkdir ubuntu-server
    
  2. Automatically create the template Vagrantfile:
    vagrant init
    
  3. Edit Vagrantfile as follows:
    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    #
    # All Vagrant configuration is done below. The "2" in Vagrant.configure
    # configures the configuration version (we support older styles for
    # backwards compatibility). Please don't change it unless you know what
    # you're doing.
    Vagrant.configure("2") do |config|
    # The most common configuration options are documented and commented below.
    # For a complete reference, please see the online documentation at
    # https://docs.vagrantup.com.
    #
    # Every Vagrant development environment requires a box. You can search for
    # boxes at https://vagrantcloud.com/search.
    config.vm.box = "hashicorp/bionic64"
    #
    # Disable automatic box update checking. If you disable this, then
    # boxes will only be checked for updates when the user runs
    # `vagrant box outdated`. This is not recommended.
    # config.vm.box_check_update = false
    #
    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine. In the example below,
    # accessing "localhost:8080" will access port 80 on the guest machine.
    # NOTE: This will enable public access to the opened port
    # config.vm.network "forwarded_port", guest: 80, host: 8080
    #
    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine and only allow access
    # via 127.0.0.1 to disable public access
    # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
    #
    # Create a private network, which allows host-only access to the machine
    # using a specific IP.
    # config.vm.network "private_network", ip: "192.168.33.10"
    #
    # Create a public network, which generally matched to bridged network.
    # Bridged networks make the machine appear as another physical device on
    # your network.
    config.vm.network "public_network"
    #
    # Share an additional folder to the guest VM. The first argument is
    # the path on the host to the actual folder. The second argument is
    # the path on the guest to mount the folder. And the optional third
    # argument is a set of non-required options.
    # config.vm.synced_folder "../data", "/vagrant_data"
    #
    # Provider-specific configuration so you can fine-tune various
    # backing providers for Vagrant. These expose provider-specific options.
    # Example for VirtualBox:
    #
    # config.vm.provider "virtualbox" do |vb|
    #   # Display the VirtualBox GUI when booting the machine
    #   vb.gui = true
    #
    #   # Customize the amount of memory on the VM:
    #   vb.memory = "1024"
    # end
    #
    # View the documentation for the provider you are using for more
    # information on available options.
    #
    # Enable provisioning with a shell script. Additional provisioners such as
    # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
    # documentation for more information about their specific syntax and use.
    # config.vm.provision "shell", inline: <<-SHELL
    #   apt-get update
    #   apt-get install -y apache2
    # SHELL
    end
    
  4. config.vm.network "public_network" - enables a bridged network by connecting your VM to your host machine. This allows Internet access for VM
  5. If you want to change your provider add the following config line:
    config.vm.provider "[provider_name]"
    
    Example of enabling HyperV for Windows based VMs:
    config.vm.synced_folder ".", "/vagrant_data", disabled: true
    config.vm.provider "hyperv"
    config.vm.provider "hyperv" do |h|
     h.enable_virtualization_extensions = false
     h.linked_clone = true
    end
    
  6. Deploy the machine:
    vagrant up
    
    During the deployment Vagrant will download the box image and automatically create SSH keys to log into the machine
  7. To log into the machine type:
    vagrant ssh
    
    You should see the following message:
  8. After adding new changes to the Vagrantfile, to apply the changes use:
    vagrant reload
    
    For example, to change the name of the machine for VirtualBox provider use:
    config.vm.provider "virtualbox" do |vb|
     # Set VirtualBox machine name
     vb.name = "ubuntu_server_18.04" 
    end
    
    vagrant reload command stops VM, apply the changes and start the machine again

Tips:

  1. To list the status of current running VM use:
    vagrant status
    
  2. To enable the feature for listing VMs you can install a third-party plugin https://github.com/joshmcarthur/vagrant-list
    To install the plugin use:
    vagrant plugin install vagrant-list
    
    To list existing VMs:
    vagrant list
    

Commands:

  1. Initialize Vagrantfile and config files:
    vagrant init
    
  2. Deploy VM:
    vagrant up
    
  3. Validate Vagrantfile for any syntax errors:
    vagrant validate
    
  4. List downloaded boxes on your host machine:
    vagrant box list
    
  5. To add the box:
    vagrant box add [box_name]
    
  6. To remove the box:
    vagrant box remove [box_name]
    
  7. To check the status of running machine:
    vagrant status
    
  8. To log into the machine:
    vagrant ssh
    
  9. To apply the changes to Vagrantfile use:
    vagrant reload
    
  10. To get list of all currently running machines use:
    vagrant global-status
    
  11. To prune any invalid cache entries in order to get fresh info use:
    vagrant global-status --prune
    
  12. To package running VM into box package use:
    vagrant package
    
  13. To stop the machine use:
    vagrant halt
    
    To resume stopped machine use:
    vagrant up
    
  14. To get debug info on deployment use:
    vagrant --debug up
    
  15. To display full list of guest ports mapped to the host machine ports:
    vagrant port [vm_name]
    
  16. To delete the machine use:
    vagrant destroy
    

Reference:

  1. Vagrant boxes
  2. Vagrant in 5 minutes
  3. Vagrant push
  4. Vagrant cheat sheet
  5. VirtualBox provider configuration
  6. https://github.com/joshmcarthur/vagrant-list
  7. Automated virtual machine deployment with Vagrant