CircleCIなどを使ってEC2に乗っかったWebアプリケーションの更新はよく記事を見かけるのですが、時代はやはりサーバーレスなのでLambdaへのデプロイも自動化できたら嬉しいですよね
現在、私が携わっているサービスである RODEM はユーザーがストレスなくサービスを利用していただくためにいかに早く処理を行うか、安定に提供できるかのためサーバーレス化に取り組んでいます。
「RODEM」って何?って思う方は以下のリンクから
https://rodem.valwebservices.com/
LambdaへのデプロイはCloudFormationの利用をします。
CodePipeLineにおけるCloudFormationへのデータのやり取りがかなり手間取ったので、今後使われる方のための参考になればと思っています。
AWSが掲げるLambdaへのデプロイフローはここにある通り、以下を構築していく形となります。
- CodePipeLineでフローの定義
- CodeBuildでのパッケージング
- CloudFormationでの反映
- CodeDeployを使ってのBlue/Greenデプロイといったデプロイ戦略
今回は1~3までを紹介します。
- CodeBuildの用意
後ほど、CodePipeLineで読み込むためにCodeBuildの準備をします。
プロバイダの設定
ビルド方法
ビルド設定に関しては、私はLambdaはnodejsで記述しているためnodejsを選びました。
プロジェクトのルートパスにbuildspec.yml
を用意する必要があります。
buildspec.ymlに関して
私の場合特にlambdaがデフォルトで読み込めないライブラリは使ってないので、
zip圧縮できればオッケーなので以下のようになっています。
version: 0.1
phases:
install:
commands:
- echo 'install phase'
build:
commands:
- echo 'build phase'
artifacts:
type: zip
files:
- "**/*"
discard-paths: no
アーティファクトの設定
これを設定しておかないと、CodePipeLineからCodeBuildを呼び出すときに呼び出せるようにしてくれ!と怒られてしまいます。
- CodePipeLineの準備
とりあえず準備
以下は変更検知の設定ですね。
CodeBuildで設定したリポジトリと同じものを選びました。
プロジェクト名はさきほどつくったCodeBuildのプロジェクトを指定します。
このあとのデプロイに関しては、あとで詳しく作りますので一旦飛ばします。
サービスロールなどは適切に設定してください。
CodeBuildでの出力結果の確認
さきほどつくったパイプラインの編集でCodeBuildのタスクが終わると出力結果として
buildspec.ymlで定義された成果がS3に出力されます。
これは私の場合はzip化したnodejsのコードになります。
特にここの出力アーティファクト名に関しては、この後記述するデプロイタスク、cloudformationでの記述でかなり大事になってきます。
- CloudFormationの準備
さきほどのパイプラインの編集であらたにタスクを定義します。
CodePipeLineを少し触っていると毎回ビルドするたびに生成する新しい成果物にはどのようにCloudformationを定義するjsonからアクセスするんだろう?という疑問がでてきます。
先に答えをいえば、アドバンストの設定で新しい成果物を取得するような記述を行います。
cloudformationのテンプレートの場所は私の場合は、プロジェクトのルートパス配下にLambdaを定義する cloudformation.json
を用意しました。
cloudformation.jsonの内容
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "20180330",
"Parameters": {
"LatestS3Bucket": {
"Type": "String"
},
"LatestS3Key": {
"Type": "String"
}
},
"Resources": {
"MyLambda": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "my-function",
"Code": {
"S3Bucket": {
"Ref": "LatestS3Bucket"
},
"S3Key": {
"Ref": "LatestS3Key"
}
},
"Description": "create by codepipeline",
"Handler": "index.handler",
"Role": "********* iam role ******************",
"Runtime": "nodejs6.10",
"Environment": {
"Variables": {
"HOGEHOGE": "あいうえお"
}
},
"Timeout": 10,
"MemorySize": 128
}
}
}
}
ここで、LatestS3Bucket
や LatestS3Key
という値が重要です。
この値にCodePipeLineから最新の成果物であるS3の場所をマッピングしてあげます。
そのマッピング元となるのがアドバンストという枠で以下の記述を行います。
{
"LatestS3Bucket": {
"Fn::GetArtifactAtt": [
"MyAppBuild",
"BucketName"
]
},
"LatestS3Key": {
"Fn::GetArtifactAtt": [
"MyAppBuild",
"ObjectKey"
]
}
}
これを行うことでcloudformation.jsonに記述されたLatestS3Key
の値が上書きされるようになり最新の成果物の位置を扱えるようになります。
CodePipeLineのオーバーライド関数については以下を参照
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-parameter-override-functions.html
上記の設定をすれば、GithubのmasterにpushするたびにCodePipeLineが起動されLambdaにソースコードがデプロイされます。CodeDeployを使った戦略はまだなので、追い追い記事にできたらと思います。
遭遇したバグ?
CloudWatch Event -> Lambda連携をつかってCodePipeLineの現在の進捗状況をSlackに通知するものを一度つくりました。
ただ一度ビルドが始まるとCodePipeLineの無限ループが始まってしまいました。なぜだ。