GitHub Actionsを使ってAWS Lambdaへ自動デプロイ (詳説＋デモ手順付きver)

# 前置き

ソースコードの管理をGitHubで行なっているのでCI/CDもGitHubに統一できたら楽だな〜と思って、GitHub Actionsを色々検証したり、実際にステージング・本番環境へデプロイするのに使ったりしています。
そこで今回はAWS Lambdaへの自動デプロイ方法を説明したいと思います。
今回例として使用するデモアプリは[こちら](https://github.com/homoluctus/demo_auto_deploy_lambda)に置いてあります。



# 概要
- CDにはタイトル通りGitHub Actionsを使用
- デプロイには[Serverless Framework](https://serverless.com/)を使う
- ただデプロイするのは簡単なので、GitHubのSecretsからLambdaの環境変数に値をセット


# GitHub Actionsとは

- GitHubのリポジトリ上でビルド、テスト、デプロイなのでCI/CDを完結できる
- CI/CDを実行する環境を選択できる
- jobを並列実行可能 ([制限](https://help.github.com/en/articles/workflow-syntax-for-github-actions#usage-limits)はある)

## Price
![](https://paper-attachments.dropbox.com/s_DCA639A55F40FCDCFD0514BDF2A4CB85E81D84A5C6C057F96CC1E47264626203_1567395766193_+2019-09-02+12.42.33.png)


# 自動デプロイ方法
# GitHub Actions

予めGitHubのSecretsに3つのパラメーターの設定が必要


- **AWS_ACCESS_KEY_ID**
- **AWS_SECRET_ACCESS_KEY**
- **SLACK_WEBHOOK**

これらが設定されていないと失敗するので注意が必要
わざと失敗させてみるのもいいですが...


## イベントトリガー

```..github/workflows/deploy.yml
on:
  push:
    branches:
      - master
```

| パラメーター   | 説明               |
| -------- | ---------------- |
| on       | イベントトリガー         |
| branches | トリガーとなるbranchの制限 |


## Workflow名

```..github/workflows/deploy.yml
name: Auto Deploy to AWS Lambda
```

----------
## Job

```..github/workflows/deploy.yml
jobs:
  deploy:
    name: Auto Deploy
    runs-on: ubuntu-18.04
    steps:
```

| パラメーター  | 説明                                                                                                                                           |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| name    | jobの名前                                                                                                                                       |
| runs-on | 環境を設定(ubuntu, macos, windows)<br>[サポートしているバージョン一覧](https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idruns-on) |
| steps   | 実際の処理を定義                                                                                                                                     |


## Steps

**最新コミットにチェックアウト**

```..github/workflows/deploy.yml
- uses: actions/checkout@master
```

| パラメーター | 説明                                                                                         |
| ------ | ------------------------------------------------------------------------------------------ |
| uses   | 使用するactionを宣言<br>[GitHub Actions Marketplace](https://github.com/marketplace?type=actions) |


**Node.jsのセットアップ**

```..github/workflows/deploy.yml
- name: Setup Node.js
  uses: actions/setup-node@v1
  with:
    node-version: '10.x'
```

| パラメーター | 説明                                                                                                                                |
| ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| with   | 引数を渡す<br>何を引数として渡せるかは、[actions/setup-nodeのaction定義ファイル](https://github.com/actions/setup-node/blob/releases/v1/action.yml)に書かれている |


**依存パッケージのインストール**

```..github/workflows/deploy.yml
- name: Install Dependencies
  run: |
    npm install serverless -g
    npm install
```

| パラメーター | 説明      |
| ------ | ------- |
| run    | コマンドの実行 |

**Lambdaへデプロイ**

```..github/workflows/deploy.yml
- name: Deploy to Lambda
  run: sls deploy
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

| パラメーター | 説明      |
| ------ | ------- |
| env    | 環境変数の定義 |

**Invoke Lambda**

```..github/workflows/deploy.yml
- name: Execute Lambda
  run: sls invoke -f slack
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

**jobの成否をSlackへ通知**

```..github/workflows/deploy.yml
- name: Notify result to slack
  uses: homoluctus/slatify@master
  if: always()
  with:
    type: ${{ job.status }}
    job_name: '*Deploy Lambda*'
    env:
      SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

| パラメーター | 説明              |
| ------ | --------------- |
| if     | jobの状態によって分岐できる |


slackの通知例

![](https://paper-attachments.dropbox.com/s_DCA639A55F40FCDCFD0514BDF2A4CB85E81D84A5C6C057F96CC1E47264626203_1567389716887_+2019-09-01+14.37.58.png)


何らかのjobが失敗した時にはサイドバーの色が緑色から赤色に変わる
リンクからGitHub Actionsの実行結果画面にとべるようになっているのですぐに原因を調べることができる


## 完成形

```..github/workflows/deploy.yml
on:
  push:
    branches:
      - master

name: Auto Deploy to AWS Lambda

jobs:
  deploy:
    name: Auto Deploy
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@master

      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: '10.x'

      - name: Install Dependencies
        run: |
          npm install serverless -g
          npm install

      - name: Deploy to Lambda
        run: sls deploy
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

      - name: Execute Lambda
        run: sls invoke -f slack
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

      - name: Notify result to slack
        uses: homoluctus/slatify@master
        if: always()
        with:
          type: ${{ job.status }}
          job_name: '*Deploy Lambda*'
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

# Serverless Framework

SlackのIncoming WebhookのURLをホストの環境変数から取得

```serverless.yml
service: auto-deploy-lambda
provider:
  name: aws
  region: ap-northeast-1
  timeout: 120

  environment:
    SLACK_WEBHOOK: ${env:SLACK_WEBHOOK}

package:
  exclude:
    - Dockerfile
    - docker-compose.yml

functions:
  slack:
    handler: src/index.post
    description: "Post message to Slack"
    timeout: 60
```


正常に実行されれば以下のような通知がLambdaからSlackへとんでくる


![](https://paper-attachments.dropbox.com/s_DCA639A55F40FCDCFD0514BDF2A4CB85E81D84A5C6C057F96CC1E47264626203_1567389696955_+2019-09-01+14.34.27.png)


# 本番運用のためのTips

- Secretsはドキュメントに残すべし
    - 後からSecretsの中身は見れないので、忘れたらやばい :scream_cat:
- 現段階ではキャッシュが使えないので、job間で極力依存関係をなくすようにする

# Let’s Demo

デモ用のアプリは[こちら](https://github.com/homoluctus/demo_auto_deploy_lambda)


# 自動デプロイ
## 手順
1. [デモリポジトリ](https://github.com/homoluctus/demo_auto_deploy_lambda)のUse this templateからPrivateリポジトリを作成
2. GitHubのSecretsにAWSの認証データとSlackのIncoming Webhooks URLをセット
3. **.github/workflows/deploy.yml**をアンコメント
4. 必要に応じて**serverless.yml**を編集
5. git commit
6. git push origin master
7. GitHub Actionsが起動される
8. デプロイされるまで待機 (暫しご歓談) 🗣️
9. Slackに通知が来る

# 自動削除
## 手順
1. **github/workflows/remove.yml**をアンコメント
2. git commit
3. git push origin master:remove
4. GitHub Actionsが起動される
5. 削除されるまで待機 (暫しご歓談) 🗣️
6. Slackに通知が来る

# Appendix
## Reference
- [Features | GitHub Actions](https://github.com/features/actions)
- [About GitHub Actions](https://help.github.com/en/articles/about-github-actions)
- [Workflow syntax for GitHub Actions](https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idruns-on)