Vagrant Quick Start

2025-06-23 content updated.

My single VM and VM compose setup please see this InfraTree.

Since year 2019 I have been knowing Vagrant from Book <<Ansible: Up and Running>> as it enables easy set up, test for Ansible, Jenkins and many other software on local VM (You have another choice using docker).

Vagrant Box Search provides you pre-built VM images, all-in-one box, etc.

But you can also build your own customized image from root image via Packer.

Introduction

Vagrant is a tool for building and managing virtual machine environments in a single workflow. You can find everything from Vagrant site.

It leverages a declarative configuration file which describes all your software requirements, packages, operating system configuration, users, and more.

Vagrant also integrates with your existing configuration management tooling like Ansible, Chef, Docker, Puppet or Salt, so you can use the same scripts to configure Vagrant for production.

For comparing Vagrant with Other Software.

Install

Installation is easy, Vagrant and VirtualBox, other providers are possible, for example, Docker, VMware.

Project

The Vagrantfile is meant to be committed to version control with your project, if you use version control. This way, every person working with that project can benefit from Vagrant without any upfront work.

The syntax of Vagrantfiles is Ruby, but knowledge of the Ruby programming language is not necessary to make modifications to the Vagrantfile, since it is mostly simple variable assignment.

1
2
3
4
5
6
7
8
# init project
mkdir vagrant_getting_started
cd vagrant_getting_started

# --minimal: generate minimal Vagrantfile
# hashicorp/bionic64: the box name
# if you have Vagrantfile, no need this
vagrant init hashicorp/bionic64 [--minimal]

Of course you can create a Vagrantfile manually:

1
2
3
# download box image
# you don't need to explicitly do this, vagrant will handle download from Vagrantfile
vagrant box add hashicorp/bionic64

In the above command, you will notice that boxes are namespaced. Boxes are broken down into two parts - the username and the box name - separated by a slash. In the example above, the username is “hashicorp”, and the box is “bionic64”.

Vagrantfile Example

Editing Vagrantfile, this is a simple example to bring up a jenkins cluster:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- mode: ruby -*-
# vi: set ft=ruby :

# image info for all machines
IMAGE_NAME = "generic/centos7"
IMAGE_VERSION = "3.0.10"

# server static ip
SERVER_IP = "192.168.3.2"
# agent static ip, start from 192.168.3.1x
AGENT_IP = "192.168.3.1"

Vagrant.configure("2") do |config|
# box for virtual machines
config.vm.box = IMAGE_NAME
config.vm.box_version = IMAGE_VERSION

# virtualbox configuration for virtual machines
config.vm.provider "virtualbox" do |v|
v.memory = 512
v.cpus = 1
end

# synced folder
config.vm.synced_folder ".", "/vagrant", owner: "root", group: "root"

# Jenkins server, set as primary
config.vm.define "server", primary: true do |server|
server.vm.hostname = "jenkins-server"
# private network
# jenkins uses port 8080 in browser
server.vm.network "private_network", ip: SERVER_IP
# provisioning
server.vm.provision :shell, path: "./provision/server.sh", privileged: true
end

# agents setup
(1..2).each do |i|
config.vm.define "agent#{i}" do |agent|
agent.vm.hostname = "jenkins-agent#{i}"
# private network
agent.vm.network "private_network", ip: "#{AGENT_IP}#{i}"
# provisioning
agent.vm.provision :shell, path: "./provision/agent.sh", privileged: true
end
end
end

Network Config

By using private_network, there is no need to do port forwarding, you are able to access the service directly from the ip on your host, if you go to check the virtualbox configuration, it uses Host-only adapter.

Please follow the proivate network range, you can try chrome incognito mode or firefox, or using curl/wget.

For SSH access, the VMs must be in the same private network:

1
2
# assign private IP
config.vm.network "private_network", ip: "192.168.2.2"

This configuration uses a private network. The VM can be accessed only from another VM that runs Vagrant and within the same range. You won’t be able to connect to this IP address from another physical host, even if it’s on the same network as the VM. However, different Vagrant VMs can connect to each other.

SSH agent forwarding, for example, git clone in VM using the private key of host:

1
config.ssh.forward_agent = true

Bring up the environment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# validate syntax
vagrant validate
# check machine status
vagrant status
# at your project root directory
vagrant up
# ssh to primary machine in your project
vagrant ssh [vm name]

# when you finish working
# destroy machine
# -f: confirm
vagrant destroy -f
# remove the box
vagrant box remove

Note that by default vagrant ssh login as user vagrant, not root user, you can use sudo to execute command or run sudo su - first.

SSH to VM

This is to demystify how SSH to VM from our host works.

1
2
3
4
5
6
7
8
9
10
11
12
13
# vagrant must be running
vagrant ssh-config

Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile <absolute path>/.vagrant/machines/<vm name>/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL

Vagrant sets up host-to-guest port forwarding on a high random port on localhost (e.g., 127.0.0.1:2222 → guest:22).You can also change the default ssh port mapping, see this blog, for example:

1
2
3
# id: "ssh"
# map host port 13001 to guest port 22
config.vm.network :forwarded_port, guest: 22, host: 13001, id: "ssh"

The underlying SSH command can be seen by ps aux | grep ssh:

1
2
3
4
5
6
7
8
9
10
# -q: quiet mode
ssh vagrant@127.0.0.1 \
-p 2222 \
-o LogLevel=FATAL \
-o Compression=yes \
-o DSAAuthentication=yes \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-i <absolute path>/.vagrant/machines/<vm name>/virtualbox/private_key

Vagrant generates new SSH key pair per VM, if you disable insert_key in Vagrantfile:

1
config.ssh.insert_key = false

Then Vagrant uses insecure default key, if you check verbose ssh command under the vagrant ssh, you will see the location of that insecure key:

1
2
ps aux | grep ssh
#-i <user home>/.vagrant.d/insecure_private_key

Synced Folder

By using synced folders, Vagrant will automatically sync your files to and from the guest machine. By default, Vagrant shares your project directory (remember, that is the one with the Vagrantfile) to the /vagrant directory in your guest machine.

Synced folder will be mapped before provisioning would run.

Vagrant also supports rsync, primarily in situations where other synced folder mechanisms are not available: https://www.vagrantup.com/docs/synced-folders/rsync.html

Vagrant has built-in support for automated provisioning. Using this feature, Vagrant will automatically install software when you vagrant up:

1
2
3
4
5
6
7
8
# use Ansible provisioner
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
end
end

Vagrant will not run it a second time unless you force it.

1
2
3
4
5
6
# reboot machine and reload provision setting if machine is already running
# if no provision needed, just run vagrant reload
# --provision: force run provision again
vagrant reload --provision
# force rerun provision when machine is running
vagrant provision

Methods to teardown:

1
2
3
4
5
6
7
8
9
10
# hibernate, save states in disk
vagrant suspend
vagrant resume

# normal power off
vagrant halt
# reclaim all resources
vagrant destroy
# boot again
vagrant up

Multi-Machine

This is helpful for cluster setup: https://www.vagrantup.com/docs/multi-machine

Convert ova to box

Convert a Virtualbox ova to a Vagrant box https://gist.github.com/chengdol/315d3cbb83cf224c3b34913095b7fff9

0%