Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

CodeBuildでサーバレスバッチ環境を運用する

この記事は Akatsuki Advent Calendar 2018 の15日目の記事です。 前回は sejimhpさんの、環境改善の必要性〜真っ白な Terminal から tmux へ移行〜 でした。

はじめに

システムを運用する上で、安価で運用負荷の少ないバッチ処理を設計したいニーズは多いと思います。そもそもバッチ処理自体を極力除外したいのですが、日々の運用ツールなども含めると、どうしても実装しなければならない場面が出てきます。

本記事では

  • 安く
  • サーバレスで
  • 並列性高く
  • スケジューラでもイベントドリブンでも

実行できる、AWS上でのバッチ環境の実装の話をしたいと思います。

よくあるAWSバッチ処理アーキテクチャパターン

AWSバッチ処理アーキテクチャパターンBest Practice for Online Game Development on AWS が詳しいです。これらのアーキテクチャに対して私見をまとめると

EC2パターン

  • Pros: シンプルで使いやすく、速やかに実装ができる。
  • Cons: EC2料金が常にかかる。環境変数などの運用管理も必要。

Lambdaパターン

  • Pros: サーバレス。AWSのリソースを扱うには便利。
  • Cons: ゲームアプリケーションのロジックなどは使い回せない。タイムアウトも短め。

ECSパターン

  • Pros: CodePipeline等のパイプラインに組み込める。
  • Cons: 結局EC2が必要で、かつバッチで使うには比較的複雑。

Fargateパターン

  • Pros: サーバレス。
  • Cons: コストが割高で、プロビジョニングに1〜2分かかる。

例を挙げればAWS Batchなどのサービスもあるのでキリがないのですが、結局似たようなProsConsになるかと思います。今回は、これらのアーキテクチャを使わず、CodeBuildでバッチ処理を実装をする話をしていきます。

CodeBuildとは?

AWSが提供するマネージドビルド環境で、buildspec.ymlに記載した通りにビルドをすることができます。  

よくあるCodeBuildの使い方

通常、docker build用の環境などに用います。 弊社でもdocker buildが主な用途で、CodeBuildでdocker build後、ECRへdocker pushし、ECS / Fargateへデプロイするために使用しています。

f:id:e__koma:20181214155303p:plain
CodeBuildの使用例

buildspec.ymlの例は以下のとおりです。 パラメータストアと連携して秘匿情報をセキュアに一元管理したり、ビルド済みのdocker imageを実行環境として使えるところも嬉しいです。

version: 0.2

env:
  parameter-store:
    AWS_ACCESS_KEY_ID: "project-id.aws.access.key.id"
    AWS_SECRET_ACCESS_KEY: "project-id.aws.secret.access.key"

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
      - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}
  build:
    commands:
      - echo Build started on $(date)
      - echo Building the Docker image...
      - |
        docker build -t ${REPOSITORY_URI}:latest -f ${DOCKERFILE_PATH} . \
        --build-arg YOUR_ENV=${YOUR_ENV}
  post_build:
    commands:
      - echo Build completed on $(date)
      - echo Pushing the Docker images...
      - docker push ${REPOSITORY_URI}:latest

CodeBuildを使用したバッチ環境

さて、本題です。 CodeBuildを使ってバッチ処理を実行する方法を説明します。

パターン1:バッチスクリプト実行

CodeBuildはビルド環境に様々な言語が用意されており、かつVPC内で実行することができるため、RubyPythonスクリプトを実行することができます。

f:id:e__koma:20181214170023p:plain
CodeBuildでスクリプト実行例
 

実行後はCloudWatchEventsでイベントフックをして、slack通知をしてもいいですし、Lambdaで別の処理に移行するのも良いでしょう。CodePiplineやJenkinsのAWS CodeBuild Pluginを使用したPipelineに組み込めば、前後関係を豊富にカスタマイズできます。

この場合のbuild_spec.ymlは非常にシンプルに書けます。

version: 0.2

env:
  parameter-store:
    YOUR_ENV: "your.env"

phases:
  build:
    commands:
      - python ./test.py
artifacts:
  files: test.log

 

パターン2:ビルド済みアプリケーションの実行

  パターン1ではスクリプトを実行するだけでしたが、ビルド済みのアプリケーションを使った運用ツールを実行したい場合があります。例えばデータベースのmigration、 ゲームアプリケーションロジックを用いたアイテムドロップシミュレータなどです。

この要望を満たすためには、ビルド済みのアプリケーションImageを再度CodeBuildにpullしてこればOKです。

f:id:e__koma:20181214171045p:plain
CodeBuildでビルド済みアプリケーションの実行例

この場合、build_spec.ymlには少し工夫が必要になります。 ビルド済みのImageをpullしてきた後、docker runをする際にENTRY_POINTを空にして、実行したいコマンドを渡します。 こうすることでENTRY_POINTを無視して、ビルド済みのアプリケーションに対してコマンドを実行することができます。

version: 0.2

env:
  parameter-store:
    YOUR_ENV: "your.env"

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
      - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}
  build:
    commands:
      - echo started on $(date)
      - docker pull ${REPOSITORY_URI}:latest
      - echo ${BATCH_NAME} starting ...
      - |
        docker run \
        -e YOUR_ENV=${YOUR_ENV} \
        --entrypoint="" -i ${REPOSITORY_URI}:latest \
        sh -c "${BATCH_COMMAND}"
  post_build:
    commands:
      - echo ${BATCH_NAME} completed on $(date)

さて、ここまで説明してきたCodeBuildでのバッチ処理のメリットをまとめます。

機能性

  • ビルド済みのアプリケーションロジックを使い回せる
  • VPC内で実行できるためEC2 / RDSなどへのアクセスができる
  • 並列性が高い。
  • リソースの範囲内であれば長時間バッチも可能

運用性

  • サーバレス
  • 成功・失敗のイベントフックが豊富
  • Pipelineへの組み込みが容易なため前後関係の定義ができる

コスト

  • 従量課金のため、とにかく安い。

デメリットを挙げるとすれば以下のとおりです。

デメリット

  • プロビジョニングに30秒ほどかかる(ただしFargateのプロビジョニングよりかは速い)
  • 使える最大リソースは8vCPU、15GBメモリなので、これ以上のパワーが必要な処理ではリソースが足りない。

まとめ

CodeBuildを使ったバッチ処理を紹介してきました。 CodeBuildをバッチ環境として使い始めたプロジェクトでは、バッチサーバという概念がなくなりました。 興味がある人は、ぜひ使ってみてください!