copy
Ansible
高速化
遅い
syncronize

ansible copyモジュールが遅い問題

概要

これまで手運用でscpで実行していた処理を、Ansible化するに伴いcopyモジュールでの実行に変更したところ、やたら遅い。時間的にいえば5倍弱くらいかかる。(10GBくらいのデータと28GBくらいのデータをアップロードする必要があるのだが、それぞれ15分、45分もかかる)。ネットにもansible copy very slowなどという記事が結構ある。

大抵の記事ではsynchronizeモジュールを代替として使えという提案になっている。
実際に置き換えてどう変わるのか実験する。

syncronizeモジュールのリファレンス訳

synchronizeはplaybookで一般的なタスクをすばやく簡単に実行するためのrsyncのラッパーである。実行すると、管理サーバ上で実行される。もちろん、commandモジュールを利用して自身でrsyncコマンドを呼び出すことも可能だが、公平な数の定型オプションとホストファクトも追加する必要があります。同期化はrsyncのフルパワーへのアクセスを提供することを意図していませんが、最も一般的な呼び出しをより簡単に実装します。あなたのユースケースに応じて、コマンドやシェルを使って直接rsyncを呼び出す必要があるかもしれません。

パラメータ

パラメータ 選択肢 コメント
archive yes/no (デフォルト:yes) rsync archiveフラグ。再帰フラグ、リンクフラグ、パーミッションフラグ、時間フラグ、オーナーフラグ、グループフラグ、-Dフラグを有効にする
checksum yes/no (デフォルト:no) mod-timeとサイズではなくchecksumに基づいてスキップする。
compress yes/no (デフォルト:yes) 転送中にファイルデータを圧縮する。問題が発生しない限りこのオプションを有効にしておいてください。
copy_links yes/no (デフォルト:no) シンボリックリンクが指す本体がコピーされるときにシンボリックリンクをコピーする
delete yes/no (デフォルト:no) 転送後にsrcに存在しない場合dest内のファイルを削除する。このオプションはrecursive=yesである必要がある
dest(必須) yes/no (デフォルト:no) 同期元ホストから同期される管理対象ホスト上のパス。絶対パスでも相対パスでもOK。
dest_port よくわからん 管理対象ホストのSSHのポート番号。Ansible2.0以前ではこの値よりansible_ssh_portインベントリ変数が優先された
dirs yes/no (デフォルト:no) 再帰なしでディレクトリを転送する
existing_only yes/no (デフォルト:no) 同期先に存在するファイルのみ同期
group yes/no (デフォルト:no) グループを同期する
link_dest(ver2.5から) 翻訳できず
links yes/no (デフォルト:archiveパラメータと同じ) シンボリックリンクとしてシンボリックリンクをコピーする
mode pull/push(デフォルトpush) 同期の方向を指定pushではローカルホストorデリゲートがsrc側、pullではリモートホストがsrc側
owner yes/no(デフォルト:archiveパラメータと同じ) オーナーを同期する(スーパーユーザー時のみ)
partial yes/no (デフォルト:no)
rsyncに、残りのファイルの後続の転送をはるかに高速化する部分ファイルを保持するように指示します。
perms yes/no(デフォルト:archiveパラメータと同じ) パーミッションを同期する
private_key SSHベースのrsync接続に使用する秘密鍵を指定する
recursive yes/no(デフォルト:archiveパラメータと同じ) ディレクトリ内を再帰的に同期する
rsyc_opts 配列で特別な追加オプションを渡す
rsync_path リモートホストで実行するrsyncコマンドを指定する。rsync man pageの--rsync-pathを参照
rsync_timeout デフォルト:0 rsyncコマンドの--timeoutを秒で指定する
set_remote_user デフォルト:yes リモートのパスのためのuser@を指定する。インベントリユーザと一致しないホストのリモートユーザを定義するカスタムssh設定がある場合は、このパラメータをnoに設定する必要があります。
src(必須) 同期先に同期される同期元ホスト上のパス。絶対パスでも相対パスでもOK。
times yes/no(デフォルト:archiveパラメータと同じ) タイムスタンプを同期する
use_ssh_args(ver2.0より) yes/no(デフォルト:no) ansible.cfgでのssh_argsの値を使う
verify_host yes/no(デフォルト:no) 同期先ホストの鍵を検証する

注意

  • rsyncが管理サーバ、管理対象サーバともにインストールされていなければならない
  • synchronizeモジュールにとって、"local host"は同期元、"destination host"は同期先のホスト。
  • "local host"はdelegate_toパラメータによって異なるホストに書き換えることができる。これにより一台のリモートマシンで2台のリモートホスト間のコピーができる。
  • syncronizeのモジュールのsrcパラメータに対するユーザーとパーミッションはlocal hostでAnsibleタスクを実行するユーザーのものである。(またはdelegete_toを使うならばdelegate_toホストのremote_userのもの)
  • syncronizeのモジュールのdestパラメータに対するユーザーとパーミッションは、become=yesとなっているならば、同期先のremote_userまたはbecome_userのものである。
  • 現在、synchronizeモジュールはパスワードなしのsudoでの権限昇格に限定されている。これはrsync自身がリモートマシンに接続していて、rsyncにsudoの認証情報を渡す方法を提供されていないためです。
  • 現時点では、同期方式(ssh、paramiko、local、およびdocker)は、これらの接続タイプに対して決定されているため、同期をサポートする接続タイプはごくわずかです。 rsync自体が接続を行い、rsyncがパスワードを接続に渡す方法を提供しないため、これらの接続にはパスワードが必要ではないことに注意してください。
  • dest=~/x~<remote_user>/xというパスになる。たとえsudoを使っているとしても。
  • 冗長な出力で user/host/パスが予想されるものであることを検証しろ。 など

置き換え実験

rsyncコマンドがインストールされていないと使えないと公式に書いてあるので、インストールされていることが前提。

元々のcopyモジュール部分

- name: copyモジュールでのデータアップロード
  copy:
    src: <管理サーバ上のアップロード対象ファイルのパス>
    dest: <管理対象サーバ上のアップロード先のパス>
  when: not ansible_check_mode

置き換えその1

- name: synchronizeモジュールでのデータアップロード
  synchronize:
    src: <管理サーバ上のアップロード対象ファイルのパス>
    dest: <管理対象サーバ上のアップロード先のパス>
  when: not ansible_check_mode

→エラーメッセージ

failed": true, "msg": "sudo: sudo を実行するには tty がなければいけません。すみません\nrsync: connection unexpectedly closed (0 bytes received so far) [sender]\nrsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]\n", "rc": 12}

管理対象サーバの/etc/suodersの「Defaults requiretty」をコメントアウトしておかないとだめだそう。
コメントアウトするとうまくいったけど、すっごくおそかった。copyモジュールで15分かかるデータファイルでsyncronizeモジュールで14分。誤差レベル。
これはきっとデフォルトで圧縮を噛ませているからでは?ということで、再度実験。

置き換えその2

- name: synchronizeモジュールでのデータアップロード
  synchronize:
    src: <管理サーバ上のアップロード対象ファイルのパス>
    dest: <管理対象サーバ上のアップロード先のパス>
    compress: no
  when: not ansible_check_mode

爆速!3分で終わった。圧縮しないほうが良さそう。でも/etc/sudoersの「Defaults requiretty」をコメントアウトがだるい・・・インフラ担当に必要性を説明して作業依頼出してとか・・・めんどくせぇ