Vagrant Quick Start

My Vagrant singleton virtual machine and cluster setup for different usage, see this git repo.

早在2019年使用Ansible (from Book <<Ansible: Up and Running>>)的时候就了解到了Vagrant,知道它能非常方便的provisioning virtual machine cluster for testing and demo purpose (比如测试Ansible的功能模块, Jenkins, Nginx).这次系统地学习了,这样在本地部署实验集群也很方便了(还有一个选择是docker compose)。

Ansible playbooks are a great way to specify how to configure a Vagrant machine so new comers on your team can get up and running on day one. Of course you can use other provisioners.

Vagrant Box Search 提供诸如 Windows, MacOS等许多操作系统的box image. 还有Openshift, Kubernetes all-in-one box等, 但是可能有的配置过于繁杂,可以自己使用root image build your custom image via Packer.

Introduction

First read the Vagrant web site. Vagrant Blog (from HashiCorp). To see what’s new in latest version.

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 as production.

Vagrant vs. Other Software Compare with VirutalBox CLI tools, Docker and Terraform.

Install

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

Download and install VirtualBox: https://www.virtualbox.org/wiki/Downloads

Download and install Vagrant: https://www.vagrantup.com/downloads

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”.

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
48
49
# -*- 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.50.1x
AGENT_IP = "192.168.3.1"

# Vagrantfile for Jenkins
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

使用了private IP后,不再需要port forwarding了,比如VM中有apache server listening on port 80,则可以在host browser上直接访问http://192.168.2.2. 查看virtualbox当前VM的网络配置,对应的adapter用的是Host-only adapter.

注意,在使用private IP的时候,一般遵循private network的范围限制, 我发现chrome上可能无法访问,可以使用firefox or chrome 匿名模式。或直接使用curl, wget等命令。

还有一点要注意,防火墙firewall是否关闭或设置相应的rules,否则也可能访问不到port:

同一网段的private IP是集群必备,否则不能相互SSH访问。

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

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

Public network, allow general public access to VM, 但本地测试使用意义不大。

1
2
# when start, it will prompt you select which interface to use
config.vm.network "public_network", ip: "192.173.2.2"

SSH agent forwarding, for example, git clone from 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 config

Vagrant SSH setting. SSH to vagrant machine without running ‘vagrant ssh’: Vagrant will generate key pair for each VM, check by vagrant ssh-config:

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

这个SSH 是如何创建的呢?在创建VM后只有 NAT,host并不能访问VM,vagrant 会自动设置 NAT port forwarding 映射SSH port 22 on VM, 然后生成SSH public-private key等内容,之后使用vagrant ssh就可以访问了. 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"

To see the full ssh command vagrant uses, run ps aux | grep ssh to check, for example:

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

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

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 support 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 so that the guest machine can be repeatably created and ready-to-use.

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 only if 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

可以软连接synced folder中的文件或文件夹到需要的地方,这样方便在host machine中编辑.

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

When to use suspend vs halt

Multi-Machine

这个是非常实用的部分,对于测试ansible 以及 jenkins: 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

VirtualBox

Start from PluralSight 2014年的Vagrant课程,记录的时候会有一些更新。 Virtualbox command line tool:

1
2
3
4
# list VMs
vboxmanage list vms
# show running VMs
vboxmanage list runningvms

Networks types: Networks types video

  • Not attached. In this mode, Oracle VM VirtualBox reports to the guest that a network card is present, but that there is no connection. This is as if no Ethernet cable was plugged into the card. 断网模式。

  • Network Address Translation (NAT). If all you want is to browse the Web, download files, and view email inside the guest, then this default mode should be sufficient for you. 从VM内部可以上网,如果外界或host要访问VM的服务,需要port forwarding. (host is used as a proxy for VM)

  • Host-only networking. This can be used to create a network containing the host and a set of virtual machines, without the need for the host’s physical network interface. Instead, a virtual network interface, similar to a loopback interface, is created on the host, providing connectivity among virtual machines and the host. 可以确保host和VMs 相互通信,但VM不能访问外界。

  • Bridged networking. This is for more advanced networking needs, such as network simulations and running servers in a guest. When enabled, Oracle VM VirtualBox connects to one of your installed network cards and exchanges network packets directly, circumventing your host operating system’s network stack. 这个是最全的访问模式,VM, host, 外界均可互访。Docker, Docker compose的默认网络就是这种类型。

  • Internal networking. This can be used to create a different kind of software-based network which is visible to selected virtual machines, but not to applications running on the host or to the outside world. 只能选中的VMs之间互访。

  • NAT Network. A NAT network is a type of internal network that allows outbound connections. 选中的VMs之间互访,加上outbound.

0%