Vagrant

From 太極
Revision as of 19:41, 1 January 2016 by Brb (talk | contribs) (→‎Provisioning)
Jump to navigation Jump to search

Official website https://www.vagrantup.com/

Resources

Download

The version available now is 1.8.1.

Use vagrant -v to see the vagrant version currently installed in your machine.

Documentation

https://docs.vagrantup.com/v2/

Books

  • Vagrant Virtual Development Environment Cookbook (2015)
  • Creating Development Environments with Vagrant (2015, 2nd Ed)
  • Pro Vagrant (2015)
  • Vagrant: Up and Running (2013)

Some commands

vagrant up
vagrant halt # gracefully shut down

vagrant suspend 
vagrant resume

vagrant destroy # stops the running machine Vagrant is managing and destroys all resources

vagrant box SUBCOMMANDS
vagrant box remove ubuntu/trusty32

vagrant ssh

vagrant package # This packages a currently running VirtualBox environment into a re-usable box.

Examples

A simple example

$ mkdir precise32
$ cd precise32
$ vagrant init hashcorp/precise32
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.
$ cat Vagrant
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hashcorp/precise32"
end
$ vagrant up
vm
* The box 'hashcorp/precise32' could not be found.

The solution from stackoverflow works.

If we open VirtualBox GUI, we will see a new guest machine called precise32_default_XXXXXXXX is created and running though we do not see Ubuntu precise 32 desktop application in a new window.

A web server

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "web", primary: true do |web|
    web.vm.box = "ubuntu/trusty64"
    web.vm.network "forwarded_port", guest:80, host:8888
    web.vm.provision "shell", inline: "apt-get install -y nginx"
  end
end

Start the machine with the vagrant up command. Open a web browser on your host machine at http://localhost:8888. This will present the nginx Welcome page.

See my gist for the output.

A GUI example

Go to

  1. https://atlas.hashicorp.com/boxes/search. Type 'GUI' to search
  2. https://atlas.hashicorp.com/chad-thompson/boxes/ubuntu-trusty64-gui

Run vagrant init chad-thompson/ubuntu-trusty64-gui. Edit Vagrantfile.

Vagrant.configure(2) do |config|
  config.vm.box = "chad-thompson/ubuntu-trusty64-gui"
  config.vm.provider "virtualbox" do |vbox|
    vbox.gui = true
  end
end

Then run vagrant up (1.5GB download).

Note that when I run df -h in the VM, it shows

Filesystem  Size Used Avail  Mounted on
/dev/sda1   21G  3.1G  17G   /
/vagrant    1.8T 445G 1.4T   /vagrant

The /vagrant partition contains the Vagrantfile.

We can also make the Vagrantfile a bit more general by including multiple providers in the same Vagrantfile.

Vagrant.configure(2) do |config|
  config.vm.box = "chad-thompson/ubuntu-trusty64-gui"
  config.vm.provider "virtualbox" do |vbox|
    vbox.gui = true
  end
  config.vm.provider "vmware_fusion" do |fusion|
    fusion.gui = true
  end
end

Share folders/Synced folders

Default implementation from providers

Suppose we want to set up a web server to develop html files. We share a source folder that contains html documentation with the guest.

  1. In the working directory, create a new dir called vagrantsite.
  2. In the vagrantsite dir, create a file named index.html.
  3. Create a new Vagrantfile in the working directory.
  4. Add a synced_folder directive to the web server configuration.
  5. Create an additional command to the web.vm.provision line to create a symbolic link from this directory to a directory in the nginx default web directory.
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "web", primary: true do |web|
    web.vm.box = "ubuntu/trusty64"
    web.vm.network "forwarded_port", guest:80, host:8888
    web.vm.synced_folder "vagrantsite/", "/opt/vagrantsite"
    web.vm.provision "shell", inline, "apt-get install -y nginx; ln -s /opt/vagrantsite /usr/share/nginx/html/vagrantsite"
  end
end 

Now executing vagrant up command and open the page http://localhost:8888/vagrantsite/ in a web browser.

Note

  • Vagrant shares the working directory of the Vagrantfile in the root vagrant directory by default. Executing ls /vagrant command should return this information.
  • Sharing folders will require proper tools to be installed in the host machine. For VirtualBox, this means having the guest additions installed. For VMware, this means VMware tools installed.

Shared folders can also be implemented in different ways

  • Using networked file systems such as NFS (Linux, OS X) and SMB (Windows). These options might offer significantly better file-sharing performance than shared folder functionality of the hypervisor; i.e. NFS is better than using the guest additions method in VirtualBox. See http://mitchellh.com/comparing-filesystem-performance-in-virtual-machines.
  • A Vagrant machine executing on a remote hypervisor (eg a cloud service) will usually not have shared filesystems available. Vagrant provides methods to copy files from host ot guest using the rsync protocol.

