AWSサービスの概要を一覧化するスクレイピング

背景

AWSにはサービスが多種多様にあり、なかなか全体感が一覧できません。
初学者には「全体的にどんなサービスがあるの?」というのが俯瞰的に見ることができないのか「サービスのカテゴリとサービス名と、その概要を一覧化してくれ」なんてことがあろうかと思います。
対してうるせぇググれよさっと各サービスの概要説明を一覧にして差し上げるのがクラウド時代のエンジニアの所作と思われます。知らんけど。

やってみる

cheerio-httpcliでクローリング&スクレイピングしてみました。
最初はHeadless Chromeで始めたのですが、どうやらSPAはなさそうでcheerio-httpcliでよいだろうと書き直しました。

コードは以下に配置しています。
https://github.com/morimop/aws-services-list

  • 重複あっても気にしない
  • 一応言語切り替えができるかもしれない雰囲気は出してみる

うまくいかなかったところ

サービスごとにレイアウトが統一されていないので、ここを取ってくればいい、という単純な判定はできませんでした。

index.js
            const pElements = [].filter.call(
              $('main').find('p'),
              (pn)=>{
                if($(pn).find('a').length == 0){
                  return true;
                };
                return ($(pn).find('a').text() != $(pn).text());
              });

この箇所はEMRのページのせいです。このページだけHadoopやらSparkやらのリンクが冒頭に付いているので、これを除外しています。

index.js
          return $('p').parent().text().trim();

mainが見つからなかったページはとりあえず何か取ってくる、という雑仕様です。
AWS Marketplaceのページが相当おかしな感じになります。

結果

出力は./tmp/以下にJSONで出力していますので、JSON to CSVしたりするとEXCELで見られると思われます。
sample-services.PNG
圧巻。

詳細を以下に貼り付けます。長いので前半のちょっとだけを転載します。

