ＡＷＳ上でPostgreSQL、Scrapy、Metabaseが動く個人用データ収集環境の構築

#目指せ百万円！不労所得！
株価分析のための簡単な分析基盤をAWS上に作ろうと思ったら、想像以上に試行錯誤したので、忘備録として。

仕組みとしては
 1. Scrapyを使って株価をサイトからスクレイピング。cronで定期実行。
 2. スクレイピングした株価をデータベースに格納
 3. 格納されたデータをBIツールで可視化

目指せ不労所得は忘れてください。

# 過去のデータ収集基盤
- 個人のMac上にdockerで構築。
    - elasticsearch(データベース)
    - kibana(可視化ツール)
    - 自作ウェブスクレイピングプログラム(Python/BeautifulSoup)

# 試行錯誤した結果のデータ収集基盤
- AWS EC2
    - PostgreSQL(データベース)
    - Metabase（可視化ツール）
    - Scrapy (Pythonスクレイピング・フレームワーク)
- AWS lambda
    - EC2の定期起動/定期停止に使用

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235984/c3ebf113-b2df-ed38-9a3a-569ba9602b4b.png" width=400 >

#なぜAWS上に移行したかったか
- 当初の構成はできたのはいいが、以下の問題点が
    - スクレイピング中ずっと自分の（ノート）パソコンを起動しっぱなしにするのは、なんだかカッコよくない。
    - 分析するための基盤なのに、スクレイピングプログラムを自分で起動しなければデータを集めてくれない残念仕様。
    - 俺のパソコン、データ容量が足りない
    - AWS試したかった

# 構築で使うモノ
- docker
   - 他環境に移植する手間を減らす
   - 個人用途だと必要性は全く感じないがk8s対応も一応視野に
- Metabase(BIツール)
    - Kibanaの代わり
    - 導入楽そう
    - SQL知らなくても、それなりの図を出してくれそう
- PostgreSQL(データベース)
    - Elasticsearchの代わり
    - Metabaseとの連携が楽
    - PostgreSQLは色々分析するのに便利な機能があると、どっかで書いていた
- Scrapy(webスクレイピング・フレームワーク)
    - フレームワーク活用してスクレイピングやった方があとで色々使いまわしやすい
      - 実際、elasticsearchからPostgreSQLに出力先を変える変更は楽だった
    - 個人で一から開発しているとどうしてもハードコーディングが生まれるが、フレームワークに沿って書けば、可読性、可用性の高いプログラムを楽に書ける

## 断念したもの
- Elasticsearch （データベース）
- Kibana （可視化ツール）
    - 両方ともメモリを食う
    - 無料枠の範囲内（1インスタンス1GBメモリ）でやろうと思うと、ElasticsearchとKibanaはオーバースペック。動作が安定しない。
    - クラスタ構成が必要なほどデータを集めない(おそらく100GBも使わない)
    - そもそもElastic社が個人用途を想定して作っていない（当たり前っちゃ当たり前
        - https://qiita.com/RyuKahou/items/78e9e2d9ca373bf5e82b
        - https://www.elastic.co/guide/en/elasticsearch/guide/current/deploy.html
    
# 環境構築

## 1. EC2インスタンスの構築

