Google Cloud Storageで静的ファイル配信

Google Cloud Storage (GCS)には、サイト配信やスタティックファイル配信の機能があります。AWSのS3と似た機能です。
Google Cloud SDKをインストールすると、gsutil rsyncコマンドを利用してローカルファイル一式をホスティングできます。

画像やCSSなどの静的ファイルの日常運用は以下のような流れになります。(なお、ここでは SDKのセットアップやバケットの初期設定は割愛しています)

準備:プロジェクトの確認

まず、gcloudコマンドでバケットを置くプロジェクトを指定します。

$ gcloud config set project some_project_id

プロジェクトを1つしか使用していない場合は問題になりませんが、複数のプロジェクトを操作するアカウントでは適切なプロジェクトを選択しておくことが必要です。

現在アクティブなプロジェクトを確認するには、gcloud config listコマンドのproject欄の出力を使えます。

gsutil rsyncでファイル転送

下記のコマンド例のように、gsutil rsyncコマンドを用いて、ローカルホストのsrc_dirをsome_bucket内のdest_dirとして同期できます。

$ gsutil -m rsync -d -r src_dir gs://some_bucket/dest_dir

-mオプションは並列実行を指定するもので、複数のファイルを転送する場合、オプションなしの場合より高速に動作します。サブコマンド(rsync)の前に指定する点に注意が必要です。

-dや-rオプションは再帰動作の挙動を指定するもので、両方指定した場合にはGoogle Cloud Storage上のディレクトリ構成はローカルと同じ状態になります。挙動の詳細は rsyncサブコマンドのリファレンスを参照してください。

service accountによるアクセス

サービスアカウントを用いてGCSを操作する場合、操作コマンド実行前にアカウントを有効にしておく必要があります。クレデンシャルファイルは予め取得してgsutilの実行環境に置いておきます。
gcloud auth activate-service-accountコマンドのほか、gsutil -eコマンドのプロンプトにクレデンシャルを指定する方法もあります。

gsutil aclでファイルを公開

オブジェクトごとのアクセス権限を設定できるバケットの場合、ファイルを転送した時点では、非公開状態になっているため、gsutil aclコマンドでpublic-read属性をセットすることにより、外部から読み取りアクセスできるようになります。バケット全体を一律公開する設定の場合は初期状態で公開されています。

$ gsutil -m acl -ar set public-read gs://some_bucket/dest_dir

gsutil rsyncで2回目以降の同期を実施した際に、public-read属性が外れるケースもあるため、rsync後に連続してaclを実行することで配信状態を継続できます。

aclも-mオプションは並列実行、-arは再帰動作の指定です。挙動の詳細は aclサブコマンドのリファレンスを参照してください。

このほか、index.htmlや404などのWebサイト向け設定は、「 Google Cloud Storageのスタティックホスト」で解説しています。

外部からのファイルアクセス

Google Cloud Storageにアップロードしたファイルは、http://storage.googleapis.com/some_bucket/から始まるアドレスでブラウザからアクセスできます。

具体的なURLがわかりにくい場合は、 GCPのコンソールのStorageのメニューからファイルブラウザで確認できます。

表形式のファイル一覧に掲載されている「公開リンク」のリンク先がそのファイルの具体的なURLです。

画像ファイルなどは、imgタグにこのURLを指定すればインクルードできます。

また、http / https のどちらでもアクセスできるため、//storage.googleapis.com/some_bucket/dest_dir/some_file.png などのようにスキーマなしのURLを指定すれば、ホストのSSLサポートに合わせて配信できます(httpとhttpsの混在によるブラウザエラーを避けられる)。

nginxのバックエンドとして利用する

GCSのファイルをnginxでプロキシ配信する構成も可能です。コンテナ環境むけオリジンファイルホストとして便利です。
以下はconfig例の抜粋です。ヘッダー操作とURLのrewriteが必要になります。

server {
	    proxy_set_header    Host storage.googleapis.com;
	    proxy_set_header    Connection "";
	    proxy_hide_header   x-goog-hash;
	    proxy_hide_header   x-goog-generation;
	    proxy_hide_header   x-goog-metageneration;
	    proxy_hide_header   x-goog-stored-content-encoding;
	    proxy_hide_header   x-goog-stored-content-length;
	    proxy_hide_header   x-goog-storage-class;
	    proxy_hide_header   x-xss-protection;
	    proxy_hide_header   accept-ranges;
	    proxy_hide_header   alternate-protocol;
	    proxy_hide_header      Set-Cookie;
	    proxy_ignore_headers   "Set-Cookie";
	    proxy_intercept_errors on;

	    proxy_http_version     1.1;
  
    location ~ ^/(.*[0-9])$ {
	    proxy_pass http://storage.googleapis.com/some_bucket/$1/index.html;
    }
  
    location ~ ^/(.+)/$ {
	    proxy_pass http://storage.googleapis.com/some_bucket/$1/index.html;
    }

    location = / {
	    proxy_pass http://storage.googleapis.com/some_bucket/index.html;
    }

    location / {
	    proxy_pass http://storage.googleapis.com/some_bucket$uri;
    }
}

rewriteの例はかなり複雑ですが、GCSリクエスト時には index.html などのファイル名を付ける必要があるためURLを加工しています。//とスラッシュが重複するリクエストもエラーになるため、末尾スラッシュの有無で処理を変えるといった工夫が求められます。

また、uglyurl形式の場合には、以下のようなrewite例になるでしょう。

    location ~ ^/(.*[0-9])$ {
	    proxy_pass http://storage.googleapis.com/some_bucket/$1.html;
    }
  
    location ~ ^/(.+)/$ {
	    proxy_pass http://storage.googleapis.com/some_bucket/$1.html;
    }
中馬崇尋
Chuma Takahiro