EC2上にLambda開発環境をCodeDeployで自動で生成する


## AWS Lambda

lambda関数を利用する際、標準でインストールされていないパッケージを使いたい場合があります。
その際、lambdaコンテナはAmazon Linux AMIをベースとした開発環境なので、同様の環境で生成されたsite-packagesが必要となります。
また、lambda上でテストする場合、パッケージをzip化してuploadする必要があるので少し面倒です。

## やりたいこと

EC2上にlambda関数の開発環境をCodeDeployで自動生成する。

## CodeDeploy内容
1. python3.6をインストールする。
2. vertualenvをインストールしてpython3.6と2.7の仮想環境を作成する。
3. lambda_setフォルダをec2-user直下に作成し、そこにlambda_function.pyを配置する。

以上をymlとshファイルで作成し、GitHubで管理する。

## EC2の準備

インスタンスの作成（略）
⇒インスタンスタイプはAMI
⇒ネットワーク、サブネットはデフォルト
⇒IAMロール＝EC2RoleforAMCodeDeploy
⇒タグ設定
⇒作成

## CodeDeployAgentインストール

TeraTermで起動して下記コマンドを実行します。

```console:
$ sudo yum update
$ sudo yum install ruby
$ sudo yum install aws-cli
$ cd /home/ec2-user
$ aws s3 cp s3://aws-codedeploy-ap-northeast-1/latest/install . --region ap-northeast-1
$ chmod +x ./install
$ sudo ./install auto
```

確認（念のためリスタート）

```console:
$ sudo service codedeploy-agent status
$ sudo service codedeploy-agent restart
```

## GitHubの準備

GitHubからデプロイするためのリポジトリを作成してフォルダを構成しておきます。（s3でも可能）
scripsにはシェルスクリプトを、srcには格納したいファイルを、ymlファイルにはデプロイ内容を記載してリポジトリ直下に置きます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/257113/2cea6d43-f760-ba85-b54d-a04e0b4ec48f.png" width=30%>



```yml:appspec.yml
version: 0.0
os: linux
files:
  - source: src/
    destination: /home/ec2-user/lambda_set/
hooks:
  BeforeInstall:
    - location: scripts/construct_venv.sh
      timeout: 2000
    - location: scripts/sample_pip_install.sh
      timeout: 300
```

* souce・・・EC2へ送るデータ元
* destination・・・EC2の格納先
* hooks・・・実行するスクリプト


```shell:construct_venv.sh
#!/bin/bash
prefix='/home/ec2-user/'

sudo yum -y groupinstall 'Development tools'
sudo yum -y install zlib-devel openssl-devel

mkdir ${prefix}python3.6
cd ${prefix}python3.6
wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz
tar zxvf Python-3.6.1.tgz
cd ${prefix}/python3.6/Python-3.6.1
./configure
make
sudo make install

sudo /usr/local/bin/pip3.6 install virtualenv
/usr/local/bin/virtualenv -p /usr/local/bin//python3.6 ${prefix}encrypt_3
/usr/local/bin/virtualenv -p /usr/bin/python2.7 ${prefix}encrypt_2

cd ${prefix}
mkdir lambda_set
```

```shell:sample_pip_install.sh
#!/bin/bash
prefix='/home/ec2-user/'

cd ${prefix}encrypt_3
source bin/activate
pip install boto3
pip install pandas

deactivate
```

prefixを指定しているのは、CodeDeployによるシェルスクリプトが走るのは/opt/codedeploy-agent/というディレクトリだからです。TeraTerm等で入る際に紛らわしいのでec2-userにディレクトリを移動していますが、必要に応じて変えたら良いと思います。
また、locationによるシェルスクリプトの実行は変数は破棄されるので変数を使う場合は毎回指定が必要です。

## CodeDeployの準備
* まずアプリケーションを作成します。今回はインプレースデプロイを選びます。

![deploy1.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/57d1da1f-1674-c5f0-c17e-e398a06e154a.png)

* EC2インスタンスで設定したタグを使って、デプロイ先のインスタンスを指定します。

![deploy2.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/b906395d-0bc0-d864-c271-f580e6df1617.png)

* ロードバランサーとデプロイの設定をします。（未設定ならデフォルトで問題なし）

![deploy3.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/f9de4f96-086d-5bdd-d298-6c0dda116047.png)

* サービスロールはCodeDeploy用のRoleとしてAWSCodeDeployRoleを持つものを指定します。

![deploy4.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/1f842ded-50a6-a32d-5c18-30f28dcf7f24.png)

* アクションから新しいリビジョンのデプロイをします。

![deploy5.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/b6d2edc8-a48d-23fb-6f92-9781715fca08.png)

* GitHubの設定を行います。

![deploy6.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/bb48e424-7e42-79cc-7dbc-61752df8565a.png)

![deploy7.PNG](https://qiita-image-store.s3.amazonaws.com/0/257113/c9e556ea-6507-d416-7361-dcd0f3166b08.png)

* コミットIDはコンソールから下記により取得できます。

```console:
git show -s --format=%H
```

## 結果

デプロイが完了すれば、EC2インスタンスにencrypt_3とencrypt_2という仮想環境が作成され、src/に保存していたlambda_function.pyが/home/ec2-user/lambda_setに保存されています。

今回はサンプルとしてpython3.6の環境でboto3とpandasをインストールしました。（sample_pip_install.sh）
このshを好きに変えていけば、思い通りの環境を構築できます。

また、指定しているlambda_function.pyの中をAWSのlambdaに揃えておいて、jsonデータを生成して入力に用いて結果を表示するという関数にしておけばlambda上でのテストと同様の事ができます。

注意としてはpip installはvirtualenvをインストールしたユーザーと同ユーザーで行う必要があるという点です。

## おわりに

下記書籍ではEC2での環境構築を手動でやっていたので、CodeDeployで自動化できたら楽だろうなというモチベーションで試してみました。lambda用のライブラリzip化のみであればもっとスマートな方法はあると思います。

例えば、pythonのバージョンを分けてLambdaを使うメリットの中では、pandasとstatsのライブラリを同時にlambdaで使う場合等がありました。python3ではこの二つのライブラリは50MBを超えてしまうのでzip化してuploadすることができませんが、python2ならばこれらは40MB少しで済みます。そういった面でも2系列を使うメリットはあると思います。

## コード

https://github.com/NibuTake/codedeploy

## 参考

[Lambda実践ガイド](https://book.impress.co.jp/books/1116101044)

[AWS CodeDeployとGitHubを連携してEC2に簡単自動デプロイ](https://qiita.com/dq-nobuko-takatsuki/items/ba365966ae61e177a4da)