9

我正在使用 Vagrant v1.5.1 创建一个虚拟机 (VM) 集群。配置完所有虚拟机后,是否可以在其中一台机器上运行单个脚本?我要运行的脚本将设置从一个 VM 到所有其他 VM 的无密码 SSH。

例如,我在 Vagrant (CentOS 6.5) 中配置的节点如下。

  • 节点1
  • 节点2
  • 节点3
  • 节点4

我的Vagrantfile样子如下。

(1..4).each do |i|
 config.vm.define "node-#{i}" do |node|
  node.vm.box = "centos65"
  ...omitted..
 end
end

完成所有这些之后,我需要在 node1 上运行一个脚本来启用到 node2、node3 和 node4 的无密码 SSH。

我知道您可以在配置每个 VM 时运行脚本,但在这种情况下,我想在配置所有 VM 后运行一个脚本,因为我需要所有 VM 都启动并运行才能运行最后一个脚本。

这在流浪者中可能吗?

我意识到我也可以向后迭代。

r = 4..1
(r.first).downto(r.last).each do |i|
 config.vm.define "node-#{i}" do |node|
  node.vm.box = "centos65"
  ...omitted..
  if i == 1
   node.vm.provision "shell" do |s|
    s.path = "/path/to/script.sh"
   end
  end
 end
end

这会很好用,但实际上,我还需要设置从 node2 到 node1、node3 和 node4 的无密码 SSH。在上述方法中,这只适用于 node1,但不适用于 node2(因为不会配置 node1)。

如果有一个 Vagrant 插件允许在我的集群中的所有节点之间使用密码 SSH,那就更好了。

4

4 回答 4

5

这个问题已经有一年了,无论如何我找到了它,因为我有同样的问题,所以这是我用来解决问题的方法,有人可能会觉得它有用。

我们需要“无业游民触发器”才能使其发挥作用。vagrant 触发器的问题是它们会为您正在创建的每台机器触发,但我们想确定所有机器都启动的时刻。如果该事件对应于正在创建的最后一台机器,我们可以通过检查每个 UP 事件来做到这一点:

Vagrant.configure("2") do |config|

  (1..$machine_count).each do |i| 

  config.vm.define vm_name = "w%d" % i do |worker|

   worker.vm.hostname = vm_name
   workerIP = IP
   worker.vm.network :private_network, ip: workerIP

   worker.trigger.after :up do
     if(i == $machine_count) then
       info "last machine is up"
       run_remote  "bash /vagrant/YOUR_SCRIPT.sh"
     end   
   end

  end
 end
end

这适用于不支持在 Vagrant(VBox、VMWare)上并行执行的提供程序。

于 2016-03-31T10:15:20.090 回答
2

Vagrant 中没有“在配置所有 VM 后运行”的钩子,因此您需要自己实现它。我能想到的几个选择:

1:在所有虚拟机运行后运行 SSH 设置脚本。

例如,如果脚本被命名ssh_setup.sh并存在于共享文件夹中:

$ for i in {1..4}; do vagrant ssh node$i -c 'sudo /vagrant/ssh_setup.sh'; done

2:对所有主机使用相同的 SSH 密钥并在配置期间设置

如果所有节点共享相同的无密码 SSH 密钥,您可以复制到~.ssh所需的文件authorized_keys中,例如 ,id_rsa等。

于 2014-08-04T19:11:29.947 回答
1

添加更新的答案。

vagrant-triggers插件于2018 年5月合并Vagrant 2.1.0

我们可以简单地使用触发器类中的only_on 选项选项。

假设我们有以下配置:

servers=[
  {:hostname => "net1",:ip => "192.168.11.11"},
  {:hostname => "net2",:ip => "192.168.22.11"},
  {:hostname => "net3",:ip => "192.168.33.11"}
]

我们现在可以在最后一台机器启动后轻松执行触发器:

# Take the hostname of the last machine in the array
last_vm = servers[(servers.length) -1][:hostname]

Vagrant.configure(2) do |config|
    servers.each do |machine|
        config.vm.define machine[:hostname] do |node|

            # ----- Common configuration ----- #
            node.vm.box = "debian/jessie64"
            node.vm.hostname = machine[:hostname]
            node.vm.network "private_network", ip: machine[:ip]

            # ----- Adding trigger - only after last VM is UP ------ #
            node.trigger.after :up do |trigger|
                trigger.only_on = last_vm  # <---- Just use it here!
                trigger.info = "Running only after last machine is up!"
            end
        end
    end
end

我们可以检查输出并看到触发器只有在“net3”启动后才真正触发:

==> net3: Setting hostname...
==> net3: Configuring and enabling network interfaces...
==> net3: Installing rsync to the VM...
==> net3: Rsyncing folder: /home/rotem/workspaces/playground/vagrant/learning-network-modes/testing/ => /vagrant
==> net3: Running action triggers after up ...
==> net3: Running trigger...
==> net3: Running only after last machine is up!
于 2019-07-22T22:26:16.930 回答
1

