AWS CLI を使ってファイル単位で S3 に同期するには

AWS CLI の s3 サービスで提供されている sync コマンドを使えば、ローカルにある myfolder ディレクトリを S3 上の myfolder ディレクトリに簡単に同期できる。

$ aws s3 sync myfolder s3://mybucket/myfolder

この sync では差分ファイルのみが S3 にアップロードされる仕組みになっているけれど、sync で指定できるのはディレクトリのパスだけ。ではディレクトリ単位ではなく、ローカルのファイル単位で S3 上のファイル内容と差分がある場合にのみアップロードしたい時にはどうすればいいのか?
差分があってもなくてもアップロードすりゃいいじゃんって気もするが、せっかくなので考えてみた。

cp コマンドではファイルが常にアップロードされてしまうので、これだけではダメ。そういった用途のコマンドオプションも存在していない。

無理かなと諦めたかけた時に、ドキュメント内で発見したのが s3api サービス。このサービスでは s3 サービスより細かい単位の操作コマンドを提供していて、その一つの head-object コマンドを使うと S3 上のオブジェクト(ファイル)のメタデータを取得できる事が分かった。

$ aws s3api head-object --bucket mybucket --key myfolder/assets.json
{
    "AcceptRanges": "bytes",
    "ContentType": "binary/octet-stream",
    "LastModified": "Tue, 08 Sep 2015 05:52:44 GMT",
    "ContentLength": 37254,
    "ETag": "\"45860d6b237d4ad5310608627d2f1513\"",
    "Metadata": {}
}

(なぜ ETag の値だけ引用符が?)

出力結果の ETag がファイルの MD5 ハッシュ値で、sync でもこの ETag でローカルファイルとの差分の有無を判定していると思われる。なので、次のようにローカルファイルの MD5 ハッシュ値を取得して S3 上のものと比較すれば差分の有無を判定できる。

$ md5sum myfolder/assets.json
45860d6b237d4ad5310608627d2f1513  myfolder/assets.json

上記のコマンドを組み合わせれば、ファイル単位での S3 同期コマンドを実装できるはず。

Last updated on September 9, 2015