CodePipelineを用いたLambdaのデプロイについての所感

JX通信社Advent Calendar 2019」7 日目の記事です。 こんにちは。2019年9月からJX通信社のエンジニアとなった鈴木(泰)です。趣味は映画観賞です。

はじめに

JX通信社では AWS の Lambda Layer、Lambda 関数を使った Serverless なアプリケーションの開発に従事しています。

私が初めて Lambda 関数に触れたのは2019年の9月です。 3ヶ月のあいだ業務で扱ってきたこともあり、現在では Lambda 関数をサクサク作れるようになりました。 また、複数の Lambda 関数を連携させて1つのアプリケーションを組んでみたり、共通する処理を Layer として切り出したりと、少しずつ複雑なこともできるようになりました。

最近の問題は、増えてきた Lambda 関数の管理です。 特に、Lambda 関数のデプロイにかかる手間の大きさが問題(詳細は後述します)でした。

本記事では、AWS CodePipeline を使用してアプリケーションのデプロイを自動化したという話、CodePipelineを使用しての所感を、忙しい人向けに(あまり長くならないように)紹介したいと思います。

TL;DR

  • Lambda 関数のデプロイを手作業でやるのがダルい・・・
  • CodePipeline を使って、デプロイを自動化しました!
  • せっかくなので、CodePipeline 使ってみた感想をシェアさせてください。

CodePipelineとは何か?(ざっくりと)

本題に入る前に、少しだけCodePipelineに触れておきます。

CodePipelineとは、CDを構築するための仕組みです。 こちらの図にある通り、Sourceからプロダクション環境へのデプロイまでのパイプラインを構築できます。

より厳密には、CodePipelineはStageを繋げてパイプラインを構築するための仕組みです。 Stageとは1つ以上のActionを含む、Actionのまとまりです。 Actionが具体的な処理の最小単位です。 StageのなかのActionの実行順番は、直列にも並列にもできます(詳しくはこちら)。

CodePipeline を用いてデプロイを自動化しました

私が所属するチームでは、複数の Lambda 関数と 1 つの Layer を用いた社内アプリケーションを運用しています。 Layer は、Lambda 関数の中で共通して使われる処理を含みます。

デプロイ作業の手間が大きかった

これまでは、このアプリケーションを手作業でデプロイしていました。 次のようなデプロイ手順(開発者が変更を push した後)です。

  1. Git 上のソースコードを自分の MacBook Pro へ clone し、Lambda 関数デプロイ用の zip アーカイヴに固めます。
  2. 手順 1 にて作成したアーカイヴを AWS 上へアップロードします(この作業を AWS の UI から行なっていました)。
  3. Layer にアップデートがあった場合、各 Lambda 関数が使用している Layer のバージョンを更新します(この作業を AWS の UI から行なっていました)。

上の作業にかかる時間が大体10分ぐらいでしょうか。 確かに、1度だけであれば手間はかからないです。

しかしながら、 この社内アプリケーションは未だ発展途上の段階にあるため、修正が高頻度で発生します。 そのため、毎日デプロイ作業が発生し、作業頻度が増えれば増えるほど作業ミスも多くなり、とても大きな時間が削り取られていました笑。

構築したデプロイパイプライン

私たちが目指したのは

  • ソースコードを Git へプッシュするだけ。デプロイまでは自動で完了する。

という世界観でした。 この社内アプリケーションの要件と構造自体はシンプルなものであったため、上の世界観を目標とすることは十分に現実的でした。

次のようなデプロイのパイプラインができました。

図1 f:id:taisuzuk:20191205103812j:plain

パイプライン構築後のデプロイ手順(開発者が変更を push した後)

なんとこれだけです。

  1. 「Lambda 関数を Deploy して良いですか?」というリクエストメールを管理者が受け取り、「リクエストを承認」をクリックする(図 1 の Mannual Approval)。

パイプライン(図1)の解説

  • GitLab のマスターブランチ へ push すると、GitLab から CodeCommit へレポジトリがミラーリングされます。弊社では、ソースコードレポジトリとして GitLab エンタープライズを使用しているため、CodePipeline からソースコードを直接取得できません。そのため、CodeCommit へミラーリングしています。
  • 1 つ目の CodeBuild と CloudFormation は、Layer をビルド・デプロイするためのものです。CodeBuild は、Layer が格納されている zip と SAM パッケージを生成し、成果物として S3 へ保存します。CloudFormation は S3 上に保存されている成果物を Serverless 実行環境へ反映します。
  • 2 つ目の CodeBuild と CloudFormation は、Lambda 関数をビルド・デプロイするためのものです。CodeBuild は、Lambda 関数が格納されている zip と SAM パッケージを生成し、成果物として S3 へ保存します。CloudFormation は S3 上に保存されている成果物を Serverless 実行環境へ反映します。
  • Mannual Approval は、Lambda 関数のデプロイを開始するかどうか?を、ソースコード管理者へ確認するためのものです(なぜこの確認が必要となるのか?については長くなるので省きます笑)。確認には Slack を用いています。具体的には、次のようなメッセージが Slack へ通知されます。f:id:taisuzuk:20191205113451p:plain
  • Mannual Approval は、CodePipeline の Mannual Approval Action を用いて作りました。この機能は(ざっくりと説明)、承認・拒否のどちらかのボタンをクリックするまで、パイプラインを一時的に停止するためのものです。

