Difference between revisions of "HashiCorp/Vagrant"

From Ever changing code
Jump to navigation Jump to search
 
(191 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Getting started =
= Introduction =
Create Vagrant project, by creating ''Vagrantfile'' in your current directory
Vagrant is configured on a per project basis. Each of these projects has its own Vagran file. The Vagrant file is a text file in which vagrant reads that sets up our environment. There is a description of what OS, how much RAM, and what software to be installed etc. You can version control this file.
vagrant init


Add boxes (standard VMs from providers in Virtualbox, VMware or Hyper-V format)
= Install | [https://github.com/hashicorp/vagrant/blob/v2.2.10/CHANGELOG.md Changelog] =
vagrant box add hashicorp/precise64        #username: hashicorp boximage: precise64, this is preconfigured repository
Check your distro most likely Ubuntu version candidate
#Box can be specified via URLs or local file paths
<source lang=bash>
vagrant box add --force <span style="color: green">ubuntu/14.04</span> <nowiki>https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box</nowiki>
 
vagrant box add --force ubuntu/14.04-i386 https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.boxvi
</source>
 
 
Download or upgrade
<source lang=bash>
# Install using Ubuntu package manager (2022)
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
apt-cache policy vagrant
sudo apt update
sudo apt install ./vagrant  
 
# Install downloading a package from sources
LATEST=$(curl -s GET https://api.github.com/repos/hashicorp/vagrant/tags | jq -r '.[].name' | head -n1 | tr -d v); echo $LATEST
VERSION=${LATEST:=2.2.18};
wget https://releases.hashicorp.com/vagrant/${VERSION}/vagrant_${VERSION}_linux_amd64.zip
sudo install /usr/bin/vagrant
#sudo dpkg -i vagrant_${VERSION}_x86_64.deb
#sudo apt-get update && sudo apt-get install -f  # resolve missing dependencies
 
# Fix plugins if needed
vagrant plugin update
vagrant plugin repair
vagrant plugin expunge --reinstall
</source>
 
 
Install ruby is recommended as configuration within '''Vagrant''' file is written in Ruby language.  
<source lang=bash>
sudo apt-get install ruby
sudo gem install bundler
sudo gem update  bundler    # if update needed
</source>
 
 
Repair plugins after the upgrade
<source lang=bash>
vagrant plugin repair    # use first
vagrant plugin expunge --reinstall
vagrant plugin update    # then update broken plugin
</source>


Configure Vagrantfile to use the box as your base system
= Images aka <code>box</code> management =
Vagrant comes with a preconfigured image repositories.
;Manage boxes
<source lang=bash>
vagrant box [list | add | remove] [--help]
</source>
 
 
;Add a box (image) into local repository
These are standard VMs from providers in Virtualbox, VMware or Hyper-V format taken from a given repository
<source lang=bash>
vagrant box add hashicorp/precise64      #user: hashicorp boximage: precise64, this is preconfigured repository
vagrant box add ubuntu/xenial64
vagrant box add ubuntu/xenial64    --box-version 20170618.0.0 --provider virtualbox
vagrant box add bento/ubuntu-18.04 --box-version 201812.27.0  --provider hyperv
 
# Box can be specified via URLs or local file paths, Virtualbox can only nest 32bit machines
vagrant box add --force ubuntu/14.04      https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
vagrant box add --force ubuntu/14.04-i386 https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.box
</source>
 
 
Windows images
* devopsgroup-io/windows_server-2012r2-standard-amd64-nocm
* peru/windows-server-2016-standard-x64-eval
* scotch/box
 
 
;Update a box to the latest version
<source lang=bash>
$> vagrant box list
ubuntu/bionic64                                          (virtualbox, 20190411.0.0)
ubuntu/bionic64                                          (virtualbox, 20190718.0.0)
 
$> vagrant box update --box ubuntu/bionic64
Checking for updates to 'ubuntu/bionic64'
Latest installed version: 20190718.0.0
Version constraints: > 20190718.0.0
Provider: virtualbox
Updating 'ubuntu/bionic64' with provider 'virtualbox' from version
'20190718.0.0' to '20200124.0.0'...
Loading metadata for box 'https://vagrantcloud.com/ubuntu/bionic64'
Adding box 'ubuntu/bionic64' (v20200124.0.0) for provider: virtualbox
Downloading: https://vagrantcloud.com/ubuntu/boxes/bionic64/versions/20200124.0.0/providers/virtualbox.box
Download redirected to host: cloud-images.ubuntu.com
 
$> vagrant box list
ubuntu/bionic64                                          (virtualbox, 20190411.0.0)
ubuntu/bionic64                                          (virtualbox, 20190718.0.0)
ubuntu/bionic64                                          (virtualbox, 20200124.0.0) # <- new downloaded
</source>
 
 
;Delete all images (aka boxes)
<source lang=bash>
vagrant box prune
</source>
 
= vagrant init - your first project =
;Configure Vagrantfile to use the box as your base system
<source lang="ruby">
Vagrant.configure("2") do |config|
config.vm.box      = "ubuntu/bionic64"
config.vm.hostname = "ubuntu" #hostname, requires reload
end
</source>
 
 
;Create Vagrant project, by creating ''Vagrantfile'' in your current directory
<source lang="bash">
vagrant init                    #initialises an project
vagrant init ubuntu/xenial64    # initialises official Ubuntu 16.04 LTS (Xenial Xerus) Daily Build
vagrant init ubuntu/bionic64    #supports only VirtualBox provider
vagrant init bento/ubuntu-18.04 #supports variety of providers
 
#Windows
vagrant init devopsgroup-io/windows_server-2012r2-standard-amd64-nocm #Windows 2012r2, VirtualBox only; cannot ssh
vagrant init peru/windows-server-2016-standard-x64-eval              #Windows 2016, halt works
vagrant init gusztavvargadr/windows-server                            #Windows 2019, full integration
</source>
 
 
;Power up your Vagrant box
<source lang="bash">
vagrant up
</source>
 
 
;Ssh to the box. Below example of nested virtualisation 64bit VM(host) runs 32bit (guest vm)
<source lang="bash">
piotr@vm-ubuntu64:~/git/vagrant$ vagrant ssh    #default password is "vagrant"
vagrant@vagrant-ubuntu-precise-32:~$ w
13:08:35 up 15 min,  1 user,  load average: 0.06, 0.31, 0.54
USER    TTY      FROM            LOGIN@  IDLE  JCPU  PCPU WHAT
vagrant  pts/0    10.0.2.2        13:02    1.00s  4.63s  0.09s w
</source>
 
 
;Shared directory between Vagrant VM and an hypervisor provider
Vagrant VM shares a directory mounted at <tt>/vagrant</tt>  with the directory on the host containing your Vagrantfile. This can be manually mounted from within VM as long the shared directory is setup in  GUI.
 
Eg. vm_name > Settings > Shared Folders > Name: vagrant | Path: /home/piotr/vm_name
<source>
sudo mount -t vboxsf -o uid=1000 vagrant /vagrant #firts arg 'vagrant' refers to GUI setiing
</source>
 
= Troubleshooting =
<source>
vagrant --debug up
</source>
== Nesting VMs ==
The error below is due to Virtualbox cannot run nested 64bit virtualbox VM. Spinning up a 64bit VM stops with an error that no 64bit CPU could be found. Update [https://forums.virtualbox.org/viewtopic.php?f=1&t=90831 VirtualBox 6.x Nested virtualization, VT-x/AMD-V in the guest].
<pre>
Error:
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.
</pre>
 
= Manage power states =
*<code>vagrant suspend</code> - saves the current running state of the machine and stop it
*<code>vagrant halt</code> - gracefully shuts down the guest operating system and power down the guest machine
*<code>vagrant destroy</code> - removes all traces of the guest machine from your system. It'll stop the guest machine, power it down, and remove all of the guest hard disks
 
= Snapshots =
You can easily save snapshots.
<source lang=bash>
# Get status
$ vagrant status
Current machine states:
default                  poweroff (virtualbox) # <- 'default' it's machine name
                                                # in multi-vm Vagrant config file
The VM is powered off. To restart the VM, simply run `vagrant up`
 
# List
vagrant snapshot list
==> default:
11_b4-upgradeVbox-stopped
12_Dec01_stopped
 
# Save
                        <nameOfvm> <snapshot-name>
vagrant snapshot save    default    13_Dec30_external-eks_stopped
 
# Restore
vagrant snapshot restore default    13_Dec30_external-eks_stopped
</source>
 
= Lookup path precedence for Vagrant project file =
When you run any vagrant command, Vagrant climbs your directory tree starting first in the current directory you are in. Example:
/home/peter/projects/la/Vagrant
/home/peter/projects/Vagrant
/home/peter/Vagrant
/home/Vagrant
/Vagrant
 
= Configuration =
== Networking ==
'''Private''' network is network that is not accessible from Internet. Networking stanza is a part of the main <tt>|config|</tt> loop.
 
DHCP IP address assigned
config.vm.network "private_network", type: "dhcp"
 
Static IP assigment
config.vm.network "private_network", ip: "192.168.80.5"
auto_config: false    #optional to disable auto-configure
 
'''Public network'''
These networks can be accessible from outside of the host machine including Internet, are usually '''Bridged Networks'''.
 
Examples of dhcp and static IP assignment
config.vm.network "public_network", type: "dhcp"
config.vm.network "public_network", ip: "192.168.80.5"
 
Default interface. The name need to match your system name otherwise Vagrant will prompt you to choose from available interfaces during ''vagrant up'' process.
config.vm.network "public_network", bridge: 'eth1'
 
== Port forwarding ==
Vagrant can forward any host(hypervisor) TCP port to guest vm specyfing in ~/git/vargant/Vagrant file
config.vm.network :forwarded_port, guest: 80, host: 4567
Reload virtual machine <code>vagrant reload</code> and run from hypervisor web browser http://127.0.0.1:4567 to test it.
 
== Sync folders ==
Vagrant v2 renamed ''Shared folders'' into '''Sync folders'''. This feature mounts HostOS directory into GuestOS. allowing workflow of editing files with IDE installed on a host machine but access them within GuestOS. The files sync both directions (as mount on GuestOS), Remember, taking <code>vagrant snapshot save ubuntu-snap1</code> '''will NOT save''' the '''Sync folder''' content as it's just mounted directory.
 
 
When configuring, 1st argument is a path existing on a '''host machine'''. If relative then it's relative to the root-project folder (where Vagrantfile exists) and 2nd arg is a full path to the mounted dir on guest-os.
 
 
;Enabling Sync folders and Symlinks
This can be done at any time, it's applied during <code>vagrant up | reload</code>. In general symlinks are disabled by VirtualBox as insecure.
<source lang=ruby>
Vagrant.configure("2") do |config|
#                    path on the host      mount on the guestOS
                              \            /       
    config.vm.sync_folder "git-host/", "/git", disabled: false
end
  config.vm.provider "virtualbox" do |vb|
    vb.name  = File.basename(Dir.pwd) + "_vagrant"
    ...
    vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//git",    "1"]
#  vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//vagrant", "1"]
 
    # symlinks should be active in root of vm by default
#  vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root",  "1"]
  end
</source>
 
 
Disabling
<source lang=ruby>
  Vagrant.configure("2") do |config|
  Vagrant.configure("2") do |config|
  config.vm.box = "<span style="color: green">ubuntu/14.04</span>"
    config.vm.sync_folder "../data/", "/vagrant-data", disabled: true
end
</source>
 
 
Modifying the Owner/Group
<source lang=ruby>
config.vm.sync_folder "../data/", "/vagrant-data", disabled: true,
    owner: "root", group: "root"
</source>
 
 
References
* [https://www.vagrantup.com/docs/synced-folders/basic_usage.html#id synced-folders] Hashicorp docs
 
= Vagrant providers =
Vagrant can work with a wide variety of backend providers, such as VMware, AWS, and more without changing Vagrantfile. It's enough to  specify the provider and Vagrant will do the rest:
<source>
vagrant up --provider=vmware_fusion
vagrant up --provider=aws
</source>
== Hyper-V ==
*Enable Hyper-V
*if you running Docker for Windows make sure is disabled as only one application can bound to Internal NAT vswitch, if you are using it
*WSL and Windows Vagrant versions must match
*the terminal you run WSL or PowerShell runs with elevated privileges
When running in WSL, make sure you have <code>export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1"</code>,
*you are in native Bash.exe not eg. ConEmu terminal with as it was proven not working at the time. You can change default provider by <code>export VAGRANT_DEFAULT_PROVIDER=hyperv</code>
 
Optional: Set the user-level environment variable in PowerShell:
<source>
[Environment]::SetEnvironmentVariable("VAGRANT_DEFAULT_PROVIDER", "hyperv", "User")
</source>
 
;Workarounds
Copy insecure private key from <code>https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant to WSL ~/.vagr
ant_key/private_key</code> because Microsoft filesystem does not support Unix style file permissions, until WSL2 is released.
<source>
$ wget https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant -O ~/.vagrant_key/private_key
# then set in Vagrantfile
config.ssh.private_key_path = "~/.vagrant_key/private_key"
</source>
 
 
When running on HyperV you need to choose a vswitch you will use. Vagrant will prompt you, select "Default Switch", w
hich is eqvivalent of NAT Network. You need to creat your own vswitch if you want access to Internet.
 
Go to Hyper-V Manager, open Virtual Switch Manager..., create External switch, name: vagrant-external, press OK. Then
run.
 
<source>
vagrant up --provider hyperv
 
    default: Please choose a switch to attach to your Hyper-V instance.
    default: If none of these are appropriate, please open the Hyper-V manager
    default: to create a new virtual switch.
    default:
    default: 1) DockerNAT
    default: 2) Default Switch
    default: 3) vagrant-external
    default:
    default: What switch would you like to use?3    #<-- select 3
</source>
Read more https://www.vagrantup.com/docs/hyperv/limitations.html
 
Run Vagrant file
<source lang=bash>
vagrant up --provider=hyperv
</source>
 
=== References ===
*[https://gist.github.com/savishy/8ed40cd8692e295d64f45e299c2b83c9 Create vSwitch in Hyper-V to run Vagrant]
*[https://techcommunity.microsoft.com/t5/Virtualization/Copying-Files-into-a-Hyper-V-VM-with-Vagrant/ba-p/382376 Copying Files into a Hyper-V VM with Vagrant]
*[https://techcommunity.microsoft.com/t5/Virtualization/Vagrant-and-Hyper-V-Tips-and-Tricks/ba-p/382373 Vagrant and Hyper-V -- Tips and Tricks] techcommunity.microsoft.com
 
= Provisioners =
==Shell provisioner==
Vagrant can run from shared location script or from inline: Vagrant file shell provisioning commands.
 
Create provisioning script
<source lang=bash>
vi ~/git/vagrant/bootstrap.sh   
#!/usr/bin/env bash
export http_proxy=<nowiki>http://username:password@proxyserver.local:8080</nowiki>
export https_proxy=$http_proxy
apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then
  rm -rf /var/www
  ln -sf /vagrant /var/www  # sets Vagrant shared dir to Apache DocumentRoot
fi
</source>
 
 
Configure Vagrant to run this shell script above when setting up our machine
<source lang=bash>
vi ~/git/vagrant/Vagrantfile 
Vagrant.configure("2") do |config|
  config.vm.box = ubuntu/14.04-i386
  config.vm.provision: shell, path: "bootstrap.sh"
end
</source>
 
 
Another example of using shell provisioner, separating a script out
<source lang=bash>
$script = <<SCRIPT
echo    " touch /home/vagrant/test_\\`date +%s\\`.txt " > /home/vagrant/newfile
chmod +x        /home/vagrant/newfile
echo "* * * * * /home/vagrant/newfile" > mycron
crontab mycron
SCRIPT
 
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.provision "shell", inline: $script , privileged: false
end
</source>
 
 
Bring the environment up 
<source lang=bash>
vagrant up                  #runs provisioning only once
vagrant reload --provision  #reloads VM skipping import and runs provisioning
vagrant ssh                  #ssh to VM
wget -qO- 127.0.0.1          #test Apache is running on VM
</source>
 
 
;Provisioners - shell, ansible, ansible_local and more
 
This section is about using Ansible with Vagrant,
*<code>ansible</code>, where Ansible is executed on the '''Vagrant host'''
*<code>ansible_local</code>, where Ansible is executed on the '''Vagrant guest'''
 
==Ansible provisioner==
 
Specify Ansible as a provisioner in Vagrant file
<source lang=ruby>
# Run Ansible from the Vagrant Host
config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
  end
  end
</source>
== Chef_solo provisioner ==
Create recipe, the following dirctory structure is required, eg. recipe name is: vagrant_la
├── cookbooks
│   └── vagrant_la
│      └── recipes
│          └── default.rb
Vagrant
Recipe
<source lang=ruby>
vi cookbooks/vagrant_la/recipes/default.rb
execute "apt-get update"
package "apache2"
execute "rm -rf /var/www"
link "var/www" do
        to "/vagrant"
end
</source>


;Power up your Vagrant box
vagrant up


Error:
In Vagrant file add following
''Timed out while waiting for the machine to boot. This means that
<source lang=ruby>
Vagrant was unable to communicate with the guest machine within
config.vm.provision "chef_solo" do |chef|
the configured ("config.vm.boot_timeout" value) time period.
        chef.add_recipe "vagrant_la"
end
</source>
 
 
Run <code>vagrant up</code>
 
== Puppet manifest ==
Create Vagrant provisioning stanza
<source lang=ruby>
config.vm.define "web" do |web|
        web.vm.hostname = "web"
        web.vm.box = "apache"
        web.vm.network "private_network", type: "dhcp"
        web.vm.network "forwarded_port", guest: 80, host: 8080
        web.vm.provision "puppet" do |puppet|
                puppet.manifests_path = "manifests"
                puppet.manifest_file = "default.pp"
        end
end
</source>
 
 
Create a required folder structure for puppet manifests
├── manifests
│   └── default.pp
└── Vagrantfile
 
 
Puppet manifest file
vi manifests/default.pp
exec { "apt-get update":
        command => "/usr/bin/apt-get update",
}
package { "apache2":
        require => Exec["apt-get update"],
}
file { "/var/www":
        ensure => link,
        target => "/vagrant",
        force => true,
}
 
= Box images advanced=
vagrant box list  #list all downloaded boxes
 
Default path of boxes image, it can be specified by environment variable <tt>VAGRANT_HOME</tt>
C:\Users\%username%\.vagrant.d\boxes  #Windows
~/.vagrant.d/boxes                    #Linux


If you look above, you should be able to see the error(s) that
Change default path via environment variable
Vagrant had when attempting to connect to the machine. These errors
export VAGRANT_HOME=my/new/path/goes/here/
are usually good hints as to what may be wrong.


If you're using a custom box, make sure that networking is properly
==Box format==
working and you're able to connect to the machine. It is a common
When you un-tar the <tt>.box</tt> file it contains 4 files:
problem that networking isn't setup properly in these boxes.
|--Vagrantfile
Verify that authentication configurations are also setup properly,
|--box-disk1.vmdk  #compressed virtual disk
as well.
|--box.ovf        #description of virtual hardware
|--metadata.json


If the box appears to be booting properly, you may want to increase
== [https://www.vagrantup.com/docs/virtualbox/boxes.html Create box] from current project (package a box) ==
the timeout ("config.vm.boot_timeout") value.''
This allows to create a reusable box that contains all changes to the software we made, VirtualBox or Hyper-V supported only.


The error above is due to Virtualbox cannot run nested 64bit virtualbox VM. Spinning up a 64bit VM stops with an error that no 64bit CPU could be found.


[https://www.vagrantup.com/docs/cli/package.html Command basics]
<source lang=bash>
<source lang=bash>
piotr@vm-ubuntu64:~/git/vagrant$ vagrant up
vagrant package [options] [name|id]
Bringing machine 'default' up with 'virtualbox' provider...
# --base NAME - instead of packaging a VirtualBox machine that Vagrant manages,
==> default: Importing base box 'ubuntu/14.04-i386'...
#              this will package a VirtualBox machine that VirtualBox manages
==> default: Matching MAC address for NAT networking...
# --output NAME - default is package.box
==> default: Setting the name of the VM: vagrant_default_1456318357740_51238
# --include x,y,z - additional files will be packaged with the box
</source>
 
 
Package
<source lang=bash>
$ vagrant version # -> Installed Version: 2.2.9
 
# Optional '--vagrantfile NAME' can be included, that automatically restores '--include' files
# learn more at https://www.vagrantup.com/docs/vagrantfile#load-order
$ time vagrant package --output u18cli-1.box --include data,git-host,git-host3rd,sync.sh,cleanup.sh
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Exporting VM...
==> default: Preparing network interfaces based on configuration...
==> default: Compressing package to: /home/piotr/vms-vagrant/u18cli-1/2020-05-23-u18cli-1.box
    default: Adapter 1: nat
==> default: Packaging additional file: data              # <- dir
==> default: Forwarding ports...
==> default: Packaging additional file: git-host          # <- dir
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Packaging additional file: git-host3rd        # <- dir
==> default: Booting VM...
==> default: Packaging additional file: cleanup.sh        # <- file
==> default: Waiting for machine to boot. This may take a few minutes...
real 15m27.324s user 8m23.550s sys 0m16.827s
     default: SSH address: 127.0.0.1:2222
</source>
    default: SSH username: vagrant
 
    default: SSH auth method: private key
 
    default: Warning: Remote connection disconnect. Retrying...
Re-ristribute the <tt>.box</tt> file then restore it.
    default: Warning: Remote connection disconnect. Retrying...
<source lang=bash>
    default:
# Add the packaged box to local system box repository
    default: Vagrant insecure key detected. Vagrant will automatically replace
#                        _____box-name________ __box-file_____
    default: this with a newly generated keypair for better security.
$ vagrant box add --name box-packages/u18cli-1 u18cli-1-v1.box
    default:  
==> box: Box file was not detected as metadata. Adding it directly...
    default: Inserting generated public key within guest...
==> box: Adding box 'u18cli-1-v1.box' (v0) for provider:
    default: Removing insecure key from the guest if it's present...
    box: Unpacking necessary files from: file:///home/piotr/vms-vagrant/test-box-restore/u18cli-1-v1.box
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> box: Successfully added box 'box-packages/u18cli-1' (v0) for 'virtualbox'!
==> default: Machine booted and ready!
 
==> default: Checking for guest additions in VM...
# List boxes
     default: The guest additions on this VM do not match the installed version of
$ vagrant box list
     default: VirtualBox! In most cases this is fine, but in rare cases it can
box-packages/u18cli-1 (virtualbox, 0)
    default: prevent things such as shared folders from working properly. If you see
 
    default: shared folder errors, please make sure the guest additions within the
$ ls -l ~/.vagrant.d/boxes
    default: virtual machine match the version of VirtualBox you have installed on
total 16
    default: your host and reload your VM.
drwxrwxr-x 3 piotr piotr 4096 Jul 16 17:44 box-packages-VAGRANTSLASH-u18cli-1
    default:  
</source>
    default: Guest Additions Version: 4.1.44
 
    default: VirtualBox Version: 4.3
 
==> default: Mounting shared folders...
Restore. Create/re-use Vagrantfile using box you added to your local box repository
     default: /vagrant => /home/piotr/git/vagrant
<source lang=bash>
# vi Vagrantfile
config.vm.box = "box-packages/u18cli-1.box"
 
vagrant up
# restore '--include' files coping them from
# 'ls -l ~/.vagrant.d/boxes/box-packages-VAGRANTSLASH-u18cli-1/0/virtualbox/include/*'
</source>
 
= [https://tuhrig.de/resizing-vagrant-box-disk-space/ Resizing Vagrant box disk] =
* [https://www.vagrantup.com/docs/disks/usage Resizing primary disk] native way
 
= Enable Vagrant to use proxy server for VMs =
Install proxyconf plugin or use <code>vagrant plugin list</code> to verify if installed
vagrant plugin install vagrant-proxyconf
 
Configure your Vagrantfile, here particularly host 10.0.0.1:3128 runs CNTLM proxy
Vagrant.configure("2") do |config|
    <nowiki>config.proxy.http = "http://10.0.0.1:3128"
     config.proxy.https = "http://10.0.0.1:3128"</nowiki>
    config.proxy.no_proxy = "localhost,127.0.0.1"
 
= Virtualbox Guest Additions =
== Sync using vagrant-vbguest plugin ==
Install plugin
<source lang=bash>
vagrant gem install vagrant-vbguest    #for vagrant < 1.1.5
vagrant plugin install vagrant-vbguest #for vagrant 1.1.5+
 
#Verify current version, running on a host(hypervisor)
vagrant vbguest --status
 
#Add to your Vagrant file (Vagrant 1.1.5+)
if Vagrant.has_plugin?("vagrant-vbguest")
  host.vbguest.auto_update = true
  host.vbguest.no_remote  = true
end
</source>
 
 
Then install the correct version matching your host installation
<source lang=bash>
vagrant vbguest --do install
 
#Full command options
vagrant vbguest [vm-name] [--do start|rebuild|install] [--status] [-f|--force] \
                [-b|--auto-reboot] [-R|--no-remote] [--iso VBoxGuestAdditions.iso] [--no-cleanup]
</source>
More you will find at [https://github.com/dotless-de/vagrant-vbguest vagrant-vbguest] plugin project.
 
== Manual upgrade ==
Find out what version you are running, execute on a guest VM
<source lang=bash>
vagrant@ubuntu:~$ modinfo vboxguest | grep ^version
version:       6.0.10 r132072
 
vagrant@ubuntu:~$ lsmod | grep -io vboxguest | xargs modinfo | grep -iw version
version:       6.0.10 r132072
 
vagrant@u18cli-3:~$ sudo /usr/sbin/VBoxService --version
6.0.10r132072
</source>
 
 
Download the extension, you can explore [http://download.virtualbox.org/virtualbox here]
<source lang=bash>
wget http://download.virtualbox.org/virtualbox/5.0.32/VBoxGuestAdditions_5.0.32.iso
#you need to get it mounted or extracted the content and run inside the VM.
</source>
 
== References ==
*[https://github.com/chilcano/box-vagrant-wso2-dev-srv/blob/master/_downloads/vagrant-vboxguestadditions-workaroud.md Upgrade Vbox extension additions within Vagrant box]
 
= List all Virtualbox SSH redirections =
<source>
vboxmanage list vms | cut -d ' ' -f 2  > /tmp/vms.out && for vm in $(cat /tmp/vms.out); do vboxmanage showvminfo "$vm" | grep ssh; done
vboxmanage list vms | cut -d ' ' -f 1 | sed 's/"//g' > /tmp/vms.out && for vm in $(cat /tmp/vms.out); do echo $vm; vboxmanage showvminfo "$vm" | grep ssh; done
vboxmanage list vms \
  | cut -d ' ' -f 1 \
  | sed 's/"//g' > /tmp/vms.out \
  && for vm in $(cat /tmp/vms.out); do vboxmanage showvminfo "$vm" \
                                      | grep ssh \
                                      | tr --delete '\n'; echo " $vm"; done
 
sed 's/"//g'      #removes double quotes from whole string
tr --delete '\n'  #deletes EOL, so the next command output is appended to the previous line
</source>
 
= Vagrant file =
;Ruby gotchas
Vagrant configuration file is written in Ruby specification, therefore you need to remember
*don't use dashes in object names, '''don't''': <tt>jenkins-minion_config.vm.box = "ubuntu/xenial64"</tt>
*don't use symbols (here underscore) in variable names, '''don't''': <tt>(1..2).each do |minion_number|</tt>
 
 
== HAProxy cluster, multi-node Vagrant config  ==
<source lang="bash">
git clone https://github.com/jweissig/episode-45
</source>
 
 
This creates ''Ansible'' mgmt server, Load Balancer and Web nodes [1..2]. HAProxy will be configured via Ansible code.
<source lang="bash">
# -*- mode: ruby -*-
# vi: set ft=ruby :
 
Vagrant.configure("2") do |config|
# create mgmt node
config.vm.define :mgmt do |mgmt_config|
    mgmt_config.vm.box = "ubuntu/trusty64"
    mgmt_config.vm.hostname = "mgmt"
    mgmt_config.vm.network :private_network, ip: "10.0.15.10"
    mgmt_config.vm.provider "virtualbox" do |vb|
      vb.memory = "256"
    end
    mgmt_config.vm.provision :shell, path: "bootstrap-mgmt.sh"
end
 
# create load balancer
config.vm.define :lb do |lb_config|
    lb_config.vm.box = "ubuntu/trusty64"
    lb_config.vm.hostname = "lb"
    lb_config.vm.network :private_network, ip: "10.0.15.11"
    lb_config.vm.network "forwarded_port", guest: 80, host: 8080
    lb_config.vm.provider "virtualbox" do |vb|
      vb.memory = "256"
    end
end
 
# create some web servers
# https://docs.vagrantup.com/v2/vagrantfile/tips.html
  (1..2).each do |i|
     config.vm.define "web#{i}" do |node|
        node.vm.box = "ubuntu/trusty64"
        node.vm.hostname = "web#{i}"
        node.vm.network :private_network, ip: "10.0.15.2#{i}"
        node.vm.network "forwarded_port", guest: 80, host: "808#{i}"
        node.vm.provider "virtualbox" do |vb|
          vb.memory = "256"
        end
     end
  end
end
</source>
 
 
Boot strap script <tt>bootstrap-mgmt.sh</tt>
<syntaxhighlight lang="shell">
#!/usr/bin/env bash
# install ansible (http://docs.ansible.com/intro_installation.html)
apt-get -y install software-properties-common
apt-add-repository -y ppa:ansible/ansible
apt-get update
apt-get -y install ansible
 
# copy examples into /home/vagrant (from inside the mgmt node)
cp -a /vagrant/examples/* /home/vagrant
chown -R vagrant:vagrant /home/vagrant
 
# configure hosts file for our internal network defined by Vagrantfile
cat >> /etc/hosts <<EOL
# vagrant environment nodes
10.0.15.10  mgmt
10.0.15.11  lb
10.0.15.21  web1
10.0.15.22  web2
10.0.15.23  web3
10.0.15.24  web4
10.0.15.25  web5
10.0.15.26  web6
10.0.15.27  web7
10.0.15.28  web8
10.0.15.29  web9
EOL
</syntaxhighlight>
 
 
Gitbash path -  <code>/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe</code>
 
Set bootstrap script for Proxy or No-proxy specific system
<source lang="bash">
Vagrant status
Vagrant up
Vagrant ssh mgmt
ansible all --list-hosts
ssh-keyscan web1 web2 lb > ~/.ssh/known_hosts
ansible-playbook ssh-addkey.yml -u vagrant --ask-pass
ansible-playbook site.yml
</source>
 
 
Once set it up you can navigate on your laptop to:
<source lang="bash">
http://localhost:8080/              #Website test
http://localhost:8080/haproxy?stats #HAProxy stats
</source>
 
 
Use to verify end server
<source lang="bash">
curl -I http://localhost:8080
</source>
 
 
[[File:X-Backend-Server.png|none|left|Curl -i X-Backend-Server]]
 
 
Generate web traffic
<source lang="bash">
vagrant ssh lb
sudo apt-get install apache2-utils
ansible localhost -m apt -a "pkg=apache2-utils state=present" --become
ab -n 1000 -c 1 http://10.0.2.15:80/ # Apache replaced 'ab' with 'hey'
</source>
 
= Vagrant DNS =
== Multi-machine mDNS discovery ==
Multi-machine setup requires 3 ingredients* :
* each machine to have different hostname
* a way of getting the IP address for a hostname (eg. mDNS)
* connect the VMs through a private network
 
 
In multi-machine configuration we need a way of getting the IP address for a hostname. We use <code>mDNS</code> for this. By default <codemDNS</code> only resolves host names ending with the <code>.local</code> top-level domain (TLD). This can cause problems if that domain includes hosts which do not implement mDNS but which can be found via a conventional unicast DNS server. Resolving such conflicts requires network-configuration changes that violate the zero-configuration goal. Install <code>avahi</code> system on all machines to facilitate service discovery on a local network via the <code>mDNS/DNS-SD</code> protocol suite.
<source lang=bash>
config.vm.provision "shell", inline: <<-SCRIPT
  apt-get install -y avahi-daemon libnss-mdns
SCRIPT
</source>
 
 
;References
*[https://github.com/lathiat/nss-mdns nss-mdns] system which allows hostname lookup of *.local hostnames via mDNS in all system programs using nsswitch
*[https://www.avahi.org/ avahi.org]
 
== Set host system DNS server resolver ==
<source lang=ruby>
config.vm.provider :virtualbox do |vb|
     vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
end
</source>
 
= Ubuntu with GUI =
This article is going to describe to setup Vagrant Virtualbox VM with GUI, setting up xserver with xfce4 as desktop environment.
== Locales ==
This is not working
<source lang=bash>
    locale-gen en_GB.utf8 #en_GB.UTF-8
    update-locale LANG=en_GB.UTF-8
    locale-gen --purge "en_GB.UTF-8"
    dpkg-reconfigure --frontend=noninteractive locales
    dpkg-reconfigure --frontend=noninteractive keyboard-configuration
    localedef -i en_GB -c -f UTF-8 en_GB.utf8
    sudo update-locale LANG=en_GB.UTF-8
    locale-gen --purge "en_GB.UTF-8"
</source>
</source>


;Shared directory between Vagrant VM and an hypervisor provider
Troubleshooting
Vagrant shares a directory at /vagrant with the directory on the host containing your Vagrantfile
<source lang=bash>
locale -a #shows which locales are available on your system
sudo less /usr/share/i18n/SUPPORTED
cat /etc/default/locale
 
#Set system wide locales (does not work for users)
localectl set-locale LANG=en_GB.UTF-8 LANGUAGE=en_GB:en
localectl set-keymap gb
localectl set-x11-keymap gb
 
#Quick kb change
apt-get install -yq x11-xkb-utils; setxkbmap gb
</source>
 
== Gnome3 ==
This setup installs Ubuntu desktop and may require a restart to apply changes to like a taskbar with shortcuts.
<source lang="ruby">
# -*- mode: ruby -*-
# vi: set ft=ruby :
 
Vagrant.configure("2") do |config|
  config.vm.box      = "ubuntu/bionic64" #bento/ubuntu-18.04, ubuntu/xenial64
 
  machineName = File.basename(Dir.pwd) #name as a current working dir
# machineName = 'u18gui-1'
  config.vm.hostname = machineName
 
  # Manually check for updates `vagrant box outdated`
  config.vm.box_check_update = false
 
  # Vbguest plugin
  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = false
    config.vbguest.no_remote  = true
  end
 
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
  # Public network, which generally matched to bridged network.
  # config.vm.network "public_network"
 
  # config.vm.synced_folder "hostDir", "/InVagrantMount/path"
  # config.vm.synced_folder "../data", "/vagrant_data"
 
  config.vm.provider "virtualbox" do |vb|
    vb.gui    = true
    vb.memory = "3072"
    vb.name  = machineName + "_vagrant"
  end
 
  config.vm.provision "shell", inline: <<-SHELL
    export DEBIAN_FRONTEND=noninteractive
    setxkbmap gb
    apt-get update && apt-get upgrade -yq
    apt-get install -yq ubuntu-desktop --no-install-recommends
    apt-get install -yq terminator tmux
    #only U16 xenial to fix Unity
    #apt-get install -yq unity-lens-files unity-lens-applications indicator-session --no-install-recommends
  SHELL
end
</source>
 
 
Running up
<source lang="bash">
vagrant plugin install vagrant-vbguest
vagrant up && vagrant vbguest --do install && vagrant reload
</source>
 
== Xface ==
Get a basic Ubuntu image working, boot it up and vagrant ssh.
Next, enable the VirtualBox display, which is off by default. Halt the VM and uncomment these lines in Vagrantfile:
<source lang=ruby>
config.vm.provider :virtualbox do |vb|
  vb.gui = true
end
</source>
 
 
Boot the VM and observe the new display window. Now you just need to install and start xfce4. Use vagrant ssh and:
<source lang="bash">
sudo apt-get install -y xfce4 virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11
#guest additions are already installed on most of the Vagrant boxes
</source>
 
Don't start the GUI as root because you really want to stay the vagrant user. To do this you need to permit anyone to start the GUI:
<source lang="bash">
sudo vim /etc/X11/Xwrapper.config and edit it to allowed_users=anybody
sudo startxfce4&
sudo VBoxClient-all #optional
</source>
 
You should be landed in a xfce4 session.
 
(Optional) If VBoxClient-all script isn't installed or anything is missing, you can replace with the equivalent:
<source lang="bash">
sudo VBoxClient --clipboard
sudo VBoxClient --draganddrop
sudo VBoxClient --display
sudo VBoxClient --checkhostversion
sudo VBoxClient --seamless
</source>
 
== References ==
*[http://stackoverflow.com/questions/18878117/using-vagrant-to-run-virtual-machines-with-desktop-environment Vagrant GUI vms] stackoverflow
 
= Windows=
<source lang=ruby>
# -*- mode: ruby -*-
# vi: set ft=ruby :
 
Vagrant.configure("2") do |config|
  config.vm.box = "gusztavvargadr/windows-server"
  config.vm.box_check_update = false
  config.vm.provider "virtualbox" do |vb|
    vb.gui = true      # Display the VirtualBox GUI when booting the machine
    vb.memory = "3072"  # Customize the amount of memory on the VM:
  end
  # Plugins
  config.vbguest.auto_update = false
  config.vbguest.no_remote = true
end
</source>
 
 
Shared location
* enable Network Sharing
* Vagrant path is mapped to <code>\\VBOXSVR\vagrant</code>


Delete Vagrant VM
= WIP DevOps workstation =
vagrant destroy
This to contain:
*bashrc with git branch in ps1
*bash autocomplete (...samename)
*bash colored symlinks
*bash_logout and .profile to eval ssh-agent and kill on exit
*git install
*ansible 1.9.4
*java Oracle
*clone tfenv and install terraform
*vim install
*vundle install
*[done] python 2.7 OOB in 16.04
*[done]python pip: awscli, boto, boto3, etc..


Delete downloaded Vagrant VM image file
Challenges:
vagrant box remove
*Ubuntu 16.04 official box does not come with a default ''vagrant'' user but instead comes with ''ubuntu'' user. This causes a number of incompatibilities.
**Read more at launchpad [https://bugs.launchpad.net/cloud-images/+bug/1569237 vagrant xenial box is not provided with vagrant/vagrant username and password ]
* Solutions
** on W10 host both users: ubuntu & vagrant exist. Only vagrant has insecure_pub installed OOB. I am coping vagrant user pub key into ubuntu user authorized_keys
** on U16.05 host the official image does not seem to come with vagrant user but Ubuntu user works OOB
** Read more at SO
***[Vagrant's Ubuntu 16.04 vagrantfile default password https://stackoverflow.com/questions/41337802/vagrants-ubuntu-16-04-vagrantfile-default-password]
***[https://stackoverflow.com/questions/30075461/how-do-i-add-my-own-public-key-to-vagrant-vm How do I add my own public key to Vagrant VM?]
*** [https://blog.ouseful.info/2015/07/27/running-a-shell-script-once-only-in-vagrant/ Running a Shell Script Once Only in vagrant]


= Resources =
= References =
*[https://www.vagrantup.com/docs/getting-started/ Vagrant Start up documentation]
*[https://www.vagrantup.com/docs/getting-started/ Vagrant Start up documentation]
*[https://atlas.hashicorp.com/boxes/search Vagrant Hashicorp VMs repository] Virtualbox
*[https://atlas.hashicorp.com/boxes/search Vagrant Hashicorp VMs repository] Virtualbox
*[https://cloud-images.ubuntu.com/vagrant/ Vagrant Ubuntu VMs images] Virtualbox
*[https://cloud-images.ubuntu.com/vagrant/ Vagrant Ubuntu VMs images] Virtualbox
*[https://www.vagrantup.com/docs/provisioning/ansible_intro.html Vagrant and Ansible provisioner] Vagrant docs
*[https://manski.net/2016/09/vagrant-multi-machine-tutorial/#multi-machine.3A-the-naive-way Vagrant Tutorial – From Nothing To Multi-Machine] Tutorial

Latest revision as of 09:30, 3 October 2022

Introduction

Vagrant is configured on a per project basis. Each of these projects has its own Vagran file. The Vagrant file is a text file in which vagrant reads that sets up our environment. There is a description of what OS, how much RAM, and what software to be installed etc. You can version control this file.

Install | Changelog

Check your distro most likely Ubuntu version candidate



Download or upgrade

# Install using Ubuntu package manager (2022)
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
apt-cache policy vagrant
sudo apt update
sudo apt install ./vagrant 

# Install downloading a package from sources
LATEST=$(curl -s GET https://api.github.com/repos/hashicorp/vagrant/tags | jq -r '.[].name' | head -n1 | tr -d v); echo $LATEST
VERSION=${LATEST:=2.2.18}; 
wget https://releases.hashicorp.com/vagrant/${VERSION}/vagrant_${VERSION}_linux_amd64.zip
sudo install /usr/bin/vagrant
#sudo dpkg -i vagrant_${VERSION}_x86_64.deb
#sudo apt-get update && sudo apt-get install -f   # resolve missing dependencies

# Fix plugins if needed
vagrant plugin update
vagrant plugin repair
vagrant plugin expunge --reinstall


Install ruby is recommended as configuration within Vagrant file is written in Ruby language.

sudo apt-get install ruby
sudo gem install bundler
sudo gem update  bundler    # if update needed


Repair plugins after the upgrade

vagrant plugin repair    # use first
vagrant plugin expunge --reinstall
vagrant plugin update    # then update broken plugin

Images aka box management

Vagrant comes with a preconfigured image repositories.

Manage boxes
vagrant box [list | add | remove] [--help]


Add a box (image) into local repository

These are standard VMs from providers in Virtualbox, VMware or Hyper-V format taken from a given repository

vagrant box add hashicorp/precise64      #user: hashicorp boximage: precise64, this is preconfigured repository
vagrant box add ubuntu/xenial64
vagrant box add ubuntu/xenial64    --box-version 20170618.0.0 --provider virtualbox
vagrant box add bento/ubuntu-18.04 --box-version 201812.27.0  --provider hyperv

# Box can be specified via URLs or local file paths, Virtualbox can only nest 32bit machines
vagrant box add --force ubuntu/14.04      https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
vagrant box add --force ubuntu/14.04-i386 https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.box


Windows images

  • devopsgroup-io/windows_server-2012r2-standard-amd64-nocm
  • peru/windows-server-2016-standard-x64-eval
  • scotch/box


Update a box to the latest version
$> vagrant box list
ubuntu/bionic64                                          (virtualbox, 20190411.0.0)
ubuntu/bionic64                                          (virtualbox, 20190718.0.0)

$> vagrant box update --box ubuntu/bionic64
Checking for updates to 'ubuntu/bionic64'
Latest installed version: 20190718.0.0
Version constraints: > 20190718.0.0
Provider: virtualbox
Updating 'ubuntu/bionic64' with provider 'virtualbox' from version
'20190718.0.0' to '20200124.0.0'...
Loading metadata for box 'https://vagrantcloud.com/ubuntu/bionic64'
Adding box 'ubuntu/bionic64' (v20200124.0.0) for provider: virtualbox
Downloading: https://vagrantcloud.com/ubuntu/boxes/bionic64/versions/20200124.0.0/providers/virtualbox.box
Download redirected to host: cloud-images.ubuntu.com

$> vagrant box list
ubuntu/bionic64                                          (virtualbox, 20190411.0.0)
ubuntu/bionic64                                          (virtualbox, 20190718.0.0)
ubuntu/bionic64                                          (virtualbox, 20200124.0.0) # <- new downloaded


Delete all images (aka boxes)
vagrant box prune

vagrant init - your first project

Configure Vagrantfile to use the box as your base system
Vagrant.configure("2") do |config|
 config.vm.box      = "ubuntu/bionic64"
 config.vm.hostname = "ubuntu" #hostname, requires reload
end


Create Vagrant project, by creating Vagrantfile in your current directory
vagrant init                    #initialises an project 
vagrant init ubuntu/xenial64    # initialises official Ubuntu 16.04 LTS (Xenial Xerus) Daily Build
vagrant init ubuntu/bionic64    #supports only VirtualBox provider
vagrant init bento/ubuntu-18.04 #supports variety of providers

#Windows
vagrant init devopsgroup-io/windows_server-2012r2-standard-amd64-nocm #Windows 2012r2, VirtualBox only; cannot ssh
vagrant init peru/windows-server-2016-standard-x64-eval               #Windows 2016, halt works
vagrant init gusztavvargadr/windows-server                            #Windows 2019, full integration


Power up your Vagrant box
vagrant up


Ssh to the box. Below example of nested virtualisation 64bit VM(host) runs 32bit (guest vm)
piotr@vm-ubuntu64:~/git/vagrant$ vagrant ssh    #default password is "vagrant"
vagrant@vagrant-ubuntu-precise-32:~$ w
13:08:35 up 15 min,  1 user,  load average: 0.06, 0.31, 0.54
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
vagrant  pts/0    10.0.2.2         13:02    1.00s  4.63s  0.09s w


Shared directory between Vagrant VM and an hypervisor provider

Vagrant VM shares a directory mounted at /vagrant with the directory on the host containing your Vagrantfile. This can be manually mounted from within VM as long the shared directory is setup in GUI.

Eg. vm_name > Settings > Shared Folders > Name: vagrant | Path: /home/piotr/vm_name

sudo mount -t vboxsf -o uid=1000 vagrant /vagrant #firts arg 'vagrant' refers to GUI setiing

Troubleshooting

vagrant --debug up

Nesting VMs

The error below is due to Virtualbox cannot run nested 64bit virtualbox VM. Spinning up a 64bit VM stops with an error that no 64bit CPU could be found. Update VirtualBox 6.x Nested virtualization, VT-x/AMD-V in the guest.

Error:
 Timed out while waiting for the machine to boot. This means that
 Vagrant was unable to communicate with the guest machine within
 the configured ("config.vm.boot_timeout" value) time period.

Manage power states

  • vagrant suspend - saves the current running state of the machine and stop it
  • vagrant halt - gracefully shuts down the guest operating system and power down the guest machine
  • vagrant destroy - removes all traces of the guest machine from your system. It'll stop the guest machine, power it down, and remove all of the guest hard disks

Snapshots

You can easily save snapshots.

# Get status
$ vagrant status
Current machine states:
default                   poweroff (virtualbox) # <- 'default' it's machine name
                                                # in multi-vm Vagrant config file
The VM is powered off. To restart the VM, simply run `vagrant up`

# List
vagrant snapshot list
==> default: 
11_b4-upgradeVbox-stopped
12_Dec01_stopped

# Save
                        <nameOfvm> <snapshot-name> 
vagrant snapshot save    default    13_Dec30_external-eks_stopped

# Restore
vagrant snapshot restore default    13_Dec30_external-eks_stopped

Lookup path precedence for Vagrant project file

When you run any vagrant command, Vagrant climbs your directory tree starting first in the current directory you are in. Example:

/home/peter/projects/la/Vagrant
/home/peter/projects/Vagrant
/home/peter/Vagrant
/home/Vagrant
/Vagrant

Configuration

Networking

Private network is network that is not accessible from Internet. Networking stanza is a part of the main |config| loop.

DHCP IP address assigned

config.vm.network "private_network", type: "dhcp"

Static IP assigment

config.vm.network "private_network", ip: "192.168.80.5"
auto_config: false     #optional to disable auto-configure

Public network These networks can be accessible from outside of the host machine including Internet, are usually Bridged Networks.

Examples of dhcp and static IP assignment

config.vm.network "public_network", type: "dhcp"
config.vm.network "public_network", ip: "192.168.80.5"

Default interface. The name need to match your system name otherwise Vagrant will prompt you to choose from available interfaces during vagrant up process.

config.vm.network "public_network", bridge: 'eth1'

Port forwarding

Vagrant can forward any host(hypervisor) TCP port to guest vm specyfing in ~/git/vargant/Vagrant file

config.vm.network :forwarded_port, guest: 80, host: 4567

Reload virtual machine vagrant reload and run from hypervisor web browser http://127.0.0.1:4567 to test it.

Sync folders

Vagrant v2 renamed Shared folders into Sync folders. This feature mounts HostOS directory into GuestOS. allowing workflow of editing files with IDE installed on a host machine but access them within GuestOS. The files sync both directions (as mount on GuestOS), Remember, taking vagrant snapshot save ubuntu-snap1 will NOT save the Sync folder content as it's just mounted directory.


When configuring, 1st argument is a path existing on a host machine. If relative then it's relative to the root-project folder (where Vagrantfile exists) and 2nd arg is a full path to the mounted dir on guest-os.


Enabling Sync folders and Symlinks

This can be done at any time, it's applied during vagrant up | reload. In general symlinks are disabled by VirtualBox as insecure.

Vagrant.configure("2") do |config|
#                    path on the host       mount on the guestOS
                              \             /         
     config.vm.sync_folder "git-host/", "/git", disabled: false
 end
  config.vm.provider "virtualbox" do |vb|
    vb.name   = File.basename(Dir.pwd) + "_vagrant"
    ...
    vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//git",     "1"]
#   vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//vagrant", "1"]

    # symlinks should be active in root of vm by default
#   vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root",   "1"]
  end


Disabling

Vagrant.configure("2") do |config|
     config.vm.sync_folder "../data/", "/vagrant-data", disabled: true
 end


Modifying the Owner/Group

config.vm.sync_folder "../data/", "/vagrant-data", disabled: true,
    owner: "root", group: "root"


References

Vagrant providers

Vagrant can work with a wide variety of backend providers, such as VMware, AWS, and more without changing Vagrantfile. It's enough to specify the provider and Vagrant will do the rest:

vagrant up --provider=vmware_fusion
vagrant up --provider=aws

Hyper-V

  • Enable Hyper-V
  • if you running Docker for Windows make sure is disabled as only one application can bound to Internal NAT vswitch, if you are using it
  • WSL and Windows Vagrant versions must match
  • the terminal you run WSL or PowerShell runs with elevated privileges

When running in WSL, make sure you have export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1",

  • you are in native Bash.exe not eg. ConEmu terminal with as it was proven not working at the time. You can change default provider by export VAGRANT_DEFAULT_PROVIDER=hyperv

Optional: Set the user-level environment variable in PowerShell:

[Environment]::SetEnvironmentVariable("VAGRANT_DEFAULT_PROVIDER", "hyperv", "User")
Workarounds

Copy insecure private key from https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant to WSL ~/.vagr ant_key/private_key because Microsoft filesystem does not support Unix style file permissions, until WSL2 is released.

$ wget https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant -O ~/.vagrant_key/private_key
# then set in Vagrantfile
config.ssh.private_key_path = "~/.vagrant_key/private_key"


When running on HyperV you need to choose a vswitch you will use. Vagrant will prompt you, select "Default Switch", w hich is eqvivalent of NAT Network. You need to creat your own vswitch if you want access to Internet.

Go to Hyper-V Manager, open Virtual Switch Manager..., create External switch, name: vagrant-external, press OK. Then

run.
vagrant up --provider hyperv

    default: Please choose a switch to attach to your Hyper-V instance.
    default: If none of these are appropriate, please open the Hyper-V manager
    default: to create a new virtual switch.
    default:
    default: 1) DockerNAT
    default: 2) Default Switch
    default: 3) vagrant-external
    default:
    default: What switch would you like to use?3    #<-- select 3

Read more https://www.vagrantup.com/docs/hyperv/limitations.html

Run Vagrant file

vagrant up --provider=hyperv

References

Provisioners

Shell provisioner

Vagrant can run from shared location script or from inline: Vagrant file shell provisioning commands.

Create provisioning script

vi ~/git/vagrant/bootstrap.sh     
#!/usr/bin/env bash
export http_proxy=<nowiki>http://username:password@proxyserver.local:8080</nowiki>
export https_proxy=$http_proxy 
apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then 
  rm -rf /var/www
  ln -sf /vagrant /var/www  # sets Vagrant shared dir to Apache DocumentRoot
fi


Configure Vagrant to run this shell script above when setting up our machine

vi ~/git/vagrant/Vagrantfile   
Vagrant.configure("2") do |config|
   config.vm.box = ubuntu/14.04-i386
   config.vm.provision: shell, path: "bootstrap.sh"
end


Another example of using shell provisioner, separating a script out

$script = <<SCRIPT
echo    " touch /home/vagrant/test_\\`date +%s\\`.txt " > /home/vagrant/newfile
chmod +x        /home/vagrant/newfile
echo "* * * * * /home/vagrant/newfile" > mycron
crontab mycron
SCRIPT

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.provision "shell", inline: $script , privileged: false
end


Bring the environment up

vagrant up                   #runs provisioning only once
vagrant reload --provision   #reloads VM skipping import and runs provisioning
vagrant ssh                  #ssh to VM
wget -qO- 127.0.0.1          #test Apache is running on VM


Provisioners - shell, ansible, ansible_local and more

This section is about using Ansible with Vagrant,

*ansible, where Ansible is executed on the Vagrant host
*ansible_local, where Ansible is executed on the Vagrant guest

Ansible provisioner

Specify Ansible as a provisioner in Vagrant file

# Run Ansible from the Vagrant Host
 config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
 end

Chef_solo provisioner

Create recipe, the following dirctory structure is required, eg. recipe name is: vagrant_la

├── cookbooks
│   └── vagrant_la
│       └── recipes
│           └── default.rb
Vagrant


Recipe

vi cookbooks/vagrant_la/recipes/default.rb
execute "apt-get update"
package "apache2"
execute "rm -rf /var/www"
link "var/www" do
        to "/vagrant"
end


In Vagrant file add following

config.vm.provision "chef_solo" do |chef|
        chef.add_recipe "vagrant_la"
end


Run vagrant up

Puppet manifest

Create Vagrant provisioning stanza

config.vm.define "web" do |web|
         web.vm.hostname = "web"
         web.vm.box = "apache"
         web.vm.network "private_network", type: "dhcp"
         web.vm.network "forwarded_port", guest: 80, host: 8080
         web.vm.provision "puppet" do |puppet|
                 puppet.manifests_path = "manifests"
                 puppet.manifest_file = "default.pp"
         end
 end


Create a required folder structure for puppet manifests

├── manifests
│   └── default.pp
└── Vagrantfile


Puppet manifest file

vi manifests/default.pp
exec { "apt-get update":
       command => "/usr/bin/apt-get update",
}
package { "apache2":
       require => Exec["apt-get update"],
}
file { "/var/www":
       ensure => link,
       target => "/vagrant",
       force => true,
}

Box images advanced

vagrant box list   #list all downloaded boxes

Default path of boxes image, it can be specified by environment variable VAGRANT_HOME

C:\Users\%username%\.vagrant.d\boxes  #Windows
~/.vagrant.d/boxes                    #Linux

Change default path via environment variable

export VAGRANT_HOME=my/new/path/goes/here/

Box format

When you un-tar the .box file it contains 4 files:

|--Vagrantfile
|--box-disk1.vmdk  #compressed virtual disk
|--box.ovf         #description of virtual hardware
|--metadata.json

Create box from current project (package a box)

This allows to create a reusable box that contains all changes to the software we made, VirtualBox or Hyper-V supported only.


Command basics

vagrant package [options] [name|id]
# --base NAME - instead of packaging a VirtualBox machine that Vagrant manages, 
#               this will package a VirtualBox machine that VirtualBox manages
# --output NAME - default is package.box
# --include x,y,z -  additional files will be packaged with the box


Package

$ vagrant version # -> Installed Version: 2.2.9

# Optional '--vagrantfile NAME' can be included, that automatically restores '--include' files 
# learn more at https://www.vagrantup.com/docs/vagrantfile#load-order
$ time vagrant package --output u18cli-1.box --include data,git-host,git-host3rd,sync.sh,cleanup.sh
==> default: Clearing any previously set forwarded ports...
==> default: Exporting VM...
==> default: Compressing package to: /home/piotr/vms-vagrant/u18cli-1/2020-05-23-u18cli-1.box
==> default: Packaging additional file: data               # <- dir
==> default: Packaging additional file: git-host           # <- dir
==> default: Packaging additional file: git-host3rd        # <- dir
==> default: Packaging additional file: cleanup.sh         # <- file
real	15m27.324s user	8m23.550s sys	0m16.827s


Re-ristribute the .box file then restore it.

# Add the packaged box to local system box repository
#                        _____box-name________ __box-file_____
$ vagrant box add --name box-packages/u18cli-1 u18cli-1-v1.box
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'u18cli-1-v1.box' (v0) for provider: 
    box: Unpacking necessary files from: file:///home/piotr/vms-vagrant/test-box-restore/u18cli-1-v1.box
==> box: Successfully added box 'box-packages/u18cli-1' (v0) for 'virtualbox'!

# List boxes
$ vagrant box list
box-packages/u18cli-1 (virtualbox, 0)

$ ls -l ~/.vagrant.d/boxes
total 16
drwxrwxr-x 3 piotr piotr 4096 Jul 16 17:44 box-packages-VAGRANTSLASH-u18cli-1


Restore. Create/re-use Vagrantfile using box you added to your local box repository

# vi Vagrantfile
config.vm.box = "box-packages/u18cli-1.box"

vagrant up
# restore '--include' files coping them from
# 'ls -l ~/.vagrant.d/boxes/box-packages-VAGRANTSLASH-u18cli-1/0/virtualbox/include/*'

Resizing Vagrant box disk

Enable Vagrant to use proxy server for VMs

Install proxyconf plugin or use vagrant plugin list to verify if installed

vagrant plugin install vagrant-proxyconf

Configure your Vagrantfile, here particularly host 10.0.0.1:3128 runs CNTLM proxy

Vagrant.configure("2") do |config| 
    config.proxy.http = "http://10.0.0.1:3128"
    config.proxy.https = "http://10.0.0.1:3128"
    config.proxy.no_proxy = "localhost,127.0.0.1"

Virtualbox Guest Additions

Sync using vagrant-vbguest plugin

Install plugin

vagrant gem install vagrant-vbguest    #for vagrant < 1.1.5
vagrant plugin install vagrant-vbguest #for vagrant 1.1.5+

#Verify current version, running on a host(hypervisor)
vagrant vbguest --status

#Add to your Vagrant file (Vagrant 1.1.5+)
if Vagrant.has_plugin?("vagrant-vbguest")
  host.vbguest.auto_update = true
  host.vbguest.no_remote   = true
end


Then install the correct version matching your host installation

vagrant vbguest --do install 

#Full command options
vagrant vbguest [vm-name] [--do start|rebuild|install] [--status] [-f|--force] \
                 [-b|--auto-reboot] [-R|--no-remote] [--iso VBoxGuestAdditions.iso] [--no-cleanup]

More you will find at vagrant-vbguest plugin project.

Manual upgrade

Find out what version you are running, execute on a guest VM

vagrant@ubuntu:~$ modinfo vboxguest | grep ^version
version:        6.0.10 r132072

vagrant@ubuntu:~$ lsmod | grep -io vboxguest | xargs modinfo | grep -iw version
version:        6.0.10 r132072

vagrant@u18cli-3:~$ sudo /usr/sbin/VBoxService --version
6.0.10r132072


Download the extension, you can explore here

wget http://download.virtualbox.org/virtualbox/5.0.32/VBoxGuestAdditions_5.0.32.iso
#you need to get it mounted or extracted the content and run inside the VM.

References

List all Virtualbox SSH redirections

vboxmanage list vms | cut -d ' ' -f 2  > /tmp/vms.out && for vm in $(cat /tmp/vms.out); do vboxmanage showvminfo "$vm" | grep ssh; done
vboxmanage list vms | cut -d ' ' -f 1 | sed 's/"//g' > /tmp/vms.out && for vm in $(cat /tmp/vms.out); do echo $vm; vboxmanage showvminfo "$vm" | grep ssh; done
vboxmanage list vms \
  | cut -d ' ' -f 1 \
  | sed 's/"//g' > /tmp/vms.out \
  && for vm in $(cat /tmp/vms.out); do vboxmanage showvminfo "$vm" \
                                      | grep ssh \
                                      | tr --delete '\n'; echo " $vm"; done

sed 's/"//g'      #removes double quotes from whole string
tr --delete '\n'  #deletes EOL, so the next command output is appended to the previous line

Vagrant file

Ruby gotchas

Vagrant configuration file is written in Ruby specification, therefore you need to remember

  • don't use dashes in object names, don't: jenkins-minion_config.vm.box = "ubuntu/xenial64"
  • don't use symbols (here underscore) in variable names, don't: (1..2).each do |minion_number|


HAProxy cluster, multi-node Vagrant config

git clone https://github.com/jweissig/episode-45


This creates Ansible mgmt server, Load Balancer and Web nodes [1..2]. HAProxy will be configured via Ansible code.

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
 # create mgmt node
 config.vm.define :mgmt do |mgmt_config|
     mgmt_config.vm.box = "ubuntu/trusty64"
     mgmt_config.vm.hostname = "mgmt"
     mgmt_config.vm.network :private_network, ip: "10.0.15.10"
     mgmt_config.vm.provider "virtualbox" do |vb|
       vb.memory = "256"
     end
     mgmt_config.vm.provision :shell, path: "bootstrap-mgmt.sh"
 end

 # create load balancer
 config.vm.define :lb do |lb_config|
     lb_config.vm.box = "ubuntu/trusty64"
     lb_config.vm.hostname = "lb"
     lb_config.vm.network :private_network, ip: "10.0.15.11"
     lb_config.vm.network "forwarded_port", guest: 80, host: 8080
     lb_config.vm.provider "virtualbox" do |vb|
       vb.memory = "256"
     end
 end

 # create some web servers
 # https://docs.vagrantup.com/v2/vagrantfile/tips.html
  (1..2).each do |i|
    config.vm.define "web#{i}" do |node|
        node.vm.box = "ubuntu/trusty64"
        node.vm.hostname = "web#{i}"
        node.vm.network :private_network, ip: "10.0.15.2#{i}"
        node.vm.network "forwarded_port", guest: 80, host: "808#{i}"
        node.vm.provider "virtualbox" do |vb|
          vb.memory = "256"
        end
    end
  end
end


Boot strap script bootstrap-mgmt.sh

#!/usr/bin/env bash 
# install ansible (http://docs.ansible.com/intro_installation.html)
apt-get -y install software-properties-common
apt-add-repository -y ppa:ansible/ansible
apt-get update
apt-get -y install ansible

# copy examples into /home/vagrant (from inside the mgmt node)
cp -a /vagrant/examples/* /home/vagrant
chown -R vagrant:vagrant /home/vagrant

# configure hosts file for our internal network defined by Vagrantfile
cat >> /etc/hosts <<EOL
# vagrant environment nodes
10.0.15.10  mgmt
10.0.15.11  lb
10.0.15.21  web1
10.0.15.22  web2
10.0.15.23  web3
10.0.15.24  web4
10.0.15.25  web5
10.0.15.26  web6
10.0.15.27  web7
10.0.15.28  web8
10.0.15.29  web9
EOL


Gitbash path - /c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe

Set bootstrap script for Proxy or No-proxy specific system

Vagrant status
Vagrant up
Vagrant ssh mgmt
ansible all --list-hosts
ssh-keyscan web1 web2 lb > ~/.ssh/known_hosts
ansible-playbook ssh-addkey.yml -u vagrant --ask-pass
ansible-playbook site.yml


Once set it up you can navigate on your laptop to:

http://localhost:8080/              #Website test
http://localhost:8080/haproxy?stats #HAProxy stats


Use to verify end server

curl -I http://localhost:8080


Curl -i X-Backend-Server


Generate web traffic

vagrant ssh lb
sudo apt-get install apache2-utils
ansible localhost -m apt -a "pkg=apache2-utils state=present" --become
ab -n 1000 -c 1 http://10.0.2.15:80/ # Apache replaced 'ab' with 'hey'

Vagrant DNS

Multi-machine mDNS discovery

Multi-machine setup requires 3 ingredients* :

  • each machine to have different hostname
  • a way of getting the IP address for a hostname (eg. mDNS)
  • connect the VMs through a private network


In multi-machine configuration we need a way of getting the IP address for a hostname. We use mDNS for this. By default <codemDNS only resolves host names ending with the .local top-level domain (TLD). This can cause problems if that domain includes hosts which do not implement mDNS but which can be found via a conventional unicast DNS server. Resolving such conflicts requires network-configuration changes that violate the zero-configuration goal. Install avahi system on all machines to facilitate service discovery on a local network via the mDNS/DNS-SD protocol suite.

config.vm.provision "shell", inline: <<-SCRIPT
  apt-get install -y avahi-daemon libnss-mdns
SCRIPT


References
  • nss-mdns system which allows hostname lookup of *.local hostnames via mDNS in all system programs using nsswitch
  • avahi.org

Set host system DNS server resolver

config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
end

Ubuntu with GUI

This article is going to describe to setup Vagrant Virtualbox VM with GUI, setting up xserver with xfce4 as desktop environment.

Locales

This is not working

locale-gen en_GB.utf8 #en_GB.UTF-8
     update-locale LANG=en_GB.UTF-8
     locale-gen --purge "en_GB.UTF-8"
     dpkg-reconfigure --frontend=noninteractive locales
     dpkg-reconfigure --frontend=noninteractive keyboard-configuration
     localedef -i en_GB -c -f UTF-8 en_GB.utf8
     sudo update-locale LANG=en_GB.UTF-8
     locale-gen --purge "en_GB.UTF-8"

Troubleshooting

locale -a #shows which locales are available on your system
sudo less /usr/share/i18n/SUPPORTED
cat /etc/default/locale

#Set system wide locales (does not work for users)
localectl set-locale LANG=en_GB.UTF-8 LANGUAGE=en_GB:en
localectl set-keymap gb
localectl set-x11-keymap gb

#Quick kb change
apt-get install -yq x11-xkb-utils; setxkbmap gb

Gnome3

This setup installs Ubuntu desktop and may require a restart to apply changes to like a taskbar with shortcuts.

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box      = "ubuntu/bionic64" #bento/ubuntu-18.04, ubuntu/xenial64

  machineName = File.basename(Dir.pwd) #name as a current working dir
# machineName = 'u18gui-1'
  config.vm.hostname = machineName

  # Manually check for updates `vagrant box outdated`
  config.vm.box_check_update = false

  # Vbguest plugin
  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = false
    config.vbguest.no_remote   = true
  end

  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
  # Public network, which generally matched to bridged network.
  # config.vm.network "public_network"

  # config.vm.synced_folder "hostDir", "/InVagrantMount/path" 
  # config.vm.synced_folder "../data", "/vagrant_data"

   config.vm.provider "virtualbox" do |vb|
     vb.gui    = true
     vb.memory = "3072"
     vb.name   = machineName + "_vagrant"
   end
  
   config.vm.provision "shell", inline: <<-SHELL
     export DEBIAN_FRONTEND=noninteractive
     setxkbmap gb
     apt-get update && apt-get upgrade -yq
     apt-get install -yq ubuntu-desktop --no-install-recommends
     apt-get install -yq terminator tmux
     #only U16 xenial to fix Unity
     #apt-get install -yq unity-lens-files unity-lens-applications indicator-session --no-install-recommends 
   SHELL
end


Running up

vagrant plugin install vagrant-vbguest
vagrant up && vagrant vbguest --do install && vagrant reload

Xface

Get a basic Ubuntu image working, boot it up and vagrant ssh. Next, enable the VirtualBox display, which is off by default. Halt the VM and uncomment these lines in Vagrantfile:

config.vm.provider :virtualbox do |vb|
  vb.gui = true
end


Boot the VM and observe the new display window. Now you just need to install and start xfce4. Use vagrant ssh and:

sudo apt-get install -y xfce4 virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11
#guest additions are already installed on most of the Vagrant boxes

Don't start the GUI as root because you really want to stay the vagrant user. To do this you need to permit anyone to start the GUI:

sudo vim /etc/X11/Xwrapper.config and edit it to allowed_users=anybody
sudo startxfce4&
sudo VBoxClient-all #optional

You should be landed in a xfce4 session.

(Optional) If VBoxClient-all script isn't installed or anything is missing, you can replace with the equivalent:

sudo VBoxClient --clipboard
sudo VBoxClient --draganddrop
sudo VBoxClient --display
sudo VBoxClient --checkhostversion
sudo VBoxClient --seamless

References

Windows

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "gusztavvargadr/windows-server"
  config.vm.box_check_update = false
  config.vm.provider "virtualbox" do |vb|
     vb.gui = true       # Display the VirtualBox GUI when booting the machine
     vb.memory = "3072"  # Customize the amount of memory on the VM:
  end
  # Plugins
  config.vbguest.auto_update = false
  config.vbguest.no_remote = true
end


Shared location

  • enable Network Sharing
  • Vagrant path is mapped to \\VBOXSVR\vagrant

WIP DevOps workstation

This to contain:

  • bashrc with git branch in ps1
  • bash autocomplete (...samename)
  • bash colored symlinks
  • bash_logout and .profile to eval ssh-agent and kill on exit
  • git install
  • ansible 1.9.4
  • java Oracle
  • clone tfenv and install terraform
  • vim install
  • vundle install
  • [done] python 2.7 OOB in 16.04
  • [done]python pip: awscli, boto, boto3, etc..

Challenges:

References