Vagrant 2 Basics

I use Moonshine to provision the Linode server for deploying rubyplus.com. I wanted to find a provisioning tool that is not dependent on any Rails version. Ansible seems lightweight but still there is a learning curve. It is attractive because it can deploy and provision servers. So, it can replace Capistrano and provisioning tools like Chef or Puppet. Ideally I want to play with production like environment before I invest money on another Linode server.

VirtualBox was useful when I was teaching Rails for Silicon Valley Ruby meetup. The problem is that taking snapshots of pre-installed Rails stack takes lot of memory. Export and import works fine so the students can focus on learning web programming instead of wasting time on installation issues. Another problem is we need to manually create a new preconfigured Rails stack whenever there is a new version of Rails, Elastic Search, Postgres etc. This is time consuming.

Vagrant automates the creating the managing virtualized development environments. We checking the Vagrantfile and anyone can run vagrant up to get a working environment. This is perfect for my experimentation purposes like learning Kafka or building my own shell scripts to replace Moonshine for my next Rails project to be deployed on Linode. I can have different virtual machines for different purposes. If you want to learn Vagrant, read the Vagrant Up and Running written by the author of Vagrant, Mitchell Hashimoto. The book uses Vagrant version 1.2.3. But it gave me the basic concepts needed to learn things that I need to get my job done on my own.

Another good use case is onboarding new developers to the team. You don't have to spend days to setup your development environment. You can get everything setup in a few hours. It's also nice not to force anyone to update the README whenever something changes in the development environment. Since everything is in Vagrantfile, it can be updated and it becomes executable documentation for the application environment.

First, install VirtualBox by downloading the installer for Mac OS X. Install Vagrant, it comes with installers for different OS. You can check the installed version.

$ vagrant --version
Vagrant 2.2.1

Create a new directory and run the following command:

$ vagrant init precise64 http://files.vagrantup.com/precise64.box
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

This creates the Vagrantfile that looks like this:

# -*- 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 = "precise64"

  # The url from where the 'config.vm.box' box will be fetched if it
  # doesn't already exist on the user's system.
  config.vm.box_url = "http://files.vagrantup.com/precise64.box"

  # 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
  # Puppet, Chef, Ansible, Salt, and Docker 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

You can discover boxes by searching vagrantup or the bento boxes. Let's get Ubuntu 18.04.

$ vagrant init bento/ubuntu-18.04

This creates the Vagrant file:

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 = "bento/ubuntu-18.04"
end

You can now run:

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'bento/ubuntu-18.04' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'bento/ubuntu-18.04'
    default: URL: https://vagrantcloud.com/bento/ubuntu-18.04
==> default: Adding box 'bento/ubuntu-18.04' (v201808.24.0) for provider: virtualbox
    default: Downloading: https://vagrantcloud.com/bento/boxes/ubuntu-18.04/versions/201808.24.0/providers/virtualbox.box
    default: Download redirected to host: vagrantcloud-files-production.s3.amazonaws.com
==> default: Successfully added box 'bento/ubuntu-18.04' (v201808.24.0) for 'virtualbox'!
==> default: Importing base box 'bento/ubuntu-18.04'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'bento/ubuntu-18.04' is up to date...
==> default: Setting the name of the VM: vag2_default_1543013804004_69944
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Remote connection disconnect. Retrying...
    default: 
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default: 
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => /Users/bparanj/vag2

You can check the status:

$ vagrant status
Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

Uncomment the line:

config.vm.network "forwarded_port", guest: 80, host: 8080

in the Vagrantfile to expose the port 80 to 8080 on the host. You can pickup the changes by running:

$ vagrant reload
==> default: Attempting graceful shutdown of VM...
==> default: Checking if box 'bento/ubuntu-18.04' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 80 (guest) => 8080 (host) (adapter 1)
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => /Users/bparanj/vag2
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.

SSH into the box:

$ vagrant ssh

Go to vagrant directory and run http server:

vagrant@vagrant:~$ cd /vagrant
vagrant@vagrant:/vagrant$ pwd
/vagrant
vagrant@vagrant:/vagrant$ sudo python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.0.2.2 - - [23/Nov/2018 23:19:11] "GET / HTTP/1.1" 200 -

In the browser, hit http://localhost:8080/. You will see list of directory listing showing the files in the vagrant folder. In the next article, we will see how to use shell scripts to provision a VM.


Related Articles


Create your own user feedback survey