“category” “services__name” “services__href” “services__abstruct”
“コンピューティング” “Amazon EC2” https://aws.amazon.com/jp/ec2/?nc2=h_m1 “Amazon Elastic Compute Cloud (Amazon EC2) は、安全でサイズ変更可能なコンピューティング性能をクラウド内で提供するウェブサービスです。ウェブスケールのクラウドコンピューティングを開発者が簡単に利用できるよう設計されています。 Amazon EC2 のシンプルなウェブサービスインターフェイスによって、手間をかけず、必要な機能を取得および設定できます。お客様のコンピュートリソースに対して、高機能なコントロールが提供され、Amazon の実績あるインフラストラクチャ上で実行できます。Amazon EC2 では、わずか数分間で新規サーバーインスタンスを取得して起動できるようになります。これにより、コンピューティング要件の変化に合わせて、すばやく容量をスケールアップおよびスケールダウンできます。実際に使用した分のみ料金が発生するため、Amazon EC2 はコンピューティングの経済性も変革します。Amazon EC2 を利用すれば、耐障害性に優れたアプリケーションの構築が可能になり、よくある障害のシナリオとは無縁になります。”
“” “Amazon EC2 Container Registry” https://aws.amazon.com/jp/ecr/?nc2=h_m1 “Amazon EC2 Container Registry (ECR) は、完全マネージド型の Docker コンテナレジストリです。このレジストリを使うと、開発者は Docker コンテナイメージを簡単に保存、管理、デプロイできます。Amazon ECR は Amazon EC2 Container Service (ECS) に統合されているため、開発から本番までのワークフローを簡略化できます。Amazon ECR を使用すると、自前のコンテナリポジトリの運用や、基盤となるインフラストラクチャのスケーリングの検討は不要になります。Amazon ECR は非常に可用性が高くスケーラブルなアーキテクチャでイメージをホストするため、コンテナをアプリケーションに確実にデプロイすることが可能です。AWS Identity and Access Management (IAM) に統合すると、各リポジトリをリソースレベルで制御できます。Amazon ECR に前払い料金などの義務はありません。リポジトリに保存したデータ量とインターネットに送信されたデータ量に対してのみ料金が発生します。 AWS 無料利用枠の一環として、Amazon EC2 Container Registry を無料でお試しいただけます。Amazon ECR では、新しいお客様に、月 500 MB 分のストレージを 1 年間にわたって提供いたします。”
“” “Amazon EC2 Container Service” https://aws.amazon.com/jp/ecs/?nc2=h_m1 “Amazon EC2 Container Service (ECS) は、非常にスケーラブルかつ高性能なコンテナ管理サービスで、Docker コンテナに対応しており、Amazon EC2 インスタンスのマネージド型クラスターでアプリケーションを簡単に実行できます。Amazon ECS を使用すると、自社でクラスター管理インフラストラクチャのインストール、運用、スケールを行う必要がなくなります。簡単な API 呼び出しを使用して、Docker 対応アプリケーションの起動と終了、クラスターの完了状態のクエリ、多くの使い慣れた機能 (セキュリティグループ、Elastic Load Balancing、EBS ボリューム、IAM ロールなど) へのアクセスを実行できます。Amazon ECS を使用することで、リソースニーズと可用性要件に基づいて、クラスター全体のコンテナの配置をスケジューリングできます。ビジネスまたはアプリケーション固有の要件を満たすために、独自のスケジューラーまたはサードパーティ製のスケジューラーを統合することもできます。 Amazon EC2 Container Service に追加料金は発生しません。アプリケーションを保存および実行するために作成した AWS リソース(EC2 インスタンス、EBS ボリュームなど)に対してのみ料金が発生します。”
“” “Amazon Lightsail” https://amazonlightsail.com “Everything you need to jumpstart your project on AWS—compute, storage, and networking—for a low, predictable price. Launch a virtual private server with just a few clicks.”
“” “Amazon VPC” https://aws.amazon.com/jp/vpc/?nc2=h_m1 “Amazon Virtual Private Cloud (Amazon VPC) により、アマゾン ウェブ サービス (AWS) クラウドの論理的に分離したセクションをプロビジョニングできます。これにより、AWS リソースをユーザー定義の仮想ネットワークで起動できます。ユーザーの IP アドレス範囲の選択、サブネットの作成、ルートテーブルとネットワークゲートウェイの構成など、仮想ネットワーク環境を完全にコントロールできます。VPC では、リソースやアプリケーションに安全かつ簡単にアクセスできるよう、IPv4 と IPv6 を両方とも使用できます。 Amazon Virtual Private Cloud のネットワーク設定は容易にカスタマイズすることができます。例えば、インターネットとのアクセスが可能なウェブサーバーのパブリック サブネットを作成し、データベースやアプリケーションサーバーなどのバックエンドシステムをインターネットとのアクセスを許可していないプライベート サブネットに配置できます。セキュリティグループやネットワークアクセスコントロールリストなどの複数のセキュリティレイヤーを活用し、各サブネットの Amazon EC2 インスタンスへのアクセスをコントロールすることができます。”
“” “AWS Batch” https://aws.amazon.com/jp/batch/?nc2=h_m1 “AWS Batch を使用することにより、開発者、科学者、およびエンジニアは、数十万件のバッチコンピューティングジョブを AWS で簡単かつ効率的に実行できます。AWS Batch では、送信されたバッチジョブのボリュームと特別なリソース要件に応じて、コンピューティングリソース (CPU やメモリ最適化インスタンス) の最適な数量とタイプを動的にプロビジョニングできます。AWS Batch を使うと、ジョブを実行するためのバッチコンピューティングソフトウェアやサーバークラスターをインストールしたり、管理したりする必要がなくなります。これにより、結果の分析と問題解決に集中できます。AWS Batch では、Amazon EC2 やスポットインスタンスなどの AWS コンピューティングサービスと機能を最大限に活用して、バッチコンピューティングワークロードを計画、スケジュール作成、実行します。 AWS Batch に対する追加料金はありません。バッチジョブを保存したり実行したりするために作成した AWS リソース (EC2 インスタンスなど) に対してのみ料金が発生します。”
“” “AWS Elastic Beanstalk” https://aws.amazon.com/jp/elasticbeanstalk/?nc2=h_m1 “簡単に開始でき、不足を感じることなく利用 AWS Elastic Beanstalk は、Java、.NET、PHP、Node.js、Python、Ruby、Go および Docker を使用して開発されたウェブアプリケーションやサービスを、Apache、Nginx、Passenger、IIS などの使い慣れたサーバーでデプロイおよびスケーリングするための、使いやすいサービスです。”
“” “AWS Lambda” https://aws.amazon.com/jp/lambda/?nc2=h_m1 “AWS Lambda を使用すれば、サーバーのプロビジョニングや管理なしでコードを実行できます。課金は実際に使用したコンピューティング時間に対してのみ発生し、コードが実行されていないときには料金も発生しません。Lambda を使用すれば、実質どのようなタイプのアプリケーションやバックエンドサービスでも管理を必要とせずに実行できます。コードさえアップロードすれば、高可用性を実現しながらコードを実行およびスケーリングするために必要なことは、すべて Lambda により行われます。コードは、他の AWS サービスから自動的にトリガーするよう設定することも、ウェブやモバイルアプリケーションから直接呼び出すよう設定することもできます。 AWS Lambda とは(日本語字幕)”
“” “Auto Scaling” https://aws.amazon.com/jp/autoscaling/?nc2=h_m1 “Auto Scaling により、アプリケーションの可用性を維持できると同時に、お客様が定義する条件に応じて Amazon EC2 のキャパシティーを動的および自動的に縮小あるいは拡張できます。Auto Scaling を EC2 インスタンスのフリート管理に使用することによって、フリートの状態と可用性を維持し、必要な数の Amazon EC2 インスタンスを確実に実行できます。また、Auto Scaling を EC2 インスタンスの動的スケーリングに使用することによって、需要が急激に上昇したときには Amazon EC2 インスタンスの数を自動的に増やしてパフォーマンスを維持し、需要が落ち着いた状態にあるときには能力を縮小してコストを削減できます。Auto Scaling は需要のパターンが一定のアプリケーションにも、使用量が時間、日、週で変動するアプリケーションにも適しています。Auto Scaling を Amazon EC2 で使用する以外に、Application Auto Scaling を使用して、Amazon ECS、Amazon EC2 スポットフリート、Amazon EMR クラスター、AppStream 2.0 フリート、Amazon DynamoDB といった AWS のその他のサービスのリソースを自動的にスケールできます。 12 か月間の AWS 無料利用枠と、24 時間年中無休のカスタマーサービスやサポートフォーラムなどの AWS の基本的なサポート機能を利用できます。”
“” “Elastic Load Balancing” https://aws.amazon.com/jp/elasticloadbalancing/?nc2=h_m1 “Elastic Load Balancing は、アプリケーションへのトラフィックを複数のターゲット (Amazon EC2 インスタンス、コンテナ、IP アドレスなど) に自動的に分散します。Elastic Load Balancing は、変動するアプリケーショントラフィックの負荷を、1 つのアベイラビリティーゾーンまたは複数のアベイラビリティーゾーンで処理できます。Elastic Load Balancing では、3 種類のロードバランサーが用意されています。これらはすべて、アプリケーションの耐障害性を高めるのに必要な高い可用性、自動スケーリング、堅牢なセキュリティを特徴としています。 Application Load Balancer”
“ストレージ” “Amazon Simple Storage Service (S3)” https://aws.amazon.com/jp/s3/?nc2=h_m1 “今日の企業に求められるのは、大規模なデータを簡単かつ安全に収集、保存、分析する能力です。Amazon S3 は、ウェブサイトやモバイルアプリケーション、社内アプリケーション、IoT センサーやデバイスからのデータなど、どこからの、どのような量のデータでも保存と取得が可能なオブジェクトストレージです。これは 99.999999999% の耐久性を提供し、すべての業界のマーケットリーダーによって使用される何百万ものアプリケーションのデータを保管できるように設計されています。S3 では最も厳格なセキュリティ要件を満たす包括的なセキュリティおよびコンプライアンス機能が提供されます。お客様は柔軟にデータを管理して、コスト最適化、アクセス制御、コンプライアンスに対応できるようになります。S3 は、インプレースクエリ機能を備えた唯一のクラウドストレージソリューションであり、S3 の保管データに強力な分析を直接実行できます。また、Amazon S3 は、ISV ソリューションやシステムインテグレータのパートナーによる最大のエコシステムを備えた、最も強力なサポートが提供されているストレージプラットフォームです。 “

