Vagrant 是一个使用 Ruby 编写,基于纯文本文件自动化创建和配置虚拟机的工具。

基于 VirtualBox 和 [[VMware]] ,通过 Vagrant 去控制虚拟机。

Vagrant 是 hashicorp 公司的产品。该公司有大量的开源项目

Vagrant 提供了 vagrant 命令,通过 Vagrantfile 文件声明虚拟机配置。

Prerequisite

Terminology

  • Box,Vagrant 中的虚拟机镜像
  • Provider,为 Vagrant 提供虚拟化支持的具体工具,比如 VirtualBox,或 VMware
  • Provisioning,虚拟机实例启动后的初始化

安装 Vagrant

Linux

按照官网的介绍安装

macOS

brew cask install virtualbox
brew cask virtualbox-extension-pack
brew cask install vagrant

下载一个虚拟机:

vagrant box add ubuntu/trusty64

初始化一个 Ubuntu 镜像:

vagrant init ubuntu/trusty64

在初始化之后可以在当前目录下找到 Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
end

ubuntu/trusty64 是在 Vagrant 官网搜索到的虚拟机的镜像。

启动虚拟机:

vagrant up
❯ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'ubuntu/trusty64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'ubuntu/trusty64'
    default: URL: https://vagrantcloud.com/ubuntu/trusty64
==> default: Adding box 'ubuntu/trusty64' (v20190514.0.0) for provider: virtualbox
    default: Downloading: https://vagrantcloud.com/ubuntu/boxes/trusty64/versions/20190514.0.0/providers/virtualbox.box
Download redirected to host: cloud-images.ubuntu.com
==> default: Successfully added box 'ubuntu/trusty64' (v20190514.0.0) for 'virtualbox'!
==> default: Importing base box 'ubuntu/trusty64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/trusty64' version '20190514.0.0' is up to date...
==> default: Setting the name of the VM: vagrant_default_1630040745169_54425
==> default: Clearing any previously set forwarded ports...
Vagrant is currently configured to create VirtualBox synced folders with
the `SharedFoldersEnableSymlinksCreate` option enabled. If the Vagrant
guest is not trusted, you may want to disable this option. For more
information on this option, please refer to the VirtualBox manual:

  https://www.virtualbox.org/manual/ch04.html#sharedfolders

This option can be disabled globally with an environment variable:

  VAGRANT_DISABLE_VBOXSYMLINKCREATE=1

or on a per folder basis within the Vagrantfile:

  config.vm.synced_folder '/host/path', '/guest/path', SharedFoldersEnableSymlinksCreate: false
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    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 it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default: 
    default: Guest Additions Version: 4.3.40
    default: VirtualBox Version: 6.1
==> default: Mounting shared folders...
    default: /vagrant => /home/einverne/Git/vagrant

修改 Vagrant 可以自定义虚拟机网络,内存和 CPU 等等。

# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
  machine_box = "ubuntu/trusty64"

  config.vm.define "local-env-1" do |machine|
    machine.vm.box = machine_box
    machine.vm.hostname = "local-env-1"
    machine.vm.network "private_network", ip: "192.168.33.11"
    machine.vm.provider "virtualbox" do |node|
        node.name = "local-env-1"
        node.memory = 2048
        node.cpus = 2
    end
   end

   config.vm.define "local-env-2" do |machine|
    machine.vm.box = machine_box
    machine.vm.hostname = "local-env-2"
    machine.vm.network "private_network", ip: "192.168.33.12"
    machine.vm.network "forwarded_port", guest: 26379, host: 26380
    machine.vm.provider "virtualbox" do |node|
        node.name = "local-env-2"
        node.memory = 2048
        node.cpus = 2
    end
   end
end

启动之后可以通过 vagrant ssh $name 登录虚拟机。

在虚拟机启动后 /vagrant 目录会挂载宿主机的同级目录。文件是同步的,这样就可以通过该目录来共享文件。

执行额外的操作

在 Vagrantfile 中可以如下语法:

config.vm.provision :shell, path: "bootstrap.sh"

会执行 bootstrap.sh 脚本。

Vagrant Box

Vagrant Box 相对于 Vagrant,就像是 Docker Image 对应于 Docker。

可以使用:

vagrant box add name

来添加 Box。

升级 Box

vagrant box update --box name

删除 Box

vagrant box remove name

Vagrant 常用命令

常用命令有:

  • vagrant up
  • vagrant halt: 关闭虚拟机
  • vagrant destroy:销毁虚拟机
  • vagrant status
  • vagrant reload
  • vagrant restart
  • vagrant box list: 列出当前机器缓存的镜像

常用配置

网络配置

和 Docker 类似,Vagrant 也有几种不同的网络配置:

端口映射,将宿主机端口映射到虚拟机端口,宿主机 8080 端口映射到虚拟机 80 端口:

config.vm.network "forwarded_port", guest: 80, host: 8080

私有网络(host-only),只有宿主机能访问虚拟机,多个虚拟机在同一个网段,相互可以访问:

config.vm.network "private_network", ip: "192.168.21.4"

公有网络(bridge),虚拟机和宿主机相当于局域网中独立的主机,设置静态IP:

config.vm.network "public_network", ip: "192.168.1.120"

如果使用 public_network 而不配置 IP,那么会 DHCP 自动获取 IP 地址。

共享目录

设置共享目录,Vagrant 使用 rsync 来同步文件:

config.vm.synced_folder "/directory/of/host_machine", "/directory/of/guest_machine"

Provision

虚拟机实例启动之后,通过工具自动设置,支持 Shell,Puppet,Chef,Ansible 等等:

config.vm.provision "shell", run: "always", inline: <<-SHELL
    sudo yum install -y net-tools
SHELL

run: “always”表示每次vagrant up的时候,都执行Provision。

引用外部脚本:

config.vm.provision "shell", path: "script.sh

并非每次vagrant up的时候,都会执行Provision。只有在下面3种情况下Provision才会执行:

  • 首次执行vagrant up
  • 执行vagrant provision
  • 执行vagrant reload –provision

使用 Ansible

  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
  end

使用虚拟机内部的 Ansible:

Vagrant.configure("2") do |config|
  # Run Ansible from the Vagrant VM
  config.vm.provision "ansible_local" do |ansible|
    ansible.playbook = "playbook.yml"
  end
end

创建自己的虚拟机

vagrant package --output hadoop_master.box hadoop_master

hadoop_master是虚拟机实例名称,hadoop_master.box是box名。
在创建box的时候,如果虚拟机实例正在运行,vagrant会先halt,然后再export。

将box添加到本地仓库:

vagrant box add hadoop_master hadoop_master.box

查看本地仓库的box列表:

$ vagrant box list
centos7       (virtualbox, 0)
hadoop_master (virtualbox, 0)

创建并且切换到用于测试的项目目录:

mkdir ~/test_vagrant && cd ~/test_vagrant

创建Vagrantfile,并使用刚才新创建的hadoop_master.box作为box:

vagrant init -m hadoop_master

创建,并启动虚拟机:

vagrant up

登陆到虚拟机:

vagrant ssh

可以看到和创建box之前的虚拟机是一模一样的

延伸阅读