[0から始めるAWS入門：概要](https://qiita.com/hiroshik1985/items/6433d5de97ac55fedfde)を参考にVPCとEC2インスタンス（`t2.micro`）を3つ作成。今回3インスタンスともOSは`Amazon Linux`を選択しましたが、dockerを使うのでOSはお好みで。

３インスタンスに`docker`と`docker-compose`をインストール。以下の通りコマンドを入力すればインストールされます（参考：[dockerとdocker-composeのインストール(Linux編)](https://qiita.com/youtanagai/items/ff67ceff5497a0e0b1af)）
    
- ちなみに、下のコマンドを実行しただけだと`sudo /usr/local/bin/docker-compose`と指定しないと`docker-compose`してくれないので、面倒ならログインユーザーを docker グループに追加する等々してください。

```shell-session
sudo yum update -y
sudo yum install docker -y
sudo systemctl start docker
sudo systemctl enable docker
sudo -i
curl -L https://github.com/docker/compose/releases/download/1.6.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
exit
```

`t2.micro`だとメモリが心許ないので以下のようにスワップ領域を設定
    - [スワップファイルを使用して、Amazon EC2 インスタンスのスワップ領域として動作するようにメモリを割り当てる](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-memory-swap-file/)
    - [AWS Amazon Linux スワップファイル作成によりSwap領域のサイズを増やす](https://qiita.com/na0AaooQ/items/278a11ed905995bd16af)

```shell-session
$ sudo dd if=/dev/zero of=/swapfile bs=1G count=2
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo vi /etc/fstab
$ /swapfile swap swap defaults 0 0
```

## 2. Postgresインスタンスの構築

docker-composeを使えば、以下のymlをコピペして`docker-compose up -d`すれば環境構築は完了する。

　- `postgresql.conf`は[PGTune](https://pgtune.leopard.in.ua/#/)で適宜設定
　- Postgresのdockerはデータを永続化させる為にボリュームを作成

```yml:docker-compose.yml
version: '2'
services:
    postgres:
        image: postgres
        environment:
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: postgres
            POSTGRES_DB: metabase
        ports:
            - "5432:5432"
        container_name: postgres-db
        volumes:
            - "./postgresql/postgresql.conf:/etc/postgresql.conf"
            - postgres-data:/var/lib/postgresql/data
        command: 'postgres -c config_file="/etc/postgresql.conf"'
        restart: always
volumes:
    postgres-data:
        driver: local
```

## 3. Metabaseインスタンス

- `Metabase`の設定の詳細は[Running Metabase on Docker](https://metabase.com/docs/v0.12.0/operations-guide/running-metabase-on-docker.html)を参照
- 基本的に以下のymlをコピペして`docker-compose up -d`すれば環境構築は完了
- Metabase起動後のMetabaseのセットアップは[Centos7.4にMetabaseのインストールをするまで](https://qiita.com/snow_rain000/items/153c9305b78bf61bb635)を参考に入力

```yml:docker-compose.yml
version: '2'
services:
    metabase:
        image: metabase/metabase
        container_name: metabase
        ports:
            - "3000:3000"
        environment:
            - JAVA_TOOL_OPTIONS=-Xmx1g
            - MB_DB_TYPE=postgres
            - MB_DB_DBNAME=metabase
            - MB_DB_PORT=5432
            - MB_DB_USER=postgres
            - MB_DB_PASS=postgres
            - MB_DB_HOST= 10.0.0.* #Postgres EC2インスタンスのプライベートIP
        restart: always
```


## 4. Scrapyインスタンス

Scrapyの環境は以下の通り構築。

- ScrapyProjectは`scrapy startproject`コマンドで作成したScrapyプロジェクトフォルダを指している。
- Scrapyの使い方は以下のサイトに譲る
    - [10分で理解する Scrapy](https://qiita.com/Chanmoro/items/f4df85eb73b18d902739)
    - [Python, Scrapyの使い方（Webクローリング、スクレイピング）](https://note.nkmk.me/python-scrapy-tutorial/)


```:ディレクトリ構成
/home/ec2-user/scrapydock
├── Scrapy_Docker
├── docker-compose.yml
├── requirements.txt
└── ScrapyProject
    ├── scrapy.cfg
    └── ScrapyProject
        ├── __init__.py
        ├── __pycache__
        ├── items.py
        ├── middlewares.py
        ├── pipelines.py
        ├── settings.py
        └── spiders
            ├── __init__.py
            └── __pycache__
```

```Dockerfile:Scrapy_Docker
FROM python:3.7.2

ARG project_dir=/app/
RUN mkdir $project_dir
ADD requirements.txt $project_dir

RUN apt-get update -y
RUN apt-get install vim -y

WORKDIR $project_dir
RUN pip install -r requirements.txt

ADD ./ScrapyProject $project_dir/ScrapyProject
WORKDIR $project_dir/ScrapyProject
```

```txt:requirements.txt
pandas
scrapy
beautifulsoup4
pytz
xlrd
psycopg2
```

```yml:docker-compose.yml
version: '2'
services:
  nikkei_parser:
    container_name: nikkei_scrapy
    build:
      context : .
      dockerfile: Scrapy_Docker
    tty: true
```

ディレクトリ構成の通りにファイルを配置できたら、`docker-compose build`のみ行う。

`crond`を使って以下のシェルを管理者権限で定期実行すれば、定期的にウェブスクレイピングを行ってくれます(参考：[/etc/crontabと/etc/cron.d設定ファイルの書き方](https://www.server-memo.net/tips/etc-crontab.html))

```shell:scrape.sh
docker rm nik_scrape
docker run --name nik_scrape scrapydock_nikkei_scrapy scrapy crawl nikkei_Spider
```

##5. Lambdaの設定
３つのインスタンスを24時間起動し続けると無料枠を超えてしまうので、動かしたい時にだけ、EC2を起動します。
[できるだけシンプルな仕組みで簡単にEC2の自動起動・停止を実現したい！](https://dev.classmethod.jp/cloud/aws/simple-auto-start-stop-for-ec2/)を参考に。
記事の内容をコピペすれば実現できます。

# 気になるお値段
- 2ヶ月ほどこの収集基盤を放置運用しているが、費用は月500円ほどAWSにお支払いしています。

# 参考(Metabaseの画面)

- ある企業の株価を表示

<img width="1469" alt="スクリーンショット 2019-04-28 4.29.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235984/693a2b0e-d0ea-65af-d076-307383f049a0.png">


# 構築する際に参考にしたもの
- [Running Metabase on Docker](https://metabase.com/docs/v0.12.0/operations-guide/running-metabase-on-docker.html)
- [Docker-docs-ja/Docker Compose](http://docs.docker.jp/compose/toc.html)
- [0から始めるAWS入門：概要](https://qiita.com/hiroshik1985/items/6433d5de97ac55fedfde)
    - 上の記事を完璧に理解してググれば、なんとなくAWSを使いこなせるようにはなれる気がします。
- [できるだけシンプルな仕組みで簡単にEC2の自動起動・停止を実現したい！](https://dev.classmethod.jp/cloud/aws/simple-auto-start-stop-for-ec2/)
    - ほぼコピペすればLambdaでEC2の起動と停止ができるようになります。
- [PGTune](https://pgtune.leopard.in.ua/#/)
    - Postgresのチューニングに使用
- [10分で理解する Scrapy](https://qiita.com/Chanmoro/items/f4df85eb73b18d902739)
- [Python, Scrapyの使い方（Webクローリング、スクレイピング）](https://note.nkmk.me/python-scrapy-tutorial/)
- [「人とWebに優しい」Scrapyの使い方サンプル〜 #PyConJP 2017のつづき(なお野球)](https://shinyorke.hatenablog.com/entry/scrapy-example-yakiu)
    - 元ネタ