Amazon Web Services ブログ

Amazon EMR ウェブインターフェイスの使いやすい URL を動的に作成する

Amazon EMR により、データアナリストやサイエンティストは、Spark、HBase、Presto、Flink などの一般的なフレームワークを実行する任意のサイズのクラスターを数分でデプロイできます。クラスターを起動すると、Amazon EMR は、クラスター用に選択したフレームワークとアプリケーションを使用して、基盤となる Amazon EC2 インスタンスを自動的に設定します。これには、Hue ワークベンチ、Zeppelin ノートブック、Ganglia 監視ダッシュボードやツールなどの定評があるウェブインターフェイスが含まれます。

これらのウェブインターフェイスは EMR マスターノードでホストされており、マスターノードのパブリック DNS 名 (マスターパブリック DNS 値) を使用してアクセスする必要があります。マスターパブリック DNS 値は動的に作成されますが、あまり使いやすくなく覚えにくいです。たとえば、ip-###-###-###-###.us-west-2.compute.internal などです。一般的なワークベンチまたはノートブックインターフェイスに接続するための使いやすい URL がないと、ワークフローに影響を及ぼし、敏捷性を妨げる可能性があります。

一部の顧客は、カスタムブートストラップアクション、ステップ、定期的に新しいクラスタをチェックしてより使いやすい名前を DNS に登録する外部スクリプトを使用して、この課題に取り組んでいます。こうしたアプローチは、データの実務者にさらに負担をかけたり、スクリプトを実行するために追加のリソースを必要としたりします。さらに、一般的には、こうしたスクリプトに関連する遅延時間があります。クラスターが終了した後に DNS レコードをクリーンアップしてもそれほど大きな効果はなく、むしろセキュリティリスクが発生することがあります。

この記事のソリューションは、ウェブインターフェイスに簡単にアクセスできる使いやすいマスターノード名を登録するサーバーレスの自動化されたアプローチを提供します。

AWS のサービス

Building a Dynamic DNS for Route 53 using CloudWatch Events and Lambda という同僚の記事から一部インスピレーションを得て、このソリューションは Amazon CloudWatch EventsAWS LambdaAmazon Route 53 を活用して、Route 53 プライベートホストゾーンに CNAME を使いやすい名前で動的に登録します。

深く掘り下げる前に、これらの主要なサービスについて、そしてこのソリューションをどのように構成しているかをレビューします。

CloudWatch Events

CloudWatch Events は、AWS リソースの変化を表すほぼリアルタイムのシステムイベントのストリームを配信します。単純なルールを使用して、イベントを照合して 1 つ以上のターゲット関数またはストリームにルーティングすることができます。イベントは、次の 4 つの方法のいずれかで生成できます。

  • リソースの状態が変化したときに AWS のサービスから
  • AWS CloudTrail を介して配信される API コールから
  • アプリケーションレベルのイベントを生成できる独自のコードから
  • cron スタイルのスケジューリングで発行

このソリューションでは、クラスターの状態が変化したときに EMR によって自動的に放出される最初のタイプのイベントを取り上げます。このイベントの状態に基づいて、クラスターの状態が「STARTING」に変化したときに Route 53 の DNS レコードを作成または更新するか、クラスターが不要になって状態が「TERMINATED」に変化したときに DNS レコードを削除します。すべての EMR イベントの詳細については、Monitor CloudWatch Events を参照してください。

Route 53 プライベートホストゾーン

プライベートホストゾーンとは、1 つまたは複数の VPC 内のドメインおよびそのサブドメインへのトラフィックをルーティングする方法に関する情報を保持するコンテナです。プライベートホストゾーンを使用すると、名前や IP アドレスをインターネットに公開することなく、内部リソースにカスタム DNS 名を使用することができます。

Route 53 は、広範な種類のレコードタイプを備えたリソースレコードセットをサポートしています。このソリューションでは、別のドメイン ( 「正規」ドメイン) の別名としてドメイン名を指定するために使用される CNAME レコードを使用します。EMR マスターパブリック DNS 値の CNAME として、クラスターの使いやすい名前を使用します。

EMR クラスターは通常、プライベートサブネット内にデプロイされ、VPC 内または VPN または AWS Direct Connect 経由のオンプレミスリソースからアクセスされるため、プライベートホストゾーンを使用しています。オンプレミスネットワークからプライベートホストゾーンのドメイン名を解決するには、How can I resolve Route 53 private hosted zones from an on-premises network via an Ubuntu instance? の説明に従って、DNS フォワーダーを設定します。

