AWS CodeBuild を使って Scala の Lambda Function をDockerコンテナ上でビルドする

eyecatch_codebuild

はじめに

AWSフルマネージドのビルドサービス欲しいよね、需要ありそう って話してたら本当にきて驚いています。

以前私は、LambdaでJavaサポートしてるからScalaも動くはずという趣旨の記事を書いたのですが、同じ理屈でCodeBuildもいけるやろという見切り発車です。そう意気込んでいたら、公式ドキュメントにScalaのサンプルがありました。

サンプルの方針としては、まずsbtを実行できるDockerイメージを使ってScalaプロジェクトををビルド可能なようにし、sbt packageで作成したJARをS3に配備する、というもののようです。そのままなぞってやるのでは面白くないので、この記事では以下のように差分を出しました。

  • ブラウザ経由ではなくコマンドラインクライアントでCodeBuildのプロジェクト作成とビルド実行を行う
  • ScalaのプロジェクトはHelloWorldではなく Scalaの Lambda Function とする
  • 生成されたJARが実際に動作するかどうか確認する

やること

  1. Lambda用のScalaプロジェクトを準備する
  2. buildspec.yml 作成
  3. CodeBuildプロジェクト作成(CLI)
  4. ビルド実行(CLI)
  5. CodeBuildプロジェクト修正(CLI)
  6. Lambdaにアップロードして使ってみる

1.Lambda用のScalaプロジェクトを準備する

別の記事で書いた Scala の Lambda Function を使うことにします。

2. buildspec.yml 作成

CodeBuildはリポジトリルートにあるbuildspec.ymlを使うようです。ここにビルド時の指示を書いていきます。

version: 0.1

phases:
  install:
    commands:
      - echo Nothing to do in the install phase...
  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
  build:
    commands:
      - echo Build started on `date`
      - sbt test # -- ①
  post_build:
    commands:
      - echo Build completed on `date`
      - sbt assembly # -- ②
artifacts:
  type: zip
  files:
    - external/target/scala-2.11/lambda-hero-external-0.1.0.jar # -- ③
  • ①: sbt でテストを実行します。
  • ②: sbt-assemblyプラグインを使ってJARファイルを生成します。
  • ③: 生成したJARの場所をここで指定します。

2.CodeBuildプロジェクト作成

ブラウザのAWSコンソールからでもプロジェクトを作成できるのですが、せっかくなのでコマンドラインから作成してみます。プロジェクトの作成指示にはJSONファイルを使うようです。create-project.jsonをプロジェクトルートに作成しました。

{
  "name": "lambda-hero-cli",
  "source": {
    "type": "GITHUB",
    "location": "https://github.com/cm-wada-yusuke/lambda-hero.git"
  },
  "artifacts": {
    "type": "S3",
    "location": "codebuild-lambda-hero-no-exits-bucket", // -- ①
    "packaging": "NONE"
  },
  "environment": {
    "type": "LINUX_CONTAINER",
    "image": "1science/sbt", // -- ②
    "computeType": "BUILD_GENERAL1_SMALL"
  },
  "serviceRole": "arn:aws:iam::945068354201:role/service-role/codebuild-lambda-hero-scala-service-role" // -- ③
}
  • ①: 生成したJARを設置するバケット名を指定します。ここでは後で修正する例を示すためわざと存在しないバケット名を指定しています。
  • ②: Dockerイメージを指定しています。SBTが実行できるコンテナです。(1science/sbt - Docker Hub
  • ③: ここは、最初どのような権限を持ったロールを指定すればよいかわからなかったので、一度AWSコンソールから適当なプロジェクトを作成しそのロールのポリシーを流用する形でこのプロジェクト用のロールを作成しました。大きくは、CloudWatchLogsへの読み書きS3バケットの読み書き ができれば良いようです。

create-project.jsonを作成したら、以下のコマンドを実行します。

$ aws --region us-west-2 codebuild create-project --cli-input-json file://./create-project.json

「こんなプロジェクト作ったよ」というJSONのレスポンスが返ってきたら成功です。

{
    "project": {
        "name": "lambda-hero-cli",
        "serviceRole": "arn:aws:iam::945068354201:role/service-role/codebuild-lambda-hero-scala-service-role",
        "created": 1480673353.563,
        "artifacts": {
            "namespaceType": "NONE",
            "packaging": "NONE",
            "type": "S3",
            "location": "codebuild-lambda-hero-no-exits-bucket",
            "name": "lambda-hero-cli"
        },
        "lastModified": 1480676864.941,
        "timeoutInMinutes": 60,
        "environment": {
            "computeType": "BUILD_GENERAL1_SMALL",
            "image": "1science/sbt",
            "type": "LINUX_CONTAINER",
            "environmentVariables": []
        },
        "source": {
            "type": "GITHUB",
            "location": "https://github.com/cm-wada-yusuke/lambda-hero.git"
        },
        "encryptionKey": "arn:aws:kms:us-west-2:945068354201:alias/aws/s3",
        "arn": "arn:aws:codebuild:us-west-2:945068354201:project/lambda-hero-cli"
    }
}

コンソールをみてみたら、確かにプロジェクトがつくられていることがわかります。

00

3.ビルド実行

以下のコマンドを実行します。

$ aws  --region us-west-2 codebuild start-build --project-name lambda-hero-cli

う〜ん、楽ですねぇ〜。

ところがエラーになってしまいました。

10

どうやらJARアップロード先のバケット名が誤っていたようです。プロジェクトの設定を修正しましょう。

4.CodeBuildプロジェクト修正

基本的には設定を上書きする格好になります。なので、プロジェクト生成時に使ったJSONを修正して使えます。

"artifacts": {
  "location": "codebuild-lambda-hero-no-exits-bucket",
},

これを、実際に存在するバケット名に修正しました。

"artifacts": {
  "location": "codebuild-lambda-hero",
},

以下のコマンドを実行します。プロジェクトのアップデートと、ビルドの実行です。

$ aws --region us-west-2 codebuild update-project --cli-input-json file://./create-project.json
$ aws --region us-west-2 codebuild start-build --project-name lambda-hero-cli

こんどは無事に完了しました。S3にJARが配備されたことも確認できます。

20

5.Lambdaにアップロードして使ってみる

生成したJARをLambdaにアップロードします。正常に作れていれば、ヒーロの一覧を取得できるはずです。

30

無事にDynamoDBのデータをとってくることができました。JARの生成も問題ないようです。

おわりに:感想

  • 普段からAWSを使っていれば他のサービスと同等の感覚で利用できるので、学習コストが小さいと思いました
  • ビルド、デプロイの流れがAWSで完結できるため、さらにCIがやりやすくなるのではと感じました
  • 他の言語やDockerイメージを使ってビルドをやってみたいと思いました
  • S3って万能ですね

AWS Cloud Roadshow 2017 福岡