ネットの海の片隅で

技術ネタの放流、あるいは不法投棄。

middleman, CodeBuild, S3, CloudFront でいい感じにシュッとやる

モチベーション

自分が何者であるかを表明しておく場所が Web に欲しいなという気持ちがあった。

そのために osa.in.net というドメインを取得していたが、肝心のコンテンツが一切なかったのでとりあえず仕組みをつくることにした。

要件

安くて簡単

自分が何者であるかを表明するのは大事だが、使用頻度はそれほど高くないので手間も金もかけたくない。

HTTPS

時は既に2017年なので、原始人でもないかぎり HTTPS を喋ってほしい。

自動デプロイ

いちいちデプロイするのは面倒なので勝手にデプロイされてほしい。

構成

  • 静的ページをつくって S3 に置く
  • 独自ドメインHTTPS を喋らせるために CloudFront を経由させる
  • 静的ページは middleman をつかって生成する
  • CodeBuild を使って自動デプロイする

設定

middleman の使い方とか S3, CloudFront, Route 53 の基本的な設定なんかは Web に腐るほどあるのでここでは書かない。

ここでは少し手間取った以下の2点について書いておく。

  • 自動デプロイ
  • いい感じの URL

自動デプロイ

はじめは CodePipeline を使って CI/CD パイプラインを作ろうと思っていた。 しかし、CodeDeploy は S3 へのデプロイに対応していないことが発覚。 「Build とは? Deploy とは?」という気持ちを抱えつつ、CodeBuild でデプロイすることに。

やることは主に3つ。

  • ビルド環境の構築
  • ビルド
  • デプロイ

環境構築を毎回やるのは効率が悪いんだけど、いちいち docker image を管理するのが面倒なので毎回構築している。

ビルドについては middleman の機能をそのまま使っているが、デプロイについては middleman-s3_sync を使っている。 CodeBuild の IAM Role に S3 Bucket へのパーミッションをつけてあげれば、環境変数経由でいい感じに credential を受け渡してアップロードしてくれる。

なお、CodeBuild 用の build spec ファイルはこんな感じ。

# test/buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - sudo apt-get update
      - sudo apt-get install -y nodejs
      - bundle install
  build:
    commands:
      - bundle exec middleman build
  post_build:
    commands:
      - bundle exec middleman s3_sync

これで、master に変更が入るたびに middleman によってビルドされた静的ファイルが S3 へ自動デプロイされるようになった。

CodeBuild の料金が $0.005/min で、実行に1分半くらいかかるので1円/デプロイくらいのコストがかかる。

いい感じの URL

ここで「いい感じの URL」というのは https://example.com/path/to/page のようなものを指す。 URL の末尾を削って https://example.com/path/to としてもページがあってアクセスできるようにしたい。 そのために拡張子を含まない URL にする必要がある。

S3 において、拡張子を含まない URL を提供することは難しくない。 S3 の Static Website Hosting では directory index が有効になっているので、/path/to/page/index.html が存在していれば /path/to/page でアクセスできる。

また、この形式でファイルを吐き出すオプションが middleman にあるので、それを使えばビルドも簡単にできる。

この際の注意点として、S3 の Static Website Hosting の結果を CloudFront 経由で配信する場合、CloudFront の Origin として S3 Origin を選ぶと directory index がうまく動かず Access Denied を返してしまう。 そこで、Custom Origin を選択した上で、Static Website Hosting のエンドポイントを設定してあげると動くようになる。

ただ、この状態で /path/to/page にアクセスすると /path/to/page/ にリダイレクトされてしまう。 これは directory index がその名前の通りディレクトリを指しているために起こってしまうことで、S3 の設定などでどうにかすることはできない。

もちろん、EC2 を立てるなどすれば /path/to/page のままアクセスすることは可能だが、EC2 は S3 の Static Website Hosting より遥かに高いし、サーバーのお世話をしたくない。

そこでダーティではあるが、以下のような JS を書くことでごまかすことにした。

document.addEventListener('DOMContentLoaded', function() {
  var path = window.location.pathname;

  if (path.match(/\/$/)) {
    path = path.replace(/\/$/, '');
    history.replaceState(null, null, path);
  }
});

これで、事実上 /path/to/page でアクセスできるようになった。

おわりに

こうして作ったサイトが https://osa.in.net で動いている。

コンテンツがほとんどない、デザインが非常にアレなどの問題はあるが、今後少しずつ足していくことにする。