alezzandro.com

How to create RHEL based Vagrant boxes

Introduction

 

How many times you needed a fast-way to test your POC?

Vagrant is a system tool that lets you easily start and stop a virtual machine exposing the only thing you need: ssh console.

 

Every vagrant box is composed by a disk image file, some metadata related to the hypervisor chosen by the author and a default Vagrantfile.

A Vagrantfile is nothing more than a vm descriptor file. You can control vm memory, network etc, for more information about a Vagrantfile I suggest you take a look into the online documentation. A default Vagrantfile is generated through the command "vagrant init box_name" directly in the current user dir.

Vagrant uses a well-known user called "vagrant" created with default password "vagrant", this user has been added to /etc/sudoers file (previously by the author) so he can obtain super-user access to the whole machine without password.

Vagrant tool can easily login as "vagrant" user thanks to a public insecure key placed inside .ssh/authorized_keys file. This key will be automatically replaced by Vagrant itself at first boot.

 

 

Prerequisites

 

This short how to requires Vagrant plugin named: vagrant-libvirt.

You can obtain it through the following commands on your Fedora system (userspace or through yum):

# vagrant plugin install vagrant-libvirt

# sudo yum install vagrant-libvirt

 

Automatic Build of RHEL Vagrant Boxes

I've started experimenting on automating the build process of RHEL based vagrant boxes.

The process requires only a dvd or ISO image pre-downloaded on your system. The process requires only a Linux system with libvirt installed.

 

REQUIREMENTS:

- Just one: Red Hat Enterprise Linux ISO.

 

PLEASE NOTE: in this example I'll show you how to create a rhel72 vagrant box, anyway you can change the kickstart file according to your needs.

 

# git clone https://github.com/alezzandro/vagrant-rhel-box

# cd vagrant-rhel72-box

Let's create a disk for our box, in my case I just chose to create a 20G disk, the installation size will be less than 1G, the disk is also thin-provisioned, so we won't waste any space creating a larger disk.

# qemu-img create -f qcow2 -o compat=0.10 rhel-vagrant-7.2.x86_64.qcow2 20G

 

After that we can review the command inside the build.sh script:

$ cat build.sh

#!/bin/bash

set -x

 

tree=../../rhel-server-7.2-x86_64-dvd.iso

 

virt-install --connect=qemu:///system \

    --network=bridge:virbr0 \

    --initrd-inject=./rhel-7.2-ci-cloud_edit.ks \

    --extra-args="ks=file:/rhel-7.2-ci-cloud_edit.ks no_timer_check console=tty0 console=ttyS0,115200 net.ifnames=0 biosdevname=0" \

    --name=rhel-vagrant-7.2.x86_64 \

    --disk ./rhel-vagrant-7.2.x86_64.qcow2,size=20,bus=virtio \

    --ram 2048 \

    --vcpus=2 \

    --check-cpu \

    --accelerate \

    --hvm \

    --location=$tree \

    --nographics --noreboot #--debug

 

LIBGUESTFS_BACKEND=direct virt-sparsify --compress -o compat=0.10 --tmp ./tmp/ rhel-vagrant-7.2.x86_64.qcow2 box.img

 

tar cvzf rhel72.box ./metadata.json ./Vagrantfile ./box.img

 

As you can see we launch a virt-install command injecting our custom kickstart.

I've added some custom instruction on the kickstart for supporting vagrant customization and required packages.

I've also replaced the standard reboot command (at the end of the installation) with poweroff that together with "--noreboot" option of virt-install, allow us to automate the build process.

 

So, edit whatever you changed from the original setup I made for RHEL 7.2 and run the build.sh.

# sh build.sh

 

Please note: in case you created a disk of a different size you should also update the metadata.json file.

 

That's all!

 

Manual build of a Vagrant-ready virtual machine

 

This is the manual process.

 

Build your Vagrant box

 

But now, after the boring (and so short) explanation about Vagrant we can move forward looking at how to create RHEL based Vagrant boxes.

First of all we need a working installation of a Gnu/Linux system, in our case a Red Hat Enterprise Linux 6.5 on KVM.

 

As we saw in the introduction we need to create a user named vagrant and to set its password and root's password to string "vagrant".

# adduser vagrant

# echo vagrant | passwd vagrant --stdin

# echo vagrant | passwd --stdin

 

After that we need to download and set the vagrant insecure public key needed by the tool for automatically login into the system:

# su - vagrant

# wget https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub

# mkdir .ssh

# mv vagrant.pub .ssh/authorized_keys

# chown -R vagrant:vagrant .ssh/

# chmod 700 .ssh

# chmod 600 .ssh/authorized_keys

 

Then we have to enable vagrant user as sudoers without password (We have to change the file permission because by default the file is read-only. Then we have to remove the requirement for a tty):

# chmod +w /etc/sudoers

# echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# perl -pi -e 's/(^Defaults\s+requiretty)/# $1/g' /etc/sudoers

# chmod -w /etc/sudoers

 

