Study Topic: Vagrant
This is a Study Leave topic.
What Is It?
From Vagrant Docs V2: Why Vagrant?:
Vagrant provides easy to configure, reproducible, and portable work environments built on top of industry-standard technology and controlled by a single consistent workflow to help maximize the productivity and flexibility of you and your team.
To achieve its magic, Vagrant stands on the shoulders of giants. Machines are provisioned on top of VirtualBox, VMware, AWS, or any other provider. Then, industry-standard provisioning tools such as shell scripts, Chef, or Puppet, can be used to automatically install and configure software on the machine.
Why Study It?
Standard method of provisioning VMs
Toggl code
Toggl code is TECH-VAGRANT
Deliverables
Max 7 hours of time: get something running and see what you can do!
WriteUp
TODO:
- Look at AWS
- DONE: Install Vagrant
- DONE: Install VirtualBox
- DONE: Get HashiCorp Atlas login (morrism, new)
- DONE: Initial examples (write up as you do them) in Vagrant Getting Started
- DONE: Work through "Vagrant: Up and Running"
AWS
Look at How to deploy on Amazon EC2 with Vagrant
Installed AWS plugin:
- $ vagrant plugin install vagrant-aws
Installation
Don't Use Ruby Gems!
There's a lot of stuff still around saying you should install Vagrant via Ruby Gems but this is out of date! Abandoning RubyGems (21Mar2013) sets out why things have changed: Vagrant was originally packaged as a Ruby Gem, but:
- This was a barrier to entry for non-Ruby users
- Not having all dependencies done via the package manager system meant it was less clear what caused any problems with an installation
- Using the packaging system gave more flexibility and scope for improvement
Installing Vagrant
Nowadays there are packages for Win, OsX, Deb & Rpm. Check the Vagrant downloads page for the latest versions.
For instance, CentOS Installation steps are simple, first download RPM:
- wget https://dl.bintray.com/mitchellh/vagrant/vagrant_x.y.z_x86_64.rpm -O vagrant_x.y.z_x86_64.rpm
Install it:
- sudo rpm -i vagrant_x.y.z_x86_64.rpm
That’s it! Let’s check to make sure Vagrant works:
- Command: vagrant -v
- Result: Vagrant 1.4.2
Installlng VirtualBox
Since VirtualBox is free and is supported out-of-the-box by Vagrant, it's a good thing to download when working through introductory examples.
See VirtualBox downloads for standard stuff.
For instance, for CentOS7, can go through to Linux, then Oracle Linux 7 ("OL7") / Red Hat Enterprise Linux 7 ("RHEL6") / CentOS 7 AMD64, for a final link of http://download.virtualbox.org/virtualbox/4.3.28/VirtualBox-4.3-4.3.28_100309_el7-1.x86_64.rpm
Using Vagrant
Repository
For boxes, see Ashicorp Atlas
Basic Commands
See Vagrant Docs V2: Command Line Interface
I'm running off subdirectories of home/Vagrant, e.g. home/Vagrant/precise32
To set up new instance, change to new directory, then create VagrantFile via
- $ vagrant init hashicorp/precise32
Starting:
- $ vagrant up (works even if it has to download everything)
- $ vagrant resume (only works if was stopped by vagrant suspend)
Stopping:
- $ vagrant suspend (stores RAM image for quick restart)
- $ vagrant halt (power down equivalent)
- $ vagrant destroy (remove all cruft, need to reimport everything if restarting)
To connect
- $ vagrant ssh
Vagrantfile settings (version 2)
See Vagrant Docs V2: Vagrantfile
- config.vm.network "forwarded_port", guest : 80, host : 8080 will allow host to access guest port 80 via port 8080
Vagrant will map /vagrant on the VM to the host machine's Vagrantfile directory
- config.vm.synced_folder ".", "/foo" will change syncing of Vagrantfile folder from '/vagrant" to "/foo"
Sharing
See Vagrant Docs V2: Vagrant Share
When logged in (vagrant login):
- Http Sharing: you can issue vagrant share to then get a public URL allowing web browser access
- SSH Sharing: vagrant share --ssh
- Connect: when using vagrant share, others can then use vagrant connect to access all forwarded ports
Provisioning
See Vagrant Docs V2: Provisioning
"Provisioning" refers to the installation of software on a booted system. Vagrant supports provisioning with shell scripts, Chef or Puppet. The examples here will be from shell scripts, because they are easy to understand and won't bring a whole new system into the mix at this point.
Alternatives to shell scripts:
- Chef: Chef Solo (for small deployments) or Chef Client (for organisations already with a Chef Server)
- Puppet: masterless (for small deployments) or Puppet Agent (for organisations already with a Puppet Master)
Shell provisioning can be put inline in the Vagrantfile, or specified in an external script.
Shell Provisioning Example:
Create bootstrap.sh in your Vagrantfile directory:
#!/usr/bin/env bash apt-get update apt-get install -y apache2 if ! [ -L /var/www ]; then rm -rf /var/www ln -fs /vagrant /var/www fi
Next, we configure Vagrant to run this shell script when setting up our machine. We do this by editing the Vagrantfile, which should now look like this:
Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise32" config.vm.provision :shell, path: "bootstrap.sh" config.vm.network :forwarded_port, host: 4567, guest: 80 end
Then browsing to http://127.0.0.1:4567 will show the Vagrantfile directory in the web browser - add an index.html to see a page instead of directory contents
Networking
See Vagrant Docs V2: Networking
Port forwarding
config.vm.network "forwarded_port", guest: 80, host: 8080
- Simple but gets tedious as number of ports increases
- Host (and other machines on network) can talk to guest, but guest can't talk to host
Host-Only Networking
config.vm.network "private_network", ip: "192.168.33.10"
- Gives the guest an IP that only the host & guests can access
- Allows host and all guests to interact with each other
- Host gets IP as set, but with final octet = 1, eg 192.168.33.1
- It's the best way to work with a multimachine environment that requires the guests to intercommunicate
Bridged Networking
This makes the virtual machine look like a separate physical machine on the main network
config.vm.network "public_network"
- Fully-fledged network member, which is maximally useful (unless you want isolation)
- Can't pick the IP as it's served via DHCP, so need to SSH into the guest and get the IP via ifconfig
- May be no point if the main network router doesn't allow connection between machines
Composing Options
You can set up multiple networks: VirtualBox limit is 8 per guest. These networks can be the same or different types.
The First Network Interface
The first network, generally named "eth0" / "en0", is required to be a NAT (Network Address Translation) device that Vagrant uses for port forwarding: this is how Vagrant gets SSH access to the virtual machine.
Multiple Machines
See Vagrant Docs V2: Multi-Machine
Example:
config.vm.define "web" do |web| web.vm.network "forwarded_port", guest: 80, host: 8080 web.vm.provision "shell", path: "provision.sh" web.vm.provision "shell", inline: "apt-get -y install mysql-client" web.vm.network "private_network", ip: "192.168.33.10" end config.vm.define "db" do |db| db.vm.provision "shell", path: "db_provision.sh" db.vm.network "private_network", ip: "192.168.33.11" end
With db_provision.sh:
export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y mysql-server sed -i -e 's/127.0.0.1/0.0.0.0/' /etc/mysql/my.cnf restart mysql mysql -uroot mysql <<< "GRANT ALL ON *.* TO 'root'@'%'; FLUSH PRIVILEGES;"
All the config.vm settings are inherited, then one can specialise as desired. See the individual network settings.
Vagrant commands now can take arguments if you want to run them on specific machines:
- $ vagrant reload web
- $ vagrant up db
- $ vagrant status web
You can specify multiple machines too:
- $ vagrant reload db web
Or even use a regular expression (start and end with /)
- $ vagrant reload /node\d/
Some commands are single-machine only so will now require a parameter:
- $ vagrant ssh db
Boxes
Box data is off ~/.vagrant.d/boxes - so Box info is stored by user rather than by project directory.
To add:
- $ vagrant box add boxname or url or boxfilepath
To list:
- $ vagrant box list
To remove (a box is at least 200Meg, can be several Gig):
- $ vagrant box remove boxname
- Eg vagrant box remove precise64
To repackage an installed box so can pass boxfile onwards:
- $ vagrant box repackage boxname provider version
To package a box from the current vagrant instance:
- $ vagrant package
The Vagrant book has extensive instructions in Chapter 6 about how to produce a box from a VirtualBox image.
PlugIns
Plugins can add new commands, configuration options and provisioners. They can also add or change functionality within existing events (e.g. vagrant up, vagrant destroy). They can also add new guest- or host-specific functionality to help Vagrant work with any operating system.
To install (names refer to gems in the central, official RubyGems repo): $ vagrant plugin install name or gemfilepath To uninstall: $ vagrant plugin uninstall name To show installed: $ vagrant plugin list
Plugins are written in Ruby and packaged as RubyGems.
The definition contains main details: name, contained components. Should not make any Vagrant calls that might expire.
The "Vagrant: Up And Running" book has a lot of detail on how to make plugins - clearly Ruby expertise is necessary.
Environment Variables
- VAGRANT_CWD: where to look for Vagrantfile (default: cwd)
- VAGRANT_HOME: where to store global state (default: ~/.vagrant.d)
- VAGRANT_LOG: log verbosity: debug, info, warn, error. Info most useful generally. (default: none)
- VAGRANT_NO_PLUGINS: if set to any value, disables plugin load (default: unset)
- VAGRANT_VAGRANTFILE: filename of Vagrantfile (default: Vagrantfile)
Common Issues
64bit issues
Tried this with precise64 and got the below, might be worth looking at this thread
==> default: Successfully added box 'hashicorp/precise64' (v1.1.0) for 'virtualbox'! ==> default: Importing base box 'hashicorp/precise64'... ==> default: Matching MAC address for NAT networking... ==> default: Checking if box 'hashicorp/precise64' is up to date... ==> default: Setting the name of the VM: Vagrant_default_1434649082545_79341 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... The guest machine entered an invalid state while waiting for it to boot. Valid states are 'starting, running'. The machine is in the 'poweroff' state. Please verify everything is configured properly and try again. If the provider you're using has a GUI that comes with it, it is often helpful to open that and watch the machine, since the GUI often has more helpful error messages than Vagrant can retrieve. For example, if you're using VirtualBox, run `vagrant up` while the VirtualBox GUI is open.
Running VirtualBox and starting in the GUI, get this:
Failed to open a session for the virtual machine Vagrant_default_1434649082545_79341. VT-x is disabled in the BIOS. (VERR_VMX_MSR_VMXON_DISABLED). Result Code: NS_ERROR_FAILURE (0x80004005) Component: Console Interface: IConsole {8ab7c520-2442-4b66-8d74-4ff1e195d2b6}
The answer is to go into the BIOS (press F12 at boot time) and enable Virtualisation options.