Lambda

Lambda は、サーバーのプロビジョニングまたは管理を行うことなく、コードを実行できるコンピューティングサービスです。Lambda は必要な時にだけコードを実行し、毎秒何千ものリクエストにまで自動的に拡張します。Lambda は、高可用性を保持し、サーバーや OS の保守、およびパッチ適用を行います。消費したコンピューティングの時間分だけを支払います。コードが実行されていない場合は無料です。

Lambda は、オブジェクトが Amazon S3 バケットに配置されたときや、この場合のように CloudWatch イベントが発生したときなど、イベントに応答してコードを呼び出す機能を提供します。このソリューションの一部として、イベントがルールと一致したときに CloudWatch Events によって呼び出されるターゲットとして Lambda 関数をデプロイします。また、Lambda 関数ポリシーLambda 実行ロールを含む、Lambda 権限モデルに基づいて必要な権限も設定します。

すべてをまとめる

これですべての部分が完成したので、完全なソリューションをまとめることができます。次の図は、ソリューションの仕組みを示しています。

  1. EMR クラスターの起動や終了などのユーザーアクティビティを開始します。
  2. EMR は、自動的にイベントを CloudWatch Events ストリームに送信します。
  3. CloudWatch Events ルールは、指定されたイベントと一致し、ターゲット (この場合は Lambda 関数) にルーティングされます。この場合、EMR クラスターの状態変化を使用しています。
  4. Lambda 関数は、以下の重要なステップを実行します。
    • イベント詳細から clusterId の値を取得し、それを使用して EMR をコールします。DescribeCluster API を使用して、以下のデータポイントを取得します。
      • MasterPublicDnsName – マスターノードのパブリック DNS 名
      • 使いやすい名前を含んでいるタグを探し、クラスターの CNAME として使用します。使いやすい名前を含むキー名は、値を host.domain.com として指定する必要があります。ここで、ドメインは DNS レコードを更新するプライベートホストゾーンです。
    • イベントの詳細の状態に基づいて DNS を更新します。
      • 状態が「STARTING」の場合、関数は Route 53 API をコールして、ドメインタグで指定されたプライベートホストゾーン内のリソースレコードセットを作成または更新します。これは、MasterPublicDnsName にマップされた CNAME レコードです。
      • 逆に、状態が「TERMINATED」の場合、関数は Route 53 API をコールして、プライベートホストゾーンから関連付けられたリソースレコードセットを削除します。

ソリューションをデプロイする

このソリューションのすべてのコンポーネントがサーバレスなので、AWS サーバーレスアプリケーションモデル (AWS SAM) テンプレートを使用してソリューションをデプロイします。AWS SAM は、AWS CloudFormation によってネイティブにサポートされており、サーバーレスのリソースを表現するための簡略化された構文を提供し、結果としてコードの行数を削減します。

SAM テンプレートの概要

このソリューションでは、SAM リソースなしの場合の 142 行に比べて、SAM テンプレートには 76 行のテキストがあります (YAML でのテンプレートの書き込みもわずかに小さくなります)。このソリューションは、AWS マネジメントコンソール、AWS コマンドラインインターフェイス (AWS CLI)、AWS SAM Local を使用してデプロイすることができます。

CloudFormation の transform は、複数行のリソース宣言をテンプレート内の 1 行に集約することで、テンプレートの作成を簡素化します。CloudFormation にテンプレートがサーバーレスアプリケーションを定義するよう通知するには、テンプレート形式のバージョンの下に以下の行を追加します。

"AWSTemplateFormatVersion":"2010-09-09",
"Transform":"AWS::Serverless-2016-10-31",

SAM の前に、AWS::Lambda::Function リソースタイプを使用して Lambda 関数を定義します。次に、関数の権限を定義するためのリソース (AWS::Lambda::Permission)、Lambda の実行ロールを定義するための別のリソース (AWS::IAM::Role)、最後にこの関数をトリガーする CloudWatch Events のリソース (Events::Rule) が必要です。

SAM では、関数用の単一のリソース AWS::Serverless::Function だけを定義する必要があります。この単一のリソースタイプを使用すると、必要な IAM ポリシーや CloudWatch イベントだけでなく、関数ハンドラ、ランタイム、コード URI などの関数プロパティを含め、必要なものすべてを定義できます。

