matsukaz's blog

Agile, node.js, ruby, AWS, cocos2d-xなどなどいろいろやってます

AWS CodeBuildでAmazon EFSを利用する方法

Amazon EFSがついに東京リージョンでも使えるようになりましたね! 今日はAWS CodeBuildでAmazon EFSを利用するメリットと、その設定方法について説明します。

tl;dr

  • AWS CodeBuildには、ビルド時間を短縮するためのキャッシュ機能が用意されている
    • ビルド時に利用したライブラリ、コンパイル後のファイル、ccacheのファイルキャッシュなど、次回のビルド時に再利用できるものをキャッシュできる
    • ただし毎回S3上のキャッシュファイルの同期が発生するため、データ量が多いと DOWNLOAD_SOURCE フェーズ(キャッシュのダウンロード)や、 POST_BUILD フェーズ(キャッシュのアップロード)で時間がかかってしまう(4GBでそれぞれ2分程度)
    • ビルドプロジェクト(ビルド対象)ごとのキャッシュとなり、他のビルドプロジェクトと共有できない
  • AWS CodeBuildでAmazon EFSをキャッシュ保存先として利用できるようになると、以下のメリットが得られる

    • マウントするだけでキャッシュを利用できる(ビルド時間の短縮化
    • ビルドプロジェクトをまたがって同じキャッシュを利用できる(キャッシュの共有
    • EC2インスタンスにマウントすればキャッシュの内容を確認/編集することもできる(キャッシュの管理
  • キャッシュ用途以外にも、ビルド途中の成果物やログファイルなど永続化しておきたいデータをAmazon EFSに保存しておくこともできる

  • ここで説明する方法でAWS CodeBuildからAmazon EFSを利用すれば、いままで実現が難しかったことがいろいろできるように!

AWS CodeBuildって?

まずAWS CodeBuildの説明から。

aws.amazon.com

  • 完全マネージド型のビルドサービス
  • 従量課金
    • 実行時間のみ課金されるため、低コストで利用可能
  • Dockerコンテナ上でビルドを行う仕組み
    • ビルド処理を記述した設定ファイル(デフォルトではbuildspec.yml)を用意しておくだけで、記述された内容をDockerコンテナ上で実行
    • アーカイブとして指定したファイルは、ビルド実行後にS3上にアップロードしてくれる
    • AWSが用意しているものDockerイメージ以外にも、Dockerリポジトリ上のイメージや、独自に作成したイメージも利用可能(Amazon ECRに事前登録しておく)
    • Dockerコンテナは数十秒程度で起動するため、ビルド処理以外の時間はほとんどかからない(Dockerコンテナの実行環境はAWS内であらかじめ用意されているため)

弊社での用途としては

  1. Androidビルドを行うための専用Dockerイメージを作成し、出来上がったイメージをECSに登録(Android SDKAndroid NDK、ccache、その他ビルドに必要なライブラリのインストール)
  2. 1 でECSに登録したDockerイメージを利用してAndroidビルドを行い、できあがったapkファイルやビルド時のログファイルなどをS3にアップロード

といった処理をAWS CodeBuildで行っています。

Amazon EFSって?

続いてAmazon EFSについて。

aws.amazon.com

  • 完全マネージド型サービス
  • スケーラブルで高信頼性を実現した共有ファイルストレージ
  • 従量課金
    • 利用しているファイルサイズの容量に対してのみ課金される(プロビジョンドスループットモード以外なら)

弊社での用途としては

  1. 今回紹介するAWS CodeBuildを利用したAndroidビルド時のキャッシュ保存先として利用
  2. アプリの一時データ保存先として利用

といったところで採用しています。

AWS CodeBuildでAmazon EFSを利用するメリット

冒頭でも説明しましたが、AWS CodeBuildはビルド時間を短縮するためのキャッシュ機能を提供しています。 キャッシュのサイズが小さい場合や、ビルドプロジェクト(ビルド対象)ごとにキャッシュが独立していれば手軽に使える素晴らしい仕組みだと思います。

ただし、ビルドプロジェクト間でキャッシュを共有することはできませんし、S3を利用してキャッシュの同期を取る仕組みのため、キャッシュのサイズに応じて DOWNLOAD_SOURCE フェーズ(キャッシュのダウンロード)や POST_BUILD フェーズ(キャッシュのアップロード)で時間がかかるようになってしまいます(4GBでそれぞれ2分程度かかりました)。 キャッシュのサイズが数十GBに達した頃には、ビルド時間の半分近く(20分強)がキャッシュデータの同期にかかるようになってしまったため、とても利用できるものではありませんでした(;´Д`)

AWS CodeBuildでAmazon EFSを利用することで、これらの問題をすべて解決することができます!

Amazon EFSはマウントするだけで利用できるようになるため、AWS CodeBuildのキャッシュ機能のようなキャッシュの同期にかかる時間はありません(常に最新のデータがその場で反映されるため)。 同じAmazon EFSをマウントすれば、ビルドプロジェクト間で同じキャッシュを共有することもできます。 またAmazon EFSはAmazon EC2でももちろん利用できますので、キャッシュの内容を簡単に確認/編集することもできます。

設定方法

ここからは実際の設定方法になります。

事前準備

AWS CodeBuildでAmazon EFSを利用するためには、以下の条件を満たす必要があります。

このため、事前準備としては

となります。 NATゲートウェイやNATインスタンスの立て方は以下を参考にするといいんじゃないかと思います。

qiita.com

qiita.com

Amazon EFSファイルシステムの作成

ここは普通に作成すればOKです。 AWS CodeBuildからアクセスできるように、サブネットやセキュリティグループを設定を間違えないようにしましょう。

AWS CodeBuildのプロジェクト作成

以下の2点に注意して設定を行います。

特権付与

特権付与のチェックボックスをONにします。 これを忘れると、EFSをマウントしようとしたときに「operation not permitted」のエラーが発生してしまいます。

f:id:matsukaz:20180713135511p:plain

VPC設定

VPCの欄でVPC内で動作させるための設定を行います。

f:id:matsukaz:20180713135647p:plain

buildspec.ymlを設定

あとはビルド対象のソースコードに配置したbuildspec.ymlにて、Amazon EFSをマウントする記述を追加すればOKです。 以下は、Androidビルドを行うためにccacheとgradleのディレクトリをAmazon EFSに保存している例です(Amazon EFS内のディレクトリを、シンボリックリンクを張ったり環境変数で参照)

version: 0.2

env:
  variables:
    EFS_DNS: "fs-11112222.efs.us-west-2.amazonaws.com"
phases:
  install:
    commands:
      - echo Nothing to do for install phase on date
  pre_build:
    commands:
      - export NDK_CCACHE=$(which ccache)
      - mkdir -p /codebuild/output/efs
      - mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $EFS_DNS:/ /codebuild/output/efs
      - mkdir -p /codebuild/output/efs/.ccache
      - export CCACHE_DIR=/codebuild/output/efs/.ccache
      - export CCACHE_NOHASHDIR=1
      - export CCACHE_COMPILERCHECK=content
      - export CCACHE_BASEDIR=$(cd "$(pwd)/.." && pwd)
      - ccache -M 50G
      - rm -rf /root/.gradle
      - mkdir -p /codebuild/output/efs/.gradle
      - ln -s /codebuild/output/efs/.gradle /root/.gradle
  build:
    commands:
      - python tools/docker-android-build/build.py -e $TARGET_ENV
  post_build:
    commands:
      - echo Build completed on date
artifacts:
  files:
    - proj.android/build/outputs/apk/*.apk
    - build.log
  discard-paths: yes

あとはCodeBuildからビルドしてみて、Amazon EFS上にキャッシュファイルが保存されていれば成功です! AWS CodeBuildで標準でサポートして欲しいぐらいに便利なので、オススメです!(๑•̀ㅂ•́)و✧

ではでは!(`・ω・´)ゞ

www.wantedly.com

AWSによるサーバーレスアーキテクチャ

AWSによるサーバーレスアーキテクチャ