我正在使用Vagrant v1.5.1来创建虚拟机(VM)群集。配置完所有虚拟机后,是否可以在其中一台机器上运行单个脚本?我想运行的脚本将从一个VM设置无密码SSH到所有其他VM。
例如,我在Vagrant(CentOS 6.5)中配置的节点如下所示。
我的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。
我知道您可以在配置每个虚拟机时运行脚本,但在这种情况下,我希望在配置所有虚拟机后运行脚本,因为我需要启动并运行所有虚拟机来运行最后一个脚本。
这是否可以在Vagrant中使用?
我意识到我也可以向后迭代。
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密码,那就更好了。
答案 0 :(得分:4)
问题是一年之久,无论如何我发现它是因为我遇到了同样的问题,所以这里是我用来解决问题的工作,有人可能觉得它很有用。
我们需要“vagrant triggers”来实现这一目标。流浪者触发器的事情是它们为你正在创建的每台机器开火,但我们想要确定所有机器都是UP的时刻。我们可以通过检查每个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)上并行执行的提供程序。
答案 1 :(得分:1)
Vagrant中没有挂钩“在配置完所有虚拟机后运行”,因此您需要自己实现它。我能想到几个选项:
1:在所有VM运行后运行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
等。
答案 2 :(得分:1)
这对我非常有效:我使用了每个VM设置脚本,在上一个脚本中,我在第一个VM上通过ssh调用了后置脚本。
在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
我希望,我没有跳过任何重要的事情,但是我认为这个想法很明确。
注意:默认情况下,Vagrant设置了用于interVM访问的ssh密钥。您可以根据需要使用common_provision.sh
答案 3 :(得分:0)
You can install vagrant-triggers plugin
This will allow you to run anything before & after up/resume/destroy commands
答案 4 :(得分:0)
添加更新的答案。
vagrant-triggers插件于2018年5月merged至Vagrant 2.1.0。
我们可以简单地使用 trigger 类中的only_on option选项。
假设我们具有以下配置:
var data = './' var context = requireAll(require.context( data, false, /[^.]{5}$/));
我们现在可以在最后一台机器启动后轻松执行触发器:
servers=[
{:hostname => "net1",:ip => "192.168.11.11"},
{:hostname => "net2",:ip => "192.168.22.11"},
{:hostname => "net3",:ip => "192.168.33.11"}
]
我们可以检查输出,并仅在“ net3”启动后才能触发触发器:
# 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