LambdaにVPCを設定してインターネットに接続出来るようにする

## 概要
表題の通りです。
下記がイメージ図になります。

![LambdaVPC.png](https://qiita-image-store.s3.amazonaws.com/0/71899/26d2c9ca-46e9-fdd5-30fd-dd569f8ed257.png)

VPCにNAT Gatewayを作成、そのNAT GatewayにEIP（パブリックIP）を割り当てます。
Lambdaはprivateセグメントを経由し、そこからpublicセグメントにあるNAT Gatewayを経由してインターネットへ接続を行います。

| セグメント | サブネット |
|:-:|:-:|:-:|
| public subnet  | 10.0.10.0/24  |
| private subnet  | 10.0.1.0/24  |


## VPCの作成を行う

今回はLambda専用のVPCとして作成します。
左メニューからVPCを選択して、「VPCの作成」、今回は「lambda_vpc」というネームタグでCIDRは「10.0.0.0/16」で作成します。

<img width="749" alt="VPC-11.png" src="https://qiita-image-store.s3.amazonaws.com/0/71899/86442eee-02ab-31be-9e0e-7e7f5306895f.png">

<img width="650" alt="VPC-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/71899/0671fec1-1534-916a-048a-4aac32c7801b.png">

## インターネットゲートウェイ
VPCからインターネット接続を行う為のインターネットゲートウェイを作成します。
左メニュー「インターネットゲートウェイ」から作成します。ネームタグは「lambda_igw」で作ります。

<img width="884" alt="igw1.png" src="https://qiita-image-store.s3.amazonaws.com/0/71899/fb426294-8756-ab43-7f17-aaf1c23d87d5.png">

<img width="647" alt="iwg2.png" src="https://qiita-image-store.s3.amazonaws.com/0/71899/3a7b1d50-2efe-1a7c-37c1-a44ba311bb0c.png">

先程作成した「lambda_vpc」にアタッチします。

![iwg3.png](https://qiita-image-store.s3.amazonaws.com/0/71899/7e0576e3-58ea-00e1-aaa1-4fefa3181a37.png)

## サブネットの作成

次はサブネットの作成を行います。
インターネットに接続するpublicセグメントとインターネットに直接繋げないprivateセグメントを作成します。（図を見たら分かる通り、このprivateセグメントにLambdaが格納されます。）

左メニューのセグメントから「サブネットの作成」を選び、以下のように２つのセグメントを作成します。

### publicセグメント
- ネームタグ
    - lambda_public
- VPC
    - 作成した「lambda_vpc」

- アベイラビリティーゾーン
    - ap-northeast-1a
- CIDRブロック
    - 10.0.10.0/24

### privateセグメント
- ネームタグ
    - lambda_private
- VPC
    - 作成した「lambda_vpc」

- アベイラビリティーゾーン
    - ap-northeast-1a
- CIDRブロック
    - 10.0.1.0/24

## publicサブネットのインターネットゲートウェイをデフォルトゲートウェイに設定

ルートテーブルから作成されているルートテーブルを選び、「ルート」の「編集」をクリックし、送信先に「0.0.0.0/0」を指定し、ターゲットに先ほど作成したインターネットゲートウェイ（lambda_igw）を指定し、保存します。

![lambda_public_rt.png](https://qiita-image-store.s3.amazonaws.com/0/71899/f2c5d233-b7f2-c095-bf8e-ee39c858ee42.png)

初期状態では名前がついていないので、分かりやすいように「lambda_public_rt」というネームタグを付けておきます。

「サブネットの関連付け」より先程作成した「lambda_public」を関連付けます。

![lambda_public_rt2.png](https://qiita-image-store.s3.amazonaws.com/0/71899/0a861931-6f39-bd09-969a-3be5ac8e7f66.png)

ここまでの手順でインターネット接続が可能なpublicセグメントとインターネット接続が不可能なprivateセグメントが作成されました。

## NAT Gatewayの作成
メニューから「NATゲートウェイ」を選択し、「NAT、ゲートウェイの作成」をクリックします。

<img width="1089" alt="NATgateway.png" src="https://qiita-image-store.s3.amazonaws.com/0/71899/cbc1f39b-4d30-97e2-dab1-6d6e23b07423.png">

サブネット欄にカーソルを当てるとサブネットの一覧が表示されるので、先ほど作成したpublicセグメント（lambda_public）を選択します。Elastic IPは今回は新規に作成しますので「新しいEIPの作成」を押してください。

![NATgateway2.png](https://qiita-image-store.s3.amazonaws.com/0/71899/11a08511-f36f-074e-4b5a-2a29c556602c.png)

これでNAT Gatewayの作成は完了です。

## NAT Gatewayをprivateセグメントのデフォルトゲートウェイに設定

ルートテーブルから「ルートテーブルの作成」をクリックし、ネームタグを入力し、VPCに「Lambda_vpc」を選択します。

![lambda_private_rt.png](https://qiita-image-store.s3.amazonaws.com/0/71899/c9bd379a-4f02-31e7-7674-5c7c1319aeed.png)

作成されたルートテーブルを選択し、「ルート」タブで「編集」をクリックし、「別ルートの追加」で以下のように送信先に「0.0.0.0/0」、ターゲットに作成したNAT Gatewayを指定し、保存します。

![lambda_private_rt2.png](https://qiita-image-store.s3.amazonaws.com/0/71899/9165eb01-2680-f343-a9a4-102b5ef238d7.png)

最後に「サブネットの関連付け」タブに移り、編集からprivateサブネットを関連付けます。

![lambda_private_rt3.png](https://qiita-image-store.s3.amazonaws.com/0/71899/7e4896e6-f7b5-c485-6386-f91971dc768f.png)

ここまでの手順でVPCの設定が完了です。

## LambdaにVPCの設定を行う

LambdaにVPCの設定を行います。
以下のように作成した「lambda_vpc」を選択し、Subnetsにprivateサブネットである「lambda_private」を指定します。
security GroupsはとりあえずデフォルトでOKです。

![LambdaVPC.png](https://qiita-image-store.s3.amazonaws.com/0/71899/15ddba12-4b3f-e350-12a6-99e3c199ab67.png)

※warningが出ていますが、これは「Lambdaに少なくとも2つのサブネットを選択しておいてね」という警告です。テストで使う分にはこれで十分なので今回はこのまま進めます。

## インターネットに接続出来るか確認する

インターネットに接続が出来る事を確認します。
下記のコードは http://qiita.com/api/v2/schema に接続を行いJSON形式のデータを取得するサンプルです。

```js:sample.js
'use strict';

const request = require('request');

const headers = {
  'Content-Type':'application/json'
};

const options = {
  url: 'http://qiita.com/api/v2/schema',
  method: 'GET',
  headers: headers
};

exports.handler = (event, context, callback) => {

  request(options, (error, response, body) => {
    console.log(body);
    callback(
      null,
      response
    );
  });
};
```

JSON形式のレスポンスがあれば成功です。
中身は長いので http://qiita.com/api/v2/schema を確認して下さい。

## まとめ

LambdaにVPCを設定しインターネットに接続する手順をでした。
（ほとんどがVPCの設定の話になってしまいました）

この設定を行う事でElastiCache等のVPC内のリソースにアクセスしつつ、DynamoDBのようなサービスにも接続可能なLambda関数を定義出来ます。

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/vpc.html)を見ると・・・

> VPC に充分な数の ENI またはサブネット IP がない場合は、リクエスト数が増えても Lambda 関数を拡張できず、関数の失敗数が増えます。現在 AWS Lambda では、ENI または IP アドレスの不足によって発生したエラーは CloudWatch Logs に記録されません。対応する CloudWatch Logs のないエラーが増えている場合は、Lambda 関数を同期的に実行してエラー応答を取得します (たとえば、AWS Lambda コンソールで Lambda 関数をテストすると、コンソールで Lambda 関数が同期的に呼び出され、エラーが表示されます)。

と記載がありますので、実際に運用する際は2つ以上のサブネットを割り当てておく事をオススメします。