Amazon VPC勉強メモ

・ネットマスクは/28(14IP)-/16の範囲で利用可能
サブネットで利用できないIP
1. ネットワークアドレス(.0)
2. VPCルータ(.1)
3. Amazonが提供するDNS(.2)
4. AWSで予約されている(.3)
5. ブロードキャストアドレス(.255)

・VPC作成後はVPCアドレスブロックは変更できない

・同一リージョン内のAZは高速専用線でつながっている。リージョン間はインターネット経由

ネットワークACL(アクセスリスト)でネットワークレベルでのセキュリティソフトを設定

ENI(Elasticネットワークインターフェース)
EC2で利用するネットワークの仮想インターフェース
EC2ごとにENIを複数持つことが可能
下記の情報をENIに紐づけて維持可能
1. プライベートIP(固定の設定可能)
2. Elastic IP
3. MACアドレス
4. セキュリティグループ

Floating IP
サーバに障害が起こった際に、ENIを維持して対応する
※VPCではサブネットを超えてアドレスを付け替えることができない点に注意
参考URL:https://goo.gl/JKphCj

サブネット内のDHCP
サブネット内のENIにIPを自動割り当て
※プライベートIPを固定にした場合はDHCP経由で該当のIPが割り当てられる

・VPCで使えるAmazonが提供するDNS
169.254.169.253
VPCのネットワーク範囲のアドレスに+2をプラスしたIP

プライベートホストゾーン
VPC内のインスタンスのみ参照可能。Route53のプライベートホストゾーンを利用

インターネットゲートウェイ(IGW)
VPC内のリソースにインターネットの接続を提供。VPCにアタッチする
単一障害店や帯域幅のボトルネックはない

メインルートテーブルカスタムルートテーブル
メインルートテーブル:VPCを作成したときに自動的に割り当て
カスタムルートテーブル:任意で作成したルートテーブル。メインに変更することも可能

パブリックサブネットの設定
自動で割り当て:サブネットに自動割り当てを設定
固定で割り当て:Elastic IPをアタッチ

Elastic IP
費用がかかるのは下記の場合
1. 追加でEIPを利用する場合
2. 起動中のEC2インスタンスに割り当てられていないとき
3. アタッチされていないENIに割り当てられている場合
4. 1ヶ月でリマップ(割り当て、取り外し)が100回を超えた場合

NATゲートウェイ
プライベートサブネットのリソースがインターネットに通信するために必要
AZごとに設置するのがベストプラクティス

VPCエンドポイント
プライベートサブネットからS3バケットにアクセス可能
S3アクセスのためにIGWNATインスタンスが不要

バーチャルプライベートゲートウェイ(VGW)
オンプレミスとのVPN接続のためのエンドポイントとなる仮想ルータ。VPC側
単一障害点や帯域幅のボトルネックはなし

カスタマゲートウェイ(CGW)
オンプレミス側。AWSとのVPN接続のため

VPN接続
VGWCGW間でIPsecトンネルが設定

・VPC Peering

2 つの VPC 間でトラフィックをルーティングすることを可能にするネットワーク接続
https://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-peering.html

ネットワーク接続の最大送信単位 (MTU)に注意。VPC Peeringは1500

異なるAWSアカウントでも可能
但し、異なるリージョン間では使用できない

セキュリティグループ
仮想ファイアウォール
1つのEC2で5つのセキュリティグループが設定可能
デフォルトですべての通信は禁止
VPCぴあリング先のセキュリティグループが設定可能

ネットワークACLVSセキュリティグループ
ネットワークACL:サブネットレベルで効果。ステートレスなので戻りのトラフィックも明示的に許可設定
セキュリティグループ:サーバーレベルで効果。ステートフルなので戻りのトラフィックは気にしなくてよい

・オンプレミスとのハイブリッド構成
Direct Connectを使用する
VPCからオンプレミスへの通信をするためには、各サブネットのルートテーブルの設定が必要
宛先:オンプレミスのIP
ターゲット:VGWのID
VPNとDirect Connectで冗長可能。Direct Connectが優先

・VPC設計
アプリケーション/監査/フェーズ(本番/検証/開発)/部署などによる分割

VPC Flow Logs
ネットワークトラフィックをキャプチャ氏、CloudWatchへPublishする機能
ネットワークインターフェースを送信元/送信先とするトラフィックが対象
CloudWatch Logsの標準料金のみ課金
VPC Flow Logsで取得できない通信
1. Amazon DNSサーバへのトラフィック

・VPCのリミット
リージョン当たりのVPCの数:5
VPC当たりのサブネット:200
AWSアカウント当たり1リージョンのEIP:5
ルートテーブルあたりのルートの数:100
VPCあたりのセキュリティグループの数:500

参考URL:
http://kakakakakku.hatenablog.com/entry/2016/08/07/232305
https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-2016-amazon-vpc

続きを読む

「Microservices Meetup vol.6」に行ってきた

2017/1/19のデイリーストックランキングにランクインしました。

【毎日自動更新】Qiitaのデイリーストックランキング!ウィークリーもあるよ_-_Qiita.png


いままでの。
「Microservices Meetup vol.2」行ってきたメモ。
「Microservices Meetup vol.4」に行ってきた

図らずして1回おきに参加してますね。

Connpassのイベントページ

少し間が空いてしまったがまた定期的に開催していきたいです。
登壇したいよーって人は直接リプ投げてください
by @qsona さん

Microservices on AWS by @Keisuke69 さん

Keisuke Nishitani @ AWS

Specialist Solutions Architect

サーバーレスアプリケーション開発ガイド 2月発売

マイクロサービスのポイント

  • 管理運用まで含めて分散型
  • 各コンポーネントが独立している
    • 単独で実行できないのは適切に設計されていない

独立して分散していると負荷の高い機能の単位でスケールさせられる=コスト効率が良い

  • 一つのことをうまくやる

    • 複雑化したら分割する
  • 多言語

    • チーム(機能)にはそれぞれの問題に対して適切なツールを選択する自由がある
    • OS、言語、各種ツールに至るまで最適なアプローチを目指せる
  • 検索:Elasticsearch / Solr

  • ソーシャル:グラフDB

  • ログデータ:Cassandra

  • セッション:Redis

†AWSでは:AWSには100ちょいのサービスがあって、その中で更にチームが分かれている。
各チームに社内標準の開発プロセスは存在しない。

  • ブラックボックス

    • 詳細は外部のコンポーネントに公開されない
  • DevOps
    • マイクロサービスにおける組織原理

†AWSでは:運用のみのチームはない。オンコールも開発チームが請け負う

  • 俊敏性

    • 狭い範囲のコンテキストで活動=サイクルタイムが短い
    • システムもシンプル
    • パラレルな開発とデプロイが可能
  • イノベーション

    • 選択に対する権限と責任を持つのでイノベーションを起こしやすい
    • DevとOpsの対立がないため、効率化やイノベーションが起こしやすい
  • 拡張性

    • 適切に非干渉化されてていることで水平方向に単独にスケールできる
  • 可用性

    • ヘルスチェック、キャッシング、隔壁、サーキットブレーカーと言った仕組みは全体の可用性を向上させる

