Introduction
Vagrant provides Boxes with various operating system such as Ubuntu, Debian, or CentOS. Using the vagrant utility, we can provision development environments in minutes. In our development environment, we come across situations where we have to modify the vagrant boxes with various customizations. In this blog, we would go through steps to build custom vagrant box to use for environment provisioning.
Prerequisites
- Vagrant binary should be installed in the local environment.
- Access to vagrant public box catalog to fetch base os box to build vagrant environment.
- Need to have one or more providers configured in the local environment. We have various options to choose as a provider – VirtualBox, Hyper-V, Docker and VMware. I would be using “virtualbox” as the provider.
Build local vagrant box
We would build a local vagrant environment and then package it as a custom box. The vagrant binary provides various options to manage vagrant box operations.
$ vagrant box -h
Usage: vagrant box <subcommand> [<args>]
Available subcommands:
add
list
outdated
prune
remove
repackage
update
For help on any individual subcommand run `vagrant box <subcommand> -h`
--[no-]color Enable or disable color output
--machine-readable Enable machine readable output
-v, --version Display Vagrant version
--debug Enable debug output
--timestamp Enable timestamps on log output
--debug-timestamp Enable debug output with timestamps
--no-tty Enable non-interactive output
Add the vagrant box of choice in the local environment. I have chosen the ubuntu/focal64 vagrant box. We can notice that this box is pulled for “virtualbox” as provider by default since this vagrant box is available with “virtualbox” as provider only.
$ vagrant box add ubuntu/focal64
==> box: Loading metadata for box 'ubuntu/focal64'
box: URL: https://vagrantcloud.com/ubuntu/focal64
==> box: Adding box 'ubuntu/focal64' (v20211026.0.0) for provider: virtualbox
box: Downloading: https://vagrantcloud.com/ubuntu/boxes/focal64/versions/20211026.0.0/providers/virtualbox.box
Download redirected to host: cloud-images.ubuntu.com
==> box: Successfully added box 'ubuntu/focal64' (v20211026.0.0) for 'virtualbox'!
Create a folder on local environment and initialize the vagrant environment. This step would primarily produce the default Vagrantfile, which can be configured with further resource, network and os customizations.
$ vagrant init ubuntu/focal64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
$ ls -l
total 8
-rw-r--r-- 1 user1 user1 3020 Nov 4 13:26 Vagrantfile
We would modify the Vagrantfile to put some of the basic customizations.
- Private Network
- Server – cpu and memory
- Update the server during the launch.
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.box = "ubuntu/focal64"
ubuntu.vm.hostname = "ubuntu.example.com"
ubuntu.vm.network "private_network", ip: "192.168.56.20"
ubuntu.vm.provider "virtualbox" do |v|
v.name = "ubuntu"
v.memory = 2048
v.cpus = 2
# Prevent VirtualBox from interfering with host audio stack
v.customize ["modifyvm", :id, "--audio", "none"]
end
end
config.vm.provision "shell", inline: <<-SHELL
echo "TASK1 -> Update VM"
apt-get update
apt-get install -y apache2
SHELL
end
Launch the server virtual machine with vagrant command option.
$ vagrant up
Bringing machine 'ubuntu' up with 'virtualbox' provider...
==> ubuntu: Importing base box 'ubuntu/focal64'...
==> ubuntu: Matching MAC address for NAT networking...
==> ubuntu: Checking if box 'ubuntu/focal64' version '20211026.0.0' is up to date...
==> ubuntu: Setting the name of the VM: ubuntu
==> ubuntu: Clearing any previously set network interfaces...
==> ubuntu: Preparing network interfaces based on configuration...
ubuntu: Adapter 1: nat
ubuntu: Adapter 2: hostonly
==> ubuntu: Forwarding ports...
ubuntu: 22 (guest) => 2222 (host) (adapter 1)
==> ubuntu: Running 'pre-boot' VM customizations...
==> ubuntu: Booting VM...
==> ubuntu: Waiting for machine to boot. This may take a few minutes...
ubuntu: SSH address: 127.0.0.1:2222
ubuntu: SSH username: vagrant
ubuntu: SSH auth method: private key
ubuntu:
ubuntu: Vagrant insecure key detected. Vagrant will automatically replace
ubuntu: this with a newly generated keypair for better security.
ubuntu:
ubuntu: Inserting generated public key within guest...
ubuntu: Removing insecure key from the guest if it's present...
ubuntu: Key inserted! Disconnecting and reconnecting using new SSH key...
==> ubuntu: Machine booted and ready!
==> ubuntu: Checking for guest additions in VM...
==> ubuntu: Setting hostname...
==> ubuntu: Configuring and enabling network interfaces...
==> ubuntu: Mounting shared folders...
ubuntu: /vagrant => /user1/vagrantzone/ubuntu
==> ubuntu: Running provisioner: shell...
ubuntu: Running: inline script
ubuntu: TASK1 -> Update VM
ubuntu: Hit:1 http://archive.ubuntu.com/ubuntu focal InRelease
---
SSH inside the server, add and enable the docker.service and activate docker for the default user “vagrant” in the server machine.
$ vagrant ssh
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-89-generic x86_64)
Last login: Thu Nov 4 05:44:43 2021 from 10.0.2.2
vagrant@ubuntu:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
vagrant@ubuntu:~$ systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2021-11-04 05:45:58 UTC; 3min 56s ago
With this basic set of customization, we can build our own vagrant box now. We have created another folder “myboxes” to store all the custom-boxes. From the local environment, we can run vagrant package
command to initiate the box build process.
$ vagrant package --output=/user1/vagrantzone/myboxes/myserver.box
==> ubuntu: Attempting graceful shutdown of VM...
==> ubuntu: Clearing any previously set forwarded ports...
==> ubuntu: Exporting VM...
==> ubuntu: Compressing package to: /user1/vagrantzone/myboxes/myserver.box
As a result, the customized vagrant box would be created and placed at /user1/vagrantzone/myboxes
.
Versioning custom vagrant box
At this stage, it can be added at vagrant local repo with vagrant box add
command. But, we would observe that the version would show as “v0”. For various business reasons, we would need to have the box versioned in a better way.
Based on the local setup, we can have seperate folders for each customized server and use the folder to fetch the box for environment build purpose. To add various metadata information (incl. box version), we can create a json based config in folder forcustomized server i.e :/user1/vagrantzone/myboxes
.
$ cat myserver.json
{
"name": "myserver",
"description": "my custom server",
"versions": [
{
"version": "1.0.0",
"release_date": "04-Nov-2021",
"providers": [
{
"name": "virtualbox",
"url": "file:///user1/vagrantzone/myboxes/myserver.box",
"checksum": "e0e406709d0e397c6170d928ead6eacdf19c60e1bc5e5abba66cbbcc1c6633be",
"checksum_type": "sha256"
}
]
}
]
}
In above vagrant config file, we have generated the sha256 key using the shasum tool
$ shasum -a 256 myserver.box
e0e406709d0e397c6170d928ead6eacdf19c60e1bc5e5abba66cbbcc1c6633be myserver.box
Now, we can add the customized vagrant box to local vagrant repo.
$ vagrant box add --name=myserver myserver.json
==> box: Loading metadata for box 'myserver.json'
box: URL: file:///user1/vagrantzone/myboxes/myserver.json
==> box: Adding box 'myserver' (v1.0.0) for provider: virtualbox
box: Unpacking necessary files from: file:///user1/vagrantzone/myboxes/myserver.box
box: Calculating and comparing box checksum...
==> box: Successfully added box 'myserver' (v1.0.0) for 'virtualbox'!
$ vagrant box list
myserver (virtualbox, 1.0.0)
ubuntu/focal64 (virtualbox, 20211026.0.0)
The customized vagrant box is ready to be used for environment provisioning purpose.
Push vagrant box to vagrant cloud
Above process shows steps to customize the box and use in local environment.
If we want to push to a global repository and share the customized vagrant image, we need to have access and account at Vagrant Cloud
. All the users get access to upload and share their vagrant boxes. Customized vagrant boxes can be pushed to vagrant Cloud and it can be shared in same way as vagrant gold boxes. For the free account, we can create boxes in “public” mode, and for private access need to purchase the subscription.