Vagrant allows for the repeatable creation and management of virtual machine (VM) development environments.
The VM can contain numerous applications or systems in order to support development.
Created by HashiCorp
Vagrant supports many configuration management systems
including shell (Bash & Powershell), Ansible, Salt, Puppet & others.
Docker is a container platform that is intended to run single processes or small applications.
Docker containers share the host OS but isolate the processes between containers.
(The host still has access to the container processes)
Docker images share layers thus reduces the storage required for duplicate containers.
If the lifecycle of your application lives in containers, stick with containers.
Vagrant VMs have a complete guest OS and full isolation...
including processes, file system & network interfaces from host system and other VMs.
Vagrant itself doesn't have an equivalent to Docker layers,
Providers such as VirtualBox provide Linked Clones.
If your application lifecycle ends on steel or in virtual machines then give Vagrant a try.
Can Vagrant and Docker co-exist? Sure, Docker is a Vagrant provider.
Grab Vagrant from https://www.vagrantup.com
and install per instructions in Getting Started
Make sure that VirtualBox, Docker, VMWare or Hyper-V is available.
VirtualBox is the default provider,
but VMWare is recommended as it provides better performance and stability.
I have never had any issues with VirtualBox stability, can't comment on performance.
Service providers such as
Rackspace, AWS (EC2 and VPC), Google & Linode
have custom providers.
You may use shell scripts (I.E.: BASH), Ansible, Chef or Puppet
I have had good success using BASH scripts for personal project environments.
In an enterprise environment, a DevOps team might use a configuration management system.
More about this later...
Run the init command in the root of the project folder.
This will create a Vagrantfile in your project.
$ vagrant init [box]
$ vagrant init ubuntu/xenial64
The Vagrantfile is a Ruby script and can be updated in any programmic way you like as long as it returns the appropriate values.
There are examples of consuming JSON configuration files using Rudy and translating the JSON objects into the necesary Rudy values.
If you plan on using Puppet for provisioning you might consider PuPHPet, "a gui configurator for the Vagrant automation tool" to create your Vagrantfile & Puppet configuration.
Vagrant.configure("2") do |config|
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "base"
end
The Vagrantfile will initially have a lot of comments but only 1 line is initially important... "config.vm.box"
You have to search for a box from the Vagrant website that suits your needs.
(https://app.vagrantup.com/boxes/search)
You will find boxes available for various needs including...
full LAMP stacks, Rudy, Docker, Chef, Puppet.
$ vagrant box add "ubuntu/xenial64"
Popular boxes are "hashicorp/precise32" or "hashicorp/precise64" (Ubuntu 12.04)
Or "laravel/homestead" if you are a Laravel developer, you may have heard of it :P
I prefer "ubuntu/xenial64" (Ubuntu 16.04)
Vagrant Boxes are equivalent to Docker Images.
Vagrant.configure("2") do |config|
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/xenial64" # Ubuntu 16.04
end
You are now ready to start your Vagrant box with the image selected.
Inline shell script provisioning
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y apache2
rm -rf /var/www/html
ln -fs /vagrant /var/www/html
systemctl restart apache2
SHELL
Associating a provisioning shell script
config.vm.provision "shell", path: "./scripts/update.sh"
config.vm.hostname = "vagrant-intro-simple"
config.vm.network "forwarded_port", guest: 80, host: 8787
Multiple config.vm.network entries are allowed.
config.vm.synced_folder "src/", "/srv/website"
By default, the root of your project on the host is shared to the guest at /vagrant.
Provider specific configurations can be contained within a conditional section to be only applied appropriately.
config.vm.provider "virtualbox" do |v|
# Overrides the name of the VM in VirtualBox
v.name = "test-vagrant"
v.linked_clone = true
end
config.vm.provider "vmware_fusion" do |v|
v.linked_clone = false
v.vmx["memsize"] = "1024"
v.vmx["numvcpus"] = "2"
end
When using linked clones 2 VMs will be created initially, 1 base VM and 1 cloned VM.
Additional cloned VM will only create a single additional VM.
The base VM will not be started, just used as a "data source", do NOT delete the base VM!
$ vagrant up
This will download the box image, if not cached, create the VM and start it in headless mode
The VM will be named after the folder the Vagrantfile exists appended by a timestamp.
$ vagrant halt
$ vagrant status # outputs status of the vagrant machine(s)
$ vagrant ssh # connect to the machine using ssh
$ vagrant rdp # connects to machine via RDP
$ vagrant provision # provisions an existing machine
$ vagrant destroy # remove VM - Danger Will Robertson!
$ vagrant validate # validates the Vagrantfile
$ vagrant box # manages boxes: installation, removal, etc.
$ vagrant box add # add box to the local cache
$ vagrant box list # list boxes in local cache
$ vagrant box outdated # check if boxes in use are up to date
$ vagrant box prune # removes old versions of cached boxes
$ vagrant box remove # remove box from local cache
$ vagrant box repackage # package a new box to local cache
$ vagrant box update # update the box to the latest version
Vagrant.configure("2") do |config|
# set the box
config.vm.box = "ubuntu/xenial64"
# make the vm accessible from the host
config.vm.network "forwarded_port", guest: 80, host: 8787
# give it a unique hostname so we don't collide with other VMs with the same box
config.vm.hostname = "vagrant-intro-simple"
# do some stuff after the initial boot... i.e.: install apache and create a link to the source code
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y apache2
rm -rf /var/www/html
ln -fs /vagrant /var/www/html
systemctl restart apache2
SHELL
end
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.provision "shell", inline: <<-SHELL
apt-get update
SHELL
config.vm.define "web" do |web|
web.vm.hostname = "vagrant-intro-multi-web"
web.vm.network "forwarded_port", guest: 80, host: 8887
web.vm.network "private_network", ip: "10.0.0.10"
web.vm.provision "shell", path: "./scripts/apache.sh"
end
config.vm.define "db" do |db|
db.vm.hostname = "vagrant-intro-multi-db"
db.vm.network "private_network", ip: "10.0.0.20"
db.vm.provision "shell", path: "./scripts/mariadb.sh"
end
end
#!/usr/bin/env bash
echo "Installing Apache, PHP, xDebug & MariaDB client"
apt-get install -y apache2 libapache2-mod-php php php-mcrypt php-curl php-mysql php-xdebug mariadb-client-core-10.0
echo "Creating Apache html folder soft link"
rm -rf /var/www/html
ln -fs /vagrant /var/www/html
echo "Enabling mod_rewrite"
a2enmod rewrite
echo "Disabling sendfile as per vagrant suggestion"
cat <<- EOF >> /etc/apache2/apache2.conf
EnableSendfile Off
EOF
echo "Adding xDebug configuration"
cat <<- EOF >> /etc/php/7.0/mods-available/xdebug.ini
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.remote_connect_back=1
xdebug.idekey=PHPSTORM
EOF
echo "Restarting Apache"
systemctl restart apache2
#!/usr/bin/env bash
echo "Installing MariaDB"
apt-get install -y mariadb-server
echo "Creating vagrant user and vagrant_intro database"
mysql -u root -e "CREATE USER 'vagrant'@'10.0.0.10' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'vagrant'@'10.0.0.10';
CREATE USER 'admin'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'admin'@'%';
FLUSH PRIVILEGES;
CREATE DATABASE vagrant_intro;
CREATE TABLE vagrant_intro.users(id int(10) unsigned auto_increment primary key, username varchar(255) not null);"
echo "Updating bind address in /etc/mysql/mariadb.conf.d/50-server.cnf to 0.0.0.0 to allow external connections."
sudo sed -i "s/.*bind-address.*/\bind-address = 0.0.0.0/" /etc/mysql/mariadb.conf.d/50-server.cnf
echo "Restarting MySQL"
systemctl restart mysql
Vagrant is integrated into numerous IDEs including Eclipse, Komodo and Jetbrains products.
Most Vagrant VMs are headless, but can still be managed from VirtualBox.
It is not recommended though as any changes made in VirtualBox will not be reproducable.
Vagrant vs Docker: Which is better for WordPress development?
How is Docker different from a normal virtual machine?
Hashicorp Ecosystem