ossh:多くのサーバーでのコマンドの並列実行

多くのサーバーでBarminのpatchsomeコマンド を実行する必要がある場合があり、実行 結果をあまり長く待たないことをお勧めします。このために、私は ossh(それらすべてを支配する1つのSSH)を作成しました。これがどのように機能するかの例です:



$ wc -l /tmp/ossh.ips
21418 /tmp/ossh.ips
$ time ossh -n -h /tmp/ossh.ips -c uptime -p 1000 >/tmp/ossh.out

real    3m10.310s
user    0m30.970s
sys     0m19.282s
$ grep 'load average' /tmp/ossh.out | sort -n -k5 | tail -n1
10.23.91.97   [1]  13:37:55 up 828 days,  2:34,  0 users,  load average: 8.29, 4.45, 3.90
$

      
      





この例では、ファイル/tmp/ossh.ipsにマシンの21418IPアドレスが含まれています。 -nは、アドレスで名前を判別するために逆クエリを実行する必要がないことを意味します。 -c uptimeは、実行するコマンドを設定します。 -p 1000は、同時に最大1000の接続を許可します。出力からわかるように、コマンドはかなり迅速に機能しました。



osshは他に何ができますか?



$ ossh -?
Usage: ossh [-?AinPv] [-c COMMAND] [-C COMMAND_FILE] [-H HOST_STRING] [-h HOST_FILE] [-I FILTER] [-k PRIVATE_KEY] [-l USER] [-o PORT] [-p PARALLELISM] [-T TIMEOUT] [-t TIMEOUT] [parameters ...]
 -?, --help        Show help
 -A, --askpass     Prompt for a password for ssh connects
 -c, --command=COMMAND
                   Command to run
 -C, --command-file=COMMAND_FILE
                   file with commands to run
 -H, --host=HOST_STRING
                   Add the given HOST_STRING to the list of hosts
 -h, --hosts=HOST_FILE
                   Read hosts from file
 -i, --ignore-failures
                   Ignore connection failures in the preconnect mode
 -I, --inventory=FILTER
                   Use FILTER expression to select hosts from inventory
 -k, --key=PRIVATE_KEY
                   Use this private key
 -l, --user=USER   Username for connections [$LOGNAME]
 -n, --showip      In the output show ips instead of names
 -o, --port=PORT   Port to connect to [22]
 -p, --par=PARALLELISM
                   How many hosts to run simultaneously [512]
 -P, --preconnect  Connect to all hosts before running command
 -T, --connect-timeout=TIMEOUT
                   Connect timeout in seconds [60]
 -t, --timeout=TIMEOUT
                   Run timeout in seconds
 -v, --verbose     Verbose output
$

      
      





ホストのリストは、コマンドラインで-Hオプションを使用して直接指定できます(複数のホストの場合は、スペースで区切る必要があり、以下の例のようにリスト全体を引用符で囲む必要があります)。 -hオプションを使用してファイルからロードされます。ファイル内の#で始まる行は無視されます。アドレスには、ポートmy.host:2222を含めることができます。ブレース拡張を使用できます。「host {1,3..5} .com」は「host1.comhost3.comhost4.comhost5.com」になります。-Hと-hはどちらも複数回使用できます。



承認のために使用されます

  • -Aオプションを使用するときにosshが要求するパスワード
  • オプション-kで指定されたsshスイッチ
  • ssh-agent(この場合、SSH_AUTH_SOCK環境変数を定義する必要があります)


その順番で。



コマンドを実行する前に、すべてのマシンにログインできることを確認する必要がある場合があります。これには-Pオプションがあります。デフォルトでは、少なくとも1台のマシンが使用できない場合、osshは失敗します。失敗した接続を無視する場合は、-iオプションを使用します。



Osshは在庫システムを使用できます。これを行うには、パスにossh-inventoryコマンドが含まれている必要があります。このコマンドには、-Iオプションのパラメーターが渡されます。このオプションは複数回使用できます。 ossh-inventoryコマンドは、次の形式で行を標準出力に出力する必要があります。

_ _
      
      





ここで、machine_addressは、DNS名またはIPアドレスのいずれかです。



実行するコマンドは、-C(ファイルから読み取る)または-c(コマンドラインから取得)オプションで指定します。これらのオプションは複数回使用できます。-Cと-cの両方が存在する場合、ファイルからのコマンドが最初に実行され、次にコマンドラインから実行されます。



