本地覆盖Vagrantconfiguration设置(per-dev)

我希望这个问题得到普遍的回答,但为了说明这个问题,这里有一个用例:

我正在使用Vagrant进行简单的LMAP项目。 我使用独立的Puppet进行configuration。 现在,可能会有一些开发人员坐在代理之后,他们需要对虚拟机进行一些额外的configuration。 我在Puppet方面有一些工作:我可以将代理IP(如果有的话)作为一个事实传递给Vagrantfile木偶,如果设置了,Puppet会作出相应的反应。

我唯一的问题是:开发人员如何在开发环境中指定/覆盖此设置,而无需更改Vagrantfile (版本控制下,并且必须保持dev-environment-neutral)?

如果人们可以重写一个叫做Vagrantfile.local的文件中的一些Vagrant设置,那么我会通过.gitignore排除。

由于Vagrantfile只是Ruby,我尝试了以下内容:

 # Also load per-dev custom vagrant config custom_vagrantfile = 'Vagrantfile.local' load custom_vagrantfile if File.exist?(custom_vagrantfile) 

文件包含基本上工作,但它看起来像在包含的文件,我不在同一个stream浪上下文了…

 Vagrant::Config.run do |config| config.vm.provision :puppet do |puppet| puppet.facter = { "proxy" => "proxy.host:80" } end end 

…也会“重置”我在主Vagrantfile所做的所有其他木偶configuration值,这让我觉得我正在朝着错误的方向前进。 我应该注意到,我是Ruby的总noob;)

任何人都可以给我一个提示,甚至一个工作的解决scheme,如何在每个开发定制可以在这里做一般?

我会build议使用环境variables来dynamic改变Vagrantfile的行为而不用编辑文件本身。

为了给出一个真实世界的例子,默认情况下,你可以如何使用Ubuntu的基本框,但是有一个环境variables定义了一个可选的Linux发行版:

 if ENV['OPERATINGSYSTEM'] if ENV['OPERATINGSYSTEM'].downcase == 'redhat' os_name = 'centos' config.vm.box = 'centos' config.vm.box_url = 'https://dl.dropbox.com/u/7225008/Vagrant/CentOS-6.3-x86_64-minimal.box' else raise(Exception, "undefined operatingsystem: #{ENV['OPERATINGSYSTEM']}") end else os_name = 'precise64' config.vm.box = 'precise64' config.vm.box_url = 'http://files.vagrantup.com/precise64.box' end 

这个例子来自https://github.com/puppetlabs/puppetlabs-openstack_dev_env

Vagrantfile只是Ruby,所以YAML是另一种select。

例如,在Vagrantfile我这样做:

 # -*- mode: ruby -*- # vi: set ft=ruby : require 'yaml' settings = YAML.load_file 'vagrant.yml' db_ip_address = settings['db']['ip_address'] api_ip_address = settings['api']['ip_address'] Vagrant.configure("2") do |config| config.vm.box = "ffuenf/ubuntu-13.10-server-amd64" config.vm.box_url = "https://vagrantcloud.com/ffuenf/ubuntu-13.10-server-amd64/version/4/provider/virtualbox.box" config.vm.define "db" do |db| db.vm.synced_folder settings['db']['artifacts_dir']['host'], settings['db']['artifacts_dir']['guest'] db.vm.network "private_network", ip: db_ip_address ... other stuff ... end config.vm.define "api" do |api| api.vm.synced_folder settings['api']['artifacts_dir']['host'], settings['api']['artifacts_dir']['guest'] api.vm.network "private_network", ip: api_ip_address api.vm.network "forwarded_port", guest: settings['api']['forwarded_port']['guest'], host: settings['api']['forwarded_port']['host'] end end 

然后,我有一个vagrant.yml文件(我刚刚vagrant.yml了这个名称;你可以使用任何你喜欢的名字)进行开发者特定的configuration:

 db: ip_address: 192.168.4.14 artifacts_dir: host: /Users/willie/myapp/db-scripts guest: /opt/myapp/db api: ip_address: 192.168.4.15 forwarded_port: host: 9080 guest: 8080 artifacts_dir: host: /Users/willie/myapp/artifacts guest: /opt/myapp/api 

