YDiary

メモ的な

Git LFSをAmazon S3でいい感じにする話

はじめに

皆さんはソースコードリポジトリの保存先として,GitHubなどのホスティングサービスをお使いでしょうか. また,リソースファイルなどのバイナリファイルを管理するためのリポジトリのサイズが肥大化していたりしないでしょうか.

実は,GitHubなどのホスティングサービスでは推奨されるリポジトリのサイズが決められており,そのサイズを大幅に超過するようなリポジトリは運営による凍結・削除の対象となってしまうことがあるのです.

この記事では,そうしたリポジトリの肥大化を,バイナリファイルをソースコードとは別で管理することによって防ぐことが可能なGit LFS (Large File Storage)と,Git LFSのサーバとしてAmazon S3を活用する方法などを紹介します.

推奨されるリポジトリのサイズ

ホスティングサービスで推奨されるリポジトリのサイズは次の通りです.

  • GitHub: 1 GB*1
  • Bitbucket: 1 GB soft limit, 2 GB hard limit*2

また,GitHubにおいては次のように,推奨されるリポジトリのサイズを大きく超過してしまったがために,リポジトリを削除されてしまった例が存在します.

Git LFSとは

上のスライドでも述べられていますが,Git LFSとはGitで大きなバイナリファイルを効率的に扱うための仕組みです. もともとバイナリファイルは差分を取ることが難しいため,Gitで差分を管理するメリットがほとんどありませんでした. そこで,バイナリファイルに関してはポインタ(ハッシュ)だけをGitで管理して,実体は専用サーバで扱おうというのがGit LFSの考え方です.

https://git-lfs.github.com/

これにより,どんなに大きなバイナリファイルであっても,Gitで管理するのはそのポインタファイルのみになるのでリポジトリサイズの肥大化を防ぐことが可能です. また,GitHubにおける単一ファイルの100MBサイズ制限なども回避することが可能です.

Git LFSの優れているところは,Gitのsmudge/clean filterとして動作するため,通常のGitのワークフローと同じように扱えるという点です.

GitHubでGit LFSを使う場合

一般的なGit LFSの導入方法は先達の解説記事に譲るとして,ここでは導入した後の話をします.

GitHubで管理しているGitリポジトリに一般的な方法でGit LFSを導入した場合,LFSサーバとして,GitHubのサーバを使用することになります.しかし,GitHubが提供しているLFSサーバは,

  • 1 GBのディスククオータ
  • 1 GBの下り転送量/月

までは無料で使用することが可能であるものの,それを超えて使用する場合にはdata packを購入する必要があります*3.data packは一つあたり$5/月で,

  • 50 GBのディスククオータ
  • 50 GBの下り転送量/月

を使用することが可能です.

ディスククオータだけならまだしも,下り転送量制限があるのが厄介です.例えば,10 GBのデータを5台のサーバにGitHub経由でフルデプロイしただけで50 GBの下り転送量を使い切ってしまいます.もちろん,そうした状況は稀ですし,その都度data packを追加購入すれば済む話ではあるのですが,いちいち残り転送量を気にしたくないことと少しでもコストを削減したいことから,LFSに関してはGitHub以外のサーバの使用を検討することにしました.

Git LFSの仕組み

Git LFSAPIの仕様に関しては,こちらの記事がとても参考になります.

jyn.jp

上記の記事の通り,Git LFSではファイルのやり取りにHTTPを使用しており,ファイルのアップロードには PUT を,ダウンロードには GET を,アップロード・ダウンロード先のURLの問い合わせには POST を使用しています.

さて,PUTでファイルをアップロードしてGETでファイルをダウンロードするストレージと聞いて何かを思い出さないでしょうか.

そうです,オブジェクトストレージです.Git LFSのストレージサーバは正にオブジェクトストレージなのです.そのため,クライアントからのアクセスに対して上手いことURLを返すことができれば,Amazon S3などのオブジェクトストレージをそのままLFSサーバとして使用することができるのです.

また,サーバをAWS EC2で動かしている場合,Amazon S3からのデータ転送料金もかからないため,GitHubのdata packを購入する場合と比較して,コストを5分の1から10分の1程度にまで抑えることが可能です.

Git LFSAmazon S3でいい感じにする

いよいよ本題です.

Git LFSAmazon S3でいい感じに使うために,次に示すようなプロキシサーバをC#HttpListener を使って作りました*4 このプロキシサーバがやっていることは次の通りです.

  • クライアントからのPOSTリクエストを待ち受け、jsonを受け取る
  • upload 操作の場合は、S3側に該当のファイルがあるかどうかを調べ、無い場合のみ upload 操作のURLを返す
  • download 操作の場合は、S3側に該当のファイルがあるかどうかを調べ、ある場合のみ download 操作のURLを返す(無い場合は404 errorを返す)

たったこれだけの実装で,Amazon S3LFSサーバとして使用することができました.

LFSサーバは,次のコマンドで .lfsconfig ファイルに lfs.url として記述することで明示的に指定することが可能です*5
git config -f .lfsconfig lfs.url https://lfs.example.jp/Media

おわりに

というわけで,Git LFSを導入することによってリポジトリのサイズが抑えられ,また,LFSサーバとしてAmazon S3を使用できるようにするプロキシを実装することで月々のコストも抑えることができました.

厳密に測定してはいませんが,S3が速いのか,LFSを導入したことでリポジトリのCloneやPull,Pushなどの速度も速くなった気がします.


S3と同じregionのAWS EC2でCloneかけたら2Gbpsぐらい出てびっくりした

ソースコードはこちらのリポジトリで公開しています. github.com

*1:https://help.github.com/articles/what-is-my-disk-quota/

*2:https://confluence.atlassian.com/bitbucket/what-kind-of-limits-do-you-have-on-repository-file-upload-size-273877699.html

*3:https://help.github.com/articles/about-storage-and-bandwidth-usage/

*4:既にいくつかストレージとしてAmazon S3を使用するLFSサーバの実装は存在しますが,試してみたところメンテナンスされてなくて動かなかったり,環境構築が面倒くさかったりしたのと,使い慣れたC#の方がいざというときにメンテナンスがしやすいため,新たに実装することにしました.

*5:https://github.com/git-lfs/git-lfs/blob/master/docs/api/server-discovery.md#custom-configuration