我在从 Ansible playbook 中“分离”运行远程应用程序启动脚本时遇到了麻烦。脚本可以运行,但我无法让它分离/保持分离状态。我可能做错了什么,但是什么呢?
这是我的复制器。
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); } } } }
将其编译为 Test.class(javac Test.java),然后使用“java Test”运行该类即可按预期工作(给出 10 条输出消息然后退出)。
运行此应用程序的可执行 shell 脚本(如 chmod 755)如下所示:
#!/bin/bash java Test &
手动运行它也完全没问题:Java 应用程序运行并在我的控制台中生成相同的标准输出,但是 shell 脚本已退出并且我重新控制我的 bash 会话。
现在通过另一台服务器的 ansible playbook 运行它。我尝试以不同的方式使用“命令”模块和“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"
所有这些都运行良好,即 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
答案1
答案2
谷歌服务器现在肯定出问题了,不过我找到了解决办法。当我意识到 Ansible 通过单独的 ssh 调用执行所有远程命令时,我通过从 ansible 服务器手动执行该操作进行了测试,发现这与 ssh 功能有关。
答案显然是,使用我调用的脚本来执行双背景技巧,结合 nohup 使其忽略挂断信号 (SIGHUP),并断开 stdout 和 stderr 流。因此,远程启动脚本不再执行以下操作:
java Test &
...但现在却:
( ( nohup java Test 1>/dev/null 2>&1 ) & )
这正是我想要的。 ansible-playbook 现在启动远程脚本,进而启动 java 应用程序,但随后将其双重背景化并 nohups 并断开输出流。
这个 stackoverflow 帖子帮助过我。
答案3
使用 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"