サーバ型(EC2)とサーバレス型(S3+APIGateway+Lambda+DynamoDB)で全件検索

こんにちはjimbot3です。
今回サーバレスをより実感できるようするために、
サーバ型(EC2)とサーバレス型(S3+APIGateway+Lambda+DynamoDB)で、
それぞれ全件検索を行うにはどのような作業が必要なのかを試してみました。


# 作ったもの① EC2での全件検索
まず、サーバ型としてEC2オンリーで全件検索をつくりました。
これは単に、グローバルIPを持ったサーバがEC2だと容易に手に入るという理由であって、
EC2では無く "グローバルIPを持った物理サーバ" と考えても同じです。

####1-1 EC2を用意しMySQLのインストールとテーブルの作成

```
$ whoami
ec2-user
$ cat /etc/system-release
Amazon Linux AMI release 2018.03

######MySQLのインストールとテーブルの作成######
$ sudo yum install -y mysql mysql-server
$ sudo chkconfig mysqld on
$ sudo service mysqld start
mysql> create database jimbot3 character set utf8;
mysql> connect jimbot3
mysql> create table jimbot3 (ID varchar(32) UNIQUE, BirthDay date,Name varchar(128));
mysql> insert into jimbot3 (ID, BirthDay, Name) values('001' ,19940525, 'Nanase Nishino');
mysql> insert into jimbot3 (ID, BirthDay, Name) values('002' ,19920122, 'Mai Shinuchi');
mysql> select * from jimbot3;
+------+------------+----------------+
| ID   | BirthDay   | Name           |
+------+------------+----------------+
| 001  | 1994-05-25 | Nanase Nishino |
| 002  | 1992-01-22 | Mai Shinuchi   |
+------+------------+----------------+
2 rows in set (0.00 sec)
```

#### 1-2 htmlファイルの作成
このhtmlがウェブインターフェイスになります

```
$ vi index.html
```

◆index.htmlの中身は以下になります

```html
<html lang="ja">
<head>
    <title>GetMember</title>
    <h1>Welcome to Jimbot3</h1><hr>
</head>
<body>
    <form action="/cgi-bin/getall.py" method="get">
        <input type="submit"  value="Select">
    </form>
</body>
</html>
```

#### 1-3 htmlから呼び出されるPython実行ファイルの作成

```
$ sudo pip install PyMySQL
$ sudo pip install --upgrade pip
$ mkdir cgi-bin
$ cd cgi-bin/
$ vi getall.py
```

◆getall.pyの中身は以下に記載

```python
#!/usr/bin/env python
# -*- coding:utf-8 -*-
print('Content-type: text/html; charset=UTF-8\r\n')
import pymysql.cursors

connection = pymysql.connect(host='localhost',
      user='root',
      password='',
      db='jimbot3',
      charset='utf8',
      cursorclass=pymysql.cursors.DictCursor)
with connection.cursor() as cursor:
    sql = "SELECT * FROM jimbot3"
    cursor.execute(sql)
    results = cursor.fetchall()
    for r in results:
        print(r)

```

実行ファイルのパーミッションの変更とhttpリクエストを受けられるようコマンド実行

```
$ chmod 755 getall.py
$ cd
$ python -m CGIHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
```

#### 1-4 webアクセス
http://グローバルIP:8000でアクセスしSelectボタンを押下
<img width="688" alt="008.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/7038eae7-dfa9-4608-76d8-adc4ad6a0466.png">


MySQLに登録した全件検索結果が表示される
<img width="1107" alt="009.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/9078817c-fcc7-9bf4-1a7d-1f6a09be1846.png">

# 作ったもの② S3+APIGateway+Lambda+DynamoDBでの全件検索
AWSの記事 "サーバーレス：サーバーに煩わされることなく、アプリケーションを構築、実行"
にある構成でサーバレス環境を構築。もちろんこの構成であればサーバーの管理が不要

https://aws.amazon.com/jp/serverless/

