7

У меня проблемы с запуском сценария запуска удаленного приложения "отдельно" от Ansible playbook. Скрипт запустится, но я не могу заставить его остаться / отстраненным. Я, наверное, что-то делаю не так, но что?

Вот мой репродуктор.

  1. Мое удаленное Java-приложение в Test.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 выходных сообщений и затем завершается).

  1. Мой исполняемый скрипт оболочки (как в chmod 755), выполняющий это приложение, выглядит следующим образом:

    #!/bin/bash
    java Test &
    

Выполнение этого вручную также прекрасно: приложение Java запускается и генерирует тот же стандартный вывод в моей консоли, но сценарий оболочки завершился, и я снова стал контролировать мой сеанс bash.

  1. Теперь, чтобы запустить его через ANSIBLE playbook с другого сервера. Я пытался использовать модуль "команда" и модуль "оболочка" по-разному, но безрезультатно ...

    ---
    - 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"
    

Все это работает просто отлично, то есть запускается сценарий оболочки, приложение Java запускается и делает свое дело (т.е. запускается в течение 10 секунд, генерирует выходные данные и завершает работу). Но ansible-playbook работает до тех пор, пока приложение Java не завершит работу, а затем возвращает выходные данные, сгенерированные приложением Java. Почему бы просто не отсоединить скрипт оболочки и закончить playbook?

Вывод 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

3 ответа3

15

Просто используйте асинхронное действие с poll: 0:

- command: yourscript.sh
  async: 45
  poll: 0

Эти параметры необходимы, чтобы не допустить уничтожения дочерним процессом дочерних процессов этой задачи с помощью os.killpg.

Тогда в yourscript.sh:

java Test &
disown

disown удаляет процесс из таблицы заданий, поэтому SIGHUP не отправляется на него. nohup делает то же самое, но не обязательно.

Изменить: Обратите внимание, что отречение доступно не во всех оболочках (например, тире)

5

Серверы Google сейчас должны курить, но я нашел решение. Когда я понял, что Ansible выполняет все свои удаленные команды через отдельные вызовы ssh, я проверил это вручную с сервера ansible и обнаружил, что это связано с функциональностью ssh.

Ответ, по-видимому, заключается в том, чтобы иметь скрипт, который я вызвал, чтобы выполнить двойной фоновый трюк, в сочетании с nohup, чтобы он игнорировал сигналы зависания (SIGHUP), и в сочетании с отключением потоков stdout и stderr. Итак, скрипт удаленного запуска больше не делает:

java Test &

... но вместо этого сейчас:

( ( nohup java Test 1>/dev/null 2>&1 ) & )

который делает то, что я хочу. В ansible-playbook теперь запускается удаленный скрипт, который, в свою очередь, запускает java-приложение, но затем выполняет двойной фоновый режим и отключает его, а также отключает выходные потоки.

Эта ветка stackoverflow помогла мне.

5

Запуск вашего скрипта в качестве демона с помощью 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"

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .