最近 sbtプラグイン職人(別名 すぶた職人)になっている かとじゅん です。 今回作ったのは、AWS用のsbtプラグインです。ソースは以下にあります。 https://github.com/chatwork/sbt-aws

AWSに対応したsbtプラグインは他にも何個かあるのですが、使いたいものがなかったので、作りました(自分たちが欲しい機能しか作ってないので、全然機能足りないですが… P−Rください:P)。

とりあえず、今できることは以下だけです。

  • ElasticBeanstalk(以下 EB)の、アプリケーションバンドルを作成し、S3にアップロードしたい
  • CloudFormation(以下 Cfn)のテンプレートファイルをS3にアップロードし、スタックの作成・更新・削除をしたい

sbt-aws

では、使い方の説明を。

sbt-aws-eb

EB用のプラグインです。Cfnを通じてEBを構成する想定なので、基本的にアプリケーションバンドルの作成、S3へのアップロードする機能しかありません。

project/plugins.sbtaddSbtPlugin("com.chatwork" %% "sbt-aws-eb" % "1.0.12") を追加します。

次にbuild.sbtに以下をebBundleTargetFilesを追加します。これは何かというと、アプリケーションバンドル(zip形式)内部に格納するファイル情報です。Seq[(File, String)]という型で、タプルの左側は格納元、右側が格納先となります。

sbtでビルドしたScalaアプリケーション(jar形式)をzipに含めることがよくあると思いますが、そういうときに便利なのは (packageBin in Compile).value でjarへのパスが取得できます。それをebBundleTargetFilesに含めます。

次のコマンドを実行するとアプリケーションバンドルが作成可能です。ebBundleTargetFilespackageBin in Compileに依存しているので、jarファイルがない場合はコンパイルしjarを作成します。便利ですね。

sbt-aws-cfn

Cfn用のプラグインです。主にCfnテンプレートからスタックの作成・更新・削除などができます。

project/plugins.sbtaddSbtPlugin("com.chatwork" %% "sbt-aws-cfn" % "1.0.12") を追加します。

次にaws/cfn/templatesというディレクトリに、Cfnテンプレートファイルを配置します。

aws/cfn/templates/infra.template

build.sbtには

cfnStackName in aws := Some("example-stack")

を追加してください。

次のコマンドでスタックの作成または更新が可能です。最初にスタックがあるかないかを確認してなければ作成、あれば更新を行います。AndWaitがついていないaws::cfnStackCreateOrUpdateというタスクもありますが、こちらはスタックの作成・更新の完了を待機しません。

sbt-aws-s3

S3のためのプラグインです。作ってみたけどファイルをアップロードするぐらいしかないので、ほぼ役に立たないと思います…。

プロファイル機能

Cfnを触っているとスタックに与えるパラメータを設定ファイルで外出しにして、環境ごとに切り替える機能が欲しくなりますが、今回は簡易的なプロファイル機能を実装しました。

まず以下のような設定ファイルをtest.confとして用意します。awsという名前は固定で、キー名は今回のプラグインのSettingKeyと同じ名前になります。以下の例ではS3のバケット名を定義しています。

次のコマンドを実行すると、環境ごとに設定値を切り替えられるようになります。環境名をtestと指定するとtest.confがロードされて各設定値が反映されます。

sbt -Daws.env=test aws::cfnStackCreateOrUpdateAndWait

ebBuildBundleをassemblyに依存させる

応用テクを一つ。sbt-assemlbyで作ったFat Jarをアプリケーションバンドルに組み込む事例です。

ebBuildBundleする前にassemlbyするようにタスクの依存関係を作ります。以下のbuild.sbtを参考にしてください。

ebBundleBundleタスクに対して、dependsOnメソッドを用いて、assemblyタスクに依存するようにできました。また、outputPathはassemblyによって生成されたFat Jarへのパスが取得できます。 ebBundleBundleタスクが実行される前にassemblyが実行されるようになります。、ということは、ebUploadBundleebBundleBundleassemblycompileという依存関係が作られたことになります。あら便利。

必要に応じて Cfnのスタック構築のタスクにアプリケーションバンドルのアップロードタスクを依存させればcfnStackCreateOrUpdateAndWaitするだけ、compile, assemblyなどの一連のタスクを自動的に実行可能です。これをJenkinsなどのCI環境から実行すれば便利ですね。

cfnStackCreateOrUpdateAndWait in aws <<= (cfnStackCreateOrUpdateAndWait in aws) dependsOn(ebUploadBundle in aws)

まとめ

初めてsbtプラグインを作ってみたのですが、意外にサクサクと書けました。当然ですが、Scalaに慣れていると早いですね。

今回、やってみて思ったのですが、カスタムタスクなどをプラグインへの切り出しを最初にやるのではなく、Build.scalaなどにカスタムセッティングやカスタムタスクを追加して、安定したら必要に応じてプラグインに実装していくのもありだなと思いました。

あと、プラグインのコーディングを学ぶにはやっぱりsbt-assemlbyなどの有名なプラグインのコードを読むってのと、sbt自体のコードを読むのは必要ですね。そこがハードル高いといえば高いですが、気合でやるしかないですね。

すぶた職人になろうと思っている方の、ご参考になれば幸いです。