"DnsSetterLambda":{
         "Type":"AWS::Serverless::Function",
         "Properties":{
            "Handler":"emr-dns-setter.lambda_handler",
            "Runtime":"python2.7",
            "CodeUri":"emr-dns-setter.py.zip",
            "Description":"Create PHZ record for EMR cluster",
            "Timeout":90,
            "Policies":[
               {
                  "Version":"2012-10-17",
                  "Statement":[
                     {
                        "Effect":"Allow",
                        "Action":"ec2:Describe*",
                        "Resource":"*"
                     },
                     {
                        "Effect":"Allow",
                        "Action":[
                           "elasticmapreduce:Describe*"
                        ],
                        "Resource":"*"
                     },
                     {
                        "Effect":"Allow",
                        "Action":[
                           "logs:CreateLogGroup",
                           "logs:CreateLogStream",
                           "logs:PutLogEvents"
                        ],
                        "Resource":"*"
                     },
                     {
                        "Effect":"Allow",
                        "Action":[
                           "route53:ChangeResourceRecordSets",
                           "route53:GetHostedZone",
                           "route53:ListHostedZones",
                           "route53:ListHostedZonesByName",
                           "route53:ListResourceRecordSets"
                        ],
                        "Resource":[
                           "*"
                        ]
                     }
                  ]
               }
            ],
            "Events":{
               "CloudWatchEventDNS":{
                  "Type":"CloudWatchEvent",
                  "Properties":{
                     "Pattern":{
                        "source":[
                           "aws.emr"
                        ],
                        "detail-type":[
                           "EMR Cluster State Change"
                        ]
                     }
                  }
               }
            }
         }
      }
   },
   "Outputs":{

   }
}

 

このコードの例では、さらに注意すべき点がいくつかあります。

  • CodeUri – SAM テンプレートをデプロイする前に、まず Lambda 関数のコードの zip ファイルを S3 にアップロードします。これは手動で実行することもできますし、aws cloudformation パッケージの CLI コマンドを使用して、後述するように、ローカルアーティファクトを S3 バケットにアップロードするタスクを自動化することもできます。
  • Lambda の実行ロールおよび権限 – テンプレートで Lambda 実行ロールを指定していません。むしろ、IAM ポリシードキュメントとして必要な権限を提供しています。テンプレートが送信されると、CloudFormation は AWS::Serverless::Function リソースを展開し、Lambda 関数と実行ロールを宣言します。作成されたロールには、デフォルトの AWSLambdaBasicExecutionRole とテンプレートで指定されたインラインポリシーの 2 つのポリシーがアタッチされています。
  • CloudWatch Events ルール – CloudWatch Events リソースタイプを指定する代わりに、イベントソースオブジェクトを関数自体のプロパティとして定義しています。テンプレートが送信されると、CloudFormation はこれを CloudWatch Events ルールリソースに展開し、Lambda リソースベースの権限を自動的に作成して、CloudWatch Events ルールがその関数をトリガーできるようにします。

コンソールを使用したソリューションのデプロイ

1.) CloudFormation コンソールにログインし、[Create stack] を選択します。

2.) [Choose a template] では、[Specify an Amazon S3 template URL] を選択して、以下の URL を入力します。

https://s3.amazonaws.com/aws-bigdata-blog/artifacts/emr-dns-setter/emr-dns-setter-sam.json

注意: このソリューションを us-east-1 以外で使用する場合は、必要なファイルをダウンロードし、リージョンのバケットにアップロードし、必要に応じてスクリプトを編集してから実行するか、以下の CLI デプロイメント方法を使用する必要があります。

3.) [Next] を選択します。

4.) [Specify Details] ページでは、スタック名を保持または変更して、[Next] を選択します。

5.) [Options] ページで、[Next] を選択します。

6.) [Review] ページで、以下の手順を実行します。

  • 2 つの Transform アクセス機能を確認します。これにより、CloudFormation transform はカスタム名で必要な IAM リソースを作成できます。

  • [Transforms] で、[Create Change Set] を選択します。

変更セットが作成されるまで数秒待ってから、続行します。変更セットは次のようになります。

7.) [Execute] を選択して、テンプレートをデプロイします。

テンプレートをデプロイすると、次の 4 つのリソースが作成されているはずです。

AWS CLI を使用したソリューションのデプロイ

  • Lambda 関数コード emr-dns-setter.py と SAM テンプレート emr-dns-setter-sam.json をローカルマシンにダウンロードします。
  • emr-dns-setter-sam.json テンプレートの CodeUri プロパティを、関数コードのローカルパスに変更します。
<ファイルのパス>\emr-dns-setter.py
  • aws cloudformation パッケージの CLI コマンドを使用して、パッケージをアップロードします。
