是否可以在一个Vagrantfile中加载另一个Vagrantfile的配置?

9
Vagrant的多机功能看起来非常酷,但有一件事让我困扰(或者并不明显),那就是似乎没有很好的方法在“父”Vagrantfile和“子”Vagrantfiles之间共享配置选项。是否有一种有效且可维护的方法在父级和其子级之间共享配置选项?例如可以更清晰地说明这一点。
假设我有一个平台,由3个应用程序/服务组成:API、Web和Worker。
假设目录结构如下:
/some_platform
  /api
    # app code...
    Vagrantfile
  /web
    # app code...
    Vagrantfile
  /worker
    # app code...
    Vagrantfile
  Vagrantfile

假设/some_platform/api/Vagrantfile如下:

Vagrant.configure("2") do |config|
  config.vm.box = "debian/jessie64"
end

假设网页和工作 Vagrantfiles 看起来很相似。

现在,我通过 Multi-Machine 的奇妙之处来依赖 Vagrant 协调这些虚拟机,/some_platform/Vagrantfile 的样子如下:

Vagrant.configure("2") do |config|
  config.vm.define "web" do |api|
    api.vm.box = "debian/jessie64"
  end

  config.vm.define "web" do |web|
    web.vm.box = "debian/jessie64"
  end

  config.vm.define "web" do |worker|
    worker.vm.box = "debian/jessie64"
  end
end

我知道这个例子是编造的,但很容易看出,一旦你有了越来越复杂的配置声明,将其在两个地方重复会很烦人且有危险性。
你可能会想:“为什么每个项目都有自己的Vagrantfile?”这样做提供了一个统一的真相来源,告诉你该如何设置运行应用程序的服务器。我知道有一些 provisioners 可以使用(我会使用它们),但你仍然需要在外部声明其他一些内容,而我希望保持DRY,这样我可以通过 Multi-Machine 来启动一组应用程序集群,或者我可以工作于单个应用程序并更改其VM/服务器设置。
我真正想要的是一种将其他 Vagrantfiles 合并到“父”文件中的方法。
是否可能?还是我因尝试而变得疯狂?有没有聪明的想法来实现这一点?我已经在一些yaml文件和POROs上进行了尝试来避免这个问题,但是这些hack都不太令人满意。
2个回答

9

好消息!
实际上,您可以在Vagrantfile中应用DRY原则。DRY原则

第一步:创建一个文件 /some_platform/DRY_vagrant/Vagrantfile.sensible 用于存放一些合理的默认值:

Vagrant.configure("2") do |config|
  # With the setting below, any vagrantfile VM without a 'config.vm.box' will 
  # automatically inherit "debian/jessie64"
  config.vm.box = "debian/jessie64"
end

第二步:创建一个文件/some_platform/DRY_vagrant/Vagrantfile.worker,用于“worker”虚拟机:

Vagrant.configure("2") do |config|
  config.vm.define "worker" do |worker|
    # This 'worker' VM will not inherit "debian/jessie64". 
    # Instead, this VM will explicitly use "debian/stretch64"
    worker.vm.box = "debian/stretch64"
  end
end

最后: 创建一个文件/some_platform/Vagrantfile将所有内容联系在一起:

# Load Sensible Defaults
sensible_defaults_vagrantfile = '/some_platform/DRY_vagrant/Vagrantfile.sensible'
load sensible_defaults_vagrantfile if File.exists?(sensible_defaults_vagrantfile)

# Define the 'api' VM within the main Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.define "api" do |api|
    # This 'api' VM will automatically inherit the "debian/jessie64" which we
    # configured in Vagrantfile.sensible

    # Make customizations to the 'api' VM
    api.vm.hostname = "vm-debian-jessie64-api"
  end
end

# Load the 'worker' VM
worker_vm_vagrantfile = '/some_platform/DRY_vagrant/Vagrantfile.worker'
load worker_vm_vagrantfile if File.exists?(worker_vm_vagrantfile)

这种方法可以用于几乎所有其他的Vagrantfile配置选项,不仅限于“config.vm.box”设置。

希望这能帮到你!


1
我可以问一下,如果/some_platform/Vagrantfile有一个变量,而/some_platform/DRY_vagrant/Vagrantfile.sensible需要它,你会如何将其传递给后者?使用全局变量吗...? - Dave Mackey
1
根据我的经验,在加载Vagrantfile.sensible之前在Vagrantfile中定义的所有变量都可以在Vagrantfile.sensible中访问。@DaveMackey - Miron Veryanskiy
谢谢@Miron V,我需要进一步研究一下这个问题……似乎对我没有起作用。 - Dave Mackey

3
有两件事情你可以看看(可能还有更多,但这两个是我想到的):
  1. 查看如何使用Ruby模板化Vagrantfile?。这是一个示例,说明你可以读取另一个文件的内容,Vagrantfile只是一个Ruby脚本,所以你可以使用Ruby的全部功能。

  2. Vagrant有加载和合并的概念,详见文档。因此,如果你想在运行Vagrant命令时任何时间都执行某些操作,可以在~/.vagrant.d/文件夹下创建一个Vagrantfile,它将始终运行。

需要注意的一点(或者至少要注意的一点):Vagrantfile是一个Ruby脚本,在执行Vagrant命令(up、status、halt等)时每次都会被评估。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接