課題

  • 分散型であることは難しい

    • システム数が増える
    • 協調動作の難しさ
    • コンポーネント間のコミュニケーションメッセージ増によるレイテンシ低下
    • ネットワークの信頼性は無限ではない、帯域も無限ではない
  • 移行が大変
    • モノリシックなシステムの分割は難しい
  • 組織
    • 組織体制の変更が必要になるが、それは大変なこと
  • アーキテクチャの難易度
    • 非同期通信
    • データ整合性
    • やっぱりココが一番の課題
    • サービスディスカバリ
    • 認証
  • 運用の複雑さ

アーキテクチャ

一番シンプルなパターン

CloudFront – ALB – ECS – datastore(ElastiCache, Dynamo, )
|
S3

  • バックエンドをRESTfulなAPIにしたSPA
  • 静的なコンテンツはS3とCloudFront
    • CDN通すことでレイテンシが上がることもある
    • キャッシュとの併用を検討
  • ECSとAutoScalingをALBとともに使うことが多い
    • ALB(L7LB)でアプリレベルの情報をルーティング
    • コンテナインスタンスにリクエストを分散
    • ECSのコンテナを負荷に応じてスケールアウト/インする

コンテナのメリット

  • Portable
  • Flexible
  • Fast
    • 軽量で早い
    • ポータビリティと関連して開発サイクルも早く
  • Efficient

  • 一貫性のある環境

  • バージョン管理出来る

Dockerの特徴

  • Package
  • Ship
  • Run

ECS

  • 複数のコンテナをEC2のクラスタ上で一元管理

    • まだTokyoにきてないけど、FargateでEC2の管理もいらなくなるよ
    • EKS(Kubernetes)も発表されています

データストア

  • インメモリ

    • Memcached, Redis
    • ElastiCache
    • DB負荷の軽減
  • RDBMS
    • 無限のスケーリングには向いていない
    • Amazon RDS
  • NoSQL
    • 水平スケーリングをサポートするものが多い
    • テーブル結合ができないのでロジックの実装が必要になる場合も
    • Amazon DynamoDb, KynamoDB Accelarator(DAX)

APIの実装

  • APIの設計、改善、デプロイ、モニタリング、保守派手間がかかる
  • 異なるバージョンが混在すると大変

Amazon API Gateway

  • 複数バージョンとステージ
  • Cognite User Poolsと連携して認証を追加
  • スロットリング、モニタリング
  • バックエンドとしてLamdbaが使える

サーバーレス

  • サーバーはないに越したことはない
  • スケーリングと高可用性の担保が大変
CloudFront - API Gateway - Lamdba - datastore
   |                            (ElastiCache, Dynamo)
   |
  S3

課題をAWSでどうするか

サービスディスカバリ

  • お互いの死活確認や発見
  • ハードコードするとスケールできない

    • メタデータをどこに置くか
  • ALBを利用したサービスディスカバリ

  • DNS(Route53)のサービスディスカバリ

    • VPC単位の振り分け
  • ECSイベントストリームを使用したサービスディスカバリ

    • CloudWatchイベントで拾ってキック
    • LamdbaでRoute53に登録
    • これが一番多いかも
  • DynamoDBを使用したサービスディスカバリ

    • DNSキャッシュの問題がない
    • 自由度が高い
    • 実装が大変
    • DynamoDBストリームを活用して他のサービスへステータス変更を反映
  • イベントベースのアーキテクチャ

    • イベントで処理する
    • いわゆる結果整合性とも関連
    • Dual Write Problem
    • Event Sourcing
      • 状態の記録ではなく状態の変更「イベント」を記録
      • Amazon Kinesis
      • kinesisにpublishして他サービスはsubscribe
      • S3にログを残す
      • トランザクションログの仕組み

モニタリング

  • CloudWatch

    • ログファイルの一元化
    • CloudWatch LogsかS3に保存可能
    • ECSはCloudWatch Logsに一元化できる

分散トレース

  • AWS X-Ray
  • 複数サービスに分散したリクエスト処理を透過的に追える

LogWatchの先に Kinesis FireHorse – ほにゃほにゃ

スロットリング

  • 大事だよ

リトライ

  • 多くのエラーはリトライでカバーできるものが多い
  • リトライ多発で過負荷になることがある
    • Exponential back offもしくはフィボナッチ数列を利用したリトライ感覚の調整
    • 更に乱数でゆらぎを付けて重ならないように

LT:クラウド型医療系業務システムと Microservices への歩み by @hashedhyphen さん

https://speakerdeck.com/hashedhyphen/kuraudoxing-dian-zi-karutesisutemuto-microservices-hefalsebu-mi

クラウド型電子カルテシステムの話

  • メインロジックをRails
  • 常時接続をNode.js
  • バックエンドをScala
  • 基盤はAWS

ここに至る道のり

ファーストリリース前

  • レコメンドは大量のデータが必要

  • メインロジックで実現させようとすると厳しかった

    • Threadとか試したけど……
    • 別アプリケーションとして分離
    • JVM上でScala + Skinnyでスレッドアプリケーションンを実装
    • Microservicesちっくな構成へ
  • 障害検知時

    • メインロジック内のプロトタイプ版が動く!

会計機能リリース前

  • お金を扱う機能は安定性が欲しい
  • Scala + Cats による実装を別エンドポイントとして実装
  • マイクロサービスっぽい作りになっていたから自由度のある技術選択が出来た

まとめ

  • ちょっとマイクロサービス化したことで自由度が上がった
  • 原理主義的にならなくても恩恵がある
  • エンジニアの伸びしろ!

FrontEndからみるmicroserviceとBackendからみるmicroservice by @taka_ft さん

Takahiro Fujii @ Rakuten Travel

楽天内でも採用アーキテクチャはサービスによって異なる。

サービスとしては

  • コンシューマ向け
  • Extranet
  • In-house
  • other
    • ここまではWEBとモバイルがあって、100以上のAPIを利用する
  • API(内部APIを直接利用)

Phase 1

  • 大きなモノリシックなアプリだった
  • 機能がどんどん増えていく
    • 機能別で複数のモノリシックなアプリに分割
    • その後フロントエンドとバックエンドに分割

Phase 2

  • ドメインモデルを整理
  • なるべくRESTfulで作るようになっていった
  • 大きなAPIから小さなAPIに分離
  • I/Fの決定に時間がかかるようになった
  • API呼び出しが大変になった
  • Microservicesっぽくなってきた 2014年くらい

  • 国内予約、海外予約で多言語化だけではない商習慣に根ざしたドメインの差異による重複ロジックの増殖が起きた

  • Microservicesっぽくなってきたが、どんどん品質が下がっていった

Phase 3

