Vagrant是什么

Vagrant 是一个快速建立开发环境的工具。通过一个文件来定义虚拟机的CPU数量、内存大小、主机名、网络等,可以批量生成多个虚拟机,快速构建环境。

安装

以macOS环境为例:

$ brew install vagrant
$ vagrant version
Installed Version: 2.3.4
Latest Version: 2.3.4

You're running an up-to-date version of Vagrant!

初始化环境

Vagrant通过vagrant init命令初始化Vagrant,声明默认的Vagrantfile,此步骤非必须。

$ make vagrant_demo
$ cd vagrant_demo
$ vagrant init centos/7
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 -al
total 8
drwxr-xr-x    3 lili  staff    96 Apr 13 10:14 .
drwxr-xr-x+ 105 lili  staff  3360 Apr 13 10:14 ..
-rw-r--r--    1 lili  staff  3014 Apr 13 10:14 Vagrantfile
$ # -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "centos/7"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

Vagrantfile定义

Vagrant.configure(2) do |config|
  config.vm.box = "centos/7" 
  config.vm.box_url = "https://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7.box"
  config.vm.box_check_update = false
  config.vm.hostname = "vagrant-demo"
  config.vm.provider "virtualbox" do |vbox|
    vbox.name = "vagrantdemo"
    vbox.cpus = 2
    vbox.memory = 2048
  end   
  config.vm.network :public_network, ip: "192.168.1.2", gateway: "192.168.1.1", netmask: "255.255.255.0"
end
  • 第一行Vagrant.configure(2)中的2代表配置文件的版本

  • config.vm.box和config.vm.box_url是对虚拟机镜像的定义,参考下文

  • config.vm.box_check_update:不检查box的更新

  • config.vm.hostname:定义虚拟机系统的名称

  • config.vm.provider:定义provide

  • vbox.name:定义虚拟机在virtualbox显示的名称

  • vbox.cpus:定义虚拟机使用的CPU数量

  • vbox.memory:定义虚拟机使用的内存大小

  • config.vm.network:为虚拟机定义公网网络配置,可只写IP,若不配置gateway,默认网卡的网关将是eth0的网关,默认网卡是NAT网络模型

在配置虚拟机的virtualbox信息时,也可以使用如下格式:

vbox.customize ["modifyvm", :id, "--memory", "2048"]
vbox.customize ["modifyvm", :id, "--cpus", 2]
vbox.customize ["modifyvm", :id, "--name", "vagrantdemo"]

常用使用

1、启动虚拟机

$ vagrant up

2、查看虚拟机状态

# 查看当前项目的虚拟机状态
$ vagrant status
# 查看所有虚拟机状态,包括非当前项目下,此命令可在任意位置执行
$ vagrant global-status

3、关闭虚拟机

$ vagrant halt

4、重启虚拟机

$ vagrant reload

5、启动关闭的虚拟机

$ vagrant resume

6、虚拟机快照

# 创建快照
$ vagrant snapshot save snap1
# 列出创建的快照
$ vagrant snapshot list
# 恢复快照
$ vagrant snapshot restore snap1
# 删除快照
$ vagrant snapshot delete snap1

7、暂停虚拟机

$ vagrant supsend

8、登录虚拟机

$ vagrant ssh default

9、虚拟机与主机互传文件

默认情况下,虚拟机的/vagrant目录与Vagrantfile文件所在目录共享,如果通过scp协议复制非共享目录的文件,可通过插件vagrant-scp实现,插件安装方式见下节。

10、插件

默认情况下,插件从官网下载

$ vagrant plugin install vagrant-scp

从国内镜像站安装

$ vagrant plugin install --plugin-clean-sources --plugin-source https://mirrors.aliyun.com/rubygems/ vagrant-scp

为了后续方便,可将从国内镜像站安装的命令进行别名

$ echo 'vagrant-plugin-install="vagrant plugin install --plugin-clean-sources --plugin-source https://mirrors.aliyun.com/rubygems/"' > ~/.zshrc
$ source ~/.zshrc
$ vagrant-plugin-install vagrant-scp

查看安装的插件

$ vagrant plugin list
vagrant-scp (0.5.9, global)
vagrant-share (2.0.0, global)

删除插件

$ vagrant plugin delete vagrant-scp

box

box是构建虚拟机环境时使用的镜像,类似ISO,如果box在本地不存在的话,则默认从HashiCorp官方下载,为了加速,可从国内镜像站下载。

从官方下载镜像:

$ vagrant box add centos/7

从国内镜像站下载:

$ vagrant box add --name centos/7 https://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7.box

如果本地已经存在同名的box,可添加--force参数进行覆盖

在Vagrantfile中定义国内镜像地址:

