もやぶろ

moyashidaisukeのブログだからもやぶろ。フリーランスのエンジニアのダイスケです。プログラム関連とかギター関連とか旅行関連とか色々。

AWS CodeBuildのローカルキャッシュのCustom cacheでnode_modulesやvendorをキャッシュする

CodeBuildの新機能で、微妙にハマったのでノウハウをを。

aws.amazon.com

classmethodさんが↑のブログをいい感じに日本語で説明してくれています。いつもありがとうございます。

dev.classmethod.jp

ちなみに、この機能、日本語のマニュアルにはまだ反映されていないので注意が必要です。機能自体は日本リージョンで使えます。(2019/03/19現在)

docs.aws.amazon.com

今まで

S3にキャッシュする機構はあったので、それを使ってnode_modulesや、vendorフォルダをキャッシュする事によって、ビルドの高速化を実現できました。(差分があった時だけライブラリをダウンロードする事になるので。)

これだけでも性能的にはほぼ十分なのですが、

  • S3のセットアップが微妙に面倒
  • ネットワーク越しになるので、少し遅い

という弱点がありました。

ローカルキャッシュを使うと

新機能のローカルキャッシュを使うと、S3の設定をせずにキャッシュが実現できて楽ちんです。

コンソールで「Custom cache」にチェックを入れて、buildspec.ymlにキャッシュしたいディレクトリを指定するだけで動きます。しかもネットワーク越しではないので、S3を使う時よりも速いです。

ハマりポイント

というわけで、

cache:
  paths:
    - './node_modules/**/*'
    - './vendor/**/*'

って書けば終わりと思いきや、Dockerを使っている場合に罠があります。

こちらのオフィシャルブログにも書いているのですが、

Symlinks are used to reference cached directories.

「キャッシュディレクトリに対して、シムリンクを使うよ」と言っています。

aws.amazon.com

ログを見るとなんとなくわかるのですが、こんなログが出ます。

[Container] 2019/03/19 XX:XX:XX MkdirAll: /codebuild/local-cache/custom/XXXXXXXXXXXXXXXXXXXXXXXXXXX/node_modules
[Container] 2019/03/19 XX:XX:XX Symlinking: /codebuild/output/YYYYYYYY/src/github.com/XXXXXXX/XXXXX/node_modules => /codebuild/local-cache/custom/XXXXXXXXXXXXXXXXXXXXXXXXXXX/node_modules

/codebuild/local-cache/custom/ というディレクトリにキャッシュの本体があって、ビルド用のディレクトリの /codebuild/output/YYYYYYYY からシムリンクを貼っています。

dockerはホストとのディレクトリの設定についてはsymlinkに対応してないので、この設定だと全然動きません。(フォルダが無いとか言われる)

ではどうするかというと、

phases:
  pre_build:
    commands:
      - echo ====== Set Cache ======
      # .から始まる隠しフォルダもコピー
      - cp -r ./cache_node_modules/. ./node_modules/
      - cp -r ./cache_vendor/. ./vendor/

  post_build:
    commands:
      - echo ====== Set Cache ======
      # .から始まる隠しフォルダもコピー
      - cp -r ./node_modules/.  ./cache_node_modules/
      - cp -r ./vendor/.  ./cache_vendor/

cache:
  paths:
    - './cache_node_modules/**/*'
    - './cache_vendor/**/*'

こんな感じでキャッシュ専用のディレクトリを用意して、自分でコピーしてあげると、デフォルトでシムリンク先の実態をコピーしてくれるので、Dockerでもうまく動きます。また、最後にキャッシュフォルダに戻してあげる処理も必要です。

コメントでも書いてますが、 ./cache_node_modules/* だと .bin のような隠しフォルダがコピーされずにキャッシュの効果が半減するのでこちらにも注意です。

symlinkじゃなくて実態でcpしてくれるオプションがほしい、、、、