#### 2-1 S3に以下のhtmlファイルを配置
ここに配置したhtmlがウェブインターフェイスになります
<img width="674" alt="013.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/728ee063-c930-7cbd-2216-b336a5c3774f.png">


◆htmlの中身は以下になります

```html
<html lang="ja">
<head>
    <title>GetMember</title>
    <h1>Welcome to Jimbot3</h1><hr>
</head>
<body>
    <form action="ここにはAPI Gatewayで作られた呼び出し用URLを記載" method="get">
        <input type="submit"  value="Select">
    </form>
</body>
</html>

```

#### 2-2 DynamoDBに以下のテーブルを登録
DynamoDBにサーバ型でMySQL内に作ったテーブルと"ほぼ"同じテーブルを作成します。
この"ほぼ"というのはDynamoのテーブル内の値にはDate型が無いためString型で生年月日の入力をしたためです。

テーブルの中身
↓
<img width="862" alt="web_1_Qiita_DynamoDB.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/7def8500-36cd-2284-8a61-f6667c507078.png">

※データの詳細ですがDate型が無いです
<img width="801" alt="010.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/a7d4a703-7f0f-65fd-bd5d-ec7ac48a0e3d.png">


#### 2-3 Lambdaの作成
以下のLambdaを作成します。
このLambdaは実行されるとDynamoDBから全件検索結果を返すものです。

<img width="732" alt="web_1_Qiita_Lambda.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/07da568a-d6b9-0eb5-7f51-b234d6269900.png">

◆Lambda Dynamo_APIGatewayの中身は以下になります

```python
import boto3

dynamodb = boto3.resource('dynamodb') #AWSサービスでDynamoを利用します
table    = dynamodb.Table('jimbot3') #Dynamoでjimbot3テーブルを使います

def get_member():
    response = table.scan()
    return response['Items']
    
def lambda_handler(event, context):
    return get_member()
```

#### 2-4 API Gatewayの設定

API GatewayでGETメソッドを作成し↑で作った "Dynamo_APIGateway" のLambdaを指定
<img width="1079" alt="005.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/dd61df46-501f-0a1c-fc4a-2aee7b25d08b.png">

ステージ=実行する環境を作成します。
例えばdev(開発環境) と prod(本番環境) の2つのステージを用意して、dev に最新バージョンのデプロイを行い、
prod はdevでの検証完了後にデプロイを行うことができます、
<img width="975" alt="006.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/00085348-bee4-28c3-7f85-bc52e9352b6e.png">

devのステージ向けにデプロイされたURLをS3のhtmlファイルに記載
<img width="982" alt="007.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/10d1fe51-043d-f2f4-f69b-4c87a636b478.png">


#### 2-5 webアクセス
S3のhtmlファイルにアクセスしSelectボタンを押下
<img width="786" alt="011.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/756b9d1c-8533-7f67-9c3b-285de22df58a.png">

全件検索結果が表示される
<img width="1117" alt="012.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/322881/0b338741-9bae-2c29-a8b0-ee394ae1579b.png">


# 終わりに
サーバ型(EC2)とサーバレス型(S3+APIGateway+Lambda+DynamoDB)を比較した場合、
データをどこに置くがは違うけど原始的な考えはあまり変わらないといった印象

例えば、S3内だろうがEC2内だろうがindex.htmlはあるし、
LambdaだろうがEC2内だろうが実行プログラムはあるし、
DynamoDBだろうがMySQLだろうがテーブルデータはある。

ただ、htmlファイルと比較した場合に実行プログラムは大きく異なるため、
プログラミングスキルは磨かないといけないと感じた。

あと、DynamoDBは使いやすい。ただ、良くも悪くもボタンポチポチでテーブルが作れてしまうので、
「これからはDynamoDB!」などと言ってDynamoDBから入らずにRDSでも何でも良いけどちゃんとDBの基礎は付けたほうが良いと思う。