ローカル環境からAWS Lambdaにデプロイする（with Npm）

Node.jsのモジュールをAWS Lambdaにデプロイしているのですが、

- ソースを修正する
- エクスプローラ上でソースファイルとnode_modulesをzipファイルに圧縮する
- AWS 管理コンソールからアップロードする

と、ダサい方法を取っています。

**「コマンド一回叩けばアップロードしてくれる」**くらいのことはしたいなと思い、ローカル環境からAWSへモジュールをアップロードする仕組みを整理しました。

なおLambda関数はマネジメントコンソールから作成されていることが前提です。

# 前提環境
- Windows10（ローカル端末）
- ~~Windows Power Shell（デプロイ用のスクリプト）~~
- Python3（デプロイスクリプト）
- Npm（パッケージ管理）
- Node.js（Lambdaの実行環境）

~~私の開発環境がWindowsだったのでデプロイ用のスクリプトをPower Shellで作りましたが、Shell Scriptでも代用可能なはずです。~~
→どの環境でも実行できるようにデプロイスクリプトはPythonにしました。

パッケージ管理はNpmじゃなくても大丈夫ですが、今回は`npm run deploy`でデプロイできるようにします。

# AWS CLIのインストール（事前準備）
事前準備としてAWS CLIをインストールと認証情報を設定します。AWS CLIはコマンドラインからAWSに関する各種操作を行うためのものです。

なおAWS CLIの利用にはPythonが必要でが、ここでは手順を省略します。

## インストール
`pip` でインストールします。

```powershell
$ pip install awscli
```

正常にインストールできれば `aws-shell` でコンソールが起動します。

```powershell
$ aws-shell
Creating doc index in the background. It will be a few minutes before all documentation is available.
aws>
```

## 認証情報の設定
`aws configure` で認証情報を設定します。

```powershell
$ aws configure
AWS Access Key ID [******************]: # アクセスキー
AWS Secret Access Key [*******************]: # アクセスシークレット
Default region name [ap-northeast-1]: # デフォルトのリージョン
Default output format [None]: # awscliコマンドの実行結果の出力形式
```

「アクセスキーってなんぞや」という方はこちらをどうぞ。
[アクセスキーの生成](https://aws.amazon.com/jp/developers/access-keys/)

# ローカル環境からデプロイ
## デプロイまでの流れ
こんな感じでデプロイしてみます。

- `npm run deploy` を実行
- 対象のファイルをZipファイルに圧縮
- AWS LmabdaへZipファイルをアップロード

## プロジェクト構成
こんな感じです。

```shell
projectroot
├─deploy
|  ├─deploy.properties # デプロイ時の設定
|  └─deploy.py # awscliとかを実行する
└─src # npmのルート
   ├─node_modules 
   ├─package.json 
   └─index.js
```

## デプロイファイルの準備
デプロイのためのファイルを準備します。

`src/package.json`のscriptsに`deploy`を追加してデプロイ用スクリプトを起動します。

```json:src/package.json
{
　"name": "tweetbyalexa",
  "version": "1.0.0",
……
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "deploy": "python ../deploy/deploy.py"
  },
……
}
```
<br/>
`deploy.properties`にはターゲットとなるLambda関数名とリージョンを設定してみました。

```properties:deploy/deploy.properties
region=ap-northeast-1
function=TweetByAlexaForAccountLink
```
<br/>
`deploy/deploy.py` は、既にあるZipファイルを削除してZipファイルを再作成し、awscliでアップロードするだけです。

```python:deploy/deploy.py
# -*- coding:utf-8 -*-
import zipfile
import os
import configparser
import shutil

DEPLOY_DIR='../deploy' #npm実行場所（src）からの相対パス
BUILD_FILE_PREFIX='skill'
BUILD_FILE_NAME=os.path.join(DEPLOY_DIR,BUILD_FILE_PREFIX+'.zip')
TARGET_SOURCE_DIR='./'

if os.path.exists(BUILD_FILE_NAME):
    os.remove(BUILD_FILE_NAME)

shutil.make_archive(os.path.join(DEPLOY_DIR,BUILD_FILE_PREFIX),'zip',root_dir=TARGET_SOURCE_DIR)

config = configparser.ConfigParser()
config.read(os.path.join(DEPLOY_DIR,'deploy.properties'))

aws_cmd = "aws lambda update-function-code --region " + \
            config['setting']['region'] +" --function-name " + \
            config['setting']['function'] + " --zip-file fileb://" + BUILD_FILE_NAME
os.system(aws_cmd)
```
<br/>
`deploy.properties`で設定した値を、`aws lambda` の `--region` と `--function-name` に渡しています。

## デプロイ実行
これで `npm run deploy` を実行すれば、晴れてローカル環境からコマンド一発でデプロイできるようになりました！

```powershell
$ npm run deploy

> tweetbyalexa@1.0.0 deploy C:\project
> @powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./deploy.ps1

{
    "FunctionName": "TweetByAlexaForAccountLink",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789101234:function:TweetByAlexaForAccountLink",
    "Runtime": "nodejs6.10",
    "Role": "arn:aws:iam::12345678910:role/lambda_basic_execution",
    "Handler": "index.handler",
    "CodeSize": 6468036,
    "Description": "",

    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2018-05-12T16:31:32.803+0000",
    "CodeSha256": "aNdfdsjOJGDfsljaggat;l6+gjad78aSJGDKL=",
    "Version": "$LATEST",
    "VpcConfig": {
        "SubnetIds": [],
        "SecurityGroupIds": [],
        "VpcId": ""
    },
"Environment": {
        "Variables": {
            "CONSUMER_KEY": "***********************",
            "CONSUMER_SECRET": "************************"
        }
    },

    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "12dsgatajl-1Dfaga-3333-8gad8-dda785902398"
}
```

正常にデプロイされると結果がコンソールに出力されます。

<br/>
<br/>
以上、AWS Lambdaにローカル環境からデプロイするための非常にシンプルな方法でした。

awscliが使えればあとはいかようにでもできますね。プロパティファイルを用意せずにリージョンや関数名は引数で渡す、などでも良いかなと思います。