4

目前我正在从 puppet 切换到Ansible,我对一些概念或至少 ansible 的工作方式有点困惑。

有关设置的一些信息:

我正在使用Ansible Best Practices中的示例,并使用多个角色(剧本)等来构建我的项目。

我正在使用 Vagrant 进行配置,盒子是 Saucy64 VBox。

混乱来自哪里:

当我配置并运行 ansible 时,任务开始执行,然后是通知堆栈。

例子:

最后一个任务:

TASK: [mysql | delete anonymous MySQL server user for localhost] ************** 
<127.0.0.1> REMOTE_MODULE mysql_user user='' state=absent 
changed: [default] => {"changed": true, "item": "", "user": ""}

然后是第一个通知:

NOTIFIED: [timezone | update tzdata] ****************************************** 
<127.0.0.1> REMOTE_MODULE command /usr/sbin/dpkg-reconfigure --frontend noninteractive tzdata
changed: [default] => {"changed": true, "cmd": ["/usr/sbin/dpkg-reconfigure", "--frontend", "noninteractive", "tzdata"], "delta": "0:00:00.224081", "end": "2014-02-03 22:34:48.508961", "item": "", "rc": 0, "start": "2014-02-03 22:34:48.284880", "stderr": "\nCurrent default time zone: 'Europe/Amsterdam'\nLocal time is now:      Mon Feb  3 22:34:48 CET 2014.\nUniversal Time is now:  Mon Feb  3 21:34:48 UTC 2014.", "stdout": ""}

现在这一切都很好。随着角色的增加,越来越多的通知出现了。

现在问题来了。

当通知失败时,配置将照常停止。但是通知堆栈是空的!这意味着在错误通知之后的所有通知都不会被执行!

如果是这样,那么如果您更改了 apache 的 vhosts 设置并通知 apache 服务重新加载,那么这将丢失。

举个例子(伪语言):

- name: Install Apache Modules
  notify: Restart Apache

- name: Enable Vhosts
  notify: Reload Apache

- name: Install PHP
  command: GGGGGG # throws an error

当上面执行时:

  1. Apache 模块已安装
  2. 虚拟主机启用
  3. PHP 尝试安装但失败
  4. 脚本退出
  5. (通知在哪里?)

现在在这一点上一切似乎都是合乎逻辑的,但 Ansible 再次尝试聪明(不!*)堆栈通知,因此重新加载和重新启动 apache 将导致在配置结束时重新启动 apache 运行。这意味着所有通知都将失败!!!

现在到这里对于某些人来说这也很好。他们会说,嘿,只需重新运行配置,通知就会启动,因此 apache 最终将重新加载,站点将再次启动。不是这种情况。

在更正安装 php 的代码后第二次运行脚本时,由于设计原因,通知将不会运行。为什么?

这就是原因:Ansible 会将成功执行的任务标记为“完成/绿色”,因此不会为这些任务注册任何通知。配置将成功,为了触发通知并因此重新启动 apache,您可以执行以下操作之一:

  1. 通过 ansible 或 ssh 向服务器运行直接命令
  2. 编辑脚本以触发任务
  3. 为此添加一个单独的任务
  4. 销毁盒子实例并重新配置

这非常令人沮丧,因为需要彻底清理盒子,或者我对 Ansible 的理解不正确?

是否有另一种“回收”/重播/强制执行通知的方法?

  • 聪明的做法是要么将任务标记为未完成,然后重新启动通知,要么将通知保留一个单独的队列作为它们自己的任务。*
4

2 回答 2

3

是的,这是 Ansible 与 Puppet 相比的缺点之一。Puppet 是声明性的,不会像 Ansible(或 Chef)那样出错。它有其优点和缺点,例如 Puppet 在开始运行之前需要一点时间,因为它需要编译它的目录。

因此,如果您的 Ansible 脚本出错,那么您的通知更新将不会发生,您是对的。我们解决它的唯一方法是使用条件语句。在您的剧本中,您可以执行以下操作:

- name: My cool playbook
  hosts: all

  vars:
      force_tasks: 0

  tasks:
    - name: Apache install
      action: apt pkg=$item state=latest
      with_items:
       - apache2
       - apache2-mpm-prefork

    - name: Restart apache
      action: service name=apache2 state=restart
      when: force_tasks

然后,当您运行剧本时,您可以将 force_tasks 作为环境变量传递:

ansible-playbook -i my_inventory -e "force_tasks=True" my_ansible_playbook.yml

您可以使用标签以类似的方式完成此操作。

于 2014-02-07T22:42:53.210 回答
0

使用 --force-handlers 标志运行 ansible-playbook。这告诉 Ansible 运行任何排队的处理程序,即使任务失败并且进一步处理停止。Ansible 开发人员计划将此作为选项添加到 ansible.cfg 文件中,以便可以全局设置并忘记它。我不知道那是什么时间框架。

于 2015-03-06T00:24:25.893 回答