aws cloudformation package --template-file <FILE_PATH>\emr-dns-setter-sam.json --output-template-file serverless-output.template --s3-bucket <BUCKET_USED_TO_UPLOAD_YOUR_ARTIFACTS>  

パッケージが正常にアップロードされると、出力は次のようになります。

Uploading to 0f6d12c7872b50b37dbfd5a60385b854  1872 / 1872.0  (100.00%)
Successfully packaged artifacts and wrote output template to file serverless-output.template.

これで、serverless-output.template の CodeUri プロパティは、指定した S3 バケット内のパッケージ化されたアーティファクトを参照しています。

s3://<bucket>/0f6d12c7872b50b37dbfd5a60385b854
  • aws cloudformation deploy CLI コマンドを使用してスタックをデプロイします。
aws cloudformation deploy --template-file <FILE PATH>\serverless-output.template --stack-name <STACK_NAME> --capabilities CAPABILITY_IAM 

スタックが正常に作成されると、以下の出力が表示されます。

Waiting for changeset to be created...
Waiting for stack create/update to complete
Successfully created/updated stack – EmrDnsSetterCli

結果の検証

ソリューションをテストするには、EMR クラスターを起動します。Lambda 関数は、EMR クラスターに関連付けられた cluster_name タグを検索します。クラスターの使いやすい名前として host.domain.com と指定します。ここで、ドメインは CNAME レコードを作成するプライベートホストゾーンです。

以下は、必要なタグ cluster_name を使用して、VPC 内の特定のサブネットでクラスターを起動する CLI コマンドの例です。

aws emr create-cluster --tags LOB="finance" cluster_name="finance-ingest.domain.com" --release-label emr-5.3.1  --use-default-roles --instance-groups InstanceGroupType=MASTER,InstanceCount=1,InstanceType=m3.xlarge InstanceGroupType=CORE,InstanceCount=2,InstanceType=m3.xlarge --ec2-attributes SubnetId=subnet-xxxxxxxx,KeyName=keyname --no-auto-terminate

クラスターが起動したら、Route 53 コンソールにログインします。左側のナビゲーションペインで、[Hosted Zones] を選択して、Route 53 で現在設定されているプライベートゾーンとパブリックゾーンのリストを表示します。クラスターを起動したときに ZONE タグで指定したホストされているゾーンを選択します。リソースレコードが作成されていることを確認します。

また、TriggeredRules や Invocations の数など、毎分毎に CloudWatch に公開されている CloudWatch Events メトリクスを監視することもできます。

これで、Lambda 関数がゾーンファイルの Route 53 リソースレコードを正常に更新したことを確認したので、EMR クラスターを終了し、同じ関数でレコードが削除されていることを確認します。

結論

このソリューションは、一般的なノートブックやその他のウェブインターフェイスに簡単にアクセスできるように、EMR クラスターの使いやすい名前を自動的に割り当てるためのサーバーレスの方法を提供します。また、CloudWatch Events はクロスアカウントイベント配信もサポートしているため、複数の AWS アカウントで EMR クラスターを実行している場合、アカウント間のすべてのクラスターの状態イベントを単一のアカウントにまとめることができます。

このソリューションによって CloudWatch Events や Lambda のパワーを少し垣間見ることができ、EMR やその他の AWS のビッグデータサービスでどのように活用できかを理解できることを願っています。たとえば、EMR ステップの状態変化イベントを使用すると、アナリティクスパイプラインのさまざまな部分を連鎖させることができます。一時的なクラスターでデータ取り込みを実行し、タスクが正常に完了したら、ETL クラスターを変換して Amazon Redshift にアップロードすることができます。可能性は本当に無限です。


その他の参考資料

この記事が参考になった場合は、「Securely Access Web Interfaces on Amazon EMR Launched in a Private Subnet」および 「Respond to State Changes on Amazon EMR Clusters with Amazon CloudWatch Events」もぜひご覧ください。


著者について

Ilya は、AWS のソリューションアーキテクトです。彼は、高可用性、スケーラブル、セキュアなアーキテクチャを構築することにより、顧客が AWS プラットフォームを革新することを支援しています。余暇は屋外で時間を過ごし、子供たちとレゴでの創造を楽しんでいます。

 

 

 

Roger は、AWS のソリューションアーキテクトです。彼は、顧客がクラウドネイティブなアーキテクチャを実装し、組織としてそれらを分離することにより集中できるように支援しています。仕事以外では、木工や家族との料理を楽しんでいます。