所感

「イケてるところ」と「工夫を要する点(a.k.a 微妙な点)」についてまとめてみました。

イケてるところ

認証・認可周りの設定管理が楽

(当たり前ですが)デプロイするまでのパイプラインがAWS上で全て完結します。 サードパーティ製のサービスを選択しなくて良いことによる恩恵は、ユーザーの権限管理、サービスの学習や事前調査(AWSの実行環境との親和性を調べたり)をしなくて良いことです。

自由度が高い

(これも当たり前かもしれませんが)CodePipeline は幅広くカスタマイズ可能です。 サードパーティが提供する CI/CD サービスでできることであれば、大体のことはサポートされているように思います。 パイプラインの中に CodeBuild(CircleCIのようなビルドパイプライン)を挿れることにより、殆どのことは実現可能かと思います。

自由度への制約

1つ上で「自由度が高い」を称賛しましたが、CodePipeline は上手い具合に自由度を制限します。 より正確に言えば、ある特定の目的を達成するために、AWS は唯一の方法を提供してくれます。

論理的に考察した場合、CodePipeline を選択する決め手となりうるのは、この標準化にあるのではないか?と思います。

これがどういうことかを説明するために、少しだけパイプラインの仕組みについて述べます。

CodePipeline とは Stage を繋げたものであり、Stage は1つ以上の Action 繋げたものです。 Action が具体的な処理の最小単位となります。

f:id:taisuzuk:20191202162921j:plain

Action に設定できる処理は、AWS により予め決められています。 要するに、AWS は「XXの目的のときはYYを使うと良い」ということを提案してくれているのです。 例えば、Lambda 環境へのデプロイを実現する方法として、CodeBuild(S3 に SAM をアップロードし、この SAM を適用するコマンドを buildspec.yml に羅列し、ゴニョゴニョゴニョ・・・)を用いることで実現可能です。 しかし、CodePipeline では、Lambda 環境へのデプロイをするためには、CloudFormation を使用した方が良いということを明言します。

工夫を要する点(a.k.a 微妙な点)

ドキュメント

これは私だけかもしれないのですが、率直に言ってドキュメントが読み難い・・・というよりもどこから読んで理解したら良いのか分からない・・・というのがありました。

この理由は、CodePipeline に関わるサービスが幅広いからなのかな、と思っています。 私が参考にした CodePipeline 構築チュートリアルは、CodeCommit、CodeBuild、CodeDeploy、CloudFormation、の3つサービスを組み合わせてパイプラインを作っていました。 私は3つの全てについて無知だったため、最初何が何やら訳の分からない状態で、とりあえず動くものを作っていました笑。

私の場合、まずこのチュートリアルを見ながらとりあえず動くものを作り、その後でドキュメントを熟読しました。 時間がない場合、この方法でも問題ないと思います。 言うまでもなく、CodePipeline を習得するための良い方法は、CodePipeline で使われている各々のサービスを1つずつ理解していくことだと思います。

パイプラインの実行結果のSlack通知を自前で作らなければならない

実行結果を Slack へ通知したい場合、SNS を通して Lambda 関数から Slack へ通知しなければなりません。 つまり、イベントを受けて Slack へポストするための Lambda 関数を自前で作成しなければならないのです。

昨今のサードパーティ製のサービスであれば、Slack 連携は容易にできることが当たり前です。 今後、AWS に改善していただきたい点の1つだと思います。

私が知らないだけで簡単にできる方法あるのかな???

まとめ

「所感」では微妙な点も述べましたが、これらは「慣れ」によって十分に解消可能だと思っています。 実際のところ、私自身は CodePipeline に触れてから3週間以上経ち、当初微妙な点であると感じていたことが気にならなくなっています。 今ではサクサク CD を作れるようになりました。

これから AWS でアプリケーションを構築する方は、選択肢の1つとして検討してみては如何でしょうか? それではありがとうございました。

Appendix