Amazon Linuxコンテナイメージは AWS Lambda ネイティブライブラリ(.so)問題を解決するし財布にも優しい

全世界が泣いた！Amazon Linux Container Image！
================

> New Amazon Linux Container Image for Cloud and On-Premises Workloads | AWS Blog
https://aws.amazon.com/jp/blogs/aws/new-amazon-linux-container-image-for-cloud-and-on-premises-workloads/

ついに手元に Amazon Linux が！！！

AWS Lambda でネイティブライブラリ(.so)を参照するpythonパッケージをベンダリングするのに使ってみる
================

Amazon Linux Container Imageを使えば
今までネイティブライブラリ(.so)を使うpythonパッケージを作るのに
EC2でAmazon Linuxを起動して作ってたところの手間が減る！
お財布にも優しい！

準備
---------------

### コンテナイメージを pull しておく

> Amazon Linux Container Image - Amazon ECR
> http://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html

を参照。

確認してみる。

```
$ docker run -it 137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest cat  /etc/system-release
Amazon Linux AMI release 2016.09
$
```

確かにAmazon Linux! (感涙)


### サンプルプログラム

lambdaの中で持っている画像をリサイズして
/tmp/ に出力して
lambdaの中に置きっぱなしで終了する
意味のないプログラムです。
Serverless Framework v1です。

https://github.com/imura81gt/lambda-and-amazon-linux-container/tree/qiita

各種ファイルについて補足すると

#### 一覧

```
$ tree -FL 1 test/
test
├── Dockerfile  # Amazon Linuxコンテナ
├── event.json  # ServerlessFramework
├── handler.py  # ServerlessFramework
├── lena_std.tif # 画像ファイル
├── requirements.txt # pipでインストールするパッケージ(pip freeze >> requirements.txt)
├── serverless.yml  # ServerlessFramework
├── setup.cfg  # Amazon LinuxにPillowをインストールするのに必要だった
└── yum.list # Pillowをインストールするのに必要なyum repo管理のパッケージ

1 directory, 8 files
```


#### Dockerfile

```
FROM 137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest

RUN mkdir /app

WORKDIR /app

# lambdaは python2.7で動く
RUN yum install python27 python27-pip python27-devel python27-libs gcc  -y

ADD . .
# pipでインストールするパッケージが依存しているモノは yum.list に書いとく
# ONBUILD RUN とかにすればよかったかも
RUN yum install $(echo $(cat yum.list)) -y

CMD pip install --no-cache-dir -r /app/requirements.txt -t /app/vendor
```

NGパターン :bomb: ネイティブライブラリを使うpythonパッケージをOSX上でpipインストールしたら…
---------------

まちがって OSX 上で pip install したモノをそのまま Lambda にアップロードしたら…

```
$ cd test
$ # OSXやCentOS上で pip install した
$ # ネイティブライブラリを使うパッケージ
$ # (ex.Pillow)はLambda上では動かない。
$ pip install -r requirements.txt -t vendor/
$ $(npm bin)/sls deploy
$ $(npm bin)/sls invoke -f hello
```

エラーが出る

```
{
    "errorMessage": "Unable to import module 'handler'"

}
```

ログを見ると

```
$ $(npm bin)/sls logs -f hello
```

`Unable to import module 'handler': /var/task/vendor/PIL/_imaging.so: invalid ELF header` と出てます。

```
START RequestId: fea3d675-a59c-11e6-9977-9db5192e5233 Version: $LATEST
Unable to import module 'handler': /var/task/vendor/PIL/_imaging.so: invalid ELF header

END RequestId: fea3d675-a59c-11e6-9977-9db5192e5233
REPORT RequestId: fea3d675-a59c-11e6-9977-9db5192e5233	Duration: 0.24 ms	Billed Duration: 100 ms 	Memory Size: 1024 MB	Max Memory Used: 32 MB
```

OKパターン:star: Amazon Linux Contaier Imageを使う
-----------

Amazon Linux Container Images をpullしておく
http://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html


```
$ cd test
$ rm -rf vendor/
$ docker build . -t amazon-py
$ docker run -it -v $(pwd)/vendor:/app/vendor:rw -t amazon-py
$ $(npm bin)/sls deploy
$ $(npm bin)/sls invoke -t hello
```

実行結果は

```
null
```

ログにもエラーなし

```
$ $(npm bin)/sls logs -f hello
```

```
START RequestId: e9003709-a59e-11e6-b541-0f7fe552a859 Version: $LATEST
END RequestId: e9003709-a59e-11e6-b541-0f7fe552a859
REPORT RequestId: e9003709-a59e-11e6-b541-0f7fe552a859	Duration: 169.37 ms	Billed Duration: 200 ms 	Memory Size: 1024 MB	Max Memory Used: 33 MB
```


期待
================

DynamoDB Local みたいな感じで、 Lambda Localが誕生するといいなぁ。


追記（2017/01/27）
================

Serverless Framework Plugin を使う方法
-----

Serverless Frameworkを使っている場合は

>   Serverless Frameworkのプラグインを利用した外部モジュールの管理 ｜ Developers.IO
>   http://dev.classmethod.jp/cloud/aws/managing-external-modules-with-serverless-framework-plugin/

にかかれている

>   UnitedIncome/serverless-python-requirements: Serverless plugin to bundle Python packages
> >   https://github.com/UnitedIncome/serverless-python-requirements


を使うのが簡単で良さそうです。

（https://github.com/lambci/docker-lambdaが使われているとのこと。）

（アンオフシャルなので気をつけてねということですが、個人の適当Dockerfileよりは安心かと）


Lambda Localとか言ってたんだ俺…
-----

greengrassがそのうちビルド環境を担ってくれるんでしょうきっと。