如何 运行 特定流浪主机上的 ansible 剧本

How to run an ansible playbook on a specific vagrant host

我有一个创建 3 个服务器的 Vagrantfile。我有两本可靠的剧本。 playbook1 应该首先在每台服务器上执行。第二个 playbook2 只能在 server1 上执行,而不能在 server2 和 server3 上执行。

如何使用我的 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

以上在所有服务器上执行playbook1。如何为 playbook2.yml 添加配置以仅在 server1 和 AFTER playbook1 上执行?

鉴于您的示例 Vagrantfile 和理论上的 playbook2.ymlserver1playbook1.yml 之后仅在 server2 上执行,我们将得出以下解决方案:

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

还值得注意的是,如果你想精确排序,你可以vagrant up server1然后vagrant up server2而不是一体vagrant up

基本上,Vagrant.configure 内有一个范围影响 config.vm 内的所有虚拟机。您可以像上面那样通过 config.vm.define 实例化来将其范围限制在特定的 VM 中。使用 config.vm.define 实例化的对象 VM 与基础 config.

具有相同的 members/attributes

请注意,如果需要,您也可以这样做:

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

针对每个服务器的特定剧本。这取决于您的 // 中的确切内容(具体到每个 VM),以及您是否想要第三个 VM 的第三个剧本。

下面的示例将首先在每个服务器上执行 playbook1.yml,然后仅在服务器 1 上执行 playbook2.yml(此示例假设 playbook1.yml 可以并行化):

# -*- 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

此示例建立在 Tips and Tricks 中提供的示例之上,ansible-playbook 是并行化的并且两个 ansible-playbooks 的范围都受限于 ansible.limit 配置选项(例如 vagrant up 将首先启动虚拟机,然后对所有主机或主机子集一个接一个地执行剧本)。

注意ubuntu/bionic64 (virtualbox, 20190131.0.0) 框已安装 /usr/bin/python3,为了复制和粘贴示例以及使用动态清单,我故意在示例中保留了 server.vm.provision :shell, inline: "sudo apt install -y python",因此 ansible-playbook (2.7.6) 不会因 "/bin/sh: 1: /usr/bin/python: not found\r\n 错误而爆炸(参考 How do I handle python not having a Python interpreter at /usr/bin/python on a remote machine?)。示例 playbook1.ymlplaybook2.yml(与 Vagrantfile 在同一目录中):

---

- hosts: all
  tasks:
  - debug: 
      msg: 'executing on {{ inventory_hostname }}'

结果: