Ansibleの高速化

d2c.ioの内部では、Ansibleを使用します。 これにより、クラウドプロバイダーで仮想マシンを作成し、ソフトウェアをインストールし、クライアントアプリケーションでDockerコンテナーを管理します。







Ansibleは、ほとんど、またはまったく調整することなく動作する便利なツールです。 これは、エージェント(エージェントレスシステム)がないため可能です。そのため、サービスを提供するホストに事前にインストールする必要はありません。







ほとんどの場合、 ssh



使用してホストに接続します。 ただし、すべてのロジックは管理サーバー上にあり、Ansibleは各タスクをローカルで形成し、SSH接続を介して実行するため、このコインの裏側には一定の遅さがあります。 その後、結果を取得して分析し、次のステップに進みます。 この記事では、Ansibleを高速化する方法について説明します。







測定から始めましょう



測定できないものを改善することは不可能であるため、実行時間を計算する小さなスクリプトを作成します。







最初に、テストプレイブックを作成します。







test.yml
 --- - hosts: all # gather_facts: no tasks: - name: Create directory file: path: /tmp/ansible_speed state: directory - name: Create file copy: content: SPEED dest: /tmp/ansible_speed/speed - name: Remove directory file: path: /tmp/ansible_speed state: absent
      
      





次に、実行時間を計算するスクリプトを作成します。







time_test.sh
 #!/bin/bash # calculate the mean average of wall clock time from multiple /usr/bin/time results. # credits to https://stackoverflow.com/a/8216082/2795592 cat /dev/null > time.log for i in `seq 1 10`; do echo "Iteration $i: $@" /usr/bin/time -p -a -o time.log $@ rm -rf /home/ubuntu/.ansible/cp/* done file=time.log cnt=0 if [ ${#file} -lt 1 ]; then echo "you must specify a file containing output of /usr/bin/time results" exit 1 elif [ ${#file} -gt 1 ]; then samples=(`grep --color=never real ${file} | awk '{print $2}' | cut -dm -f2 | cut -ds -f1`) for sample in `grep --color=never real ${file} | awk '{print $2}' | cut -dm -f2 | cut -ds -f1`; do cnt=$(echo ${cnt}+${sample} | bc -l) done # Calculate the 'Mean' average (sum / samples). mean_avg=$(echo ${cnt}/${#samples[@]} | bc -l) mean_avg=$(echo ${mean_avg} | cut -b1-6) printf "\tSamples:\t%s \n\tMean Avg:\t%s\n\n" ${#samples[@]} ${mean_avg} grep --color=never real ${file} fi
      
      





テストプレイブックを10回起動し、平均値を取得します。







SSH多重化



ローカルネットワークでは:7.68秒でしたが、2.38秒になりました

リモートホストでは:26.64秒でしたが、10.85秒になりました