如果你准备定义应用于所有stream浪者箱子的设置,值得注意的是,“stream浪者实际上加载了一系列的stream浪文件,并将设置合并。” (参考https://docs.vagrantup.com/v2/vagrantfile/

所以我在~/.vagrant.d/Vagrantfile定义了以下~/.vagrant.d/Vagrantfile来增加我的stream浪者箱子的RAM数量:

 Vagrant.configure(2) do |config| config.vm.provider "virtualbox" do |vb| vb.memory = 2048 end end 

这是一个想法。 这可能是“丑陋”和“错误”,但至less它工作:)

 # file2.rb, this is your per-dev configuration file puts "included external file which uses outer var: #{foo}" # file1.rb, this would be your Vagrantfile puts 'first' foo = 'bar' external = File.read 'file2.rb' eval external puts 'second' 

让我们来运行它

 $ ruby file1.rb first included external file which uses outer var: bar second 

根据你的例子,file2.rb将只包含config用法而不定义它( config将从外部上下文提供)

  config.vm.provision :puppet do |puppet| puppet.facter = { "proxy" => "proxy.host:80" } end 

你的Vagrant文​​件可能是这样的:

 Vagrant::Config.run do |config| external = File.read 'Vagrantfile.local' eval external # proceed with general settings here config.vm.provision :puppet do |puppet| puppet.facter = { "proxy" => "proxy.host:80" } end end 

更新(另一个“数据驱动”方法)

 # Vagranfile.local config_values[:puppet][:facter][:proxy] = 'proxy.host:80' # Vargantfile Vagrant::Config.run do |config| config_values = { puppet: { facter: { proxy: nil }, manifests_file: 'my_manifest.pp' } } external = File.read 'Vagrantfile.local' eval external # this should overwrite proxy config # proceed with general settings here config.vm.provision :puppet do |puppet| if config_values[:puppet][:facter][:proxy] puppet.facter = { "proxy" => config_values[:puppet][:facter][:proxy] } end puppet.manifests_file = config_values[:puppet][:manifests_file] end end 

我相信这就是Nugrant插件被创build来解决的确切用例。 它允许你的每个开发者在YAML中有一个.vagrantuser (这是一个.gitignore-ed文件)指定自定义configuration值,然后在Vagrantfile轻松地引用这些值。

在你的情况下,一个代理开发者将他们的.vagrantuser文件看起来像这样:

 proxy: 'proxy.host:80' 

你的Vagrantfile看起来像这样(伪代码,我真的不知道ruby):

 Vagrant::Config.run do |config| config.vm.provision :puppet do |puppet| if config.user.has_key?('proxy') puppet.facter = { "proxy" => config.user.proxy } end end end 

您应该为您的开发人员捆绑一个样本/参考vagrantuser(即vagrantuser.example )文件来复制和调整其环境。

延长@Willie Wheeler的回答。 我的设置是:

 Root |-- defaults.yml |-- env.yml |-- Vagrantfile 

Vagrantfile

 # Load local env config require 'yaml' dir = File.dirname(File.expand_path(__FILE__)) # defaults settings = YAML::load_file("#{dir}/defaults.yml") if File.exist?("#{dir}/env.yml") env_settings = YAML::load_file("#{dir}/env.yml") settings.merge!(env_settings) end ... # Customize the amount of memory on the VM: vb.memory = settings["vb"]["memory"] 

defaults.yml

 vb: memory: 1024 

env.yml

 vb: memory: 204 

这将合并你的每个开发configuration的默认值。 开发人员也清楚他们实际上可以改变什么价值

您可以从YAML文件加载设置。 这在Drupal VM中演示如下:

 # Use config.yml for basic VM configuration. require 'yaml' dir = File.dirname(File.expand_path(__FILE__)) if !File.exist?("#{dir}/config.yml") raise 'Configuration file not found! Please copy example.config.yml to config.yml and try again.' end vconfig = YAML::load_file("#{dir}/config.yml") 

那么你可以像创buildconfig.yml一样:

 vagrant_box: geerlingguy/ubuntu1404 vagrant_user: vagrant vagrant_ip: 192.168.88.88 

Vagrantfile你可以使用如下的variables:

 config.vm.box = vconfig['vagrant_box'] config.vm.network "private_network", ip: vconfig['vagrant_ip']