Share Network File Systems

Sharing directories from the host machine will require the host system to export a directory for use by the guest machine. When using NFS, this means that Vagrant will add an entry to the native /etc/exports file to define the rule to export the specified directory to the guest box.

Prior to starting, make sure that Network File Share Daemon (nfsd) is installed on your host machine.

Notice the type option in the synced_folder line.

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "web", primary: true do |web|
    web.vm.box = "ubuntu/trusty64"
    web.vm.network "forwarded_port", guest:80, host:8888
    web.vm.synced_folder "vagrantsite/", "/opt/vagrantsite", type: "nfs"
    web.vm.provision "shell", inline, "apt-get install -y nginx; ln -s /opt/vagrantsite /usr/share/nginx/html/vagrantsite"
  end
end 

You can verify the shared folder is from NFS by typing vagrant ssh and executing the mount command. The mount command should contain an entry that shows type nfs for one partition.

For Windows Server Message Block (SMB) protocol, modify the synced_folder to

    web.vm.synced_folder "vagrantsite/", "/opt/vagrantsite", type:" smb"

rsync

'rsync method is useful when

  • NFS or VirtualBox shared folders aren't available in the guest machine.
  • Processes that generate significant disk activity (I/O) on shared folders
  • Vagrant can be used to control vm in remote locations (even in remote data centers over the public internet)

Pay attention to the synced_folder line.

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "web", primary: true do |web|
    web.vm.box = "ubuntu/trusty64"
    web.vm.network "forwarded_port", guest:80, host:8888
    web.vm.synced_folder "vagrantsite/", "/opt/vagrantsite", type: "rsync"
    web.vm.provision "shell", inline, "apt-get install -y nginx; ln -s /opt/vagrantsite /usr/share/nginx/html/vagrantsite"
  end
end 

When the files in the host machine are changed, we need to run vagrant rsync command on the host to synchronize the /opt/vagrantsite directory.

Customizing virtual machine settings in VirtualBox

The primary example is changing the settings of the virtual machine to use more (or less) system memory (2GB in the following example) and virtual processors (2 cpus).

Vagrant.configure(2) do |config|
  config.vm.define "web", primary: true do |web|
    web.vm.box = "ubuntu/trusty64"
    web.vm.network "forwarded_port", guest:80, host:8888
    web.vm.provision "shell", inline: "apt-get install -y nginx"
    web.vm.provider "virtualbox" do |vbox|
      vbox.memory = 2048
      vbox.cpus = 2
    end
  end
end

Start the vm with the vagrant up command. Verify the system has the amount of memory allocated by issuing the command head /proc/meminfo.

If we like to start a GUI on the vm, just add vbox.gui = true in the vbox block.

    web.vm.provider "virtualbox" do |vbox|
      vbox.memory = 2048
      vbox.cpus = 2
      vbox.gui = true
      vbox.customize ["modifyvm", :id, "--bioslogofadein", "off"]
    end

The last line use the VBoxManage command to fade the VirtualBox startup logo immediately.

A full listing of available options to modify the runtime is available in the VirtualBox documentation http://www.virtualbox.org/manual/ch08.html.

Where is vagrant saving boxes files

http://stackoverflow.com/questions/10155708/where-does-vagrant-download-its-box-files-to

  • Windows: C:/Users/USERNAME/.vagrant.d/boxes
  • Linux and Mac: ~/.vagrant.d/boxes/

We can change the default directory by modifying the VAGRANT_HOME variable. See https://docs.vagrantup.com/v2/other/environmental-variables.html.

Vagrant Share

Vagrantfile

Vagrantfile is just Ruby.

Vagrantfile template

If we run vagrant init, we will get the following vagrantfile.

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # ...
end

Precise32

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hashcorp/precise32"
end

config.vm

Config namespace: config.vm

The settings within config.vm modify the configuration of the machine that Vagrant manages.

  • config.vm.boot_timeout
  • config.vm.box
  • config.vm.box_url
  • config.vm.communicator
  • config.vm.hostname
  • config.vm.provider
  • config.vm.synced_folder

config.ssh

Boxes

Download a box w/ initializing an env

vagrant box add ubuntu/trusty64

You can also quickly initialize a Vagrant environment with vagrant init ubuntu/trusty64.

We can also specify an URL to add/download a box.

vagrant box add http://servername/boxes/environment.box

Remove a box

Something like

vagrant box remove ubuntu/trusty32

List downloaded boxes

vagrant box list

Create a new box/Package a VirtualBox machine

