pandasをLambdaのLayerとして追加する

この記事は、[ハンズラボ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/handslab) 12日目の記事です。

先日のAWS:reInventで発表された[LambdaLayers](https://aws.amazon.com/jp/blogs/aws/new-for-aws-lambda-use-any-programming-language-and-share-common-components/)で`pandas`のlayerを作成して、`lambda`から使用していきたいと思います。

# 概要
今までではlambda関数ごとにパッケージし、デプロイしなければいけません。
共通で使用したい関数やライブラリはその都度パッケージの際に`pip`などで入れる必要がありました。
`numpy`や`pandas`といったPure PythonでないライブラリはAmazonLinux環境でインストールしたファイルを使用してパッケージする必要があります。
実際、Lambdaを１つ作成する作業としては手間がかかります。

LambdaLayersにより共通で使用したい関数やライブラリをLayerに設定しておくことで、複数のLambda関数から呼び出すことができます。
すでに`numpy`と`scipy`を使用できるLayerをAWSが公開しています。

# なんかひとつ足りなくね
`numpy`, `scipy`と来たらやっぱり`pandas`でしょ。(個人の意見)
とりあえず`pandas`の依存関係を確認します。

```
  - pandas [required: >=0.15.2, installed: 0.23.4]
    - numpy [required: >=1.9.0, installed: 1.15.4]
    - python-dateutil [required: >=2.5.0, installed: 2.7.5]
      - six [required: >=1.5, installed: 1.11.0]
    - pytz [required: >=2011k, installed: 2018.7]
```
こいつらをzipで固めて`LambdaLayer`にアップロードすればいいわけです。
ちなみに依存関係は`pipdeptree`確認しました。

# zipファイルの作成
最初は`docker`環境でインストールしてzipで固めようと思いましたが、結局EC2インスタンスを作成して行いました。Pythonのバージョンは3.6.5(pyenvでインストール)

1. EC2インスタンスを作成(AmazonLinux)してsshで入る
2. pyenvを入れる([参考](https://qiita.com/rysk92/items/878fddbf23262628d89e))
3. 以下のコマンドを実行

```
$ mkdir python

$ pip install -t ./python pandas
$ zip -r pandas.zip python
```
**<font color="Red">注意点</font>**:AmazonLinux2はなくAmazonLinuxで！(どうやらLambdaはAmazonLinuxで動いてるそうです)

最後に、EC2インスタンスから出て、ローカルから作成した`pandas.zip`を`scp`でローカルにダウンロードすればOK。
また作る機会があると面倒なので[github](https://github.com/thimi0412/lambda_layer_pandas)にあげときました。(これをcloneしてきてもいいです。)

# Layerの作成
AWSのコンソール画面→Lambda→Layersから作成をします。
<img width="1425" alt="スクリーンショット 2018-12-11 17.39.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/ee3acfc5-1d69-8558-a39b-c74bac96b263.png">
名前と説明を書いてzipファイルをアップロードします。

```
10 MB より大きいファイルの場合は、Amazon S3 を使用したアップロードを検討してください。
```
とありますが、10MBを超えていてもアップロードできました。(できない場合はS3にアップロードしてURLを入力してください)
ランタイムはPython3.6で。

# 関数を作成
<img width="1369" alt="スクリーンショット 2018-12-11 17.44.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/c5865d04-a6fc-56d8-8e66-97b260fc4919.png">
Lambdaのコンソール画面から関数を作成します。
ランタイムは先ほど作成したLayerと同じにしてください。ロールについては特別何も使用しないのでなんもでいいです。

## Lambda
<img width="1617" alt="スクリーンショット 2018-12-11 17.50.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/374a2675-7d4e-436e-143a-e753a5ce162d.png">

とりあえず`pandas`で`DataFrame`を作成して出力してみます。

```python
import json
import pandas as pd

def lambda_handler(event, context):
    data = {"year": [2010, 2011, 2012, 2013],
        "pref":["千葉", "山口", "岐阜", "東京"]}
    
    df = pd.DataFrame(data)
    print(df)
    
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

## Layerを追加する
<img width="1618" alt="スクリーンショット 2018-12-11 17.55.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/68b1326c-641d-4269-7e5a-d00fb6850f7a.png">
DesignerにあるLayersをクリックしてLayerを追加します。
<img width="1480" alt="スクリーンショット 2018-12-11 17.54.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/5db2b9d7-b931-3730-04f8-7f52bd54a85f.png">
ランタイムと互換性があるレイヤーのリストから先ほど作成したLayerを選択します。バージョンは最新にします。(初めて作成したら`1`になります)
<img width="1627" alt="スクリーンショット 2018-12-11 17.59.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/7eaaf97b-9fca-53a1-fcf7-8f456b94a525.png">
こんな感じになっていればOK。

# いざテスト
<img width="1564" alt="スクリーンショット 2018-12-11 18.02.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/166626/798562bb-9d78-1784-ce3c-5c734f34dac9.png">
ちゃんと出力されました。

# いろんなことができそう
S3に入ってきたcsvファイルを処理して、S3に置き直したり、MySQLにいれたりといろんなことができそうです。
[ServerlessFlamework](https://serverless.com/)ではすでにLayerのサポートがされているので今回作成した手順より楽かつ早く作成ができるかもしれません。
参考ページ：https://serverless.com/framework/docs/providers/aws/guide/layers/

[ハンズラボ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/handslab) 明日13日目は@sr-mtmtです！