続きを読む

ネットワールド、DockerコンテナでHadoop/Sparkなどを動作させるBDaaS基盤ソフトを販売

パブリッククラウドとしては、Amazon Web Service(AWS)、Google Cloud Platform、Microsoft Azureの各クラウドサービスの上でBlueData EPICを実行できる … 続きを読む

AWS GlueでJSONをParquetに変換する

Redshift SpectrumやAthenaを使っていたり、使おうとするとS3に貯めている既存ファイルをParquetやAvroに変換したいということがあります。
AWS Glueを利用してJSONLからParquetに変換した際の手順などを記述しています。
S3上のファイルを変換するだけならばData catalog/Crawl機能は利用せずに、ETLのJobを作成するだけで利用できます。

Data catalogの作成からのGlue一連の流れを確認したい場合はクラスメソッドさんの『AWS Glue 実践入門:サービスメニュー内で展開されている「ガイド付きチュートリアル」を試してみた』が参考になるかと思います。

ジョブの作成

メニューの ETL > Jobs からAdd Jobを選択すると以下のような画面が出てきます。
以下の3項目以外は後から変更可能です。

  • Name
  • This job runs
  • Script file name

スクリーンショット 2017-09-02 12.55.48.png

「This job runs」で「A proposed script generated by AWS Glue」を選択するとGlueで事前にDataSourceを作成しておく必要がありますが、今回のようにDataSourceを使う必要がない場合は、それ以外を選択します。

スクリーンショット 2017-09-02 15.31.12.png

Connectionsは設定ができないのでそのままNextを選択すると、Reviewとして今まで設定した内容の確認がでてくるのでFinishを選択すると、スクリプトの修正画面へ遷移します。

スクリプトは以下のような内容になります。
今回はほとんどGlueの機能(GlueContext)は使わずに、SparkContext/SQLContextのみを利用して処理を行っています。
(printデバッグを行う際の注意点としては、スクリプト内でprint文を記述した場合はError Logsに出力されます。)

import sys
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from pyspark.sql import SQLContext

sc = SparkContext()
glueContext = GlueContext(sc)
sqlContext = SQLContext(sc)

## @params: [IN_PATH, IN_PATH]
args = getResolvedOptions(sys.argv, ['IN_PATH', 'OUT_PATH'])


