Devops

Vagrant box – customized with simple steps

2021-11-109 min read

Vagrant box – customized with simple steps

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

  1. Vagrant binary should be installed in the local environment.
  2. Access to vagrant public box catalog to fetch base os box to build vagrant environment.
  3. 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.

  1. Private Network
  2. Server – cpu and memory
  3. 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.