(ちょうど前日にプレスリリース)サイト前面刷新に向けての取り組み

  • FrontendsはJavaScriptに刷新
  • API GatewayにKong

組織

  • フロントエンドチームが2人から始まって半年でReactエンジニアを集めて20人以上に

    • 日本人は2, 3人

UI Component

  • SpringからJavaScriptでSPAに変更
  • zeplinのデザインモックからUI Componentを実装するようになった
  • Storyboardを使ってUI Coponentを管理
  • ドメインを含むUI Componentはドメインと結び付きが強いことが多い=専用のオーケストレーションAPIを用意してUI Componentないで処理を閉じることが出来る
  • レスポンシビリティを明示的に定義

    • どこまでフロントエンドでやるか、どこからAPIからもらうか
  • フロントエンドの「使いやすいレスポンス」の要求

  • バックエンドの「汎用的でシンプルなレスポンス」の希望

    • これらのバランスを取る
  • API Gatewayはフロントエンド(UI)チームの管轄

    • ただし状況によってはバックエンド側に持っていくことも検討するつもり

LT: “マイクロサービスはもう十分”か? by @qsona さん

https://speakerdeck.com/qsona/enough-with-the-microservices

POSTDに投稿していた翻訳記事。

スタートアップ企業のほとんどはマイクロサービスをさいようすべきではない

銀の弾丸はない。

「チーム間の依存性」の解決にマイクロサービスというアプローチは違う。疎結合と分散は別。

組織が大きくなると、複数チームが1つのコードベースを触るようになる。そしてマイクロサービス化したくなる。

しかし、モノリスの分割で十分。

チームとは何か

  • 自律的に動けるべき

    • チームが増えるとコミュニケーションコストや、しがらみ
  • チームの分割は目的にそった分割を行う

  • 悪い分割の例: Dev / Ops

  • 依存度が低いほど自律的に動ける

  • High Output という本

  • 使命型組織/技術型組織

    • Micorservicesは使命型組織
    • 組織間が密ならサービス間も密になる

話戻して

  • スタートアップは組織をキレイに分割することが難しい
  • 分割しても密になってしまう

  • 大きなモノリスになるとやはり分割は難しい

    • ドメインの意識は必要
  • マイクロサービス設計しなくても「マイクロサービス精神」で開発すると効果的なのではないか

FiNCが初期からマイクロサービスでやってた理由

  • 単独の事業にできるような一つ一つのサービスを組み合わせて提供してきたから

あとで読み返して修正します。
資料パスの追加とかも。

続きを読む

そのAWS Lambdaの.NET Core、1.0から2.0にアップデートしませんか?

概要

  • 2018年1月15日、とうとうAWS Lambdaでの.NET Coreで2.0がサポートされるようになりました🎉
  • 早速バージョンアップしてみましょう。

ソリューションのアップデート

細かいことはおいておいて、まずはアップデートしてみましょう。

題材はこれです。

CloudWatch Logsに書き込まれた内容をSlackとGoogle Homeで通知するAWS Lambda using dotnet

がんばった割に鳴かず飛ばずだったこの記事で紹介している、CloudWatch Logsを監視してSlackとGoogle Homeに通知するLambdaです。

https://github.com/toshi0607/ErrorNotificationLambda

プロジェクト構成

ErrorNotificationLambda/
├ErrorNotificationLambda/
│ ├Properties/
│ ├aws-lambda-tools-defaults.json
│ ├ErrorNotificationLambda.csproj
│ ├Function.cs
│ └Readme.md
└ErrorNotificationLambda.Tests/
  ├Properties/
  ├ErrorNotificationLambda.Tests.csproj
  ├FunctionTest.cs
  └LaunchSettingsFixture.cs
