Before we start setting things up, I assume this is what you know / what you have:
The tutorial uses an installation of Ubuntu 14.04.2 LTS as the guest machine, VirtualBox at version 5.0.0 as provider and Vagrant at version 1.7.4.
File > Import appliance ...
, select the .ova
file you downloaded before.ubuntu-14.04-server-amd64
to devops-template
.Reinitialize the MAC address of all network cards
checkbox!Import
and you’ll have a new virtual machine added to VirtualBox after a few minutes ready to run.devops-template
in VirtualBox GUI and click Settings
Network
Enable Network Adapter
(if not already activated) under the tab Adapter 1
Attached to:
NAT
(this is a requirement by Vagrant)devops-template
in VirtualBox GUI and click Start
(wait until you see the ubuntu-amd64 login:
)ubuntu
as loginname an reverse
as password.$ sudo apt-get update
$ sudo apt-get dist-upgrade -y
/root/.profile
$ sudo nano /root/.profile
# ~/.profile: executed by Bourne-compatible login shells.
if [ "$BASH" ]; then
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
fi
mesg n # replace this line by "tty -s && mesg n"
Note: This avoids an annoying warning, when you vagrant up
later.
$ sudo nano /etc/hostname
ubuntu-amd64 # replace this by "devops-template"
$ sudo nano /etc/hosts
127.0.0.1 localhost
127.0.1.1 ubuntu-amd64 # replace this by "127.0.1.1 devops-template"
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
$ sudo locale-gen en_US.UTF-8 # Or whatever language you want to use
$ sudo dpkg-reconfigure locales
$ sudo nano /etc/default/locale
LANG="en_US.UTF-8"
LANGUAGE="en_US"
vagrant
user$ sudo adduser vagrant
# Set the password to "vargrant" too!
# Set the Full Name to "Vagrant", leave the rest blank
# Add a ssh config folder and authorized_keys file
$ sudo mkdir /home/vagrant/.ssh
$ sudo touch /home/vagrant/.ssh/authorized_keys
# Set owner and permissions
$ sudo chown -R vagrant /home/vagrant/.ssh
$ sudo chmod 0700 /home/vagrant/.ssh
$ sudo chmod 0600 /home/vagrant/.ssh/authorized_keys
# Add the insecure public key, see https://github.com/mitchellh/vagrant/tree/master/keys
$ su vagrant
$ curl 'https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub' >> /home/vagrant/.ssh/authorized_keys
$ exit
vagrant
$ sudo nano /etc/sudoers.d/vagrant
vagrant ALL=(ALL) NOPASSWD: ALL
$ sudo chmod 0440 /etc/sudoers.d/vagrant
$ sudo nano /etc/ssh/sshd_config
# Add the following line at the end of the file:
UseDNS no
Hint: Do not install the guest additions with apt-get install virtualbox-guest-additions-iso
as this release is mostly outdated.
I said above that I’m using VirtualBox in Version 5.0.0
, so the guest additions should be of the same version.
# prepare
$ sudo apt-get install -y linux-headers-generic build-essential dkms
# get the right ISO from http://download.virtualbox.org/virtualbox/
$ wget http://download.virtualbox.org/virtualbox/5.0.0/VBoxGuestAdditions_5.0.0.iso
# create a mount folder
$ sudo mkdir /media/VBoxGuestAdditions
# mount the ISO
$ sudo mount -o loop,ro VBoxGuestAdditions_5.0.0.iso /media/VBoxGuestAdditions
# install the guest additions
$ sudo sh /media/VBoxGuestAdditions/VBoxLinuxAdditions.run
# remove the ISO
$ rm VBoxGuestAdditions_5.0.0.iso
# unmount the ISO
$ sudo umount /media/VBoxGuestAdditions
# remove the mount folder
$ sudo rmdir /media/VBoxGuestAdditions
$ rm -rf /etc/motd
$ sudo nano /etc/motd
--
Welcome to devops-template version 0.1.0!
--
$ sudo shutdown -r now
Now you should see a login terminal like this:
Ubuntu 14.04.2 LTS devops-template tty1
devops-template login: _
Login and check the message of the day (motd) we set up:
Last login: ...
Welcome to Ubuntu ...
* Documentation: ...
[...]
--
Welcome to devops-template version 0.1.0!
--
ubuntu@devops-template:~$ _
$ sudo shutdown -h now
Got it? Yeah, preparation is done!
Remember, we said in the message of the day, that this is version 0.1.0
.
VagrantBoxes
and VagrantTest
$ mkdir ~/VagrantBoxes
$ mkdir ~/VagrantTest
devops-template
in VirtualBoxVagrantBoxes
directory.$ cd ~/VagrantBoxes
$ vagrant package --base 'devops-template' --output 'devops_0.1.0.box'
Note: Because we will build multiple versions of the devops-template
vm, we will put the version number in the name of the box file.
Packaging will take some time, you may get your next coffee!
When packaging is done, you should see an output like this:
==> devops-template: Exporting VM...
==> devops-template: Compressing package to: ~/VagrantBoxes/devops_0.1.0.box
VagrantTest
directory.$ cd ~/VagrantTest
$ vagrant box add 'devops' file://~/VagrantBoxes/devops_0.1.0.box
If successful, you should see output like this:
==> box: Adding box 'devops' (v0) for provider:
box: Downloading: file://~/VagrantBoxes/devops_0.1.0.box
==> box: Successfully added box 'devops' (v0) for 'virtualbox'!
Note the v0
. There is no version specified yet.
$ vagrant init
Now there is a Vagrantfile
with default settings in your current directory.
Vagrantfile
using a text editor# Change the following line from
config.vm.box = "base"
# to
config.vm.box = "devops"
# save the file
Note: base
is vagrant’s default name for a box. But we told vagrant box add
the name devops
.
$ vagrant up
If done, you should see output like this:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: VagrantTest_default_1406634147824_25052
==> 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...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTest
Note: Vagrant’s default behaviour is to boot the vm in headless mode (without a GUI in background). While booting the vm you can see the new vm in your VirtualBox GUI as “-> Running”
$ vagrant ssh
Now you should see our previously added message of the day.
VagrantTest
folder is mounted$ cd /vagrant/
$ ls -la
And you should see something like this:
drwxr-xr-x 1 vagrant vagrant 136 Jul 29 13:38 .
drwxr-xr-x 23 root root 4096 Jul 29 13:42 ..
drwxr-xr-x 1 vagrant vagrant 102 Jul 29 13:38 .vagrant
-rw-r--r-- 1 vagrant vagrant 4813 Jul 29 13:39 Vagrantfile
Okay, your box works fine, well done!
$ exit # On guest
$ vagrant destroy # On host
$ vagrant box remove 'devops'
Removing box 'devops' (v0) with provider 'virtualbox'...
In order to serve multiple versions of a vagrant box and enable update notifications we need to set up a box catalog. This catalog is written in JSON code to a single file.
To keep things simple at this point we will carry on in the local filesystem of your host.
devops
boxVagrantBoxes
directory.cd ~/VagrantBoxes
devops.json
with the following content{
"name": "devops",
"description": "This box contains Ubuntu 14.04.2 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "file://~/VagrantBoxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
}]
}
What is going on here?
devops
. All versions will be grouped under this name.$ openssl sha1 ~/VagrantBoxes/devops_0.1.0.box
SHA1(~/VagrantBoxes/devops_0.1.0.box)= d3597dccfdc6953d0a6eff4a9e1903f44f72ab94
Note: This is done on a linux based system. On Windows there will be another way.
Your catalog is finished!
VagrantTest
directory$ cd ~/VagrantTest
Vagrantfile
file in a text editor# Under ...
config.vm.box = "devops"
# ... add the line
config.vm.box_url = "file://~/VagrantBoxes/devops.json"
# save the file
vagrant up
without adding the box manually using vagrant box add
$ vagrant up
When done, you should see output like this:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'devops' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'file://~/VagrantBoxes/devops.json'
default: URL: file://~/VagrantBoxes/devops.json
==> default: Adding box 'devops' (v0.1.0) for provider: virtualbox
default: Downloading: file://~/VagrantBoxes/devops_0.1.0.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.0) for 'virtualbox'!
Note the line Loading metadata for box 'file://~/VagrantBoxes/devops.json'
that confirms the catalog is read.
And note the line Adding box 'devops' (v0.1.0) for provider: virtualbox
that confirms that version 0.1.0 is added to VirtualBox.
The last two lines confirm that our checksum in the devops.json
file was correct.
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'devops' is up to date...
==> default: Setting the name of the VM: VagrantTest_default_1406640770074_13210
==> 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...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTest
Again, our machine is up and running.
If you wish you now can re-check by ssh into the machine, reading the message of the day and listing the content of /vagrant
on the guest.
Okay, now we have built a vagrant box with an initial version. Let’s add another version.
$ vagrant halt
==> default: Attempting graceful shutdown of VM...
devops-template
and click Start
/etc/motd
from 0.1.0
to 0.1.1
and save the file$ sudo nano /etc/motd
--
Welcome to devops-template version 0.1.1!
--
$ sudo shutdown -h now
To be clear: Changing the version number in /etc/motd
has nothing to do with the version itself. It just simulates
a minor but visible change to the vm template. Instead of changing the content of a file, you’ll be installing software
or editing configs on a real-world vm.
VagrantBoxes
directory.$ cd ~/VagrantBoxes
$ vagrant package --base 'devops-template' --output 'devops_0.1.1.box'
==> devops-template: Exporting VM...
==> devops-template: Compressing package to: ~/VagrantBoxes/devops_0.1.1.box
Note the raised version number 0.1.1
in the output filename!
Your directory listing of ~/VagrantBoxes
should look like this now:
$ ls -a1 ~/VagrantBoxes
.
..
devops.json
devops_0.1.0.box
devops_0.1.1.box
If you wish you can test your new box like done under chapter 3.2.
devops.json
file in a text editor and extend the content to look like this:{
"name": "devops",
"description": "This box contains Ubuntu 14.04.1 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "file:///Users/hollodotme/VagrantBoxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
},{
"version": "0.1.1",
"providers": [{
"name": "virtualbox",
"url": "file:///Users/hollodotme/VagrantBoxes/devops_0.1.1.box",
"checksum_type": "sha1",
"checksum": "0b530d05896cfa60a3da4243d03eccb924b572e2"
}]
}]
}
Don’t forget to determine the checksum of the newly created box devops_0.1.1.box
!
VagrantTest
directory.$ cd ~/VagrantTest
$ vagrant box outdated
Checking if box 'devops' is up to date...
A newer version of the box 'devops' is available! You currently
have version '0.1.0'. The latest is version '0.1.1'. Run
`vagrant box update` to update.
Suprise, suprise - a new version is available!
Note: Instead of manually asking for outdated boxes, vagrant will notify you automatically when you use the
Vagrant commands like vagrant up
, vagrant reload
, vagrant resume
, etc.!
$ vagrant box update
==> default: Checking for updates to 'devops'
default: Latest installed version: 0.1.0
default: Version constraints:
default: Provider: virtualbox
==> default: Updating 'devops' with provider 'virtualbox' from version
==> default: '0.1.0' to '0.1.1'...
==> default: Loading metadata for box 'file://~/VagrantBoxes/devops.json'
==> default: Adding box 'devops' (v0.1.1) for provider: virtualbox
default: Downloading: file://~/VagrantBoxes/devops_0.1.1.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.1) for 'virtualbox'!
Note: The box with version 0.1.0
still exists. Vagrant will never prune your boxes automatically because of potential data loss.
$ vagrant box remove 'devops'
You requested to remove the box 'devops' with provider
'virtualbox'. This box has multiple versions. You must
explicitly specify which version you want to remove with
the `--box-version` flag. The available versions for this
box are:
* 0.1.0
* 0.1.1
Okay, so…
$ vagrant box remove 'devops' --box-version '0.1.0'
~/VagrantTest/Vagrantfile:5: warning: already initialized constant VAGRANTFILE_API_VERSION
~/VagrantTest/Vagrantfile:5: warning: previous definition of VAGRANTFILE_API_VERSION was here
Box 'devops' (v0.1.0) with provider 'virtualbox' appears
to still be in use by at least one Vagrant environment. Removing
the box could corrupt the environment. We recommend destroying
these environments first:
default (ID: 3206d9d1a427459daac770f2e7e81f1b)
Are you sure you want to remove this box? [y/N]
No! Let’s destroy it first.
$ vagrant destroy
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...
Now remove it, please!
$ vagrant box remove 'devops' --box-version '0.1.0'
Removing box 'devops' (v0.1.0) with provider 'virtualbox'...
Hell yeah!
$ vagrant up
$ vagrant ssh
Now you should see the previously changed version number 0.1.1
in the message of the day after login.
--
Welcome to devops-template version 0.1.1!
--
So we are up-to-date!
What we did so far:
What we will do now:
So cleanup your desk: exit your SSH session, destroy the vm and remove it from vagrant.
$ exit # On guest
$ vagrant destroy # On host
$ vagrant box remove 'devops'
As I mentioned at the beginning, I assume that you have private/public webserver and access to its config and filesystem.
For explanation I’ll use the domain www.example.com
targeting to this webserver.
Furthermore www.example.com
points to /var/www/
on the webserver’s filesystem (document root).
To keep things easy I prefer to separate the catalog and the box files physically in the filesystem. Keep on reading and you’ll understand why.
- /var/www # document root
`- vagrant
`- devops # box name folder
|- boxes # contains all available box files
| |- devops_0.1.0.box # version 0.1.0
| `- devops_0.1.1.box # version 0.1.1
`- devops.json # box catalog
Translated to URLs we have three targets to care about (we will use these later):
I want to explain the basic webserver configuration with nginx on a linux server, because this is my favorite software. The configuration can be ported to apache and/or windows as well.
$ ssh user@example.com
$ sudo apt-get install nginx-full
# Create folders
$ sudo mkdir -p /var/www/vagrant/devops/boxes
# Set owner to www-data
$ sudo chown -R www-data:www-data /var/www
# Set permissions
$ sudo chmod -R 0751 /var/www
default
sym-linked config for virtual hosts (vhost)$ sudo rm -rf /etc/nginx/sites-enabled/default
www.example.com
sudo nano /etc/nginx/sites-available/example.com
… with the following content:
server {
listen 80 default_server;
listen [::]:80 ipv6only=on default_server;
server_name example.com www.example.com;
root /var/www;
# Match the box name in location and search for its catalog
# e.g. http://www.example.com/vagrant/devops/ resolves /var/www/vagrant/devops/devops.json
location ~ ^/vagrant/([^\/]+)/$ {
index $1.json;
try_files $uri $uri/ $1.json =404;
autoindex off;
}
# Enable auto indexing for the folder with box files
location ~ ^/vagrant/([^\/]+)/boxes/$ {
try_files $uri $uri/ =404;
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
}
# Serve json files with content type header application/json
location ~ \.json$ {
add_header Content-Type application/json;
}
# Serve box files with content type application/octet-stream
location ~ \.box$ {
add_header Content-Type application/octet-stream;
}
# Deny access to document root and the vagrant folder
location ~ ^/(vagrant/)?$ {
return 403;
}
}
$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/000-example.com
$ service nginx restart
$ exit
Now, that our boxes won’t be stored any longer on the local filesystem, we have to change their locations in the box catalog.
~/VagrantBoxes/devops.json
in your text editor and change the content to this:{
"name": "devops",
"description": "This box contains Ubuntu 14.04.1 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "http://www.example.com/vagrant/devops/boxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
},{
"version": "0.1.1",
"providers": [{
"name": "virtualbox",
"url": "http://www.example.com/vagrant/devops/boxes/devops_0.1.1.box",
"checksum_type": "sha1",
"checksum": "0b530d05896cfa60a3da4243d03eccb924b572e2"
}]
}]
}
/var/www/vagrant/devops/
.If you open the URL http://www.example.com/vagrant/devops/ in your browser you should see your JSON box catalog.
/var/www/vagrant/devops/boxes/
.If you open the URL http://www.example.com/vagrant/devops/boxes/ in your browser you should see a directory listing with both box files listed.
Vagrantfile
~/VagrantTest
directory on your host.$ cd ~/VagrantTest
Vagrantfile
file in your text editor# Change the line
config.vm.box_url = "file://~/VagrantBoxes/devops.json"
# to
config.vm.box_url = "http://www.example.com/vagrant/devops/"
# save the file
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'devops' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'http://www.example.com/vagrant/devops/'
default: URL: http://www.example.com/vagrant/devops/
==> default: Adding box 'devops' (v0.1.1) for provider: virtualbox
default: Downloading: http://www.example.com/vagrant/devops/boxes/devops_0.1.1.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.1) for 'virtualbox'!
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'devops' is up to date...
==> default: Setting the name of the VM: VagrantTest_default_1406660957112_34972
==> 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...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTest
And here it is: Your own vagrant cloud!