您如何为每个使用不同盒子的多个提供者编写 Vagrantfile?

How do you write a Vagrantfile for multiple providers that each use a different box?

我的目标是创建一个 Vagrantfile,我可以在其中选择使用 Docker 或使用 --provider 标志的 VirtualBox(例如 vagrant up --provider=virtualbox)。我 运行 遇到了一个问题,因为 Docker 供应商说我的盒子不兼容。这是真的,但我不想 Docker 使用这个框;我有一个 Docker 文件,我指向它供 Docker 使用。我希望仅当 VirtualBox 是提供者时才使用该框。如何让 Docker 提供者忽略盒子声明或仅当 VirtualBox 是提供者时才使盒子声明 运行?

这是我的 Vagrantfile:

Vagrant.require_version ">= 1.7.0"

Vagrant.configure('2') do |config|
  PROJECT_ROOT = File.expand_path(File.join(File.dirname(File.expand_path(__FILE__)), '..'))

  config.vm.provider "docker" do |d|
    d.build_dir = "."
    d.has_ssh = true
  end

  config.vm.box = "ubuntu/trusty64" # <--------- this is the line the Docker provider chokes on
  config.vm.provider "virtualbox" do |v|
    v.gui = true
  end

  config.vm.network :forwarded_port, guest: 80, host: 9002
  config.vm.network :forwarded_port, guest: 9000, host: 9000
  config.vm.network :forwarded_port, guest: 9001, host: 9001

  config.vm.synced_folder PROJECT_ROOT, '/srv'

  config.vm.provision :ansible do |ansible|
    ansible.verbose = "v"
    ansible.playbook = 'provisioning/playbook.yml'
  end
end

您只需要根据提供商移动该框条件

Vagrant.require_version ">= 1.7.0"

Vagrant.configure('2') do |config|
  PROJECT_ROOT = File.expand_path(File.join(File.dirname(File.expand_path(__FILE__)), '..'))

  config.vm.provider "docker" do |d|
    d.build_dir = "."
    d.has_ssh = true
  end

  config.vm.provider "virtualbox" do |v, override|
    override.vm.box = "ubuntu/trusty64"
    v.gui = true
  end

  config.vm.network :forwarded_port, guest: 80, host: 9002
  config.vm.network :forwarded_port, guest: 9000, host: 9000
  config.vm.network :forwarded_port, guest: 9001, host: 9001

  config.vm.synced_folder PROJECT_ROOT, '/srv'

  config.vm.provision :ansible do |ansible|
    ansible.verbose = "v"
    ansible.playbook = 'provisioning/playbook.yml'
  end
end

问题从根本上归结为这样一个事实,即 Vagrant 有一个内置的假设,即 boxes 和 providers 是完全独立的,可以任意组合交换。这不是真的。一个盒子只与它设计使用的供应商兼容。正确的设计将允许每个提供者指定自己的框,而不是让框成为全局值。此设计已存在于允许您选择 Docker 图像的 Docker 提供程序中,但不存在于任何其他提供程序中。据我所知,这是 Vagrant 中的一个错误。

我的解决方案是解析传递的提供者参数并将提供者声明包装在 if 语句中:

require 'optparse'

def get_provider
  ret = nil
  opt_parser = OptionParser.new do |opts|
    opts.on("--provider provider") do |provider|
      ret = provider
    end
  end
  opt_parser.parse!(ARGV)
  ret
end
provider = get_provider || "virtualbox"

PROJECT_ROOT = File.expand_path(File.join(File.dirname(File.expand_path(__FILE__)), '..'))

Vagrant.require_version ">= 1.7.0"

Vagrant.configure('2') do |config|
  if provider == "docker"
    config.vm.provider "docker" do |d|
      d.build_dir = "."
      d.has_ssh = true
    end
  end

  if provider == "virtualbox"
    config.vm.box = "ubuntu/trusty64"
    config.vm.provider "virtualbox" do |v|
      v.gui = true
    end
  end

  config.vm.network :forwarded_port, guest: 80, host: 9002
  config.vm.network :forwarded_port, guest: 9000, host: 9000
  config.vm.network :forwarded_port, guest: 9001, host: 9001

  config.vm.synced_folder PROJECT_ROOT, '/srv'

  config.vm.provision :ansible do |ansible|
    ansible.verbose = "v"
    ansible.playbook = 'provisioning/playbook.yml'
  end
end