Setup Build Environment with Vagrant
As a system engineer, I have to manage various build envrionmets, build all the projects against one Ubuntu version became imposssible, one change for one project may break the build for another, Vagrant wass born to make this easier.
Vagrant supports many Linux distributions and also works on macOS.
To install vagrant on macOS, issue following command:
brew install vagrant virtualbox
or this for Ubuntu:
sudo apt install -y vagrant virtualbox
To get started, follow the steps below to create a virtual machine for Ubuntu 18.04:
- Create Vagrantfile
vagrant init ubuntu/focal64
This will create a Vagrantfile under current directory, this Vagrantfile may looks like this (with comments removed):
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/focal64" end
Vagrantfile also contains some comments explaining how to configure this vm, for example we can install required packages and do environment setups, within this file.
- Bring up VM
vagrant up
- ssh into VM
vagrant ssh
For security research, you can use kalilinux with vagrant:
vagrant init kalilinux/rolling
vagrant up
# root/toor
Sharing file/folder with VM
By default, vagrant shares the current directory to the /vagrant
directory of
the VM:
vagrant@vagrant:~$ ls /vagrant/
Vagrantfile
If you need to share more directories with VM, configure it in Vagrantfile with:
config.vm.synced_folder "/opt/shared", "/tmp/jenkins"
Copy file/folder with VM
Copy files or directories to VM can be done with File Provisioner:
config.vm.provision "file", source: "/tmp/Dockerfile", destination: "/tmp/docker/Dockerfile"
config.vm.provision "file", source: "~/path/to/host/folder", destination: "$HOME/remote/newfolder"
Create docker image in VM
Docker image can be built directly in VM with Docker Provisioner:
config.vm.provision "docker" do |d|
d.build_image "/tmp/docker", args: "-t ubuntu:1804"
end
Bridged network
Remote access to node created by vagrant with ssh maybe required sometimes, for this case, we need to create a bridged network for the VM:
config.vm.network "public_network", bridge: "enp54s0"
Simple example of Vagrantfile
This is the Vagrantfile file I used for creating jenkins node:
cat Vagrantfile
Vagrant.configure("2") do |config|
config.vm.hostname = "node"
config.vm.box = "ubuntu/focal64"
config.vm.network "public_network", bridge: "enp54s0"
config.vm.synced_folder "/opt/shared", "/tmp/jenkins"
config.vm.provision "file", source: "/tmp/Dockerfile", destination: "/tmp/docker/Dockerfile"
config.vm.provision "docker" do |d|
d.build_image "/tmp/docker", args: "-t ubuntu:1804"
end
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.memory = "1024"
vb.cpus = "1"
end
end
Work with Ansible
Development envrionment setup can be done with the ansible_local
provision, add
config.vm.provision :ansible_local do |ansible|
ansible.playbook = "playbook.yml"
ansible.verbose = true
end
to Vagrantfile, and create this example playbook:
- name: Ansible apt install
become: yes
hosts: all
tasks:
- name: Environment Setup
apt:
update_cache: yes
name:
- zsh
- ripgrep
- thefuck
- fd-find
- moreutils
- docker.io
- docker-compose
state: present
The last step:
vagrant reload --provision
Execute remote commands with ssh
In case of the need for execute commands without ssh into the vm, do it like this:
vagrant ssh -c 'ls /'
vagrant ssh -- -t 'ls /'
For a real world example, below is the command I used for bootchart generation in workload perfboot for boot time benchmark with workload automation.
vagrant ssh -c "bootchart -f svg --show-pid -o /vagrant/bootchart.svg /vagrant/bootlog.tgz"
One-liners
vagrant up
vagrant up --provision # Starting the VM
vagrant ssh
vagrant reload
vagrant reload --debug
vagrant reload --provision # Restarting the VM
vagrant destroy
vagrant halt
vagrant status
vagrant box list
vagrant box update
vagrant box remove hashicorp/bionic64
vagrant box remove generic/ubuntu2004 --box-version 3.6.8
vagrant global-status | awk '/running/{print $1}'