# 引数で入力出力パスを指定
print(args['IN_PATH'])
print(args['OUT_PATH'])
in_path  = args['IN_PATH']
out_path = args['OUT_PATH']

# http://qiita.com/ajis_ka/items/e2e5b759e77933b08687
sc._jsc.hadoopConfiguration().set("mapreduce.fileoutputcommitter.algorithm.version", "2")
# http://tech-blog.tsukaby.com/archives/1162
sc._jsc.hadoopConfiguration().set("spark.speculation", "false")

sqlContext = SQLContext(sc)

jsonDataFrame = sqlContext.read.json(in_path)

jsonDataFrame.write.mode("overwrite").format("parquet").option("compression", "snappy").mode("overwrite").save(out_path)

ジョブの定義として以下のように設定しておくことでスクリプトに引数を渡すことが出来ます。
このままSpark-submitに渡されるので –引数名 というようにKeyに設定必要があります。
001c5dde2b100da9f1a30bda5471786d.png

ジョブの実行

作成したジョブを即時実行する場合は Jobs画面で ジョブを選択して Action > Run Job と選択するだけです。
5a6758243bdd00f7cd596027e85fe3fa.png

定期実行などを行いたい場合は別途 Trigger を作成する必要があります。

実行結果の確認

コードが実行されるとS3上は以下のようになります。

% aws s3 ls s3://出力先/data/
                           PRE parquet/
2017-08-15 19:41:42          0 
2017-08-29 16:32:13          0 parquet_$folder$

% aws s3 ls s3://入力元/data/jsonl/
2017-08-28 16:16:35          0 
2017-08-28 16:16:48     133687 part-00000-29825316-e4f5-49fd-a835-3f0615ea4292.json
2017-08-29 15:37:21     138225 part-00001-29825316-e4f5-49fd-a835-3f0615ea4292.json
2017-08-29 15:37:20     135261 part-00002-29825316-e4f5-49fd-a835-3f0615ea4292.json
2017-08-29 15:37:19     136963 part-00003-29825316-e4f5-49fd-a835-3f0615ea4292.json

% aws s3 ls s3://出力先/data/parquet/
2017-08-29 16:32:13        356 _common_metadata
2017-08-29 16:32:13       1606 _metadata
2017-08-29 16:32:13      44313 part-00000-b782317e-827d-4417-ab0c-acf9e32f10cf.snappy.parquet
2017-08-29 16:32:12      43462 part-00001-b782317e-827d-4417-ab0c-acf9e32f10cf.snappy.parquet
2017-08-29 16:32:12      43048 part-00002-b782317e-827d-4417-ab0c-acf9e32f10cf.snappy.parquet
2017-08-29 16:32:12      42360 part-00003-b782317e-827d-4417-ab0c-acf9e32f10cf.snappy.parquet

続きを読む

Amazon EMR 上の WebUI群 ( Hue や Zeppelin ) をSSHトンネルなしでブラウザ表示する方法

概要

EMR で構築したクラスタ上の WebUI をブラウザ表示するには SSH トンネリングを利用した接続が推奨されていますが、この方法は不便が多いため、より気軽な方法を模索しました

最終的に リバースプロキシ をおいて接続する方法 が良かったので共有します

構成

検証環境 : EMR-Release 5.2.1

SSH トンネリングによる構成

  • この図では master-public-dns-name に対してインターネット経由で SSH トンネルを作成しています
    (VPN 接続がある場合は、Local Netowark 内を通します)
  • EMR Master インスタンスのある SecurityGroup で SSH のポート(デフォルト22)を接続元指定で開け、各クライアントマシンと EMR Master インスタンス間で SSH トンネルを作成して、ポートフォワーディングによってブラウザで任意のWebUIと通信を行います

問題点

  • 各クライアント(各個人PC)マシン上で設定が必要になる(非エンジニアでは作業負荷が高い)
  • SSHで繋ぐため、クライアント(各個人PC)にEMR master への秘密鍵をばらまく必要がある(秘密鍵は隠したい)
  • 都度 SSHトンネル接続&Webブラウザアクセスの手順が面倒

Hue や Zeppelin などの分析ツールは大勢の非エンジニアが利用するケースもありえます
その場合各個人クライアントに鍵を配ったりターミナルでSSHトンネルを作成させたりする操作は煩雑でつらいものがあります

リバースプロキシをおく構成

  • プロキシサーバ に対してインターネット経由で接続します
    (SSHトンネルの例と同様、VPN 接続がある場合は Local Netowark 内を通します)
  • EMR Master とは別インスタンスでプロキシサーバを稼動させます
  • プロキシサーバまでは https、プロキシサーバから EMR master は private network 内を http で通信させます
    (個別のWebUIはSSL設定しなくて良い)
  • 各クライアント(各個人PC)マシンは追加設定不要
    (ブラウザアクセスするだけでOK)