config.vm.box = "centos/7" 
config.vm.box_url = "https://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7.box"

其中config.vm.box定义镜像的名称,config.vm.box_url定义镜像的下载地址。如果包含版本信息,可通过config.vm.box_version进行配置,例如:config.vm.box_version = "1.0.282"

查看本地镜像:

$ vagrant box list
centos/7 (virtualbox, 0)

删除本地镜像:

$ vagrant box remove centos/7
Are you sure you want to remove this box? [y/N] y
Removing box 'centos/7' (v0) with provider 'virtualbox'...

定义多台虚拟机

逐一定义

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.define "node1" do |node1|
    node1.vm.hostname = "node1"
    node1.vm.provider "virtualbox" do |vbox|
    vbox.name = "node1"
    vbox.cpus = 2
    vbox.memory = 2048
  end
  
  config.vm.define "node2" do |node2|
    node2.vm.hostname = "node2"
    node2.vm.provider "virtualbox" do |vbox|
    vbox.name = "node2"
    vbox.cpus = 2
    vbox.memory = 2048
  end
end

使用循环

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  (1..3).each do |i|
    config.vm.define "node-#{i}" do |node|
      node.vm.hostname = "node-#{i}"
      node.vm.box_check_update = false
      node.vm.provider "virtualbox" do |vbox|
        vbox.name = "node-#{i}"
        vbox.cpus = 2
        vbox.memory =2048
      end
    end
  end
end

使用预定义变量批量创建

# -*- mode: ruby -*-
# vi: set ft=ruby :

vms = [
  {
    :name => "node1",
    :eth1 => "192.168.1.11",
    :cpus => 2,
    :memory => 2048
  },
  {
    :name => "node2",
    :eth1 => "192.168.1.12",
    :cpus => 2,
    :memory => 2048
  },
  {
    :name => "node3",
    :eth1 => "192.168.1.13",
    :cpus => 2,
    :memory => 2048
  }
]

Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.box_url = "https://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7.box"
  vms.each do |i|
    config.vm.define i[:name] do |node|
      node.vm.hostname = i[:name]
      node.vm.box_check_update = false
      node.vm.provider "virtualbox" do |vbox|
        vbox.name = i[:name]
        vbox.cpus = i[:cpus]
        vbox.memory = i[:memory]
      end
      node.vm.network :public_network, ip: i[:eth1], gateway: "192.168.1.1"
    end
  end
end

执行脚本或命令

执行外部脚本

Vagrantfile文件:

Vagrant.configure("2") do |config|
  (1..3).each do |i|
    config.vm.define "master-00#{i}" do |node|
      node.vm.box = "centos7-standard"
      node.vm.box_check_update = false
      node.vm.hostname = "master-00#{i}"
      node.vm.network "public_network", ip: "192.168.1.10#{i}"
      node.vm.provision "shell", path: "post-deploy.sh" ,run: "always"
    end
  end
  (1..3).each do |i|
    config.vm.define "node-00#{i}" do |node|
      node.vm.box = "centos/7"
      node.vm.box_check_update = false
      node.vm.hostname = "node-00#{i}"
      node.vm.network "public_network", ip: "192.168.1.10#{i}"
      node.vm.provision "shell", path: "post-deploy.sh" ,run: "always"
    end
  end
end
#!/bin/bash
value=$( grep -ic "entry" /etc/hosts )
if [ $value -eq 0 ]
then
echo "
192.168.11.101  master-001
192.168.11.102  master-002
192.168.11.103  master-003
" >> /etc/hosts
fi

其中node.vm.provision配置为shell,作用是在虚拟机启动后执行的shell命令,此外provision还有file、ansible等,可参考官方。

此处将在系统启动后要执行的脚本和Vagrantfile放在同一级目录下,文件讲传到虚拟机内并执行,run指明脚本执行的频次,有once(默认值,仅在第一次执行vagrant upvagrant destroy后再执行vagrant up后执行脚本)、always(每次执行vagrant upvagrant reload后执行)、never(永远不执行)。

执行inline脚本

$script = <<-'SCRIPT'
echo "These are my \"quotes\"! I am provisioning my guest."
date > /etc/vagrant_provisioned_at
SCRIPT

Vagrant.configure("2") do |config|
  config.vm.provision "shell", inline: $script
end

Vagrant.configure("2") do |config|
  config.vm.provision "shell",
    inline: "echo Hello, World"
end

脚本参数

Vagrant.configure("2") do |config|
  config.vm.provision "shell" do |s|
    s.inline = "echo $1"
    s.args   = "'hello, world!'"
  end
end

Vagrant.configure("2") do |config|
  config.vm.provision "shell" do |s|
    s.inline = "echo $1"
    s.args   = ["hello, world!"]
  end
end
04-14 07:32