AWS でデータ分析をしてみたい - Lab1, Lab2, Lab3 -

# 背景

プライベートでデータ分析が必要になったので、せっかくだし AWS を使えないか、試行錯誤することにした。
その過程をメモ書きしていく。

# 今回目指すこと

データ分析に適した AWS のサービスを見つける。
また、それらサービスの知見を深める。

# まずはググる

色々ヒットするが、以下の AWS 公式マンガが分かりやすかった。

https://aws.amazon.com/jp/campaigns/manga/vol9-1/

データレイクとは？
 -> データの保管場所。非構造化データもそのまま保存できる。

データレイク活用の大きな流れは以下の通り。

1. 収集
1. 蓄積 <-> データカタログ
1. 加工 <-> データカタログ
1. 分析
1. 可視化

データの蓄積は S3。

データの加工・データカタログの作成は AWS Glue。
* データの加工方法に高い自由度が必要な場合は、 AWS EMR。

### Amazon EMR

Hadoop/Spark 等のマネージドフレームワーク。
自由度が高く、スケーラビリティを誇る実行基盤。

Hadoop とは？

> Hadoopとは、大規模データの蓄積・分析を分散処理技術によって実現するオープンソースのミドルウェア

https://oss.nttdata.com/hadoop/hadoop.html

Spark とは？

> Apache Sparkは巨大なデータに対して高速に分散処理を行うオープンソースのフレームワーク

https://atmarkit.itmedia.co.jp/ait/articles/1608/24/news014.html

### Amazon Redshift

大規模なデータ処理に特化したデータウェアハウス (DWH)。
高速かつスケーラブルな DWH で、S3 条のデータにもアクセスできる。

データウェアハウスとは？

> DWH（Data Ware House:データウェアハウス）とは、様々なシステムからデータを集めて整理する、データの「倉庫」

https://it-trend.jp/dwh/article/149-0001

Amazon Redshift では、RDBMS で対応できない、数 TB 規模のデータを取り扱えるようだ。

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Analytics-2021-confirmation-555.html

今回対象にしようとしているのは、精々数 GB 規模のデータなので、他のサービスが適切かもしれない。

### Amazon Athena

サーバレスのインタラクティブなクエリサービス。
S3 上のデータを標準 SQL を使って分析でき、クエリ課金でインタラクティブなアドホッククエリに強い。

アドホッククエリとは？

> その場限りで使い捨てのクエリ

https://qiita.com/Qiitaman/items/b52c69c03a949b0a1c54

# ハンズオン

以下のサイトに、AWS の各サービスのハンズオンが載っている。

https://aws.amazon.com/jp/blogs/news/aws-hands-on-for-beginners-13/

このうち、データレイクハンズオン(下記URL)は、

https://github.com/aws-samples/amazon-s3-datalake-handson/tree/master/JP

下記の AWS サービスを利用しているので、今の自分のニーズにマッチしている気がする（特にGlue, Athena, QuickSight)。

- Amazon VPC
- Amazon EC2
- AWS CloudFormation
- AWS IAM
- Amazon OpenSearch Service
- Amazon CloudWatch
- AWS Lambda
- Amazon OpenSearch Service
- Amazon Kinesis Data Firehose
- Amazon S3
- Amazon Athena
- Amazon QuickSight
- Amazon Redshift
- Amazon Redshift Spectrum
- AWS Glue

試しに、このデータレイクハンズオンを試していく。

# ハンズオンを試していく

データレイクハンズオンでは、３つのパターンを選べるようだ。

1. ニアリアルタイムデータ分析環境（スピードレイヤ）の構築：Lab1 → Lab2 → Lab3
1. 長期間のデータをバッチ分析する環境（バッチレイヤ）の構築と、パフォーマンスとコストの最適化：Lab1 → Lab4 or Lab5 → Lab6
1. すべて実施：Lab1 → Lab2 → Lab3 → Lab4 → Lab5 → Lab6

せっかくなので、３番目の「全て実施」の方向で構築していく。
完成図はこんな感じ。

![architecture_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599665/c09ce300-6c85-c3ab-2833-3ecfd2120cb8.png)

## Lab1: 初めの準備

https://github.com/aws-samples/amazon-s3-datalake-handson/blob/master/JP/lab1/README.md

### Section1: 事前準備

EC2 でキーペアを作成。

### Section2: EC2 環境構築

#### Step1: EC2 1台を CloudFormation で構築

TODO: テンプレートの書き方を学習する
(1-minilake_ec2.yaml)

このステップで、VPC 構築、 Fluentd のインストールができるらしい。すごい。これがインフラのコード化ってやつか・・・。

## Lab2: アプリケーションログをリアルタイムで可視化

### Section1: OpenSearch Service の設定

#### Step1: OpenSearch Service の起動

ちょっと詰まりあり。
以下の文言が出てこない・・・。

```
[info]: #0 Connection opened to OpenSearch cluster => {.....
```

代わりに、下記のエラーが出てくる。

```
2022-01-01 17:38:12 +0900 [warn]: #0 failed to flush the buffer. retry_time=0 next_retry_seconds=2022-01-01 17:38:12 +0900 chunk="5d481349520709f026879bd3090f8419" error_class=Elasticsearch::Transport::Transport::Errors::Forbidden error="[403] "
  2022-01-01 17:38:12 +0900 [warn]: #0 suppressed same stacktrace
20
```

どうやら、権限の問題っぽい。

https://www.mtioutput.com/entry/fluentd-failed-retry

