CI/CDやってみた① Serverless FrameworkとCodeBuildを使ってlambda functionを作る

CI/CDの勉強をするために、超簡単なアーキテクチャを作ってみました。

# 今回作るもの
以下がアーキテクチャです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950855/6420c696-b445-5501-034f-81f00e667395.png)
CodeBuildとServerless Frameworkを使用してCI/CDを作っています。



# GitHubでrepositoryを作る
適当なGitHub repositoryを作成します。
今回は全てのファイルをここで作成します。
CodeCommitでもいいのですが，GitHubでも大丈夫です。

# CodeBuildでbuild projectを作る
マネコンから作成します。
設定内容は以下の通りです。
## Source

### Source provider 
今回はGitHubを選択します。
### Repository
先ほど作成したRepositoryを選択します。

### Source version
今回作業するブランチを設定します。
`main`でも`feature/serverless`でも何でも大丈夫です。
このブランチにpushしたファイルがCodeBuildに使われます。


## Environment
**Managed image**をチェックして，以下の設定を行います。
ほぼデフォルトにしました。
### Operationg system
aws/codebuild/amazonlinux2-x86_64-standard:4.0
### Service role
CodeBuild専用のRoleを作成したあと，選択しました。
`AdminstratorAccsess`を付与してあります。
詳細)
[AWSジョブ機能の 管理ポリシー - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_job-functions.html)


## Buildspec
**Use a buildspec file**にチェックします。
今回はマネコンからではなく，`buildspec.yml`のファイルからから設定するためです。

以上でCodeBuildの作成は終わりです。

# buildspec.ymlの作成
GitHubレポジトリのrootに作成します。

```yml:buildspec.yml
#buildspecのバージョンを指定する
version: 0.2 

#ビルドの各段階で実行するコマンドを書いていく
phases: 
  install:
    commands:
      - npm install -g serverless #serverlessをインストールする
  build:
    commands:
      - sls deploy               #serverless.ymlの内容をdeployする
      - echo 'deploy finished!'
      - sls invoke -f hello --log
```

## パラメータの説明

`version`: buildspecのバージョン。特に理由がなければ0.2を指定する。
- ちなみに存在するのは0.1と0.2だけです。（2023/5現在）
- [CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-versions)


`phases`: ビルドの各段階でCodeBuildが実行するコマンドを指定する。

- `install`/ `pre_build`/ `build` / `post_build`の4段階の設定ができます。
- `commands`で具体的なコマンドを指定します。上から順番に実行されていきます。


buildspec.ymlでは`sls deploy`だけを行います。
AWSリソースの中身は`serverless.yml`で設定するのがミソです。
（今回はlambdaなので`sls invoke`も必要です。これをやらないとdeployはされてもログにHello Worldが出ません。）



# serverless.ymlの作成
GitHubレポジトリのrootに以下のようなファイルを作成します。

```yml:serverless.yml
# serverless frameworkのサービス名（プロジェクト名）を設定する
service: serverless-lambda-helloworld

provider:
  name: aws #基本AWSで固定
  runtime: python3.9
  stage: dev 


functions:
  hello:
    handler: handler.hello
```
## パラメータの説明
`service`: Serverless Frameworkのサービス名/プロジェクト名です。

`provider`:クラウドサービスの設定を行います。
- `name`:クラウドサービスを指定します。
 AWSの他にGCP,Azureなども指定できます。

- `runtime`: 言語とそのversionを指定します。
lambda functionのruntimeの設定をここで行います。

- `stage`:  stageを設定します。default値は`dev`です。


`functions`:lambda functionの設定を行います。
helloはfunctionの名前です。
- `handler`で呼び出す関数を指定します。
- - 今回は`handler.py`の`def hello()`を呼び出したいので`handler.hello`と書きます。
- - 別な例）`main.py`の`def hogehoge()`の場合，`main.hogehoge`と書きます。


もちろん、2個以上のfunctionを作ることもできます。
[Serverless Framework - AWS Lambda Functions](https://www.serverless.com/framework/docs/providers/aws/guide/functions)




# handler.pyの作成
lambda functionの設定を書きます。
通常のlambdaと同様なので説明は割愛します。
```python:handler.py
import json


def hello(event, context):
    body = {
        "message": "Hello World! From serverless!",
        "input": event,
    }
    # print("Hello World! From serverless") printだとnullになった
    return {"statusCode": 200, "body": json.dumps(body)}
```

# buildを実行する
マネコンから実行します。
先ほど作成したCode Buildの画面から`start build`をクリックすると実行されます。

CodeBuildのログにHelloWorldの文字が現れるはずです！

# 参考情報

- [CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html)
- [【初心者必見】Serverless FrameworkでAWS環境作りたいやつはこれを参考にしろ！ - サーバーワークスエンジニアブログ](https://blog.serverworks.co.jp/2021/03/23/182829)
- [Serverless Framework - AWS Lambda Guide - Serverless.yml Reference](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml)
- [Serverless Framework - AWS Lambda Functions](https://www.serverless.com/framework/docs/providers/aws/guide/functions)
- [Serverless Framework 素振り - ngyukiの日記](https://ngyuki.hatenablog.com/entry/2020/07/08/222402)
- [examples/aws-python at v3 · serverless/examples](https://github.com/serverless/examples/tree/v3/aws-python)