这对我很有效:我使用了每个 VM 配置脚本,并且在最后一个脚本中,我通过 ssh 在第一个 VM 上调用了配置后脚本。

Vagrantfile

require 'fileutils'

Vagrant.require_version ">= 1.6.0"

$max_nodes = 2
$vm_name = "vm_prefix"

#...<skipped some lines that are not relevant to the case >...
Vagrant.configure("2") do |config|
  config.ssh.forward_agent = true
  config.ssh.insert_key    = false
  #ubuntu 16.04
  config.vm.box = "ubuntu/xenial64"

  (1..$max_nodes).each do |i|
    config.vm.define vm_name = "%s-%02d" % [$vm_name, i] do |config|
      config.vm.hostname = vm_name
      config.vm.network "private_network", ip: "10.10.0.%02d" % [i+20], :name => 'vboxnet2'
      config.vm.network :forwarded_port, guest: 22, host: "1%02d22" % [i+20], id: "ssh"
      config.vm.synced_folder "./shared", "/host-shared"
      config.vm.provider :virtualbox do |vb|
        vb.name = vm_name
        vb.gui = false
        vb.memory = 4096
        vb.cpus = 2
        vb.customize ["modifyvm", :id, "--cpuexecutioncap", "100"]
        vb.linked_clone = true
      end

      # Important part:
      config.vm.provision "shell", path: "common_provision.sh"
      config.vm.provision "shell", path: "per_vm_provision#{i}.sh"

    end
  end
end

在磁盘上:(确保 post_provision.sh 至少具有所有者执行权限:rwxr..r..)

vm$ ls /vagrant/
...<skipped some lines that are not relevant to the case >...
config.sh
common_provision.sh
per_vm_provision1.sh
per_vm_provision2.sh
per_vm_provision3.sh
...
per_vm_provisionN.sh
post_provision.sh
Vagrantfile
...<skipped some lines that are not relevant to the case >...

config.sh

  num_vm="2" # should equal the $max_nodes in Vagrantfile
  name_vm="vm_prefix" # should equal the $vm_name in Vagrantfile
  username="user1"
  userpass="abc123"
    ...<skipped some lines that are not relevant to the case >...

common_provision.sh

  source /vagrant/config.sh
  ...<skipped some lines that are not relevant to the case >...

  sed -r -i 's/\%sudo.*$/%sudo       ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers
  sed -r -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
  service ssh reload

  # add user ${username}
  useradd --create-home --home-dir /home/${username}  --shell /bin/bash  ${username}
  usermod -aG admin ${username} 
  usermod -aG sudo ${username}
  /bin/bash -c "echo -e \"${userpass}\n${userpass}\" | passwd ${username}"

  # provision additional ssh keys
  # copy ssh keys from disk
   cp /vagrant/ssh/* /home/vagrant/.ssh
   cat /vagrant/ssh/id_rsa.pub >> /home/vagrant/.ssh/authorized_keys
   mkdir /home/${username}/.ssh
   cp /vagrant/ssh/* /home/${username}/.ssh
   cat /vagrant/ssh/id_rsa.pub >> /home/${username}/.ssh/authorized_keys

# not required, just for convenience
 cat >> /etc/hosts <<EOF
10.10.0.21    ${name_vm}-01
10.10.0.22    ${name_vm}-02
10.10.0.23    ${name_vm}-03
...
10.10.0.2N    ${name_vm}-0N
EOF
  ...<skipped some lines that are not relevant to the case >...

per_vm_provision2.sh 中:

#!/bin/bash

  # import variables from config
  source /vagrant/config.sh

  ...<skipped some lines that are not relevant to the case >...

 # check if this is the last provisioned vm 
 if [ "x${num_vm}" = "x2" ] ; then
   ssh vagrant@10.10.0.21 -o StrictHostKeyChecking=no -- '/vagrant/post_provision.sh'
 fi

per_vm_provisionN.sh

#!/bin/bash

  # import variables from config
  source /vagrant/config.sh

  ...<skipped some lines that are not relevant to the case >...

 # check if this is the last provisioned vm. N represents the highest number 
 if [ "x${num_vm}" = "xN" ] ; then
   ssh vagrant@10.10.0.21 -o StrictHostKeyChecking=no -- '/vagrant/post_provision.sh'
 fi

我希望,我没有跳过任何重要的内容,但我认为这个想法总体上是明确的。

注意:用于 interVM 访问的 ssh 密钥默认由 Vagrant 提供。如果需要,您可以使用添加自己的 ssh 密钥common_provision.sh

于 2020-05-21T11:05:47.660 回答