問題
以下の状況でデータを外部コピーしたいが、どのような方法が考えられるか?
- ある EC2 インスタンスにマウントされた EFS 上のファイルをコピーしたい
- 今回のケースでは、ファイルの合計サイズは30GB, ファイル総数は100万ファイルとする
- EC2 インスタンスの空きボリュームは EFS のファイル合計サイズよりも十分小さい
- 今回のケースでは空き容量が 5GB とする
- サーバーに ssh ログインしてリソースにアクセスはできるが、この AWS アカウントのリソースを編集する権限はない
- そのため、EBS の拡張や EFS のバックアップのコピーなどは使えない
- 別の AWS アカウントの権限はあるので、そのアカウント内にデータのコピー・中継を行ってもよい
- できる限り AWS 料金を安く抑えたい
解決方法
方針
- 今回は EC2 (現AWSアカウント) -> 別 AWS アカウントの S3 バケットへのコピーで解決する
- 別の AWS アカウントの IAM を発行して、
profileでアクセス可能に事前に設定する - この時、ファイルを
aws s3 syncでコピーすると、都度 PutObject を送るため、かなり時間がかかりつつ、更にS3の料金もかかってくるのでできれば別の方法を取りたい(0.0055 USD/1000 req) - 可能ならば VPC に S3 エンドポイントをアタッチしているとデータ転送速度・コストの面でより有利
実行
tar コマンドの実行結果を標準入力に流し、これを split コマンドで特定ファイルサイズに分割しつつ、最後に aws s3 cp で S3 バケットまでコピーする。
# コピー先に移動して実行。 -C オプションを使ってもOK
tar cvf - . \
| split -b 500M -d -a 4 \
--filter='aws s3 cp - s3://<BUCKET>/part-$FILE.tar --profile <your-profile>' - ""
split のオプション補足
-
--filter='': 分割ファイルごとに実行するコマンド。 ここで $FILE として分割ファイル名を受け取る。 今回はオプション組み合わせで 0000, 0001, .... が順に入る -
-: 入力元を標準入力にする(tar からのパイプを受け取る) -
"": ファイル名の先頭文字列を空文字にする。通常 split は xaa, xab のように x がプレフィックスになるが、ここでは $FILE にサフィックス(0000, 0001...)だけが入るようにしている
まとめ
このようにすることで、ファイルを1つにまとめつつ、それを適切(今回は 500MB ごと)に分割してそれを S3 ファイルにアップロードできる。 こうすると、PUT の回数が一気に減るためコスト面でも有利である。
また、今回 tar の z オプションを付けていないが、これは転送ファイルがほとんど画像・音声ファイルであり、圧縮の効果が低いと判断したため、圧縮せずにファイル結合の高速化を優先した結果である。