在 Ansible 中以分离模式运行远程脚本/应用程序

Sad*_*nny 12 script bash ansible

我无法从 Ansible 剧本“分离地”运行远程应用程序启动脚本。脚本将运行,但我无法让它获得/保持分离。我可能做错了什么,但什么?

这是我的复制器。

  1. 我在 Test.java 中的远程 Java 应用程序运行了 10 秒:

    class Test {
        public static void main(String[] args) {
            for (int I = 1; I <= 10; i++) {
                System.out.println("Hello world " + I);
    
                try { Thread.sleep(1000);
                } catch (Exception e) { System.out.println("Exception caught: " + e);
                }
    } } }
    
    Run Code Online (Sandbox Code Playgroud)

将其编译为 Test.class (javac Test.java),然后使用“java Test”运行该类按预期工作(给出 10 条输出消息,然后退出)。

  1. 我运行此应用程序的可执行 shell 脚本(如在 chmod 755 中)如下所示:

    #!/bin/bash
    java Test &
    
    Run Code Online (Sandbox Code Playgroud)

手动运行它也完全没问题:Java 应用程序在我的控制台中运行并生成相同的标准输出,但 shell 脚本已经退出,我重新控制了我的 bash 会话。

  1. 现在通过来自另一台服务器的 ansible playbook 运行它。我尝试以不同的方式使用“command”模块和“shell”模块,但无济于事......

    ---
    - hosts: vagrant1
      gather_facts: false
    
      tasks:
      - debug: msg="Running test app through Ansible shell module..."
    
      - name: Start application
        shell: "/tmp/test.sh"
        args:
          chdir: "/tmp"
          executable: "/bin/bash"
    
      - debug: msg="Running test app through Ansible command module..."
    
      - name: Start application
        command: "nohup /tmp/test.sh &"
        args:
          chdir: "/tmp"
    
    Run Code Online (Sandbox Code Playgroud)

所有这些都运行得很好,即 shell 脚本运行,Java 应用程序运行并执行其操作(即运行 10 秒,生成输出并退出)。但是 ansible-playbook 会一直运行,直到 Java 应用程序完成,然后返回 Java 应用程序生成的输出。为什么它不只是分离 shell 脚本并完成剧本?

ansible-playbook 输出是:

    monsterkill@monsterkill-ub-dt:~/playbooks$ ansible-playbook testrun.yaml -v

    PLAY [vagrant1] *************************************************************** 

    TASK: [debug msg="Running test app through Ansible shell module..."] ********** 
    ok: [vagrant1] => {
        "msg": "Running test app through Ansible shell module..."
    }

    TASK: [Start application] ***************************************************** 
    changed: [vagrant1] => {"changed": true, "cmd": " /tmp/test.sh ", "delta": "0:00:10.052927", "end": "2015-01-29 00:14:43.327418", "rc": 0, "start": "2015-01-29 00:14:33.274491", "stderr": "", "stdout": "Hello world 1\nHello world 2\nHello world 3\nHello world 4\nHello world 5\nHello world 6\nHello world 7\nHello world 8\nHello world 9\nHello world 10"}

    TASK: [debug msg="Running test app through Ansible command module..."] ******** 
    ok: [vagrant1] => {
        "msg": "Running test app through Ansible command module..."
    }

    TASK: [Start application] ***************************************************** 
    changed: [vagrant1] => {"changed": true, "cmd": ["nohup", "/tmp/test.sh", "&"], "delta": "0:00:10.045643", "end": "2015-01-29 00:14:53.557164", "rc": 0, "start": "2015-01-29 00:14:43.511521", "stderr": "nohup: ignoring input", "stdout": "Hello world 1\nHello world 2\nHello world 3\nHello world 4\nHello world 5\nHello world 6\nHello world 7\nHello world 8\nHello world 9\nHello world 10"}

    PLAY RECAP ******************************************************************** 
    vagrant1                   : ok=4    changed=2    unreachable=0    failed=0
Run Code Online (Sandbox Code Playgroud)

use*_*062 19

只需使用一个异步操作poll: 0

- command: yourscript.sh
  async: 45
  poll: 0
Run Code Online (Sandbox Code Playgroud)

需要这些选项来防止ansible使用os.killpg杀死该任务的子进程。

然后在 yourscript.sh 中:

java Test &
disown
Run Code Online (Sandbox Code Playgroud)

disown 从作业表中删除进程,因此 SIGHUP 不会发送给它。nohup 做同样的事情,但不是必需的。

编辑:请注意,并非所有外壳都提供 disown(例如破折号)


Sad*_*nny 7

谷歌服务器现在肯定在冒烟,但我找到了一个解决方案。当我意识到 Ansible 通过单独的 ssh 调用执行其所有远程命令时,我通过从 ansible 服务器手动执行此操作进行了测试,发现它与 ssh 功能有关。

显然,答案是让我调用的脚本执行双重背景技巧,结合 nohup 使其忽略挂断信号 (SIGHUP) 并结合断开 stdout 和 stderr 流。因此,远程启动脚本不再执行:

java Test &
Run Code Online (Sandbox Code Playgroud)

...但现在这样做:

( ( nohup java Test 1>/dev/null 2>&1 ) & )
Run Code Online (Sandbox Code Playgroud)

这做我想要的。ansible-playbook 现在启动远程脚本,该脚本反过来启动 java 应用程序,然后双重背景和 nohups 并断开输出流。

这个stackoverflow线程帮助了我。


Mil*_*eek 7

使用 start-stop-daemon 将脚本作为守护程序运行在这里似乎是一个更优雅的解决方案。http://manpages.ubuntu.com/manpages/raring/man8/start-stop-daemon.8.html

- name: Start application
  shell: "start-stop-daemon --start --quiet --pidfile /var/run/test --exec /tmp/test.sh"
  args:
    executable: "/bin/bash"
Run Code Online (Sandbox Code Playgroud)

  • 请在答案中提供所有相关信息。外部链接非常适合参考和进一步阅读,但它们不应成为您答案的全部内容。 (2认同)