Suppose we use vagrant to create a new box based on ubuntu/trusty64. We ssh to the box and install some software (eg r-base-core). We use vagrant halt to shut down the box. Now we can package this new box.

$ VBoxManage list vms # find out the vm name (vm is created by Vagrant)
$ vagrant package --base=trusty64_default_1451665747284_29528 --output=mytest.box

To test the new box, we can copy the box to your local Vagrant cache.

$ vagrant box add mytest.box --name=mytestbox
$ vagrant box list
mytestbox       (virtualbox, 0)
ubuntu/trusty64 (virtualbox, 20151217.0.0)

Create a new directory so we can test the new box.

cd ..
mkdir mytestbox
cd mytestbox
vagrant init mytestbox  # create Vagrantfile

Note that we can not use vagrant up to start the box now. If we try to run it, we will get the following error about the SSH authentication.

    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Authentication failure. Retrying...

I have to use Ctrl+C to stop the process and then use vagrant destroy to destroy the (unsuccessfully) running virtual machine.

Go ahead to modify the Vagrantfile created by vagrant init mytestbox command to use the correct SSH username/password. By default, Vagrant relies on a common public key that is used by most box publishers that allows access to an account called vagrant. After the first login, Vagrant will place a key in the appropriate account; so, if desired, the password can be removed from the Vagrantfile after the first boot. (verified!)

Vagrant.configure(2) do |config|
  config.vm.box = "mytestbox"
  config.ssh.username="ubuntu"
  config.ssh.password="ubuntu"
end

Strangely, though I can run vagrant up, I cannot use the password I created when I try the vagrant ssh command. I found the solution is to make sure the username and password used in the Vagrantfile the same as the virtual machine; in this case since I am using the ubuntu/trusty64 box, I should use the vagrant/vagrant as the username/password in the Vagrantfile. That is the correct Vagrantfile should be

Vagrant.configure(2) do |config|
  config.vm.box = "mytestbox"
  config.ssh.username="vagrant"
  config.ssh.password="vagrant"
end

Now we can run vagrant up and vagrant ssh commands. We could check R should be available in the virtual machine.

Provisioning

Running basic shell commands

Pay attention to the line containing config.vm.provision.

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.provision "shell", 
    inline: "echo 'Knock Knock!'  > /etc/motd"
end

Once the machine is booted, access the machine with vagrant ssh command. The login shell will display the message created with the inline shell script.

Executing shell scripts in a Vagrantfile

VAGRANTFILE_API_VERSION = "2"

$nginx_install = <<SCRIPT
   if [ ! -x /usr/sbin/nginx ]; then
      apt-get install -y nginx;
   fi

   # Default NGINX directory: /usr/share/nginx/html
   # Replace this with symbolic link to vagrant directory.
   if [ ! -L /usr/share/nginx/html ]; then
      rm -rf /usr/share/nginx/html
      ln -s /vagrant/html /usr/share/nginx/html
   fi 
SCRIPT

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "puppetlabs/ubuntu-14.04-32-nocm"
  config.vm.provision "shell", inline: $nginx_install
  config.vm.network "forwarded_port", guest:80, host:8080
end

External shell scripts

The working directory should contain both Vagrantfile and the shell script file.

Pay attention to the line containing config.vm.provision.

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.provision "shell", path: "nginx-install.sh"
  config.vm.network "forwarded_port", guest:80, host:8080
end

The script file <nginx-install.sh> looks like

#!/bin/bash

   if [ ! -x /usr/sbin/nginx ]; then
      apt-get install -y nginx;
   fi

   # Default NGINX directory: /usr/share/nginx/html
   # Replace this with symbolic link to vagrant directory.
   if [ ! -L /usr/share/nginx/html ]; then
      rm -rf /usr/share/nginx/html
      ln -s /vagrant/html /usr/share/nginx/html
   fi

Execute the vagrant up command and open the browser at http://localhost:8080 in the local machine.

As a test of idempotency, execute the vagrant provision command. You shall see this command will exit quickly as all conditions within the script should be satisfied.

Using management tools/languages: Puppet

The Vagrantfile looks like (pay attention to the line containing config.vm.provision):

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # A Vagrant box with puppet pre-installed.
  config.vm.define "web", :primary => true do |web|
     web.vm.box = "ubuntu/trusty64"
     web.vm.hostname = "web"
     web.vm.network "forwarded_port", guest: 80, host: 8080

     web.vm.provision "puppet" do |puppet|
       puppet.manifests_path = "puppet/manifests"
       puppet.manifest_file  = "site.pp"
       puppet.module_path = "puppet/modules"
     end
  end
end

Networking

Synced Folders

Multi-Machine

Providers

Virtualbox

VMware

Docker

Hyper-V