AWS Lambdaのアプリケーション作成を使ってCI/CDパイプラインを一気に構築

<img width="720" alt="Source-Build-Deploy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/c1fdb7d2-e485-61d7-b5ac-0ee48e2d18b2.png">

# AWS Lambdaのアプリケーション作成とは

AWS Lambdaのアプリケーション作成機能を利用してLambda関数を作成すると、Lambda関数自体の他に

- Lambda関数のソースコード等を管理するGitリポジトリとしてCodeCommit

- CodeCommitのmasterブランチの更新を契機にLambda関数へのデプロイを行うCodePipeline

等々、CI/CDパイプライン実現のためのAWSリソースが同時に作成されます。

Lambda関数自体は手軽に作ったものの、次のステップとしてCI/CD環境を構築するのは腰が重く、ソースの更新はマネジメントコンソール上で実施している・・・といったケースを改善するアプローチとして、このようなCI/CD環境をセットで構築する機能がリリースされたそうです。

Lambdaのマネジメントコンソール画面では、これらAWSリソースを**アプリケーション**という単位で取り扱います。

(実際には、CloudFormation(以下、CFn)によって作成されており、CFnの画面からも作成されたスタックが確認できます)

なお、利用可能なランタイムは現時点ではNode.js 10.xに限定されており、GoやPython等は使えません。

# 実際に使ってみる

本記事では、このアプリケーション作成機能を使い、Lambda関数とCI/CDパイプラインを構築します。

そしてLambda関数に対して、簡単な機能(今回はオウム返しLINE Botとします)を、CI/CDパイプラインを通じてデプロイしてみます。

## アプリケーションの作成へ進む

マネジメントコンソールのLambdaの画面から、**アプリケーションの作成**を押します。

<img width="900" alt="Lambda画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/8759fd07-7567-363f-1b48-365902088c9a.png">

## サンプルアプリケーションを選択するか、一から作る

すると、いくつかのサンプルアプリケーションが表示されます。

<img width="780" alt="サンプルアプリケーションの選択画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/9cfba88d-784f-5e25-4596-147d16a741b3.png">

例えば、一番左上の`Serverless API Backend`の場合、API Gateway + Lambda * 3 + Dynamo DBで構成されるサンプルアプリケーションとなります。

今回は、Lambda + API Gatewayのシンプルな構成を作成したかったので、一番右下にある**一から作成**を選択しました。

<img width="830" alt="一から作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/ac6667fb-7229-c2b9-5496-84a82b5e7088.png">

## アプリケーションの設定

続いて、アプリケーションの設定を行います。

今回は、LineBotを作成しようと思うので、アプリケーション名は`nodejs-linebot`にします。

ランタイムは、Node.js 10.xしか選択できないので、これを選択します。

<img width="620" alt="アプリケーションの詳細と関数の設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/0ee7ffb5-fd6f-1f06-a06e-9171b7aa841d.png">

また、ソース管理を行うGitリポジトリをCodeCommitとGitHubから選択します。

今回はシンプルにAWSで完結可能となるよう、GitHubではなくCodeCommitを選択しました。

リポジトリ名入力後、最後にアクセス権限に関するチェックボックスにチェックを入れて、**作成**を押します。

<img width="620" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/04d03a3a-1618-efc8-4216-b70eb8724d5e.png">

Lambdaアプリケーション作成のための操作としては、たったこれだけです。

## アプリケーションの作成開始

**作成**を押した後は、作成中のアプリケーション画面へ遷移します。

<img width="656" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/1788a13e-ff8e-fd45-ce46-e9fe77abfe4f.png">

裏では、CFnにより各リソースが作成されています。

作成完了まで数分かかるので、その間はEric Johnsonさんの解説動画を見るなどして完了を待ちましょう。

## アプリケーションの作成完了

CFnによる各リソースの作成が完了すると、Lambdaアプリケーション画面の下の方に作成されたAWSリソースが表示されます。

Lambdaアプリケーションでは、リソースとインフラストラクチャという2つのカテゴリに分けてAWSリソースが作成されています。

<img width="693" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/d1e3942e-52b6-4bc9-2d74-6e53546019b3.png">