下記コマンドで、root ユーザーに切り替えると、 `cp` コマンドが通った。

```
# sudo su -
```

この後、

- host: OpenSearch Service のエンドポイント
- user: OpenSearch Service のマスターユーザー名
- password: OpenSearch Service のマスターパスワード

を設定して、下記コマンドを実行したが、先程と同じエラーが出た。

```
# /etc/init.d/td-agent restart
# tail -f /var/log/td-agent/td-agent.log
```

少し気になったのは、下記のログ。

```
[403] "
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/elasticsearch-transport-5.0.4/lib/elasticsearch/transport/transport/base.rb:202:in `__raise_transport_error'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/elasticsearch-transport-5.0.4/lib/elasticsearch/transport/transport/base.rb:319:in `perform_request'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/elasticsearch-transport-5.0.4/lib/elasticsearch/transport/transport/http/faraday.rb:20:in `perform_request'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/elasticsearch-transport-5.0.4/lib/elasticsearch/transport/client.rb:131:in `perform_request'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/elasticsearch-api-5.0.4/lib/elasticsearch/api/actions/ping.rb:20:in `ping'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluent-plugin-elasticsearch-2.6.0/lib/fluent/plugin/out_elasticsearch.rb:218:in `client'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluent-plugin-elasticsearch-2.6.0/lib/fluent/plugin/out_elasticsearch.rb:451:in `rescue in send_bulk'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluent-plugin-elasticsearch-2.6.0/lib/fluent/plugin/out_elasticsearch.rb:445:in `send_bulk'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluent-plugin-elasticsearch-2.6.0/lib/fluent/plugin/out_elasticsearch.rb:432:in `write'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluentd-1.0.2/lib/fluent/plugin/output.rb:1093:in `try_flush'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluentd-1.0.2/lib/fluent/plugin/output.rb:1318:in `flush_thread_run'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluentd-1.0.2/lib/fluent/plugin/output.rb:439:in `block (2 levels) in start'
  2022-01-01 18:10:11 +0900 [warn]: #0 /opt/td-agent/embedded/lib/ruby/gems/2.4.0/gems/fluentd-1.0.2/lib/fluent/plugin_helper/thread.rb:78:in `block in thread_create'
2022-01-01 18:10:12 +0900 [warn]: #0 failed to flush the buffer. retry_time=0 next_retry_seconds=2022-01-01 18:10:12 +0900 chunk="5d481a7018422269ab33b2f73af82bc4" error_class=Elasticsearch::Transport::Transport::Errors::Forbidden error="[403] "
```

fluent-plugin-elasticsearch のバージョンが 2.4.0 となっている。
バージョン 2.6.0 をアンインストールしたら、改善するだろうか・・・。

下記コマンドを実行する。

```
# td-agent-gem uninstall -v 2.6.0 fluent-plugin-elasticsearch
# /etc/init.d/td-agent restart
# tail -f /var/log/td-agent/td-agent.log
```

同じエラーが出る。

試しに、バージョン 2.4.0 をアンインストールし、 2.6.0 をインストールしてみる。

```
# td-agent-gem uninstall -v 2.4.0 fluent-plugin-elasticsearch
Successfully uninstalled fluent-plugin-elasticsearch-2.4.0
# td-agent-gem list | grep plugin-elasticsearch
fluent-plugin-elasticsearch (2.6.0)
# /etc/init.d/td-agent restart
# tail -f /var/log/td-agent/td-agent.log
```

うーん。エラーは変わらず。
ということは、バージョンは関係ないのかな。

ちょっと原因がわからないので、一度 OpenSearch Service のドメインを作り直してみる。

ドメインを再度作り直している時に気づいたのが、

```
[要素を追加] をクリックし、タイプに [IAM ARN] を選択、プリンシパルに「 ご自身のAWSアカウントID 」を入力、アクションに [許可] を選択
```

この設定が間違っていた可能性がありそう。

色々試した結果、原因は

```
[要素を追加] をクリックし、タイプに [IPv4 アドレス] を選択、プリンシパルに「 Lab1で作成したインスタンスのパブリックIP 」を入力、アクションに [許可] を選択
```

この設定をする際、プリセットされた `*` これを残したままパブリックIP を入力したため、許可されなかった模様。
かなり時間を溶かしてしまった・・・。まあ、良い勉強になった。

[OpenSearch Dashboards の URL] のをクリックしたところ、

```
{"Message":"User: anonymous is not authorized to perform: es:ESHttpGet"}
```

と表示された。原因を調べてみる。

うーん。
リソースポリシーに記載された

```
"arn:aws:iam::814937260541:root"
```

が怪しいかなと思ったけど、どうやらこの形式は正しいようだ。

https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_identifiers.html

とすると、何でアクセスできないんだろう？

セキュリティポリシー設定で、下記の設定を忘れていた・・・。
こういうの多いな。

```
タイプに [IPv4 アドレス] を選択、プリンシパルに「 ご自身のIPアドレス 」を入力、アクションに [許可] を選択
```

これで、 Kibana で可視化できた。

## Lab3: アプリケーションログのリアルタイム可視化とアラーム

### Section1: EC2 の設定変更

#### Step1: IAM ロールの設定

#### Step2: OpenSearch へのロールの認証設定

特に問題なく設定できた。

### Section2: CloudWatch, OpenSearch Service の設定変更

#### Step1: CloudWatch Logs の設定

#### Step2: OpenSearch Service の設定

#### Step3: CloudWatch アラームの設定

特につまづくことなく、設定完了。

TODO: CloudWatch の習熟。