“`

変更箇所

csprojを変更します。

ErrorNotificationLambda.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp1.0</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <WarningLevel>0</WarningLevel>
  </PropertyGroup>

  <PropertyGroup>
    <OutputType>Library</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.CloudWatchLogsEvents" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="1.8.0" />
  </ItemGroup>

</Project>

これを

<TargetFramework>netcoreapp1.0</TargetFramework>

こう

<TargetFramework>netcoreapp2.0</TargetFramework>

以上。

Visual Studio 2017から編集する場合は、該当プロジェクトを右クリックすると「[プロジェクト名].csprojの編集」が選択できます。

4csproj.PNG

aws-lambda-tools-defaults.jsonにデフォルトのデプロイ設定を書いている場合、そちらもお忘れなく。

Publish to Lambdaするときに設定を保存しても書き換わってくれます。

また、Serverless Applicationのテンプレートからプロジェクトを作成した場合はCloudFormationのリソースもdotnetcore2.0に変更しましょう。

AWS Toolkit for Visual Studio 2017のアップデート

AWS Toolkit for Visual Studio 2017はVisual Studioからデプロイしたり、テンプレートを選択したりできるようにする拡張機能です。

今回.NET Core 2.0系対応が入った拡張機能のバージョンは1.14.0.0ですが、僕のVisual Studioにはまだ更新が降ってきていなかったので、マーケットプレースから直接.vsixをダウンロードし、インストールしました。

現在インストールされているバージョンは「ツール」->「拡張機能と更新プログラム」->「インストール済み」の中にあるAWS Toolkit for Visual Studio 2017を選択すると確認することができます。

61.14.PNG

バージョンアップすることで変更される大事なポイントは次の二点でしょう。

  • Language Runtimeで.NET Core v2.0が選択できる
  • Memoryが3008MBまで選択できる

メモリはまた上限上がったんですねw 年末のLambda共通のアップデート時点ではポータルで選択できる上限が上がっているにもかかわらず、「Upload Lambda Function」ではそれが反映されていませんでした。

72.0.PNG

8memory.PNG

動作確認

ローカルでテスト通るか?

デプロイ後ポータルでのバージョンが2.0になっているか?

82.0.PNG

本番環境のLambdaに対してテストイベントを発行した期待した結果になるか?

9vs.PNG

9slack.PNG

特に問題はなかったです。

アップデートの詳細

You can now develop AWS Lambda functions in C# using the .Net Core 2.0 runtime! Get started easily with the AWS Toolkit for Visual Studio. https://t.co/uxmrKodaUY pic.twitter.com/h442a6DwEZ

— Amazon Web Services (@awscloud) 2018年1月16日

AWS Lambda Supports C# (.NET Core 2.0)

AWS Lambda .NET Core 2.0 Support Released

一番下のが実際に開発してる人が書いた記事です。

aws-lambda-dotnetは大体この人が書いていると言っても過言ではないし、PRを出すととても丁寧に対応してくれます。

https://github.com/aws/aws-lambda-dotnet/graphs/contributors

VSTSのAWS周りタスクがリリースされた記事も英語版が出て2週間後くらいに日本語版が出たので、今回もきっとそのうち日本語版が出ることでしょう。

とても雑にまとめると、

  • .NET Core 2.0サポートすると、.NET Standard 2.0ベースでライブラリを作成するときより多くの.NET APIを利用できるので、既存の.NET資産をより使い回しやすくなる
  • テンプレはもう2.0ベースにアップデートしているので、AWS Toolkitのテンプレート使ってVisual Studioからデプロイしてしまうのが一番楽
  • Amazon.Lambda.Toolsも2.0がリリースされ、パッケージングするにあたって2.0ランタイムで必要となるファイルも生成できる
  • Amazon.Lambda.Templatesも2.0.0(同日に2.0.1がリリースされていた…!)がリリースされ、Visual Studioがなくてもすべてのテンプレがコマンドで利用できるようになった
  • プログラミングモデルは変わっていたいので、既存の1.0系プロジェクトもシュッとアップデートできる
  • AWS Tools for VSTSもアップデートされて2.0対応されたが既存のタスクを更新する必要はない

まとめ

「.NET Core 2.0対応」が目につきますが、実際は周辺のツールのアップデートがとてもとてもいい感じです。

続きを読む

AWSとAzureとGCPを比較してみる – FaaS編

FaaSについてAWSとAzureとGCPを比較してみました。

注)

1. FaaS比較表

AWS Azure GCP
Lambda Functions Cloud Functions***
言語 Python,
node.js,
java,
C#,
go
ランタイムバージョン1.X
C#,
JavaScript,
F#,
Python*,
PHP*,
TypeScript*,
バッチ (.cmd、.bat)*,
Bash*,
PowerShell*

ランタイムバージョン2.X
C#**,
JavaScript**,
Java**
node.js***
最大実行時間 5分 10分 (従量課金プラン)
無制限 (App Serviceプラン)
9分
直接HTTPアクセスを受け付けるか 受け付けない(API Gatewayと連携必要) 受け付ける 受け付ける
トリガー Amazon S3,
Amazon DynamoDB,
Amazon Kinesis Data Streams,
Amazon Simple Notification Service,
Amazon Simple Email Service,
Amazon Cognito,
AWS CloudFormation,
Amazon CloudWatch Logs,
Amazon CloudWatch Events,
AWS CodeCommit,
スケジュールされたイベント (Amazon CloudWatch Events を使用),
AWS Config,
Amazon Alexa,
Amazon Lex,
Amazon API Gateway,
AWS IoT ボタン,
Amazon CloudFront,
Amazon Kinesis Data
Blob Storage,
Cosmos DB,
Event Hubs,
HTTP,
Microsoft Graph Events(2.Xのみ),
Queue storage,
Service Bus,
Timer,
Webhooks(1.Xのみ)
HTTP,
Cloud Storage,
Cloud Pub/Sub

*試験段階
**プレビュー
***ベータ

2. 対応言語の比較

言語の種類は試験段階とプレビューを含めればAzureが一番多いのですが、正式リリースされたものに限定すればAWSの方が種類が多いです。
一方GCPは機能自体がベータリリースなので、まだこれからといった感じでしょうか。

AzureはBashにも対応しているのが特徴です。運用系のシェルスクリプトをFaaS化すれば、スクリプト用のサーバが不要になりますね。

3. 最大実行時間

最大実行時間はAzureの10分(要host.jsonのfunctionTimeoutプロパティ変更)、GCPの9分に対しAWS Lamdbaは5分と約半分です。実際にAWS Lambdaを利用していると5分の壁を結構感じます。この点は他クラウドが羨ましいですね。
2017年のRe:InventでAWSはFargateというコンテナのサービスをリリースしましたが、このサービスがlambdaが5分以上実行できないことに対するAWSからの回答のように感じます。

4. 直接HTTPアクセスを受け付けるか

AWS lambdaだけ直接HTTPアクセスを受け付けることができません。HTTPアクセスを受け付けるには、API Gatewayと連携する必要がありますが、多機能な分やや設定が面倒な印象です。(但しAPI経由でLambdaを起動することは可能)

まとめ

AWS Lambdaのリリース後、Azure・GCP・Bluemix(現IBM Cloud)は超特急で追従しました。AWS LambdaがIT業界に与えたインパクトはとても大きかったと思います。
現在は「FaaS無ければばクラウドにあらず」といったところでしょうか。

また、AWS GreengrassやAzure IoT Edge**というエッジにデプロイするサービスも出てきています。
将来AWS LambdaがiPhoneやApple Watchにデプロイできるようにならないかなーと妄想中です。

**プレビュー

続きを読む

AWS初心者がLambdaでLINE BOTを作る

LINE BOTでオウム返しのBOTを作ります。
正直AWSを触ったことが無いので、よく分からず困ったので同じように困る人が出ないように
記事にすることにしました。

言語・ツール選定

私はRaspberry pi & PHPでLine botを作ったことが有る。
内容としては位置情報を渡すと近くのコンビニを教えてくれるものだ。
しかし、Raspberry piでLine botを作ると、常にRaspberry piを起動しておく必要があり電力的に優しくなく、
サーバの構築や認証鍵の設定が面倒だった。
そこでサーバレスのLine Botを作ろうと思いました。
私が選択したのはLambda+Node.js。
選択肢としてGAS(Google App Script)もあったけれど今後の拡張性を考えた時、
ES6が簡単に使えない(変換すれば使えるが面倒な)のが嫌だと思ったのでやめました。

環境構築

LINE Developers
https://developers.line.me/ja/
↑LineBotを作るためにアカウント取得する
【公式】クラウドならアマゾン ウェブ サービス (AWS)
https://aws.amazon.com/jp/
↑AWSの登録する(日本アカウントだと駄目?)

おわり

使用するAWS

初心者なのでLambdaだけで作れると思ってました。
すると、そういう訳じゃなくいくつかサービスを利用しないといけないことが分かりました。

Lambda
サーバレス、コンピューティングサービス。
サーバ構築しなくてもイベントやトリガーで実行出来るサービス。
使用できる言語はNode.js、Java、C#、Python。
無料枠は
月1,000,000リクエスト
秒400GB 月間400,000GB
有料枠は
1,000,000リクエストごとに0.20USD(約22.6円)
他のサービスは別料金

API Gateway
API の作成、配布、保守、監視、保護が出来る。
Lambdaの関数を動作させる(キックする)ために使う。
料金はデータ送出量で変わる、使用する地域ごとに料金が違う。
無料期間が終わったら有料。

IAM (これはサービスではなく仕組み)
アクセスを安全に制御するための仕組み。権限(role)の設定をする。
Lambdaでログを取ったりするときに設定が必要。

CloudWatch Logs
ログを取るために使う。
無料枠Amazon CloudWatch でのメトリックス 10 個、アラーム 10 個、API リクエスト 1,000,000 件
まぁ、サービスがうまく稼働したら止めると思うので有料枠は気にしない。

api Gatewayの設定

+APIの作成からAPI名とエンドポイントタイプを決める。

エンドポイントとは?
ゲートウェイ VPC エンドポイント??

Amazon API Gateway で、REST API およびカスタムドメインの作成時に 2 種類の API エンドポイントから選択できるようになりました。
リージョンの API エンドポイントは、REST API をデプロイするのと同じ AWS リージョンからアクセスできる新しいタイプのエンドポイントです。
これにより、API リクエストが REST API と同じリージョンから発信される場合に、リクエストのレイテンシーを減らすことができます。
さらに、独自の Amazon CloudFront ディストリビューションとリージョンの API エンドポイントの関連付けを選択できるようになりました。
API エンドポイントの 2 つ目のタイプは、エッジ最適化 API です。
エッジ最適化 API は、API ゲートウェイによって作成および管理される CloudFront ディストリビューション経由でアクセスするエンドポイントです。
以前は、エッジ最適化 API は、API ゲートウェイを使用して API を作成する際のデフォルトオプションでした。

つまり、どーいうことだ?
何か、ドメイン関係というのは分かった、
エンドポイントとは?
https://qiita.com/NagaokaKenichi/items/6298eb8960570c7ad2e9

なるほど。
URIの設定のことね。
んで、エンドポイントタイプの違いって具体的に何?

Regional:リージョン(地域が一緒なら早い)
Edge Optimized:エッジ最適化(経由して最適化する)
って感じかな?
今回はAPI GatewayもLambdaも同じハイオワにしたので、リージョンで良さそう。

API 名を決めないと何故かエラーが出る模様。訳が分からない。泣いた。
http://kubotti.hatenablog.com/entry/2017/01/13/161022

リソースで、ポストが出来るように設定しLumbdaの関数が完成したらAPIのデプロイをする。
image.png

設定で、ARNの設定をする。
image.png
Lumbdaへのアクセスできる設定とログが取れるようアクセスを許す設定した物を割り当てる。
あ、後クライアント証明書も作った。

Lamubdaの設定

image.png
実行ロールの設定でログ監視とAPIGatewayからのアクセスが可能なアカウントを設定する。

コードはこんな感じ

index.js
'use strict';

const https = require('https');
const querystring = require('querystring');

exports.myHandler = (event, context, callback) => {
    console.log('EVENT:', event);
    var event_data = JSON.parse(event.body);
    console.log('EVENT:', JSON.stringify(event_data));
    const messageData = event_data.events && event_data.events[0];
    console.log("TEST:" + JSON.stringify(messageData.message.text));
    var id = messageData.source.userId;
    if(messageData.source.groupId != null && messageData.source.groupId.length > 0){ //グループからのメッセージ
        id = messageData.source.groupId;
    }

    if(!check(messageData.message.text)){
        callback(null, 'Success!');
        return;
    }
    var postData = JSON.stringify(
    {
        "messages": [{
            "type": "text",
            "text": getResponseMessage(messageData.message.text)
        }],
        "to": id
    });
        // @TODO KMSで管理
    var ChannelAccessToken = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; //チャンネル設定

    //リクエストヘッダ
    var options = {
        hostname: 'api.line.me',
        path: '/v2/bot/message/push',
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'Content-Length': Buffer.byteLength(postData),
            'Authorization': 'Bearer ' + ChannelAccessToken
            },
        method: 'POST',
    };
    console.log(JSON.stringify(options));
    //APIリクエスト
    var req = https.request(options,  function(res){
        res.setEncoding('utf8');
        res.on('data', function (body) {
            console.log(body);
            context.succeed('handler complete');
        });
    }).on('error', function(e) {
        context.done('error', e);
        console.log(e);
    });

    req.on('error', function(e) {
        var message = "通知に失敗しました. LINEから次のエラーが返りました: " + e.message;
        console.error(message);
        context.fail(message);
    });

    req.write(postData);
    req.on('data', function (body) {
            console.log(body);
     });
    req.end();
    console.log("TEST:" + postData);
    callback(null, 'Success!');
};

var getResponseMessage = function(message) {
    message = message.toLowerCase();
    message = message.replace('@bot ', '');
    switch (message) {
        default:
            return message;
    }
};

var check = function(message) {
    message = message.toLowerCase();
    var pattern = '@bot ';
    return message.indexOf(pattern) === 0;
};

・↑ではセキュリティガバガバなので、Lineからのアクセスかどうか検証するためにChannel SecretのIDを見るプログラムと、ChannelAccessTokenは管理するものを入れたほうが良いと思います。
・replyでも良いんですが、処理に時間がかかると処理されないらしいので今後重い処理を入れることを考えてpushにしました。
(参照:https://developers.line.me/ja/docs/messaging-api/reference/)
・グループに突っ込んだ時に関係なく反応するのがうざかったので、@botと頭につくと返すようにしました。

image.png
LINE DevelopersのChannelAccessTokenはここのやつをコピペ。

image.png
上のような形で登録する。(念のため443はつけたほうが良い)

image.png
↑のエラーが出ますが問題なく動きます。

結果

image.png
出来た。

まとめ

AWSのいい勉強になった。
私のセキュリティ意識が低いことが分かった。
よくわからないところからAPIリクエストが飛んで来ていたので気をつけたい。
LineBotはちょっと前とはAPIの書き方が変わっていた&単純にNode.jsに慣れていないというのもあって、ちょっと苦戦した。
今後は、飲み会幹事BOTなどにしていきたい。
たのしかった。

参考

https://qiita.com/akihito_nagai/items/f284ef495da380f368cc
https://qiita.com/ykyk1218/items/232437bc92f13d02a8a2
https://qiita.com/daikiojm/items/c05882bedb82d7ed664e

続きを読む

CloudFormationテンプレート(JSON) – CloudTrail 設定

1. 概要

2. 各リソースメモ

3. JSONテンプレート

CloudTrail.json
{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Description" : "CloudTrail",
     "Resources" : {
        "S3Bucket" : {
            "Type" : "AWS::S3::Bucket",
            "Properties" : {
                "BucketName" : { "Fn::Join" : [ "", [ "cloudtrail-", { "Ref" : "AWS::AccountId" } ] ] }
            }
        },
        "S3BucketPolicy" : {
            "Type" : "AWS::S3::BucketPolicy",
            "Properties" : {
                "Bucket" : { "Ref" : "S3Bucket"},
                "PolicyDocument" : {
                    "Version" : "2012-10-17",
                    "Statement" : [
                        {
                            "Sid" : "AWSCloudTrailAclCheck20150319",
                            "Effect" : "Allow",
                            "Principal" : { "Service" : "cloudtrail.amazonaws.com"},
                            "Action" : "s3:GetBucketAcl",
                            "Resource" : { "Fn::Join" : [ "", [ "arn:aws:s3:::cloudtrail-", { "Ref" : "AWS::AccountId" } ] ] }
                        },
                        {
                            "Sid" : "AWSCloudTrailWrite20150319",
                            "Effect" : "Allow",
                            "Principal" : { "Service" : "cloudtrail.amazonaws.com" },
                            "Action" : "s3:PutObject",
                            "Resource" : { "Fn::Join" : [ "", [ "arn:aws:s3:::cloudtrail-", { "Ref" : "AWS::AccountId" }, "/AWSLogs/", { "Ref" : "AWS::AccountId" }, "/*" ] ] },
                            "Condition" : { "StringEquals" : { "s3:x-amz-acl" : "bucket-owner-full-control" } }
                        }
                    ]
                }
            }
        },
        "IAMRole" : {
            "Type" : "AWS::IAM::Role",
            "Properties" : {
                "AssumeRolePolicyDocument" : {
                    "Version" : "2012-10-17",
                    "Statement" : [
                        {
                            "Sid" : "",
                            "Effect" : "Allow",
                            "Principal" : {
                                "Service" : "cloudtrail.amazonaws.com"
                            },
                            "Action" : "sts:AssumeRole"
                        }
                      ]
                },
                "Path" : "/",
                "Policies" : [
                    {
                        "PolicyName" : "cloudtrail",
                        "PolicyDocument" : {
                            "Version" : "2012-10-17",
                            "Statement" : [
                                {
                                    "Sid" : "AWSCloudTrailCreateLogStream20141101",
                                    "Effect" : "Allow",
                                    "Action" : [ "logs:CreateLogStream" ],
                                    "Resource" : { "Fn::Join" : [ "", [ "arn:aws:logs:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":log-group:CloudTrail:log-stream:", { "Ref" : "AWS::AccountId" }, "_CloudTrail_", { "Ref" : "AWS::Region" }, "*" ] ] }
                                },
                                {
                                    "Sid" : "AWSCloudTrailPutLogEvents20141101",
                                    "Effect" : "Allow",
                                    "Action" : [ "logs:PutLogEvents" ],
                                    "Resource" : { "Fn::Join" : [ "", [ "arn:aws:logs:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":log-group:CloudTrail:log-stream:", { "Ref" : "AWS::AccountId" }, "_CloudTrail_", { "Ref" : "AWS::Region" }, "*" ] ] }
                                }
                            ]
                        }
                    }
                ],
                "RoleName": "cloudtrail"
            }
        },
        "LogsLogGroup": {
            "Type" : "AWS::Logs::LogGroup",
            "Properties" : {
                "LogGroupName" : "CloudTrail",
                "RetentionInDays" : 7
            }
        },
        "CloudTrailTrail" : {
            "DependsOn" : "S3BucketPolicy",
            "Type" : "AWS::CloudTrail::Trail",
            "Properties" : {
                "CloudWatchLogsLogGroupArn" : { "Fn::GetAtt" : [ "LogsLogGroup", "Arn" ] },
                "CloudWatchLogsRoleArn" : { "Fn::GetAtt": [ "IAMRole", "Arn" ] },
                "IncludeGlobalServiceEvents" : true,
                "IsLogging" : true,
                "IsMultiRegionTrail" : true,
                "S3BucketName" : { "Fn::Join": [ "", [ "cloudtrail-", { "Ref" : "AWS::AccountId" } ] ] },
                "TrailName" : { "Ref": "AWS::AccountId" }
            }
        }
    },
    "Outputs" : {
        "S3Bucket" : {
            "Description" : "S3 Bucket Name",
            "Value" : { "Ref" : S3Bucket }
        },
        "IAMRole" : {
            "Description" : "IAM Role Name",
            "Value" : { "Ref" : IAMRole }
        },
        "LogsLogGroup" : {
            "Description" : "Log Group Name",
            "Value" : { "Ref" : LogsLogGroup }
        },
        "CloudTrailTrail" : {
            "Description" : "Trail Name",
            "Value" : { "Ref" : CloudTrailTrail }
        }
    }
}

続きを読む

AWS CloudWatchについての記事まとめ

個人メモ用記事

概要

【AWS】CloudWatch
CloudWatch 標準メトリクス(監視項目) 一覧
Black Belt Online Seminar Amazon CloudWatch
AWS Black Belt Techシリーズ Amazon CloudWatch & Auto Scaling
AWS Black Belt Techシリーズ AWS CloudTrail & CloudWatch Logs
AWS Blackbelt 2015シリーズ Amazon CloudWatch & Amazon CloudWatch Logs

ELB

CloudWatchのELB監視項目
あらたにELBを作成する時の、CloudWatch設定メモ
ELBの挙動とCloudWatchメトリクスの読み方を徹底的に理解する
CloudWatchのあるはずのメトリックスが存在しない理由
ELBのHealthyHostCountは全AvailabilityZoneの合計値をモニタリングできない?

EC2

死活監視

AWS CloudWatchでEC2の死活監視

メトリクス監視

新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する
[AWS] CloudWatch でロードアベレージとかメモリ使用量とか監視
ECSクラスタのCPUとメモリをCloudWatchメトリックスで取得してみた
EC2のメモリ使用量とdisk使用量をcollectdでサクッとCloudWatchに登録
AWS CloudWatch で、Amazon Linux のパフォーマンスとログの監視をしてみる
はじめてのCloudWatch(AWS) 〜カスタムメトリクスを作って無料枠でいろいろ監視する〜
AWS CloudWatch シェルだけでPutMetricDataを実行する
AWS CloudWatchでEC2を監視する (プロセス死活監視、ディスク使用率、iノード使用率を監視してアラートメールを送信する)

ログ取得

CloudWatch Logsを使ってログを集める!
CloudWatch Logsのインストール・設定
EC2インスタンスのログをCloudWatchで見る
AWS EC2でメモリ利用率をCloud Watchで監視する
nginxのエラーログをcloudwatch logsに送信する

RDS

Amazon RDS のモニタリング
CloudWatchのRDS監視項目

S3

Amazon CloudWatch を使用したメトリクスのモニタリング
S3のアクセス状況を可視化してみる

Auto Scaling

[翻訳]チュートリアル:CloudWatchアラームによるコンテナインスタンスのスケーリング

アラート設定

CloudWatchでエラーログの内容を通知させたい
CloudWatchアラームでSlackへ通知を行う。
AWS SNS(Amazon Simple Notification Service)の通知設定をしてみる

続きを読む

Elastic Beanstalkの.ebextensions集

timezoneをJapanにする

timezone.config
commands:
    timezone:
        command: cp -p /usr/share/zoneinfo/Japan /etc/localtime
files:
    "/etc/sysconfig/clock":
        mode: "000644"
        owner: root
        group: root
        content: |
            ZONE="Japan"
            UTC=true

swapを有効にする

swapのサイズは、ddの引数を適宜変更してください。以下の例だと、4GBになります。

swapon.config
commands:
  create_swap:
    test: test ! -f /var/run/swap/0
    command: test ! -f /var/run/swap/0 && mkdir -p /var/run/swap && dd if=/dev/zero of=/var/run/swap/0 bs=1M count=4096 && chmod 600 /var/run/swap/0 && /sbin/mkswap /var/run/swap/0 && /sbin/swapon /var/run/swap/0

sysctlでチューニングする

内容は各自秘伝のタレを入れてください。

sysctl.config
files:
    "/etc/sysctl.d/90-beanstalk.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
            vm.swappiness = 40
            net.core.somaxconn = 2048
            net.ipv4.tcp_fin_timeout = 15
            net.ipv4.tcp_slow_start_after_idle = 0
            net.ipv4.ip_local_port_range = 2048 65535
            net.core.rmem_max = 16777216
            net.core.wmem_max = 16777216
            net.ipv4.tcp_rmem = 4096 1048576 16777216
            net.ipv4.tcp_wmem = 4096 1048576 16777216

commands:
    sysctl:
        command: sysctl -p /etc/sysctl.d/90-beanstalk.conf

mecabを入れる

全文検索エンジンGroongaプロジェクトの配布されているyumリポジトリを利用します。(感謝!)

01-groonga.config
packages:
    rpm:
        groonga: https://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm

commands:
    groonga:
        command: perl -pi -e "s;/centos/.releasever/;/centos/7Server/;g" /etc/yum.repos.d/groonga.repo
02-mecab.config
packages:
    yum:
        mecab: []
        mecab-ipadic: []
        mecab-devel: []
        gcc-c++: []

その他参考

続きを読む

【2018年】AWS全サービスまとめ その2(開発者用ツール、管理ツール、メディアサービス) | Developers.IO

AWSのリソースおよびAWSで実行しているアプリケーションのモニタリングサービス。メトリクス(CPU使用率やネットワークI/Oなど)やログを収集し(CloudWatch Logs)、SNSやAutoScalingと連携するアラームを作成できる。またAWSリソースの変更イベントを監視し、Lambdaなどのターゲットに対して、リアルタイムに通知が … 続きを読む

Glueの使い方的な①(GUIでジョブ実行)

GUIによる操作でGlueジョブを作って実行する

ジョブの内容

“S3の指定した場所に配置したcsvデータを指定した場所にparquetとして出力する”

ジョブ名

se2_job0

クローラー名

se2_in0
se2_out0

全体の流れ

  • 前準備
  • クローラー作成と実行、Athenaで確認
  • ジョブの作成と実行、Athenaで確認
  • 出来上がったPySparkスクリプト確認

前準備

ジョブで使うIAM role

以下のポリシーを付与した任意の名前のロールを作っておく。今回はtest-glueという名前にした。
・AmazonS3FullAccess
・AWSGlueServiceRole
※権限は必要に応じてより厳しくしてください。今回は検証のため緩めにしてあります。

今回使うサンプルログファイル(19件)

csvlog.csv
deviceid,uuid,appid,country,year,month,day,hour
iphone,11111,1,JP,2017,12,14,12
android,11112,1,FR,2017,12,14,14
iphone,11113,9,FR,2017,12,16,21
iphone,11114,007,AUS,2017,12,17,18
other,11115,005,JP,2017,12,29,15
iphone,11116,001,JP,2017,12,15,11
pc,11118,001,FR,2017,12,01,01
pc,11117,009,FR,2017,12,02,18
iphone,11119,007,AUS,2017,11,21,14
other,11110,005,JP,2017,11,29,15
iphone,11121,001,JP,2017,11,11,12
android,11122,001,FR,2017,11,30,20
iphone,11123,009,FR,2017,11,14,14
iphone,11124,007,AUS,2017,12,17,14
iphone,11125,005,JP,2017,11,29,15
iphone,11126,001,JP,2017,12,19,08
android,11127,001,FR,2017,12,19,14
iphone,11128,009,FR,2017,12,09,04
iphone,11129,007,AUS,2017,11,30,14

S3に配置

$ aws s3 ls s3://test-glue00/se2/in0/
2018-01-02 15:13:27          0 
2018-01-02 15:13:44        691 cvlog.csv

ディレクトリ構成

in0に入力ファイル、out0に出力ファイル

$ aws s3 ls s3://test-glue00/se2/
                           PRE in0/
                           PRE out0/
                           PRE script/
                           PRE tmp/

クローラー作成と実行、Athenaで確認

ジョブ作成の前に、こちらもGlueの重要な機能の1つであるData CatalogのCrawlerを作成して動かしていきます。
クローラはデータをスキャン、分類、スキーマ情報を自動認識し、そのメタデータをデータカタログに保存する機能です。これを使って入力となるサンプルデータのスキーマを事前に抽出してデータカタログにメタデータとして保存します。Athena、EMR、RedshiftからもこのGlueのデータカタログを使えます。Hive互換のメタストアです(Hiveメタストアのマネージドサービスと思ってもらえればいいと思います)。

基本的な操作はGUIを使って行えます。

AWSマネージメントコンソールから、Glueをクリックし、画面左側メニューの”Crawlers”をクリックし、”Add crawler”をクリック
スクリーンショット 0029-12-28 13.24.04.png

クローラーの名前入力
スクリーンショット 0029-12-28 11.19.32.png

S3にあるソースデータのパス入力(今回はS3に配置してあるデータが対象)
スクリーンショット 0030-01-02 15.17.11.png

そのまま”Next”
スクリーンショット 0029-12-28 9.38.41.png

“Choose an existing IAM role”にチェックを入れ、IAM roleをプルダウンからtest-glueを選択する
スクリーンショット 0030-01-02 15.17.49.png

“Run on demand”にチェックを入れ”Next”(今回のクローラーはスケジュールせずに手動実行とする)
スクリーンショット 0029-12-28 9.39.03.png

スキーマ情報を保存するDatabaseを選択、既存のものがあればそれでもいいし、なければ下の”Add database”でdatabase作成しそれを選択
Prefixは作成されるテーブル名の先頭に付くもの。見分け分類しやすいものにしておくと良いと思います(現状テーブルにtagとかつけられないので)
スクリーンショット 0029-12-28 9.39.23.png

クローラー実行

対象のクローラーにチェックを入れ、”Run Crawler”をクリック
スクリーンショット 0030-01-01 17.02.58.png

テーブルが出来上がる

“se2_”のPrefixが付いた”se2_in0″のテーブルができています。”in0″は指定した”Include Path”の一番下のディレクトリ名です。指定した”Include Path”(ソースデータがあるS3のパス、画像の”Location”の部分に表示されている)の配下のディレクトリは自動でパーティションとして認識されます。今回は配下にディレクトリはありませんのでパーティションも作成されません。
スクリーンショット 0030-01-02 15.21.15.png

テーブルの内容を確認するとスキーマが自動で作成されています
実データ配置場所のLocationがs3://test-glue00/se2/in0
Table名のNameが、prefixのse2_とInclude Pathで指定したs3://test-glue00/se2/in0の一番下のディレクトリのin0でse2_in0

Schemaを見るとuuidやappidなどがbigintで数値型になってます、文字列型がよければここでも修正できます。
今回は一旦このまま進めます
※本来はClassifierでいい感じにしたほうがいいと思う

スクリーンショット 0030-01-02 15.23.51.png

AthenaからもGlueのData Catalog使えます
Athenaから同様のテーブルとスキーマの内容が確認できます。Athenaがスキーマ情報にGlueのデータカタログを使ってることがわかります。画面右上にもGlue Data Catalogへのショートカットもありますね。
スクリーンショット 0030-01-02 15.27.07.png

もちろんクエリ実行もできます。
スクリーンショット 0030-01-02 15.29.31.png

ジョブの作成と実行、Athenaで確認

今回のようなジョブであれば、基本は画面ポチポチするだけです

Glueのメニューから”ETL”の”Job”をクリックし、”Add job”をクリック
スクリーンショット 0030-01-01 17.36.49.png

“Name”にジョブ名を入れ、”IAM role”はクローラーでも使ったロールを指定、”Temporary directory”は任意の場所で構いません。
スクリーンショット 0030-01-02 15.31.34.png

ソースデータとなるテーブルを選択。(先程作成したテーブルをクリック)
スクリーンショット 0030-01-02 15.33.35.png

ターゲットとなるテーブルは作成していないのでここで作ります。
今回は、保存先のData storeは”S3″、出力ファイルフォーマットのFormatは”Parquet”、出力先のパスのTargetPathは”任意の場所”を指定
※圧縮も選べます
スクリーンショット 0030-01-02 15.34.41.png

ソースデータとターゲットデータのマッピング変換ができます。いらないカラムを出力から除外したり、カラムの順序を変えたり、”Data Type”をstring,long,intなどに変えたり、新しいカラムを追加してそこに出力させる(カラム名を変える時に使えそうです)などができます
スクリーンショット 0029-12-28 10.08.35.png

次にサマリがでますので問題なければ”Finish”をクリック

ジョブの実行

作成したジョブにチェックを入れ、”Action”から”Run job”をクリック
スクリーンショット 0029-12-28 10.27.38.png

数分待って以下のように”Run status”が”Succeeded”となれば問題なく完了しています。
※問題があれば、”Error”の箇所にエラーの概要、”Logs”、”Error logs”の箇所の出力がリンクになっていてクリックするとCloudWatch logsに移動します。GlueのログはデフォルトでCloudWatch logsに出力されます
スクリーンショット 0030-01-02 15.46.47.png

出力したParquetフォーマットのファイルを、ソースデータと同様にクローラーを使ってスキーマを作り、スキーマオンリードでAthenaクエリを実行してみます。クローラー作成手順は前回と同様なので割愛します。
クローラーにより自動作成されたスキーマ
スクリーンショット 0030-01-02 15.49.41.png

クエリ結果です。データ量が少なくselectしてるだけなのでアレですが、parquetになったので列単位での集計処理などが高速化されるデータフォーマットに変換ができました。
スクリーンショット 0030-01-02 15.51.00.png

“S3の指定した場所に配置したcsvデータを指定した場所にparquetとして出力する”くらいであればGlueはGUIだけでサーバーレスでできます。

出来上がったPySparkスクリプト確認

se2_job0.py
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

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

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)
## @type: DataSource
## @args: [database = "se2", table_name = "se2_in0", transformation_ctx = "datasource0"]
## @return: datasource0
## @inputs: []
datasource0 = glueContext.create_dynamic_frame.from_catalog(database = "se2", table_name = "se2_in0", transformation_ctx = "datasource0")
## @type: ApplyMapping
## @args: [mapping = [("deviceid", "string", "deviceid", "string"), ("uuid", "long", "uuid", "long"), ("appid", "long", "appid", "long"), ("country", "string", "country", "string"), ("year", "long", "year", "long"), ("month", "long", "month", "long"), ("day", "long", "day", "long"), ("hour", "long", "hour", "long")], transformation_ctx = "applymapping1"]
## @return: applymapping1
## @inputs: [frame = datasource0]
applymapping1 = ApplyMapping.apply(frame = datasource0, mappings = [("deviceid", "string", "deviceid", "string"), ("uuid", "long", "uuid", "long"), ("appid", "long", "appid", "long"), ("country", "string", "country", "string"), ("year", "long", "year", "long"), ("month", "long", "month", "long"), ("day", "long", "day", "long"), ("hour", "long", "hour", "long")], transformation_ctx = "applymapping1")
## @type: ResolveChoice
## @args: [choice = "make_struct", transformation_ctx = "resolvechoice2"]
## @return: resolvechoice2
## @inputs: [frame = applymapping1]
resolvechoice2 = ResolveChoice.apply(frame = applymapping1, choice = "make_struct", transformation_ctx = "resolvechoice2")
## @type: DropNullFields
## @args: [transformation_ctx = "dropnullfields3"]
## @return: dropnullfields3
## @inputs: [frame = resolvechoice2]
dropnullfields3 = DropNullFields.apply(frame = resolvechoice2, transformation_ctx = "dropnullfields3")
## @type: DataSink
## @args: [connection_type = "s3", connection_options = {"path": "s3://test-glue00/se2/out0"}, format = "parquet", transformation_ctx = "datasink4"]
## @return: datasink4
## @inputs: [frame = dropnullfields3]
datasink4 = glueContext.write_dynamic_frame.from_options(frame = dropnullfields3, connection_type = "s3", connection_options = {"path": "s3://test-glue00/se2/out0"}, format = "parquet", transformation_ctx = "datasink4")
job.commit()

ビルトイン変換のいくつか補足

ApplyMapping:ソースの列とデータ型をターゲットの列とデータ型にマップします

ResolveChoice:複数の型の値が含まれている場合の列の処理方法を指定します。列を単一のデータ型にキャストするか、1つ以上の型を破棄するか、またはすべての型を別々の列または構造体に保持するかを選択できます
make_structは構造体を使用してデータを表現することにより、潜在的なあいまいさを解決します。たとえば、列のデータがintまたはstringの場合、make_structアクションを使用すると、生成されたDynamicFrameにintとstringの両方を含む構造体の列が生成されます。
choiceはspecが空の場合のデフォルトのresolution actionです

DropNullFields:nullフィールドを削除します

To Be Continue

よくありそうな変換処理ケースを今後書いていければと思います。

ジョブを作る際に似たようなジョブを作りたい、テスト段階でジョブのパラメータを一部だけ変えたジョブを作りたいことあると思います。現在はジョブのコピーがGUIからはできないのでそのあたりの運用を考慮する場合はCLIの利用がおすすめです。またあとで書きます。

こちらも是非

似た内容ですがより丁寧にかかれています。安定のクラメソブログ
https://dev.classmethod.jp/cloud/aws/aws-glue-released/
https://dev.classmethod.jp/cloud/aws/aws-glue-tutorial/

Built-In Transforms
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/built-in-transforms.html
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-api-crawler-pyspark-transforms-ApplyMapping.html

続きを読む