一方、CFnの画面を見ると、2つのスタックが作成されています。

<img width="575"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/4cede736-c4b4-aed9-fbb3-1c76ed0bada9.png">

- 前述のリソースは、Lambdaアプリケーション名そのままの`nodejs-linebot`スタック

- 前述のインフラストラクチャは、もうひとつの`serverlessrepo-nodejs-linebot-toolchain`スタック

によって作成されたものとなります。

## Lambda関数を確認する

Lambda関数も画面から確認してみます。

ディレクトリ、ファイル構成は以下の通りとなっています。

サンプルのJavaScriptの`hello-from-lambda.js`のほか、CodeBuildに必要な`buildspec.yml`などが作られていることがわかります。

```
.
├── LICENSE
├── README.md
├── __tests__
│   └── unit
│       └── handlers
│           └── hello-from-lambda.test.js
├── buildspec.yml
├── package.json
├── src
│   └── handlers
│       └── hello-from-lambda.js
└── template.yml
```

Lambda関数名については、

- nodejs-linebot-**helloFromLambdaFunction**-...

といった具合に、サンプルソースの`hello-from-lambda.js`を引きずった名前になりました。

<img width="728" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/b49c9f8c-1177-2c83-5246-352e34c9ba56.png">

## CodePipelineを通してデプロイする

では、このLambda関数にLINE Botの機能をデプロイしてみます。

### LINE Botを動かすための準備

LINE Botを動かすための準備を先に行います。

デプロイそのものとは関係が無いので、折りたたみセクション化しておきます。

<details><summary>API Gatewayの作成 〜 LINEチャネルの作成 〜 Lambda関数の環境変数設定</summary><div>

#### API Gatewayの作成

Lamda関数の画面から**トリガーの作成**を押し、以下の通りAPI Gatewayを作成します。

<img width="723" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/59c8e885-5dbd-1dcb-4a93-6cd7a670ba48.png">

#### LINEチャネルの作成

LINEチャネルの作成方法の詳細は本記事では割愛しますので、以下記事、サイトなどを参考にしてください。

- [1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest - Qiita](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)

