serverless framework をつかったデプロイをwerckerで自動化する

# はじめに

- Serverless Frameworkを利用してAWS Lambdaの関数をpythonで開発しています。
- 機能実装するたびにデプロイするのが面倒だったので、CIサービスであるWerckerを使って自動化したときのメモとなります。

# AWS LambdaのFunctionデプロイ

- 何も考えずにデプロイしようとすると、ローカル環境で開発したコード群をzipファイルにアーカイブしてAWSのコンソールからアップロードする感じになります。
- デプロイ以外にもテスト実行など色々と面倒なので、多くの人が**Serverless Framework**を利用していると思います。

# Serverless Frameworkを利用したデプロイ

- [Serverless Framework](https://serverless.com/)はサーバレス環境でのAPIやFunctionの開発をいいかんじにサポートしてくれるライブラリです。
- デプロイも以下のようなコマンドでコードのアーカイブとアップロードから設定変更までもろもろやってくれます。

```bash
 sls deploy --stage prd
```

- これだけでも十分に便利なのですが、毎回ローカル環境で手動でこのコマンドを実行する必要があります。
    - もしくは、デプロイするのを忘れてしまっていたり。。

# Werckerを利用した自動デプロイ

- ぼくらの会社ではCIツールに[Wercker](http://www.wercker.com/)を利用しています。
- 他のwebアプリケーションではプロツールに[deployer](https://deployer.org/)を利用していて、githubのmasterブランチにマージされるとWercker上でビルド、テスト、サーバへのデプロイを自動実行するようにしています。
- LambdaのFunctionも同様にmasterブランチにマージで自動でデプロイされるようにします。

## 設定

- Dockerイメージ
    - Wercker上で実行されるDockerイメージは、テストコードの実行もあるのでLambdaの実行環境と同じであることが望ましいです。
    - [lambci/docker-lambda](https://github.com/lambci/docker-lambda)というLambda用Dockerイメージがあるのでこれを利用します。
- デプロイ実行
    - slsのコマンドを直接実行するように設定してもよいのですが、werckerには[Steps Marketplace](https://app.wercker.com/steps/search/)というものがあり、自分で作ったstepを公開してだれでも利用することが出来る環境があります。
    - [こちらに](https://app.wercker.com/steps/ajagnanan/serverless)公開されているstepがそのものズバリだったので利用させて頂きます。
- 設定内容
    - 上記の内容を以下のように設定に反映させます。

```yaml:wercker.yml
box: lambci/lambda:build-python3.6

build:
  steps:
    - script:
        name: run test
        code: |
          pip install -r requirements.txt
          $WERCKER_SOURCE_DIR/bin/run_test
deploy:          
  steps:
    - script:
        name: install node
        code: |
          sudo yum install -y gcc-c++ make
          curl -sL https://rpm.nodesource.com/setup_6.x | sudo bash -
          yum install -y nodejs
    - script:
        name: npm install
        code: |
          npm install
    - ajagnanan/serverless:
        task: "deploy"
        region: ap-northeast-1
        stage: prd

```

# その他
## テスト実行

- 今回の記事とは直接関係ないですが、以下のようなシェルスクリプトを用意して全てのテストコードを実行できるようにしています。
    - テストコードは`test_*.py`のような名前にしいて、この名前のテストコードが全て実行されます。
    - 上記のwercker.ymlの`$WERCKER_SOURCE_DIR/bin/run_test`で実行するようにしています。

```shell:run_test
#!/usr/bin/env python
import sys
import os
import unittest

sys.path.append(os.getcwd())


def suite():
    test_suite = unittest.TestSuite()
    all_test_suite = unittest.defaultTestLoader.discover(
        "test", pattern="test_*.py")

    print(all_test_suite)

    for ts in all_test_suite:
        test_suite.addTest(ts)
    return test_suite


if __name__ == "__main__":
    suite = suite()
    unittest.TextTestRunner().run(suite)
```

## python実行に必要なモジュールの管理

- [Serverless Python Requirements](https://github.com/UnitedIncome/serverless-python-requirements)というServerless Frameworkのプラグインを利用して、python実行に必要なモジュールの管理を行っています。
- このプラグインの機能で以下のように設定をおこなっておくと、デプロイコマンド実行時に、OSに依存するようなモジュールはLambda用Dockerイメージをダウンロードしてきてその中でビルドしてデプロイしてくれます。

```yml

  pythonRequirements:
    dockerizePip: true
```
- ただし、この設定のままだとwercker上でも同様の動きになってしまうので、環境にあわせて設定を変えられるようにしておきます。
    - 本番環境のデプロイ時のみ上記の設定をfalse(実行されない)にします。
- serverless.ymlに以下のような記述をして環境ごとに設定ファイルを作ります。

```yaml:serverless.yml

custom:
  otherfile:
    environment:
      lcl: ${file(./conf/lcl.yml)}
      dev: ${file(./conf/dev.yml)}
      prd: ${file(./conf/prd.yml)}
```

- prd.ymlファイル(本場環境用の設定ファイル)に以下のように記述します。

```yaml:prd.yml
DOCKERIZE_PIP: false
```
- serverless.ymlの該当する箇所を以下のように設定します。

```yaml:serverless.yml

pythonRequirements:
  dockerizePip: ${self:custom.otherfile.environment.${self:provider.stage}.DOCKERIZE_PIP}

```

- 開発環境などでは`true`にしておくことでローカルでデプロイ実行する際にはこの機能が有効になるようにします。

# 最後に

- AWS Lambdaはとても便利なので、色々な用途で利用していますが、一番面倒なのがテストとデプロイだと思います。
- 上記の方法で、このあたりを他のwebアプリケーションと同じように自動実行化できるのでとても便利です！