Finally we have to remove any reference to our current ethernet device's mac address inside the file: /etc/udev/rules.d/70-persistent-net.rules, for doing that you can easily comment out the line starting with "SUBSYSTEM==".

 

That's all! Power down your virtual machine, we're ready to create our box!

 

Pack your Vagrant box

 

Start downloading the content of https://github.com/adrahon/vagrant-kvm/tree/master/example_box you have to take all the files (Vagrantfile, box.xml and metadata.json).

You can do that also by a simple git clone command:

# git clone https://github.com/adrahon/vagrant-kvm.git .

 

Then start editing your brand new box, first of all we need to get the disk source file and place it on your working directory (pay attention: the vm should be shutted down!):

# sudo cp /var/lib/libvirt/images/something.qcow2 box.img

Edit also for box.img's ownership and permission according your current user.

 

Now we need to edit the file named "metadata.json" this is the one I made:

{

  "provider"     : "libvirt",

  "format"       : "qcow2",

  "virtual_size" : 10

}

 

Then we need to customize our Vagrantfile, this is the one I made:

# -*- mode: ruby -*-

# vi: set ft=ruby :

 

Vagrant.configure("2") do |config|

 

  config.vm.synced_folder ".", "/vagrant", type: "rsync"

 

  # Options for libvirt vagrant provider.

  config.vm.provider :libvirt do |libvirt|

 

    # A hypervisor name to access. Different drivers can be specified, but

    # this version of provider creates KVM machines only. Some examples of

    # drivers are kvm (qemu hardware accelerated), qemu (qemu emulated),

    # xen (Xen hypervisor), lxc (Linux Containers),

    # esx (VMware ESX), vmwarews (VMware Workstation) and more. Refer to

    # documentation for available drivers (http://libvirt.org/drivers.html).

    libvirt.driver = "kvm"

 

    # If use ssh tunnel to connect to Libvirt.

    libvirt.connect_via_ssh = false

 

    # The username and password to access Libvirt. Password is not used when

    # connecting via ssh.

    libvirt.username = "root"

    #libvirt.password = "secret"

 

    # Libvirt storage pool name, where box image and instance snapshots will

    # be stored.

    libvirt.storage_pool_name = "default"

 

    # Set a prefix for the machines that's different than the project dir name.

    #libvirt.default_prefix = ''

  end

 

  config.vm.provider :libvirt do |domain|

    domain.memory = 2048

    domain.cpus = 2

    domain.nested = true

    domain.volume_cache = 'none'

  end

 

end

 

We've almost complete the process! We need only to pack all the three files: "box.img metadata.json Vagrantfile"

# tar cvzf rhel72.box ./metadata.json ./Vagrantfile ./box.img

 

Process done!

We can now test the just created Vagrant box.

 

Testing

 

Finally we can try to import the brand new box though the command:

# vagrant box add --name rhel72 rhel72.box

 

Then create a directory and try it:

# mkdir test-libvirt && cd test-testlibvirt

# vagrant init rhel72

# vagrant up

# vagrant ssh

 

You should see something like that:

 

[alex@freddy test-libvirt]$ vagrant init rhel72

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.

[alex@freddy test-libvirt]$ vagrant up

Bringing machine 'default' up with 'libvirt' provider...

==> default: Creating image (snapshot of base box volume).

==> default: Creating domain with the following settings...

==> default:  -- Name:              test-libvirt_default

==> default:  -- Domain type:       kvm

==> default:  -- Cpus:              2

==> default:  -- Memory:            2048M

==> default:  -- Base box:          rhel72

==> default:  -- Storage pool:      default

==> default:  -- Image:             /var/lib/libvirt/images/test-libvirt_default.img

==> default:  -- Volume Cache:      none

==> default:  -- Kernel:          

==> default:  -- Initrd:          

==> default:  -- Graphics Type:     vnc

==> default:  -- Graphics Port:     5900

==> default:  -- Graphics IP:       127.0.0.1

==> default:  -- Graphics Password: Not defined

==> default:  -- Video Type:        cirrus

==> default:  -- Video VRAM:        9216

==> default:  -- Keymap:            en-us

==> default:  -- Command line :

==> default: Creating shared folders metadata...

==> default: Starting domain.

==> default: Waiting for domain to get an IP address...

==> default: Waiting for SSH to become available...

    default:

    default: Vagrant insecure key detected. Vagrant will automatically replace

    default: this with a newly generated keypair for better security.

    default:

    default: Inserting generated public key within guest...

    default: Removing insecure key from the guest if its present...

    default: Key inserted! Disconnecting and reconnecting using new SSH key...

==> default: Configuring and enabling network interfaces...

==> default: Rsyncing folder: /home/alex/Downloads/test-libvirt/ => /vagrant

 

PLEASE NOTE:

Don't forget adding to your .bash_profile the env variable selecting libvirt as your default provider.

Viceversa you can set it at runtime through:

# VAGRANT_DEFAULT_PROVIDER=libvirt

# export VAGRANT_DEFAULT_PROVIDER