osshを使用してコマンドを実行するだけでなく、ログをリアルタイムでストリーミングできます。



$ ossh -H "web05 web06" -c "tail -f -c 0 /var/log/nginx/access.log|grep --line-buffered Wget"
web05 192.168.1.23 - - [22/Jun/2016:12:24:02 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web05 192.168.1.49 - - [22/Jun/2016:12:24:07 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web06 192.168.1.117 - - [22/Jun/2016:12:24:23 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web05 192.168.1.29 - - [22/Jun/2016:12:24:30 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
...
      
      







これがローリングデプロイメントシミュレーションです。



$ ossh -p 1 -H "test0{1..3}" -c "sleep 10 && date"
test01 Wed Jun 22 12:38:24 PDT 2016
test02 Wed Jun 22 12:38:34 PDT 2016
test03 Wed Jun 22 12:38:44 PDT 2016
$
      
      







コマンドがマシン上で順番に実行されていることがわかります。一度に1台のマシンのみが関与します。実際のデプロイメントでは、「sleep 10 && date」を、たとえば「apt-get install-yyour_package」に置き換える必要があります。



osshの最初のバージョンが作成されたのはデプロイメント用でした。一般的に受け入れられている構成管理システムを使用しなかった理由を誰かが尋ねますか?実は2013年に戻ってシェフを使っていました。正確に変更が適用される時期が不確実であるため、シェフが特に私たちに適していないことは明らかでした(シェフ-クライアントは30分ごとに実行されました)。多くのマシンで一貫して変更をロールアウトするために、一部の開発者はダーティハックを使用しました。chef-clientは常に機能するわけではなく、デプロイメントを行う必要があるときにのみ(ssh経由で)一度起動されました。すでにその時点で、シェフを塩に置き換える作業が進行中でしたが、移行は容易ではなく、完了には追加の時間が必要でした。私たちは新しいサービスを開発していました、これは頻繁な展開を必要とし、唯一のDebianパッケージによって展開されました。まず、シェフのナイフユーティリティを使用しました。このユーティリティを使用すると、sshを介して目的のサーバーに接続し、それらのサーバーでコマンドを実行できます。ある時点で、この場合のchefは追加のリンクであることに気付き、osshを作成しました。



osshは、大規模で非標準的な問題を解決するためのツールであることに注意することが重要です。osshを使用する必要が頻繁に発生する場合、これがインフラストラクチャとサーバー管理がうまく機能しているかどうかを検討する理由です。osshが私を個人的に助けてくれたいくつかの状況は次のとおりです。

  • 一度、多数のサーバーで/root/.ssh/authorized_keysを整理しました(当時は約7000台でした)。開発者は、特にサービスを更新するプロセスのために、そこでキーを登録しました。すべてのマシンで使用されているすべてのキーのリストを取得し、それらのキーを削除しても壊滅的でないことを確認する必要がありました。
  • 痛みのないうるう秒
  • TCP SACK PANIC苦労していたとき、iptablesルールは構成管理システムによって展開されました。すべてが正常であることを確認するために、osshで正しいルールを確認しました。そして、それはまったく無駄では​​ありませんでした、規則が適用されなかった車がありました。
  • 時には、数百(場合によっては数千)のマシンでテスト環境を作成する必要があります。多くの場合、これらのマシンは実稼働ネットワークから分離されており、標準の構成管理システムでは使用できません。このような状況では、マシンの構成はosshを使用して行うことができます。


なぜ既製のソリューションを使用しなかったのかという疑問が予想されます。上で述べたように、何千ものマシンでコマンドを実行する必要性は、2013年に最初に私に起こりました。当時、私は並列sshしか見つけることができませんでしたが、次の点で私には合いませんでした。

  • 並列処理を150以上に上げることができず、リモートサーバーに接続するときにエラーが発生し始めました
  • parallel sshはすべての出力を累積し、コマンドの終了時にダンプしました。たとえば、ログのストリーミングはその助けを借りて不可能でした
  • 並列ssh出力は(私個人としては)解析するのが面倒でした


もともとosshはrubyで書かれていましたが、パフォーマンスを向上させるために、イベントマシンを使用し、次にファイバーを使用しました。私は最近osshを書き直しました。go-experts(私は現時点ではありません)が私のコードを見て、それを改善するための可能な方法を指摘してくれれば幸いです。



All Articles