问题
I have a Vagrantfile which creates 3 servers. I have two ansible playbooks. playbook1 should be executed on every server first. The second playbook2 should only be executed on server1 and not on server2 and server3.
How can I manage this with my Vagrantfile?
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.define "server1" do |server1|
//
end
config.vm.define "server2" do |server2|
//
end
config.vm.define "server3" do |server3|
//
end
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook1.yml"
end
end
The above executes playbook1 on all servers. How can I add config for playbook2.yml to be executed only on server1 and AFTER playbook1?
回答1:
Given your example Vagrantfile
and your theoretical playbook2.yml
executing only on server2
after playbook1.yml
on server1
, we would arrive at the following solution:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.define "server1" do |server1|
//
# restrict scope of ansible provisioner to server1 by invoking on its class method off the constructor
server1.vm.provision :ansible do |ansible|
ansible.playbook = 'playbook1.yml'
end
end
config.vm.define "server2" do |server2|
//
# perform similarly for server2, which executes after server1 provisioning due to the imperative ruby dsl
server2.vm.provision :ansible do |ansible|
ansible.playbook = 'playbook2.yml'
end
end
config.vm.define "server3" do |server3|
//
end
end
It is also worth noting that if you want to be precise about ordering, you can vagrant up server1
and then vagrant up server2
instead of an all-in-one vagrant up
.
Basically, within Vagrant.configure
there is a scope affecting all VMs within config.vm
. You can restrict its scope to specific VMs by instantiating with config.vm.define
like you do above. Object VMs instantiated with config.vm.define
have the same members/attributes as the base config
.
Note you can also do something like this if you want:
Vagrant.configure('2') do |config|
...
(1..3).each do |i|
config.vm.define "server#{i}" do |server|
//
server.vm.provision :ansible do |ansible|
ansible.playbook = "playbook#{i}.yml"
end
end
end
end
for a per-server specific playbook. This depends on what exactly is within your //
though specific to each VM, and if you wanted a third playbook for the third VM.
回答2:
The below example will execute playbook1.yml
on every server first then execute playbook2.yml
only on server1 (this example assumes that the playbook1.yml
can be parallelized):
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
N = 3
(1..N).each do |server_id|
config.vm.define "server#{server_id}" do |server|
server.vm.box = "ubuntu/bionic64"
server.vm.hostname = "server#{server_id}"
server.vm.network "private_network", ip: "172.28.128.25#{server_id}"
server.vm.provision :shell, inline: "sudo apt install -y python"
# only execute once the ansible provisioner,
# when all the machines are up and ready.
if server_id == N
server.vm.provision :ansible do |ansible|
# disable default limit to connect to all the machines
# execute playbook1 on all hosts
ansible.limit = "all"
ansible.playbook = "playbook1.yml"
ansible.compatibility_mode = "2.0"
end
server.vm.provision :ansible do |ansible|
# limit the connection to server1 and execute playbook2
ansible.limit = "server1"
ansible.playbook = "playbook2.yml"
ansible.compatibility_mode = "2.0"
end
end
end
end
end
This example builds on top of the example provided in the Tips and Tricks, the ansible-playbook
's are parallelized and the scope for both ansible-playbooks
's is limited by the ansible.limit
configuration option (e.g. a vagrant up
will bring up the virtual machines first then execute the playbooks one after the other against all hosts or subset of hosts).
Note: the ubuntu/bionic64 (virtualbox, 20190131.0.0)
box has /usr/bin/python3
installed, for the sake of having a copy & paste example and for using a dynamic inventory I deliberately kept the server.vm.provision :shell, inline: "sudo apt install -y python"
in the example so ansible-playbook (2.7.6)
doesn't bomb out with "/bin/sh: 1: /usr/bin/python: not found\r\n
errors (ref. How do I handle python not having a Python interpreter at /usr/bin/python on a remote machine?). Example playbook1.yml
and playbook2.yml
(present in the same directory as the Vagrantfile
):
---
- hosts: all
tasks:
- debug:
msg: 'executing on {{ inventory_hostname }}'
Results in:
来源:https://stackoverflow.com/questions/54468546/how-to-run-an-ansible-playbook-on-a-specific-vagrant-host