- [LINE Developers](https://developers.line.biz/ja/docs/messaging-api/getting-started/)



その際、先ほど作成したAPI Gatewayのエンドポイントを、LINEチャネルのWebhook URLに設定してください。

#### Lambda関数への環境変数の設定

LINEチャネルの基本設定画面で表示されているアクセストークンとChannel SecretをそれぞれLamdaの環境変数`ACCESS_TOKEN`, `CHANNEL_SECRET`に設定します。

<img width="794" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/115bc8c8-5ae7-2027-f3d6-309393e5704b.png">

*折りたたみセクションここまで*
</div></details>

### CodeCommitのリポジトリをローカルにgit cloneする

今回、CodeCommitにはSSHで接続して、git cloneすることにします。

SSH接続のための準備は以下を参照してください。こちらもデプロイそのものとは関係無いので、折りたたみセクション化しておきます。

<details><summary>git cloneするまでのSSH接続の準備</summary><div>

#### SSH接続の準備を行う

SSHの公開鍵、秘密鍵を作成します。

```
$ cd ~/.ssh
$ ssh-keygen -t rsa -b 2048 -f code-commit-key -m pem
```

作成された公開鍵をIAMユーザーの`AWS CodeCommitのSSHキー`に対してアップロードします。

<img width="759"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/399ec0d5-c0c4-ce85-54e0-8c0634fef4b8.png">

SSHのconfigファイルを編集します。

```
$ vi ~/.ssh/config
```

```
Host git-codecommit.*.amazonaws.com
  User APxxxxxxxxxxxxxxxxxx
  IdentityFile ~/.ssh/code-commit-key
```

*折りたたみセクションここまで*
</div></details>

#### git cloneする

ソースコードを編集するため、CodeCommitのリポジトリをローカルにgit cloneします。

```
$ cd (ローカルでソース管理するディレクトリ)
$ git clone ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/nodejs-linebot
```

### ローカルで必要なライブラリをインストールしてソースを編集する

Line BotのSDKをインストールし、オウム返しを行う`index.js`を作成します。

```console
$ cd nodejs-linebot
$ npm install @line/bot-sdk
```

```js:nodejs-linebot/index.js
const crypto = require('crypto');
const line = require('@line/bot-sdk');
const client = new line.Client({
  channelAccessToken: process.env.ACCESS_TOKEN,
  channelSecret: process.env.CHANNEL_SECRET,
});

exports.handler = function (event, context, callback) {

  // 署名の検証
  const signature = crypto.createHmac('sha256', process.env.CHANNEL_SECRET).update(event.body).digest('base64');
  if (signature !== event.headers['X-Line-Signature']) {
    callback(
      null,
      {
        statusCode:404,
        body: '{"Error": "Invalid Signature"}'
      },
    );
    return;
  }

  // オウム返し
  const body = JSON.parse(event.body);
  client.replyMessage(
    body.events[0].replyToken,
    {
      type: 'text',
      text: body.events[0].message.text,
    },
  );
};
```

### CodeCommitにpushしてCI/CDパイプラインを開始する

```console
$ git add .
$ git commit -m "feature/Line Bot"
$ git push
```

CodePipelineの画面を確認すると、CodeCommitの更新、CodeBuildによるビルドが順次完了していくことが確認できます。

<img width="634"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/addf11f1-127e-36e9-9311-aa43ebbe95aa.png">

さらに、しばらく待つとデプロイも完了しました。

<img width="632" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/e20d78d6-97d7-75e6-72fd-706772c78301.png">

### Lambda関数を確認する

Lambda関数を見ると、`index.js`を含むファイルがデプロイされていることが確認できます。

ハンドラを`index.handler`に変更して、**保存**を押します。

<img width="955" alt="Lambda関数を確認する" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/8db743b2-5781-fc24-083b-586908bde2ff.png">

### LINE Botの動作確認を行う

LINE Botにメッセージを送ります。無事、オウム返しでメッセージが返ってきました！

<img width="375" alt="LINE Botの動作確認を行う" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/f99e1f04-1236-b03e-5993-ef83dc72607d.jpeg">

# 最後に

非常に簡単にLambda関数とセットでCI/CDパイプラインが構築できてしまいました。

今回は取り扱いませんでしたが、GitHubでソースは管理し、CircleCI経由でCodePipelineに連携してデプロイする、といったパイプラインも構築できるかと思います。

今後、Node.js以外にも対応してくれることを期待したいと思います。

# 補足:Lambdaアプリケーションを削除するには

さて、このLambdaアプリケーションを削除する場合はどうするかというと、少しクセがあります。

マネジメントコンソールのLambdaアプリケーション画面から、該当のアプリケーションを選択、削除すればCFnのように関連する全てのAWSリソースを削除してくれる・・・というわけではありません。

<img width="786" alt="Lambdaアプリケーション画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/a5b530e2-6803-a92b-8c96-63c1bc47b3f9.png">

削除を選択すると、以下のダイアログが表示されます。

<img width="803" alt="Lambdaアプリケーションを削除" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/240c6943-9a23-8985-6343-542d83385790.png">

これによると、以下の手順でAWSリソースを削除する必要があります。

1. アプリケーションスタックを削除する
2. デプロイパッケージを保存しているS3バケットを削除する
3. **1の削除完了後に**ツールチェーンスタックを削除する(**先に3を実施すると1を実施できなくなる**)

アプリケーションスタックというのは、今回の記事で言うと、CFnの画面に表示されていた`nodejs-linebot`スタックのことで、ツールチェーンスタックはもうひとつの`serverlessrepo-nodejs-linebot-toolchain`スタックのことになります。

<img width="575" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/4cede736-c4b4-aed9-fbb3-1c76ed0bada9.png">

アプリケーションの削除については、このような制約事項があるので注意してください。

# 参考

- [新しいサーバーレスアプリ作成機能で CI/CD も作れます - AWSブログ](https://aws.amazon.com/jp/blogs/news/new-serverless-app-creation-with-cicd/)

- [LambdaではじめてのLINE Botを作る - Developers.IO](https://dev.classmethod.jp/etc/lambda-line-bot-tutorial/)

- [1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest - Qiita](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)