最初に確認することは、SSH接続の再利用が機能するかどうかです。 AnsibleはSSHを介してすべてのアクションを実行するため、接続の確立に遅延があると、プレイブック全体が大幅に遅くなります。 デフォルトでは、この設定はAnsibleで有効になっています。 構成ファイルでは、次のようになります。







 [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s
      
      





ただし、何らかの理由でssh_args



パラメーターをオーバーライドする場合は、 ControlMaster



ssh_args



の値を明示的に指定する必要があることに注意してください。そうしないと、Ansibleはそれらを「忘れ」ます。







以下のように、SSH接続の再利用がケースで機能するかどうかを確認できます-vvvv



パラメーターでAnsibleを起動します。







 ansible test -vvvv -m ping
      
      





出力には、必要なパラメーターを指定したSSH起動が表示されます。







 SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s ... -o ControlPath=/home/ubuntu/.ansible/cp/7c223265ce
      
      





さらに、多くのデバッグ情報の中から:







 Trying existing master Control socket "/home/ubuntu/.ansible/cp/7c223265ce" does not exist setting up multiplex master socket
      
      





また、タスクの完了後60秒以内に、開いているソケットがファイル(この例では/home/ubuntu/.ansible/cp/7c223265ce



)として観察されることを確認できます。







注意: 1台の制御マシン(青/緑展開、ステージ/製品)から複数の同一の環境で作業している場合は、足元を撃たないようにしてください! たとえば、最初に販売から現在の設定をダウンロードし、次のステップで新しいバージョンのコンポーネントでテスト環境を更新し、SSHソケットを販売から開いたままにした場合は、これらの環境でControlPath



を変更するか、ウィザードを強制的に閉じる必要があります別の環境で作業を開始する前に、セッションを開始するか、ソケットを削除します。







パイプライン処理



ローカルネットワークでは:2.38秒でしたが、1.96秒になりました

リモートホスト:10.85秒でしたが、5.23秒になりました

デフォルトでは、Ansibleは次のようにターゲットホストでモジュールを実行します。









リスト全体が各タスクに対して実行されることを考慮すると、オーバーヘッドが大きくなります。 このプロセスを高速化するために、Ansibleにはパイプラインモードがあり、Linuxのコマンド間のI / Oパイプラインに似ています。 構成ファイルでは、モード設定は次のようになります。







 [ssh_connection] pipelining = true
      
      





パイプラインモードを使用する場合、Ansibleは次のように機能します。









合計:4つのSSH接続といくつかの追加コマンドがありましたが、現在は1つです。 特にWANのリモートサーバーの場合、スピードアップは明らかです。







パイプライン処理が機能しているどうかを確認するには、次のように、高度なロギングを使用してAnsibleを実行する必要があります。







 ansible test -vvv -m ping
      
      





出力に次の形式の複数のssh



呼び出しが含まれる場合:







 SSH: EXEC ssh ... SSH: EXEC ssh ... SSH: EXEC sftp ... SSH: EXEC ssh ... python ... ping.py
      
      





そのため、コンベアモードは機能していません。 ssh



呼び出しが1つの場合:







 SSH: EXEC ssh ... python && sleep 0
      
      





したがって、パイプラインは機能します。







重要:デフォルトでは、この設定はsudo



設定のrequiretty



要件と競合する可能性があるため、Ansibleで無効になっています。 この記事の執筆時点では、Amazon EC2のUbuntuとRHELの最新のイメージは切断するrequiretty



ため、パイプラインを安全に使用できます。







PreferredAuthenticationsおよびUseDNS



ローカルネットワークでは:1.96秒でしたが、1.92秒になりました

リモートホストでは:5.23秒でしたが、4.92秒になりました

多数のターゲットマシンを制御する場合、接続速度に影響を与える些細なことが重要です。 そのような些細なことの1つは、特にローカルDNSサーバーが使用されている場合、サーバーおよびクライアント側での逆DNSクエリです。







UseDNS



UseDNSはSSHサーバー設定(ファイル/ etc / ssh / sshd_config)であり、クライアントIPアドレスのPTRレコードを強制的にチェックします。 幸いなことに、最新のディストリビューションではデフォルトで無効になっています。 ただし、念のため、プライマリSSH接続が遅い場合は、ターゲットホストを確認する価値があります。







PreferredAuthentications



これは、クライアントが使用できる認証方法についてサーバーに通知するSSHクライアント設定です。 デフォルトでは、Ansibleは







 -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey
      
      





また、Amazon EC2のRHELイメージのように、 GSSAPIAuthentication



サーバーで有効になっている場合、このモードが最初にテストされます。 これにより、不必要な手順が発生し、クライアントからのPTRレコードを検証しようとします。







ほとんどの場合、キーによる認証のみが必要であるため、これをansible.cfg



明示的に示します。







 [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey
      
      





このセットアップにより、サーバーとの不必要なネゴシエーションからクライアントが保護され、マスターセッションのインストールが高速化されます。







ファクトコレクション



ローカルネットワークでは:1.96秒でしたが、1.47秒になりました

リモートホスト:4.92秒でしたが、4.77秒になりました

プレイブックを再生するとき(アドホックコマンドは適用されません)、Ansibleはデフォルトでリモートシステムに関する情報を収集します。 この手順は、 setup



モジュールの起動に似ており、同様に別のSSH接続が必要です。 テストプレイブックでは、単一のファクトを使用しないため、playbookパラメーターを指定してこの手順をスキップできます。







 gather_facts: no
      
      





ファクトを使用してプレイブックを頻繁に開始するが、ファクトの収集がプレイブックの速度に大きく影響する場合は、外部ファクトキャッシングシステムの使用を検討してください(これについては、Ansibleのドキュメントで部分的に説明されています )。 たとえば、Redisをセットアップします。Redisは1時間に1回、新しいファクトで満たされ、すべての作業中のプレイブックでは、ファクトの強制収集をオフにします。 これらは、ローカルキャッシュから取得されます。







WAN→LAN



4.77秒でしたが、1.47秒になりました

高速通信チャネルにもかかわらず、ローカルネットワークでは、通常、すべてがグローバルネットワークよりも高速に動作します。 そのため、eu-west-1リージョンのAmazon EC2など、さまざまなサーバーでプレイブックを頻繁に実行する場合、メイン管理サーバーは同じプラットフォームに配置する必要があります。 使用シナリオによっては、管理サーバーをターゲットサーバーの近くに移動すると、プレイブックの実行を大幅に高速化できます。







プルモード



1.47秒でしたが、1.25秒になりました

さらに速度が必要な場合は、ターゲットサーバーでローカルにプレイブックを作成できます。 これにはansible-pull



ユーティリティがあります。 また、 公式のAnsibleドキュメントでそれについて読むこともできます 。 次のように機能します。









ユースケースの1つは、何かが変更された場合にリポジトリとプレイブックのポーリングをスケジュールすることです( --only-if-changed



パラメーター)。







フォーク



前のセクションでは、各ホストのプレイブックを個別に高速化することについて説明しました。 しかし、一度に数十台のサーバーのプレイブックを起動すると、「フォーク」の数(異なるサーバーでタスクを実行するための別個の並列プロセス)がボトルネックになることがあります。 構成ファイルでは、この設定は次のとおりです。







 [defaults] forks = 20
      
      





デフォルトのフォーク値は5です。これは、Ansibleが一度に最大5つのホストと通信することを意味します。 多くの場合、管理サーバーのCPUと通信チャネルの機能により、より多くのホストに同時にサービスを提供できます。 最適な量は、特定の環境で実験的に選択されます。







同時実行性に関するもう1つのポイントは、スレッドの数が少なく、サーバーが多い場合、sshマスターセッションが「悪くなる」可能性があり、本格的なSSHセッションを再インストールする必要が生じることです。 これは、デフォルトでは、Ansibleがlinear



実行戦略を使用するためです。 すべてのサーバーで1つのタスクが完了するまで待機してから、次のタスクに進みます。 「最初の」サーバーがタスクを迅速に完了し、 ControlPersist



時間が経過するまで他のすべてのサーバーでタスクが実行されるまで待機する場合があります。







ポーリング間隔



ターゲットサーバーでモジュールを起動すると、制御マシンのAnsibleプロセスは、モジュールの実行結果のポーリングモードに入ります。 これをどれほど積極的に行うかは、制御マシンのCPU負荷に影響します。 また、並列プロセスの数を増やすにはプロセッサ時間が必要です(前のセクションを参照)。 このような内部ポーリング間のタイムアウト設定は、設定ファイルに秒単位で示されます。







 [defaults] internal_poll_interval = 0.001
      
      





多数のホストで「長時間プレイ」タスクを実行する必要がある場合、その結果はそれほど頻繁にチェックする意味がないか、制御マシンに多くの空きCPUがない場合は、たとえば0.05



などのポーリングを実行できます。







-







PS:ハイライトのうち、おそらくそれがすべてです。 プレイブック自体の最適化では、すでにさらなる速度を追求する必要がありますが、これはまったく別の話です。








All Articles