EMRとは別にプロキシサーバを構築するため追加コストがかかりますが、個別クライアントは何の設定も要らず、ブラウザアクセスするだけで、Hue や Zeppelin などお好みの WebUI を参照できるようになります

構築手順

1. リバースプロキシを配置するサーバの Security Group 設定

外部から(またはLocalNetwork内)の https リクエストを許可します
ポートは、利用したい WebUI にあわせて必要な個数分開けます
後述 しますが、ドキュメントに載っていないポートが参照される場合があるので、適宜追加します)

タイプ    : カスタム TCP ルール 
プロトコル : TCP
ポート範囲 : 8888
ソース    : <アクセス元の Public IP (またはLocalNetwork内のアクセス元 Private IP )>

2. EMR Master の Security Group 設定

EMR Master の Security Group では、リバースプロキシ (private ip) からの http リクエストを許可します

タイプ    : すべてのトラフィック
プロトコル : すべて
ポート範囲 : すべて
ソース    : (Private Network のIP範囲) 

3. DNS設定

お好みのドメイン名を決め、そのドメインへのアクセスをプロキシサーバへ誘導するよう DNSレコード を設定します

ラベル : emr.your-site.com(管理下のお好みのドメイン名)
TTL   : 任意の時間 Time To Live
クラス : IN
タイプ : A
リソース : <リバースプロキシサーバの Public IP >

Route53などであれば次のような感じです(イメージ)

4. リバースプロキシの構築

プロキシサーバ上では、特定のドメイン/ポート指定でアクセスがきた場合に、EMR Master サーバの指定ポートへ代理アクセスするよう設定します
今回は EC2 で適当なインスタンスを確保し、Nginx を使ってプロキシさせます

Nginx インストール

リバースプロキシを配置するサーバにNginx をインストールします
(環境にあわせて、安定動作するものを選んでセットアップします)
https://www.nginx.com/resources/wiki/start/topics/tutorials/install/

SSL証明書の配置

SSL証明書を配置して、Nginx で https リクエストがきた場合に参照させます
(証明書は必要に応じて入手します)

