社内Gyazoの画像をAmazon S3に逃がしてスケーラブルに運用する

Gyazo、便利ですよね。大変便利なので、社内でプライベートなGyazoサーバを用意して使っている会社も多いと思います。

うちでもサーバのパフォーマンスは特に必要ないので社内に適当なVMを立てて運用していたのですが、数年単位で運用していると画像ファイルが増えていくためdiskをなんとかする必要に迫られました。

ここでどんどん増えるファイルはAmazon S3に逃がそう、という自然な発想に至るわけですが、Gyazoサーバアプリが投稿を受けたときにS3にアップロードするような改修をするのは年末の忙しい時期に面倒。楽したい。

ということで S3 と nginx を組み合わせていいかんじに運用できるようにしてみました。

Gyazoに限らず、

  • ローカルに書き込んだファイルをhttpで閲覧する
  • 一度書き込まれたファイルには変更がない
  • ファイルは消えないでどんどん増える

ようなものには応用できると思います。

S3 に bucket を用意

普通に S3 に bucket を作ります。ここでは internal-gyazo.example.com とします。

社内のみにアクセス制限している画像なので、S3から直接一般に公開してしまうわけにはいきません。しかし、S3 API をちゃんと実装して nginx から画像を取得するのは面倒なので、IPアドレス制限をして特定のIPアドレス(ここでは社内gyazoサーバ) からのみ閲覧を許可します。

bucket policy の設定を開いて、AWS Policy Generator で生成した以下のようなJSONを記述します。

{
	"Version": "2008-10-17",
	"Id": "Policy1",
	"Statement": [
		{
			"Sid": "Stmt138795173604",
			"Effect": "Allow",
			"Principal": {
				"AWS": "*"
			},
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::internal-gyazo.example.com/*",
			"Condition": {
				"IpAddress": {
					"aws:SourceIp": "192.0.2.1/32"
				}
			}
		}
	]
}
  • s3:::internal-gyazo.example.com/* に対して
  • 192.0.2.1/32 から
  • s3:GetObject を許可する

というルールです。

nginxの設定

try_files を利用して、

  • ローカルファイル (/usr/local/gyazo/data/*) がある場合はそれを返す
  • ない場合は S3 に proxy_pass

という設定をします。

実際は別途Basic認証を掛けているため、AuthorizationヘッダをS3に送ってしまうと認証エラーになるので proxy_pass する前に削除しています。

S3 のホスト名を proxy_pass に直書きしないで一旦変数に set している記述については、Nginxでproxy_passにホスト名を書いた時の名前解決のタイミング - (ひ)メモ を参照してください。

また、無駄に S3 にリクエストを飛ばさないために proxy_cache も設定しています。

proxy_cache_path /var/lib/nginx/tmp/proxy levels=1:2 keys_zone=gyazo:500m max_size=1000m inactive=24h;
server {
    listen 80 default_server;
    resolver  127.0.0.1;
    location /gyazo/data {
        root /usr/local;
        try_files $uri @s3;
    }
    location @s3 {
        set  $s3_host  "internal-gyazo.example.com.s3-ap-northeast-1.amazonaws.com";
        proxy_set_header   Host $s3_host;
        proxy_set_header   Authorization "";
        proxy_set_header   Cookie "";
        proxy_cache        gyazo;
        proxy_cache_valid  404 1m;
        proxy_cache_valid  any 24h;
        proxy_pass  https://$s3_host;
    }
    location /gyazo {
        proxy_pass  http://127.0.0.1:5000;
    }
}

運用

  • Gyazoサーバに投稿があるとローカルファイルが生成されます。その後の閲覧はローカルファイルから配信されます
  • 適当なタイミングで、ローカルファイルを S3 にアップロードして削除します
  • ローカルファイルが削除された後は、S3 から GET したファイルが配信されます

これで、ローカルファイルは適宜削除できるので disk 容量を気にする必要がなくなりました。年末にdisk 掃除ができてすっきりです。