SSHのMultiplexingによって発生するAnsibleの問題

OpenSSHの問題なのかAnsibleの問題なのか、あるいは自分の書いているPlaybookの問題なのか、原因は不明だがSSHのMultiplexingが有効になっているとshellモジュールの標準出力が取得できない場合があるという問題にあたった。

検証version

  • CentOS 7.5
  • OpenSSH 7.4
  • Ansible 2.7

Ansibleの使用するSSHオプション

Ansibleが使用しているSSHのオプションを確認する。

$ ansible all -i localhost, -m ping -vvv
略
<localhost> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s 略
略

-o ControlMaster=auto -o ControlPersist=60sのオプションによって60秒間Multiplexingのマスター接続が維持される。

つまり、AnsibleはデフォルトでSSHのMultiplexingを使っている。今回遭遇した問題はどこでも起こる可能性がある。

Playbookの概要

問題が発生したroleの内容は以下の通り。

略

- name: exec aws ec2 describe-instances
  delegate_to: localhost
  check_mode: no
  shell: |
    aws ec2 describe-instances --filters "Name=tag:Name,Values={{ inventory_hostname }}" "Name=instance-state-name, Values=running" --query "Reservations[0].Instances[0].PrivateIpAddress" |
      sed 's/"//g'
  environment: "{{ aws.environment }}"
  register: host_ip

略

このroleのどこかのタイミングでSSHのMultiplexingが使われることが、ps -ef | grep sshでわかった。[mux]という文字列が見つかる。

$ ps -ef | grep ssh
略
ssh: /home/user/.ansible/cp/ansible-ssh-localhost-22-user [mux]
略

Multiplexing中に標準出力が取得できない

ControlPersistで指定されている時間内にもう一度Ansibleを実行すると、先に記載したaws ec2 describe-instancesの標準出力が取得できないことがあった。取得できない確率は10台くらいのサーバに実行して1, 2台ほど。

ControlPersistで指定されている時間を過ぎてから、あるいはMultiplexingで接続されているSSHプロセスをkillしてからAnsibleを実行すると、この問題は発生しない。

Ansibleのパフォーマンスを上げるために-o ControlPersist=1800sを設定したところ、Multiplexingが維持される時間が長くなり、この問題の発生確率が格段に上がって発見することができた。

$ tail -3 ansible.cfg
[ssh_connection]
pipeline=True
ssh_args=-C -o ControlMaster=auto -o ControlPersist=1800s

この設定はDocumentに書かれている通りの内容である。

In particular, users may wish to raise the ControlPersist time to encourage performance. A value of 30 minutes may be appropriate.

Multiplexingを無効にする

Ansibleは60秒間という短い時間ではあるもののデフォルトでMultiplexingを使っており、上記問題が発生しうる。根本原因がわからなかったので、安全のためMultiplexingは無効化した。

$ tail -3 ansible.cfg
[ssh_connection]
pipeline=True
ssh_args=-o ControlMaster=no

※ついでに-Cオプションも消したが、これは今回の問題には関係ない。Playbook内で大きなデータをリモートサーバに送信しないため、圧縮オプションが有効になっていてもCPUを食うだけで性能向上に期待できないから消しただけだ。