ls /path/to/cert/*
/path/to/cert/your-site-ssl-certificate.crt
/path/to/cert/your-site-ssl-key.pem

Nginx 設定例(後でまとめて書きます)

ssl on;
ssl_certificate     /path/to/your-site-ssl-certificate.crt;
ssl_certificate_key /path/to/your-site-ssl-key.pem;

コンテンツ書き換え

WebUI群の中には、リンクを生成する際に 自身の名前 master-private-dns-name を使う場合があるため、ブラウザアクセスした場合に表示されるページ内のリンクが飛べない(名前解決できない)ケースが発生します
これを回避するために、Webサーバのコンテンツ書き換え機能を使って master-private-dns-name を名前解決できるドメイン(先ほどDNS登録した管理下のお好みのドメイン)に書き換える処理をはさんでおくとストレスなく使えるようになります

Nginx 設定例(後でまとめて書きます)

sub_filter '(master-private-dns-name)' 'emr.your-site.com(管理下のお好みのドメイン名)';
sub_filter_once off;

Nginx設定

利用したいWebUIのポートに対して、それぞれプロキシ設定を追加します
この際、上記で紹介したSSL設定とコンテンツ書き換えを加えて下記のように設定します

/path/to/nginx/nginx.conf

# hue wabapp
server {
    listen 8888 ssl;
    server_name emr.your-site.com;
    access_log /path/to/proxy-your-site.com.access.log main;

    ssl on;
    ssl_certificate     /path/to/your-site-ssl-certificate.crt;
    ssl_certificate_key /path/to/your-site-ssl-key.pem;

    location / {
        proxy_pass http://<master-private-ip>:8888/;
        sub_filter 'ip-xx-xx-xx-xx.region.compute.internal' 'emr.your-site.com';
        sub_filter_once off;
    }
}

# 
server {
    listen 8080 ssl;
..............(同様)
}

..............(必要なポート分設定)

この例では 共通のドメイン emr.your-site.com に対して ポートごとに振り分けさせていますが、もし個別のWebUIごとに別ドメインを割り当てるほうがお好みであれば、そのように設定することももちろん可能です
hue.your-site.com へのアクセスで <master-private-ip>:8888 へ誘導する など)
ただしURLの書き換えルールが複雑になってしまうので、そのあたり検討する必要がでてきます

対象となる WebUI 群

設定対象となる WebUI 群のリストは、Amazon EMR のドキュメント を参照します

なお利用するWebUIによってドキュメントに載っていないポートも参照されるため、状況に応じて必要なポートを登録します
(一応個人的に必要だったものを羅列します)

Web UI Name uri
Hue master-public-dns-name:8888/
Tez UI master-public-dns-name:8080/tez-ui/
Zeppelin master-public-dns-name:8890/
Yarn Web Proxy master-public-dns-name:20888/
YARN ResourceManager master-public-dns-name:8088/
Yarn ResourceManager? master-public-dns-name:8032/
Hadoop HDFS NameNode master-public-dns-name:50070/
Yarn timeline-service Webapp master-public-dns-name:8188/
Spark HistoryServer master-public-dns-name:18080/

設定を書き終えたら、Nginxのプロセスを起動させます

5. 動作確認

設定は以上です、実際にブラウザで 個別の WebUI を開いてみます

Hue
http:// emr.your-site.com :8888/

無事に個別のWebUIが開く & 表示されてるリンクへ正しく遷移できれば、設定完了です! :thumbsup:

まとめ

Amazon EMR 上の WebUI 群へのアクセスを リバースプロキシ経由 にすることで、以下の利点が得られます

  • WebUIへアクセスする チームメンバーの負担を大幅減できる
    (クライアントマシンの設定不要で、ブラウザアクセスですぐ使える)
    (SSHトンネル設定のように接続が切れることもない)
  • SSH秘密鍵をばらまかなくてよい
    (余計なリスクを負わなくてよい)
  • リバースプロキシで SSL設定をまとめて行うことができる
    (個別WebUIでSSL対応させなくてよく、設定を一元的に行える)
  • コンテンツ書き換え処理によって、 すべてのリンクをたどれるようにできる
    (単体の WebUI でなく、複数同時に公開可能)

ぜひおためしください!

参考資料

続きを読む

SparkアプリケーションのデバッグTIPS

Spark UIでスレッドダンプを見る

どこかで詰まってる/デッドロックしているなどを調べたい場合、スレッドダンプを見るのが有効ですが、それだけならSpark UI上でできます。

Screen Shot 2017-09-03 at 10.43.47 PM.png

Screen Shot 2017-09-03 at 10.44.12 PM.png

EMR上でJMXリモートデバッグ

ここではjvisualvmを使うことにします。

jvisualvmの準備

jvisualvmにプラグインを入れておくと捗ります。

Tools > Pluginsからプラグイン管理画面を開き、Threads Inspectorあたりは入れておくと便利です。

ステップを追加する

前提

  • アプリケーションはjarに固めてs3://path/to/app.jarに置いてあるとします
  • command-runner.jarspark-submitする方法でステップを実行します
  • EMRクラスタのmasterおよび各ノードは、22番が空いてるものとします

EMRにステップの追加

以下のようなコマンドラインオプションをつけてステップを追加します。

spark-submit --deploy-mode cluster --class com.example.Main --master yarn-cluster 
  --conf "spark.executor.extraJavaOptions=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8002 -Dcom.sun.management.jmxremote.rmi.port=8002 -Djava.rmi.server.hostname=127.0.0.1" 
  --conf "spark.driver.extraJavaOptions=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8003 -Dcom.sun.management.jmxremote.rmi.port=8003 -Djava.rmi.server.hostname=127.0.0.1" 
  --num-executors 3 --driver-memory 2g --executor-memory 5g --executor-cores 2  # このへんはお好みで
  s3://path/to/app.jar

これで、driverプロセスに対しては8003、executorプロセスに対しては8002でjmx接続できるようになります。

今回は、executorプロセスに接続してみます。

※注意

一つのノードで複数のexecutorが割り当てられうる設定で実行した場合、これだと8002がバッティングする可能性があります。

そういった場合はcom.sun.management.jmxremote.port=0として、動的にポートを取得するなどの手段をとる必要があります。

executorプロセスの実行されているノードの特定

YARNクラスタ上のどのノードでexecutorが実行されるかは動的に決まるため、各ノードにSSHで入ってlsofなどで8002番が使われているかどうか確認し、つなぐ先のノードを特定します。

ここでは、ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.comだったとします。

SSHトンネルを開く

手元のマシンで以下のコマンドを実行し、8002番のSSHトンネルを開きます。

$ ssh -i key.pem -NL 8002:ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com:8002 hadoop@ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

jvisualvmから接続

あとは127.0.0.1:8002に対してjvisualvmから接続すればOKです。

IntelliJでステップ実行する(localモード)

IntelliJのリモートデバッグを使えば、Sparkアプリケーションをステップ実行などできます。

ここではlocalモードで行います。(EMR上でもできるはずだけど)

前提

  • sparkバイナリを落として/path/to/spark_homeに解凍しておきます
  • アプリケーションはjarに固めて/path/to/app.jarに置いておきます

IntelliJの前準備

IntelliJを起動し、Run > Edit Configurationsから、リモートデバッグ用のconfigurationを追加しておきます。

Screen Shot 2017-09-03 at 11.23.02 PM.png

+からRemoteを選択すれば勝手にこれが入力されています。

spark-submit

リモートデバッグ用のオプションをつけて、spark-submitします。

$ cd /path/to/spark_home
$ ./bin/spark-submit --master local 
    --driver-java-options "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" 
    /path/to/app.jar

IntelliJでリモートデバッグを開始

少し経ってSparkアプリケーションが起動したら、さきほど作成したconfigurationを実行すれば、いつものようにブレークポイントを貼ったりスレッドの状態を見たりwatchを仕込んだりできます。

続きを読む

Hadoop (HDP) を0から構築する方法

Hadoop環境を構築したい

皆さんは自分用のHadoop環境をどの様に構築されていますか?
色んな方法があるようですが入り口からいろいろ模索してしまいました。
調査不足の面もあったり、構築の方法論にとどめていたりしますがご一読いただければと思います。

主な方法

  1. ローカルVMでSandoBox
  2. AzureでSandBox
  3. AWSでSandBox
  4. Hortonworks Data Cloud
  5. Ambariから構築

1. ローカルVMでSandoBox

Hortonworks Sandbox with VirtualBoxによると、メモリが自分のPCには厳しかったです。
最小4GB、AmbariやHBaseなどもろもろ載せるとホストOSに10GB、Sandboxに8GBが必要。

2.AzureでSandBox

kkitaseさまの記事が明快です。
Azureで、Hortonworks Sandboxを使い、Hadoop、Sparkを試してみよう
自分もこの方法は良いなと思いやってみましたが少し自分のほしい環境と異なっていました。
– HDP2.5が提供されている(2017/8/17現在) →希望はHDP2.6(現バージョン)
– Hive2が入ってなかったです。(HDP2.5では入っていない)
– 最小4ノード構成(仮想サーバーを4台使う)

3. AWSでSandBox

CommunityサイトHCCに似たような質問がありました。
HDP Sandbox on AWS?
ローカルVMをDLしてAWSのインストールイメージ(AMI)として使うのですが、AMIのところが自分には難しく、入力出来ない項目があり。
また、1回だけの作業ですが、10GB程度ローカルにDLするのとバケツにUPするのが一手間。
wgetとかできればいいのですが。

4. Hortonworks Data Cloud

手順など以下から。
Hortonworks Data Cloud
これは簡単でした。拡張の方法も同様に簡単です。
– 最小4ノード構成(仮想サーバーを4台使う)
– Hortonworksのソフトウェア・ライセンス費用が必要(若干ですが)

できれば

今更ですがこんなのは無いのかなと?
– 最新のVersionで
– 1台構成が可能で(自由に選択できる意味で)
– 構築手順がシンプルで
– 拡張時も同様の手順が使えて
– HiveやPigやecosystemのアプリ群はいろいろ入れたい
– 若干の費用は良いとして

5. Ambariから構築

そこでこれです。
あっさりAmbariから構築しちゃいましょう。
Ambariとはざっくり言うとHadoopの管理モジュールです。
yumで最新版を入れれます。アプリもクラスタ構成も好きにできます。1台でOKです。
Apache Ambari Installation
私はAWSのAmazon Linuxで構築しましたが問題なく、上述した自分の希望に一番あっている気がしました。

何かのお役に立てれば。

8/29 イントロの文言修正

続きを読む

ETLをサーバレス化するAWS Glueについての概要

AWS Glueが一般人でも使えるようになったというので、どんなものかと、調べてみました。
一人で調べ物した結果なので、機能を正しく把握できているかいまいち自信がありませんが、
理解した限りで公開します。全体像を理解できるような、概念的な話が中心です。

概要

AWS Glueは、日々行われるデータ集約やETL処理を自動化、およびサーバレス化するサービスです。

いま、未加工のCSVやJSONによるログデータや、
アプリケーションで使用している既存のデータベースなどがあるものの、
そのままでは分析が難しく、データ分析のために整備された領域が求められているとします。

AWS Glueの文脈では、前者をデータストア、後者をデータカタログと位置づけます。
データカタログは主に、フルマネージドなHDFS上のストレージ領域です。
たとえば、Amazon Athenaからデータカタログを分析することができます。

AWS Glueは以下の3要素からなります。

  • データ分析の中央リポジトリでありデータを一元管理するデータカタログ
  • 様々なデータストアからデータカタログにデータを集約するクローラ
  • データカタログ内のデータをETLするジョブ

AWS Glueによって、データ分析基盤のサーバレス化を進めることができます。たとえば、 (Customer's Application)-> S3 -(Glue Crawler)-> Data Catalog -> (Athena) は、データ収集から分析・可視化までをエンドツーエンドでサーバレスに構築する一例です。ここで、データの加工が必要であるならば、Data Catalog -(Glue Job)-> Data Catalogを加えればよいでしょう。

AWS Glueはフルマネージドであり、その処理はスケールアウトするため、ユーザはデータ規模やインフラ運用を意識することなく、データを加工するスクリプト(ETLの”T”に対応)の作成に集中することができます。ほかにも、AWS Glueは、データカタログ上のテーブルメタデータのバージョン管理機能や、クローラでの入力データからのスキーマ自動推論機能、クラシファイアでの検査に基づきスキーマの変更を検知する機能などを備えています。

クローラ

AWS Glueにおけるクローラとは、データストアのデータを、
データカタログに移住させるために使われる機能です。

クローラの目的は、散在する複数のデータストアそれぞれを見張らせ、
最新のデータを発見し、それらのデータをデータカタログへと集約し、データカタログを最新に保つことにあります。

クローラは、クラシファイアという要素を通じて、カラム名変更、型変換などの簡単な変換処理を行ったり、
半構造データをテーブルの形式に整えたり、スキーマの変更を検知できたりします。
クラシファイアは、デフォルトのものを使うことも、自分でカスタマイズすることもできます。

作成されたクローラには、ジョブ実行方法(オンデマンドか、スケジュールベースか、イベントベースか)が定義されています。
たとえば、クローラを定期実行させておくことで、データカタログがデータストアに対しおおむね最新であることが保証されます。

ジョブ

クローラを使って単にデータをデータカタログへと移住させただけでは、
クエリを叩けてもデータが使いにくく、ユーザにとって分析が難しい場合があります。
このとき、より分析に適した形にするために、ETL処理が必要です。

AWS Glueにおけるジョブとは、抽出・変換・ロード(ETL)作業を実行するビジネスロジックです。
ジョブが開始されると、そのジョブに対応するETL処理を行うスクリプトが実行されます。
こちらもクローラと同様に定期実行などの自動化が可能です。

ユーザは、ジョブ作成者として、抽出元(データソース)、およびロード先(データターゲット)を定義します。
ただし、データソースおよびデータターゲットは、どちらもデータカタログ上のデータです。
ユーザは、ジョブ処理環境を調整したり、生成されるスクリプトをビジネスニーズに基づいて編集したりします。

最終的に、Apache Spark API (PySpark) スクリプトが生成されます。
こうして作成されたジョブは、データカタログで管理されます。

参考文献

AWS Glue 概要

クローラ

ジョブ

続きを読む

EMR5.7でAmazonDynamoDBClientBuilderが上手く使えない対応

環境

EMRは5.7。
aws-java-sdk-dynamodbのバージョンは下記。

build.sbt
libraryDependencies += "com.amazonaws" % "aws-java-sdk-dynamodb" % "1.11.170"

sbt assembly で固めたFAT-JARをEMR上にデプロイ&実行するとエラーが発生。
ローカルでは上手く動くので原因がわからず少し困った。

事象

EMR5.7にて AmazonDynamoDBClientBuilder を利用すると NoClassDefFoundError
AmazonDynamoDBClientBuilder はパスを通している(FAT-JARに含まれている)ので、ClassNotFoundException では無いだろうと思っていたが、原因が特定できず戸惑った。

エラー1
17/08/14 10:17:39 INFO Client:
    (略)
java.lang.NoClassDefFoundError: Could not initialize class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:58)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:51)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
        (略)

しばらく動かしたりログを探すと、IllegalAccessErrorがでていた。
どうやらこれが原因なようだ。

エラー2
17/08/14 11:04:29 INFO Client:
    (略)
java.lang.IllegalAccessError: tried to access class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory from class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder
        at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder.<clinit>(AmazonDynamoDBClientBuilder.java:27)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:58)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:51)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)

調査

調べるといくつか出てきた。

どうやら、ERM5.7はaws-java-sdkのバージョンが 1.10.75.1 までしか対応していないとのこと。現在(※2017/08/15)は1.11系が出ているので、けっこう古い。というか本当なのか?

ということで、公式のドキュメントを調べると…

AWS SDK for Java が 1.10.75 にアップグレード
* http://docs.aws.amazon.com/ja_jp/emr/latest/ReleaseGuide/emr-whatsnew.html

と書いてあり、1.10.75 までは対応していることは見つけたが、それ以降のバージョンについては述べていない。うーむ、信頼できるのか?

対応

ということで、半信半疑ながらSDKのバージョンをダウングレードした。

build.sbt
libraryDependencies += "com.amazonaws" % "aws-java-sdk-dynamodb" % "1.10.75.1"

そうすると、AmazonDynamoDBClientBuilderが利用できないので、今ではdeplicatedになっているAmazonDynamoDBClientを利用して書き換えすることに。

OLD_dynamodbサンプル.scala
    val client = AmazonDynamoDBClientBuilder.standard
      .withRegion("ap-northeast-1")
      .build
    val dynamoDB = new DynamoDB(client)

こちら↑をすこし編集するのみで動いてくれた。

NEW_dynamodbサンプル.scala
    val client = new AmazonDynamoDBClient()
    client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    val dynamoDB = new DynamoDB(client)

実行結果

実行すると…
上手く動いてくれた。さすがStackOverFlow!

なぜ IllegalAccessError が出てしまうかだが、ERM上でもaws-java-sdkがロードされていると思うので、かみ合わせが悪いのか?このあたりよく分かっていない。

まとめ

EMRでDynamoDBに書き込む時は、SDKのバージョンに気をつけよう。

続きを読む