発表者は、その日何をしていたのか (発表の舞台裏 @デブサミ 2019 冬)


新しい朝が来た 希望の朝だ、発表の朝だ!

デブサミでの発表の朝を迎えて、発表者 lulzneko は 絶望していた。
なんと発表資料が完成していないのです 😱


2019年2月14日~15日 に 開催された Developers Summit(通称:「デブサミ」) で『サーバーレスで最高に楽しめるアプリ開発』と題してサーバーレスにまつわる発表をしました。その発表の舞台裏ということで、発表者が当日何をしていたのかを綴ります。

デブサミ概要

発表したイベント デブサミ ですが、技術書籍で定評のある翔泳社さんが開催している “技術者コミュニティとの連携から生まれた総合ITコンファレンス” です。

今回は Developers Summit 2019 冬 の イベントで、ホテル雅叙園東京 で 開催されました。よく結婚式などで使われ、建物内に滝と庭園がある凄い場所です。

会場入り

ストーリーとスライドの配置は完成していて、そこに載せる図 ピタゴラ装置を組み立てる 楽しみ の章で使うものが 間に合ってなかったというレベルなのですが、慌てて Power Point を 操作する朝から始まりました。

lulzneko は 遅筆で、資料の一部が間に合ってないことが結構あったりします。
今回はデブサミの次週に JAWS DAYS での発表もあるため、早めに着手したのですがギリってしまった。
あまり本質的でないところとかでも、気になってしまったり、こだわったりしてしまうのが原因なのですが。。。
スライドや文章、図が早く作れる方がうらやましいです。

急いでスライドを完成させ、所用を済ませと、あわただしく過ごして午後一の会場入りをしました。
なおデブサミの運営さんからは、”講演開始50分前までにご到着ください。” とのことですが、やはりセッションを見たいので早く到着するに越したことはないですね。
(資料の都合というより所用があって午前入りできなかったのですが、午前中のセッションも聴きたかった)

会場である雅叙園は実はエントランスとは別の裏道があります。
目黒駅を出て雅叙園に向かう、あのヤバい坂に差し掛かる手前で左に曲がります。住宅地のような感じもある道ですが気にせずに進むと右にアマゾンジャパンさんのオフィスへ行く道が出てきます。
実はこれが裏道で、アマゾンジャパンさんのオフィスへ入り、すぐに右へ行くと なが~い エスカレーターが出てきます。これを降りると、エントランスから入って左手に見えてる庭園に出ることができます。
あのヤバい坂は急で長距離なだけでなく、車もバシバシ通るので裏道(こっちも車は結構通るのですが)を使いたいところ、もちろん使わせてもらいました。(目黒駅に帰る場合はエスカレーターで登れるので、裏道のが断然いいですね)

受付

無事会場入りできたので次は受付です。

雅叙園は結婚式などでも使われる素敵な場所で、エントランスを入ってすぐに素晴らしい庭園とお洒落なレストラン街があります。

初めて来ると、IT イベント は やってなさそうな雰囲気に焦りますが、気にせずに奥まで進むと、デブサミの看板のあるエスカレーターが出てくるので、ビビらずに進むのが大事です。

エスカレーターを上がり2階へ着くと受付がありますが、発表者は3階まであがり、発表者受付に進みます。
こちらも “3F控室前の受付へお越しください。” とメールの案内にあります。

受付で、自分の名前を発表時間、lulzneko の 場合ですと「15-B-6 サーバーレスで最高に楽しめるアプリ開発」といった感じで伝え、名刺1枚を渡します。

スピーカーパス を もらって、自分の名前を書きます。
せっかくなのですが名前を書いても、ぱっと見でわからないので印刷したアイコンの切り紙を持っていて、それも差し込んでいます。

受付が終わると、”講演開始30分前” までには控室にいるようにとの説明を受けます。

あとは時間までフリーなのでセッションを楽しんだり、控室で作業したりできます。
セッションは事前登録なしでもスピーカーパスで入ることができます。

ただし lulzneko は、リハーサルに参加してなかったので、流れの確認と接続チェックがあるので、まずは控室入りとなりました。

※ 発表者受付では入場者バッグは配布されていませんでしたが、2階の受付でスピーカーパスを見せたらもらえました♪

控室 & 流れの確認

セッション用に使っているのと同じ規模の部屋になります。

長机に椅子、電源、コーヒー、お茶、スナック、お弁当が用意されています。
電源が豊富に用意されているのがありがたいです(ACアダプタ忘れましたが)。発表前に少し手直ししたり、作業したりすることがあり、電源がないとバッテリーの心配が出たりするので重要です。

スタッフの方より名前を呼ばれ、流れの確認に入ります。
スピーカー事前確認フォームで入力した内容を元に、会社名や名前、タイトルを確認します。進行の方が始まりに名前を呼んでくださるためですね。

続いて機材の確認で PC だけ、音声や映像の再生は不要、スマホを使うが接続の必要なしなどを確認し、ディスプレイへの接続チェックをします。
VAIO は HDMI、VGA どちらもいけるほか、接続問題もほぼなく助かってます。一度だけ HDMI が つながらなかったことがあったのですが、ケーブルが長すぎたと思われます。

続いて、バックアップの確認になります。
こちらも事前フォームで PDF を 提出したものの確認になります。”必ず2/12(火)までにバックアップデータを提供する。” こと案内があったのですが、当日の午前中に提出でした 🙇

PDF を 提出はしているのですが、実は発表資料はウェブアプリでできています。(ラップのアプリを埋め込みで動かしたのは、この仕掛けだったりします)

発表用のバックアップとしては、ウェブアプリが必要なので Google Chrome で プレゼン URL へ アクセスしてもらいました。
その際に URL を うまくお伝えできずに、テキストファイルを作って USB メモリーへコピーしたのですが、スタッフさんより「USB メモリー を PC へ 接続して大丈夫ですか?」との確認があり、きちんとされてるなぁと。

そして電源の確認。
忘れてしまったことを素直に白状し、使わないようにしてバッテリーが大丈夫なこと説明しました。
スタッフさんを、とても悲しい表情にさせてしまいました。すみません 🙏

発表者の移動動線

最後に、発表時の流れの説明を受けます。
受付時に以下のようなカードをもらっており、こちらの説明です。

雅叙園は結婚式などでも使われており、そのための裏動線が用意されているとのことです。すごい!

控室は図の「C会場 Ask the Speaker」の 上の部屋になります。
その部屋のエスカレーター側入り口とは別の裏口から出て、エレベーターへ回ります。
そして2階に行き、各会場へ入るという流れになります。

確かにデブサミ級のイベントになると、参加人数も多いですし、入り口で事前登録のチェックなどをしているので、発表者が入り口から入ってくると都合が悪そうです。

このような観点からも会場選びとかされているのでしょうね。ザ・プリンス パークタワー東京 が IT系イベントで使われているのも、もしかしたら?

なお Ask the Speaker の 受ける場合は、発表終了後に退出される参加者さんへ突して所定位置へ移動するとの説明を受けます。スタッフさんから「私がお客様を掻き分けて進むので、しっかり付いてきてください」とのことです。

まぁ、確かにメイン動線へ戻るためのルートはなさそうですし、早く Ask 席へ移動すること、またスタッフさんを次の発表者につけるためにも突るしかないのでしょう。

以上、説明を受けてフリーです。
コーヒーを堪能して心を落ち着け、セッションとブースへ!

発表 30分前

控室に待機し、発表準備に入ります。
スタッフさんから名前を呼ばれ、先ほど説明を受けた裏動線で移動開始です。

「B会場なので厨房を通ります。気を付けてください。」
「みなさま、ここを通る時に楽しそうにしてます。やっぱり珍しいんですかね。」
「昨日は厨房でケーキを見ていたら食べたくなって買いました。1階で売って、とてもおいしいですよ。」
「こちらで少々お待ちください。」

と、適切なナビを受けて会場裏に到着です。

倉庫のような場所の丸椅子で少々待機。30分前に移動してるとはいえ、20分の休憩があるので直前の発表の、ほぼ終了時点で待機場所到着です。

自分の資料を見直す時間もなく莫大な拍手が聞こえ「入ります。どうぞ!」の案内。

正面のすぐ横から入ってセッティング。
進行の方から名前等の最終確認を受け、発表用の「雅叙園ウォーター(秩父源流水)」を もらいます。

そして、電源の確認。
また進行のスタッフさんを、とても悲しい表情にさせてしまいました。すみません 🙏

発表者ツールとしては、まず演台の下に正面投影用と同じ内容が表示されるディスプレイがあります。
こちらに事前に映しておき、切り替えたらすぐに表示されるようになっています。すごい。
(デモのときに QRコードをスマホで撮るためにしゃがんだのが、このディスプレイです)

客席正面の真ん中に大きなカウントダウン時計があります。演台の手元にもカウントダウン時計があります。
正面のは、とても大きく見やすくて助かりました。(手元のはなぜか動いてなかった)

マイクはワイヤレスで、ハンドマイクとピンマイクがあります。
持っているほうが安定するので、ハンドを選びました。

レーザーポインターもあります。
普段は投影画像を直接指さすのですが、さすがに届かないのでお借りしました。

発表用スライド の URL を ツイート。

発表

いざ、発表!
ご清聴ありがとうございました!!

沢山のツイートありがとうございます!!
デブサミ2019【15-B-6】サーバーレスで最高に楽しめるアプリ開発 #devsumiB - Togetter

Ask the Speaker

お片づけをして、Ask 席へ向かって突ります。
スマホの片づけとかあったので、お待たせしてしまいました。すみません。

10名ぐらいの方に来ていただきました。ありがとうございます!!
いただきました質問はできる限り思い出してメモりましたので、別途まとめを書きたいと思います。

何か気になることなどQAや、またフィードバックなどありましたら、Twitter @lulzneko へ DM を いただければと思います。オープンになっているので、特にデブサミに限らず気軽にいただければと。

おわり

発表用スライド の URL を 再度ツイート。

これまでは発表前だけだったのですが、ある Twitter の 投票 で、発表後にスライドを共有してほしいというのが1番だったので再度ツイートするようにしました。遅くなってしまったので、お片づけ時にツイートすべきでした。反省。
(発表前は2番だけど、発表時に手元にあるといいこともあるので)

エゴサして、Like、RT、Follow-、バッテリー切れ…


以上、発表者の一日でした。

色々しでかし気味なヤバい一日でしたが、無事発表を終えることができました。

いろいろなイベントで話をする機会をいただいておりますが、スタッフさんとの濃密なやり取りや、裏動線を使った移動などは初めてで、これはぜひ伝えたいなと思い書いた次第です。

文才があったら発表者目線な読み物にしたかったのですが、ムリかったので淡々と描く形になりました。
発表者サイドではありますが、舞台裏がどうなっていたのか少しでも伝わりましたら幸いです。

次回は、2019年2月23日(土) 15:10~ JAWS DAYS 2019 で『AWS x JAMStack で構築・運用するサーバーレスなWeb Front』の お話をします。 もしよろしければ、お越しください。

また、ちょっと来て話をしてよ、といったようなことなどありましたら、Twitter DM を @lulzneko へ 気軽にいただければ幸いです。
これまでの発表歴は こちら [Slides | Riotz Works] https://riotz.works/slides に なります。


聴きに来てくださり、ありがとうございました。
スタッフの皆さん、支援ありがとうございました。

そして、ここまで読んでくださり、ありがとうございます。

Author: lulzneko

Riots.works での JAMStack の 利用

最近注目を集め始めている “JAMStack”、より良いパフォーマンス、より高いセキュリティ、より安価で簡単なスケーリング、より良質な開発者エクスペリエンス を 提供するアーキテクチャ。

Riotz.works でも注目しており、実際に活用しています。今回は、この JAMStack を Riotz.works で どのように使っているかを ご紹介します。

Riotz.works 公式ウェブサイト

公式ウェブサイト の トップページ https://riotz.works、Works ページ、Engineers ページ が Gridsome で JAMStack な サイト作りをしています。

Gridsome は 2019年1月現在 バージョン 0.4.5 で 速いペースで開発が行われておりますが、必要な機能が未実装だったり、実行環境によっては様々な準備や設定が必要だったりします。
StaticGen では 30位あたりになります。

数あるサイト・ジェネレータから Gridsome を 選んだのは、まずは Node.js で 作られていること念頭に置きました。
これは Riotz.works では Node.js、主に TypeScript で 開発を行っているため、スキルセットや開発環境を合わせたかったというのがあります。

続いて Vue.js ベース であることを選びました。
こちらも開発が Vue.js ベースで行っているので合わせたかったというものになります。

そうすると、比較的メジャーと思われる GatsbyJSHexo などが落ちてしまいます。
GatsbyJS は 非常に興味深いのですが、いつかは使ってみたいと思っていますが、今回は Vue.js ベースとしました。

選択肢としては Nuxt.jsVuePressGridsome、VueWebsite に なります。

Nuxt.js は アプリ作成で使っていますが、ウェブサイトやブログ構築よりアプリ向けに感じます。
そうなると Vue.js 公式である VuePress が 最有力になりそうです。

ところが、もうひとつの Gridsom も 調べたところ、 “highly inspired by Gatsby.js” とあり、また Vue.js ベースであることが、まさに私たちの考えと一致するものでした。

そしてデータソースを GraphQL で 扱えるところが魅力的です。
入力ソースは基本的に Markdown を 使いたいと考えていますが、エンジニアによっては CMS を 使いたいケースもあるでしょう。このような複数のソースを GraphQL で 扱えるのが助かります。

このような経緯から Riotz.works 公式ウェブサイト は Gridsom で 構築することにしました。

ただし、これまでの開発経緯から Articles と Slides は Gridsom とは異なる技術を使っています。
リンクを踏むとヘッダーが異なるのはこのためです。Gridsom へ 意向を考えてはいますが、なかなか着手できてない状況です。。

Riotz.works Articles ページ

Articles ページ は、Hexo で 作られた JAMStack な サイトです。

この Articles こそ Gridsom が 活用できる場所ではあるのですが、Gridsom が 登場する以前に Hexo で 作ったものになり、いずれは Gridsom へ 移行したいと考えてはいますが、Gridsom は まだ初期開発中で Category や Tags などのページを自前で作る必要があり、作りこみに手が回ってないというのが現状です。(いずれ公式でサポートされるとは思うので待ちたいというのもあり。。)

HexoStaticGen でも トップ5に入る人気のサイト・ジェネレータです。

記事は Markdown で 書けるので、エンジニア・フレンドリーといえるのではないでしょうか。
一方で表現力は落ちてしまうという点がありますが、最後は HTML を 直接書いて埋め込めるので、どうしても Markdown で 表現しきれない部分は HTML で カバーすることができます。(あまりやりたくないので奥の手という感じですが)

ブログサイトをとても手軽に作ることができ、テーマも多数用意されているので好みのデザインにすることも簡単ですし、各種 Plugin も あるので簡単に拡張することもできます。

日本語の情報も多いので、比較的簡単にやりたいことや、困りごとを解決することができます。

JAMStack な ブログ・サイトをつくり始めるには、よい入口と言えるでしょう。

Riotz.works Slides ページ

Slides ページは、静的サイトではありますが完全に手組の HTML で、”構築済み の HTML” とはなっておらず、アクセスを受けてから JavaScript で HTML を 構築しているので JAMStack な サイトではありません。

こちらは、Markdown ファイル を ソースとしたプレゼンスライドを作れる remark.js というライブラリを使っています。

仕組みとしては事前に用意された Markdown ファイルを、スライド形式の HTML に 変換して表示なので、JAMStack とは相性が良く、JAMStack な スライドシステムがあったら使いたいと考えています。

Markdown から スライドを作るライブラリとしては reveal.jsremark.js ぐらいで、どちらも事前構築の HTML には対応しておらず、現時点では現状のままか、時間を作って自前開発をしたいところです。

JAMStack な スライドシステムがあったら使いたいと考えていますが、現時点ではなさそうなので、しばらくは現状のままでしょう。

スライドシステムについては時間を作って自前開発にチャレンジしたいとも思っています。
ソースは Markdown で 書きたいというのがありますし、カジュアルな勉強会ではリアルタイムなフィードバック機能を動かしてみたいなど、いろいろとやってみたいことがあります。

ラップ、タップ、アップ 🎶

最後にハッカソンで作った ラップ、タップ、アップ 🎶 ですが、こちらも JAMStack な アプリです。

技術としては Nuxt.js を 使っていて SPA で 静的サイトとして生成、ホスティングしています。(SSR、サーバサイドレンダリングにすると JAMStack ではなくなります)
これにより基本的な画面は “構築済み の HTML” となり、CDN に 配置した際のメリットを出せます。

ラップ対戦のルーム作成は クライアントサイド の JavaScript から Web API を 呼出しています。
また動画の中継と配信も JavaScript の ライブラリからサービスを呼び出しています。

ハッカソン の 24時間という限られた時間の中で、フロントエンド と サーバサイド を 分離し HTML を ツールを使って生成するという JAMStack の アーキテクチャが まさに活かせた瞬間といえるのではないでしょうか。

サーバサイドの機能が Web API という形で提供されているため、ロジックの変更 や UI の 変更といったものが相互に依存せず最小限の修正で組み込みすることができました。


JAMStack は 公式ウェブサイトのような完全な静的サイトのほか、ブログやアナウンスなどのニュースといった緩やかな更新が発生するサイト、そしてアプリといった様々なサイトが実現でき、Riotz.works の 中でも多様な使い方をしています。

特に ラップ、タップ、アップ 🎶 のような、サイト・ジェネレータで静的ホスティングなサイトを作っていて、Web API を 呼び出しているようなケースは意外とあったりするのではないでしょうか。

実は JAMStack な サイトを作っていたけど、JAMStack というキーワードが知られてなく、そんな名前がついていたんだというケースがいろいろありそうです。(実は ラップ、タップ、アップ 🎶 作成時点では JAMStack という言葉は知らなかったです)

ただ、これだけ JAMStack な サイトと書いてきましたが 実はホスティングが GitHub Pages で、JAMStack ベスト プラクティスの CDN に 乗ってなかったりも。。

これまでの経緯から GitHub Pages を使ってて、またカスタムドメインを使っているほか、4サイト(リポジトリ)が のっかっているので一斉に引っ越しする必要があり、作業時間を作るのに苦慮しているためです。

Author: lulzneko

JAMStack、それは ハイパフォーマンスなウェブフロントを実現するアーキテクチャ

“JAMStack” と 呼ばれる、新しい ウェブの開発手法で、より良いパフォーマンス、より高いセキュリティ、より安価で簡単なスケーリング、より良質な開発者エクスペリエンス を 提供するアーキテクチャ が 注目を集め始めています。

JAMStack とは何か、どのように使い、どのようなメリットがあるのか、公式サイトの情報をもとに読み解きます。

JAMStack の 定義


オフィシャル・サイト https://jamstack.org によると、以下の要素に基づく最新のウェブ開発アーキテクチャとされています。

  • クライアントサイド の JavaScript
  • 再利用可能 な Web API
  • 構築済みの Markup (HTML)

HTML に JavaScript そして Web API なので、ウェブフロント の 開発をする場合によく使うであろう技術と言えるでしょう。

ここでは、動的な要素をサーバーサイドで 組み込んだ HTML などをレスポンスするのではなく、クライアントサイド の JavaScript から Web API を 通じて取得/更新し、クライアントサイドでダイナミックに描画する方式、いわゆる REST API などを使ったウェブフロントの作り方を指しています。

そして Markup (HTML) の 部分がポイントなのですが “prebuilt at deploy time” 、デプロイ時に事前ビルドされているとしています。そして多くの場合、サイト・ジェネレータなどを使って作ります。(ツールの紹介は後述


The JAM Stack44ページ目 の スライドにある、この図が JAMStack の アーキテクチャをシンプルに表現しています。
Git に Push されたコードから、ビルドツール(サイト・ジェネレータなど)が動作し、Web API などのデータと組み合わせて、構築済みの HTML を生成、CDN へ 配置して配信します。

なぜ JAMStack なのか

なぜ JAMStack、特に構築済みの HTML を デプロイするのか。

公式サイトでは、大きく4つ「より良いパフォーマンス」「より高いセキュリティ」「より安価で簡単なスケーリング」「より良質な開発者エクスペリエンス」の メリットを上げています。

より良いパフォーマンス

最初のページを高速に表示するためには、HTML を 事前に構築しておき CDN で 配信することが最適です。
構築済みでない場合、高速に配信できる CDN を 介することができず、また HTML を 生成するための処理を待つことにもなります。

より高いセキュリティ

サーバーサイドの処理をマイクロサービスとして API に 抽象化されているため攻撃の対象となる部分を小さくできます。
また、事前に構築済みの HTML を デプロイしているため、HTML を 処理するためのプロセスはオフラインにできることもメリットといえるでしょう。

より安価で簡単なスケーリング

デプロイするものは 構築済みの HTML となるため CDN に 配置することができ、スケーリングすることが容易になります。
CDN が 安価かというと悩ましい部分はありますが、Web サーバ と AP サーバ を スケールさせるために用意することを考えると、CDN だけでよいので簡単とはいえるでしょう。

より良質な開発者エクスペリエンス

疎結合にすることで、よりターゲットを絞った開発とデバッグを可能とします。
構成を簡素化できることは開発者の精神衛生上よいといえるでしょう。

このようにロジックを Web API として分離し、フロントエンドを構築済みの HTML としておくことで、多くのメリットを享受することができます。

ベストプラクティス

JAMStack な プロジェクトを構築する際に、いくつかのベストプラクティスを活用することでスタックのメリットを最大限に発揮できます。

CDN に 全部配置されている

JAMStack な プロジェクトは、サーバサイドのコードに依存しないため、単一のサーバではなく分散して配置することができます。
CDN から 直接サービス提供することでスピードとパフォーマンスを発揮できます。アプリがネットワークにエッジまで配置されることで、より良いユーザー体験になります。

全てが Git に 存在する

JAMStack な プロジェクトは、誰もが git clone でき、必要な依存関係を npm install などのような標準的な手順でインストールし、プロジェクトをローカルで実行する準備ができているはずです。複製するデータベースも、複雑なインストールもありません。
これによってコントリビュータの負担を減らし、ステージングとテストのワークフローも簡略化されます。

モダンなビルドツール

モダンなビルドツールの世界によるアドバンテージを受けましょう。
それは動きの速い世界でジャングル(無法地帯)を志向するかのようですが、未来のブラウザを待たずに最新のウェブ標準を使うことができるようになります。
それは現時点では Babel、PostCSS、Webpack、そして その仲間です。

自動ビルド

JAMStack の マークアップ(HTML) は、事前ビルドされているため、コンテンツの変更はビルドを実行するまで反映されません。このプロセスを自動化するとフラストレーションを軽減できます。
これを webhook で 行うことも、自動的にパブリッシュするプラットフォームなどを使うこともできます。

アトミックなデプロイ

JAMstack な プロジェクトが非常に大きくなるにつれて、新しい変更のために数百ものファイルを再デプロイする必要があるかもしれません。 これらのファイルを一度にアップロードすると、プロセスの完了までの間に不整合が生じる可能性があります。 これを避けるに、全てのファイルがアップロードされるまで変更が行われない「アトミックデプロイ」を実行できるシステムを使用します。

キャッシュの即時無効化

ビルドからデプロイへのサイクルが定期的に行われるようになったら、デプロイの実行 が 実際に反映されるようにします。CDN は 側にキャッシュを消去することができます。

サイト・ジェネレータ

JAMStack の メリットはわかったとして、それでサイトを作るには「構築済み の HTML」が 必要となってきます。
この構築済みの HTML は 手組み の HTML を 用意することではなくて、サイト・ジェネレータを使うとされています。

主なサイト・ジェネレータは、こちら StaticGen に 列挙されています。

有名どころとしては GitHub Pages でも使われている Jekyll などがあり、HugoHexo といったブログ構築用の静的ジェネレータ や Next, Nuxt といった ReactVue.js の アプリ・フレームワークなどもあります。

JAMStack というコンテキストでは GatsbyVuePressGridsome などを目にすることが多いようにも感じます。

ヘッドレス CMS

これは特に JAMStack の 要件というわけではないのですが、JAMStack な ブログ や 情報発信サイトを作る際に使われるものです。

WordPress などの CMS は コンテンツを配信するための部分が含まれ、そのままホスティングすると JAMStack な サイトにはならないので、別の仕組みが必要となりますが、WordPress などのように優れたコンテンツを管理するための仕組みが欲しくなります。
そうしたニーズに応えるのが、この ヘッドレス CMS で、最低限の UI で コンテンツを管理することができ、作成したコンテンツを API 軽油などで提供し、上記サイト・ジェネレータなどと組み合わせてサイトを作ります。

主なヘッドレス CMS は、こちら headlesCMS に 列挙されています。

前半に Open source な ヘッドレス CMS が 並び、後半に Closed source があります。
またサービスとして提供されているものは、こちらの Closed source に 含まれます。たとえば最近よく目にする Contentful は Closed source になります。

サイト・ジェネレータによっては、WordPress の REST API からコンテンツをとってきたり、ローカルの Markdown ファイル を 使うこともできるので、サイト・ジェネレータの機能と管理方法に合わせて選択します。

参考情報


実際のところ、Web API ベースなアプリ開発をしていると、意識はしてなくとも JAMStack な ウェブフロント を 作っているなぁというケースもあったりします。

さっくり言ってしまうと、そんな Web API ベースなアプリでウェブフロントを構築済みの HTML として CDN に 配置するものに、JAMStack という名前がついたという感じになります。

名前がついたことで認識され、認識されることで広まるという流れになっていくのではないでしょうか。

Author: lulzneko

2018年の振り返り

2018年最後のポスト、1年間の活動を振り返ります。

サマリー

  • 発表: 6回
  • 記事: 3本
  • アプリ開発: 3本
  • ハッカソン: 1回

発表 6回

2018.02 Agile & DevOps 勉強会 - @lulzneko & @lopburny

クローズドな Agile & DevOps 勉強会で スマートデバイス と クラウドサービス を 自動パーソナライズする IoT バックエンド開発チームにおける Agile と DevOps プラクティス の 発表をしました。

タイトルが長くでピンとこないのは、オリジナルのタイトルは製品名が入っていたからで、公開に当たって製品名を外す必要があったからになります。

ベースとなる話は昨年の Serverlessconf Tokyo 2017 で 発表した ava チームが選択した TypeScript による AWS Lambda 開発 に なり、Java で 開発していたプラットフォームを TypeScript で 開発しなおすという大手術をしたプロジェクトでどのような Agile & DevOps で やっていたのかということを話しました。

私たちとしては必要に駆られてのことでしたが、途中でプログラミング言語を切り替えるというのは衝撃を受けたというほか、そのようなことができる人たちがいるということに驚いたと言われ開発者として誇らしく感じ、そして必要なことであれば、どのような困難でも真正面から取り組んでいくスタイルは ずっとキープしていきたいと改めて感じるイベントでした。

2018.05 JJUG CCC 2018 Spring - @lulzneko

日本最大のJavaコミュニティイベント JJUG CCC で Java から TypeScript へ 切り替えて加速するサーバーレス開発 の 発表をしました。

Java の コミュニティで「Java を やめて TypeScript を 選びました」という主旨の発表になり、かなり緊張しながら入室したことを覚えています。
仕事では Java で ずっとやってきて、よく勉強でお世話になっていた会に、このような立場で発表するとは思っていませんでした。

会場は満員御礼で立ち見でも聞いてくださる方も多く、そして熱心に耳を傾けてくださり発表者冥利に尽きる会でした。

内容については賛否両論、手厳しい指摘も上がっていましたが、新たなる可能性についての話につなげられたと思っています。

批判や厳しい指摘を恐れず、発信したいことはしっかり話す。そして議論へつなげ盛り上げることの大切さを実感できた会だと感じました。

発表について1つ反省点が、タイトルは「Java から TypeScript へ 切り替えて加速する」としているのに、「Java と TypeScript の 親和性」についての話になっていたなと。資料を書いているうちに、どんどんアイデアが膨らんでしまうのに気をつけねば。。

2018.06 SPAJAM 2018 東京D予選 - @lulzneko & @lopburny & @javaponny

日本最高峰のアプリクリエイター競技会 の スマートフォン アプリ ハッカソン SPAJAM。ハッカソンの内容については後述、ここでは発表パートについて。

リアルタイム の 競演 と 参加型観戦 で 音楽を最高に楽しむ🎶 「ラップ、タップ、アップ」 で 発表しました。

徹夜でアプリ開発をしたあとの発表会。体力的にも集中力的にも かなり厳しかった。スライドに何を書くのかとても苦戦しました。

一方で話し始めるとランナーズハイならぬスピーカーズハイとでもいうような高揚感で、今までの発表の中で一番ノッテいたと思います。

発表の神様が降りてきてくださった、そんな発表でした。
このような発表を毎回できるように精進しようと心から思いました。

進行より東京D予選は最難関と言われていましたが、どのチームも素晴らしい発表をされており、最高の発表をライバルの立場として体験させてもらえたことに感謝です。

2018.09 Serverlessconf Tokyo 2018 - @lulzneko & @lopburny & @javaponny

サーバーレスアーキテクチャを用いたアプリケーション構築における知見の共有を目的とした、コミュニティ主導の技術カンファレンス で、リアルタイム動画ラップ バトル アプリを 短時間で作り上げた完全サーバーレスな秘技 の 発表をしました。

Serverlessconf Tokyo は Riotz.works の 原点ともいえるイベントで、2017年のイベントで発表させていただいたのが Riotz.works の 始まりになります。

SPAJAM で 作ったアプリは フル・サーバーレス で できており、サーバーレスで戦ったからこそ、優秀賞 を 受賞することができたと思っています。
そのサーバーレスの素晴らしさをハッカソンという観点からお伝え出来たのではないでしょうか。

今回の会場は東京タワーのスタジオで 25m プール 1面分という超巨大スクリーンでの発表でした。

このような会場は初めてで緊張したものの、発表する楽しさを強烈に実感できる場所でした。また このような場所で発表に臨めるよう技術と活動をしっかり行っていこうと思いました。

Vue Fes Japan 2018 Reject Conference - @lulzneko & @lopburny

日本で初めて開催する大規模 Vue.js カンファレンス で Vue.js/Nuxt.js で 実現できた PWA の リアルタイム動画ラップ バトル アプリ の リジェクトコン で 発表しました。

プレイドさん の オフィスで開催され、芝生スペースという素敵な場所でした。
フロント系のイベントは初めての参加で、今まで参加してきたイベントとは雰囲気が違う感じを受けましたが、楽しさはかわらず、技術イベントはいいなぁと再認しました。

懇親会では多くの方々と話をする機会がありとても楽しかったです。

東京 Node 学園祭 2018 - @lulzneko & @lopburny

年に一度、真剣に学んで楽しもう! 日本最大のNode.jsカンファレンス! で Vue.js/Nuxt.js で 実現できた PWA の リアルタイム動画ラップ バトル アプリ の 発表をしました。

TypeScript で サーバーレス を 推している身として Node.js の 総本山ともいえるイベントでお話しできるのは最高の体験でした。

記事 3本

こちらは全然かけなかったので反省です。
とくに TypeScript の スターター記事を書き始めたのに2回で止まってしまった。

引き続き TypeScript で サーバーレス は 推していきたいので、しっかり記事を書いて発信していくとともに、Nuxt.js や Gridsome などを使い始めているので、こちらも情報発信をやっていけるようにしたいです。

活動の仕方を見直して、記事を書く時間をしっかりとるようにしたいです。

アプリ開発 3本

まだ公開できないプロトタイプが1本ありますが、3本作れたのはよかったです。

ラップはハッカソン制作作品ですが、少しずつ機能追加などもやっていて、引き続きいろいろな機能を追加したり、面白いことを試せたらと思っています。

ウェブサイトは Gridsome を 使ってリニューアルしました。 Slides と Articles の 引っ越しはできていませんが、リニューアルで 念願だった Works と Engineers
が 追加できました。
Gridsome は JAM Stack として面白いので、ちゃんと使いこなせるようにしつつ情報発信をしていきたいと感がています。

ハッカソン 1回 - @lulzneko & @lopburny & @javaponny

SPAJAM の スマートフォン アプリ ハッカソン に 参加しました。
自分自身も、Riotz の メンバー 全員 で 初めてハッカソンに参加した記念すべきイベントでした。

5人でチーム編成のところ、Riotz は 3人とチャレンジングな参加でしたが、サーバーサイド は サーバーレスという武器を活かすことでチャレンジできる、そしてアプリ側もネイティブではなく敢えて PWA を 使うことで持てる技術を最大限に生かせることで戦えると考えていました。

とはいえ、日本最高峰のアプリクリエイター競技会 を 謳っているイベントであり、参加した 東京D予選 ドワンゴ会場 は 最難関の予選会場(進行談) とのことで、すごい人、すごいチームばかりでした。

午前のチームを超えて全体でのアイデアソンではポンポンすごいアイデアを出す方、発表の時間では今すぐ公開可能レベルのアプリ、TED 会場かと錯覚するプレゼン、参加者のとてつもないレベルに面食らいました。

当日発表の「音楽」というテーマに対して、メジャーからストリート、Google Home に Spotify に Tシャツ制作サービス連携、スマホのあらゆる機能活用と、想定しきれないありとあらゆるものがそろっていたと思っています。

Riotz.works は 幸いにして 優秀賞 を いただけましたが、どのチームがとってもおかしくない、最難関の予選会場(進行談) だったのではないでしょうか。

そのような方々とアイデアと技術を競えたことに感謝です。
ハッカソンは初めての参加でしたが、このような最高に高揚し意地を張れる場所に、多く参加できるよう技術の研鑽と戦うマインドをキープしていきたいと思う場でした。


この1年は Riotz.works が 発足して、ほぼ1年と半分。

多くの場所でお話しさせていただきました。サーバーレスはアプリ開発にとって最強の武器」を 標語に活動してきた自分たちの思いを沢山をお伝え出来たのかなと思っています。

一方で残していけるはずの記事がたくさん作れなかったことは反省です。
話をすること、文章を書くこと、どちらも凄く好きなのは、今文章を書いていて感じていますが、時間を作ることが下手だったのかなと。
この辺は来年に向けて改善をしっかり考えていこうと思います。

よかったところを伸ばし、反省点を見直して次の年へ繋げられるよう頑張ります。

よい お年を。

Author: lulzneko

2018年の Riotz Works の活動を振り返る

どうも、Riotz Works のうさぎ(@lopburny)です!

昨日、年内予定していた全ての用事が終わり、年末の連休に突入しました。僕は例年クリスマスが終わった時点でそわそわして集中力が持たなくなりますが、今年は色々あって今日からやっと休暇に入ります。

そして Riotz Works も結成から1年が経過し、個人的にはここ数年で最も忙しく過ごした1年で、充実できた1年だったと思います。

一方、反省点も多々あり、ちゃんと振り返って来年の活動に活かしたいという気持ちもあります。この記事は、そんな Riotz Works での活動を振り返り、発表では言えなかったこと、私が感じたことをつらつらと書いていきます。

2018年のうちにやってきた発表

※ 2018/12/29 時点

これ、ちょうど1年前は、たったの1行でした😂

まさかこのページが埋まるとは、想像していませんでしたが、何事もチャレンジしてみるもんですね。Riotz Works の活動は、今のところ仕事というわけではないので、メンバーの 100% ピュアなモチベーションでやってこれたのも効果的だったと思います。

スマートデバイスとクラウドサービスを自動パーソナライズする IoT バックエンド開発チームにおける Agile と DevOps プラクティス

@Agile & DevOps 勉強会、 発表資料はこちら

2月、@lulzneko@lopburny が発表しました。Riotz Works が結成して 1回目の発表が Serverlessconf Tokyo 2017 という大きくてパブリックな発表だったのに対して、今回(2回目)は Closed な勉強会だったので比較的緊張はしなかったです。

しかし、タイトルにもあるように、勉強会のテーマは Agile や DevOps といった開発プロセスなので、参加者のみなさんが必ずしも Web やクラウドに明るいわけではなく、様々なバックグラウンドを持つ人にどう伝わるか悩ましいところでした。

中盤の自分のパートが AWS に触れたことがない人には分かりにくい内容だったと自覚し、補足説明をたくさん入れるようにしましたが、本番では早口で突っ走るような話し方になっていたかもしれません。

発表後、「刺さる人には刺さった」というコメントをもらったときは嬉しかったです。

Java から TypeScript へ切り替えて加速するサーバーレス開発

@JJUG CCC 2018 Spring、 発表資料はこちら

5月26日。@lulzneko の単独発表です。

AWS Lambda は、リリース当初から現在に至るまで、Java ランタイムを選択すると必然的に Cold Start に悩まされることになります(Cold Start を無視してもいいケースなら問題になりません)。この問題に対するアプローチはいくつかあると思いますが、私たちのチームが身をもって実践してみたことで、「Java 開発者において、TypeScript は良い選択になり得る」というのがポイントになります。

発表会場が開始後すぐ埋まり、立ち見の方もいらっしゃるほど盛況でした。このアプローチに対するフィードバックは賛否両論ありましたが、みなさんにとって興味深い内容だったのではないかと思います。

リアルタイムの共演と参加型観戦で音楽を最高に楽しむ🎶「ラップ、タップ、アップ」

@SPAJAM 2018 東京D予選、 発表資料はこちら

6月16日~17日。今回はカンファレンスではなくハッカソンです。@lulzneko@javaponny@lopburny 3人で出場しました。メンバー全員初めてのハッカソンで、Riotz Works としても初です。もともとこの SPAJAM というハッカソンには注目していて、Riotz Works 結成前から「出てみたい」と何度か話したことがありました。そして、思い切って、エントリーしたのです。

1日目の朝、そわそわしながら会場へ向かい、午前のアイディアソンを終えて、ハッカソンのテーマ(音楽)が発表されました。会場近くの築地市場で海鮮丼を食べながら、どうする?何作る?と議論をはじめ、私が思いついたのが、このラップバトルです。言ってみたものの、これどうやってつくるの、やばくね、みたいな感じでした💦

ラップバトルのサービスは世の中にいくつも存在しますが、僕はよりインタラクティブな演出がいいなと思ったのと、ラップバトルの「対戦」と「観戦」を 同時にかつリアルタイムにできる仕組みを作ることで差別化を図りました。いわば Twitch のゲーム実況ストリーマー同士が即座で対戦を始め、その様子をそれぞれのチャンネルで数百〜数千の人たちが観戦しながらコメントやヤジを飛ばす様子。そういうのが作りたかったです。

果たして作りきれるだろうか。。。午後から真面目に調査します。数時間ほどでなんとか SkyWay のサンプルを動かすことができました。夜になって会場を出た時点で、ようやく翌日の発表に向けた最も基本的な機能(リアルタイム動画ストリーミング)ができました。そして、夜も気を抜くことはできません。オールナイトで作業して30分ほど仮眠を取り、発表直前まで開発を進めた結果、なんとかデモができるところまで作れました。

結果は・・・なんと、優秀賞をいただきました!!

今でもあの感動を忘れられません。恐らく今年起きた出来事の中で最強のインパクトでした。。

そして帰りに飲んだビールは間違いなく今年飲んできたビールの中で最高の味でした。😂

残念ながら SPAJAM の本選に出ることはできませんでしたが、次はもっと進みたいと思います!!

リアルタイム動画ラップバトルアプリを短時間で作り上げた完全サーバーレスな被疑

@Serverlessconf Tokyo 2018、 発表資料はこちら

9月29日。@lulzneko@javaponny@lopburny 3人で発表しました。Serverlessconf Tokyo での発表は、去年に続き2回目となります。夏のハッカソンの余韻がまだ残っていて、この発表の準備にも気合が入りました。特に、会場スクリーンのアスペクト比が 48:9 という、ものすごく大きくて迫力のある会場だったため、わくわくしつつもかなり緊張していました😂

気合を入れて会場に着き、生でみる会場の広さとスクリーンの迫力にびっくりしながら、デモの準備をしました。ちゃんと動くのを確認してこれはいける!と思ったんですが、本番では開始とともにデモが固まって動かないことに。そういうことにならないよう、開始10分前からアプリを立ち上げた状態で待機したのですが、なぜか開始のタイミングで 僕のスマホが固まってしまったんです。えーーー、なんで。。。ショック。。。とパニックになってしまった僕は、落ち着いて話すことができず、発表中に焦りを出してしまった気がして反省しています。

当時 @lulzneko が言っていたように、「デモが動かないことは、よくあることですね」と、一旦落ち着いて進めていき、メンバーが対応してくれることを待つべきだったことを学びました。

幸い、メンバーが対応してくれたおかげて、発表中にデモが復旧し、ハッカソンで作ったアプリを披露することができました。また、サーバーレス関連の色んな方々とお話ができて、他の発表についても、どれもすごく勉強になったので、貴重なイベントでした。

Vue.js/Nuxt.js で実現できた PWA なリアルタイム動画ラップバトルアプリ

@Vue Fes Japan 2018 Reject Conference、 発表資料はこちら

11月10日。@lulzneko@lopburny が発表しました。前回の Serverlessconf ではバックエンドの内容がメインでしたが、今回はフロントエンドにフォーカスした話です。元々、Vue Fes Japan そのものにエントリーしましたが、枠が非常に限られていたらしく、採用にはならずとも魅力的な内容だということで、 Reject Conference に参加させていただくことになりました。

Riotz Works のメンバーは、全員フロントエンド以外の領域を得意としています。ですが、フロントエンド/バックエンドの領域にこだわらず、思いついたことは自ら形にしていくことが大事だと思っていますし、ハッカソンでものを作っていく中で、人の目にダイレクトに届くUIの重要性と楽しさに気づいてしまったので、もっと極めたいなと思っています。

今回の発表は、今まで数を重ねてきたこともあり自信持ってできた気がして、懇親会でも色んな方々とお話させていただき、個人的に最も楽しくできた発表でした。

Vue.js/Nuxt.js と TypeScript で実現する PWA なリアルタイム動画ラップバトルアプリ〜フル Node.js エコシステムで戦ったモバイルアプリのハッカソン〜

@東京Node学園祭2018、 発表資料はこちら

11月23日。@lulzneko@lopburny が発表しました。今回も話のネタそのものは変わらないですが、Riotz Works が Node.js を使い始めて、2018年をどう過ごしたかという集合体のような内容です。またサーバーサイド(Node.js)→フロントエンド(Vue.js)→Node.js環境全般 という流れができたのと、Node.js コミュニティでの発表ということで胸が熱くなりました。

発表も比較的慣れてきたところで順調に進みましたが、React 界隈の方々が多く、前回よりは重い空気になることもありました。ですが発表の順番が最後で、たくさんの方々に聞いていただき、たくさんフィードバックをもらえたので、かなり手応えのあったイベントでした。

2018年を振り返って、よかったこと

あえて2点にしぼると、こんな感じです。

  • ハッカソンに出て、アイディアを形にできたこと
  • 次々と発表が決まり、絶え間なくイベントに参加できたこと

2018年を振り返って、反省したいこと

たくさんありますが、これも2点にしぼります。Riotz Works というより個人的な話ですね。

  • タスクの優先順位を考慮した、自分のリソース管理
  • 発表以外のアウトプットができていない点

当たり前な話ですが、何らかの活動を継続して進めていくためには、自分の体力・時間などのリソース管理を上手にできることが重要なポイントかなと思います。

僕は思いつきとその時のモチベーションに左右されやすいタイプで、できないことも意地を張って挑戦し続けたりするので、無駄にした時間が結構ありました。目標やコミットしたことに対して確実に結果を出すためには、もっと冷静に自分を見直して、シビアにならないといけないですね。

あと、もっとブログ書きたかったのですが、上記のリソース管理ができなかったせいか、できていません。書きたい話は結構あります。2019年からばんばん出して行きたいと思います。

終わりに

ちょっと長くなってしまいましたが、いかがだったでしょうか。
Riotz Works は 2019年も楽しく活動していきたいと思います。みなさん良いお年を〜

Author: lopburny

API Gateway の WebSocket で チャット を 実装 w/Serverless Framework

この記事は Serverless Advent Calendar 2018 の 22日目になります。

AWS re:Invent で 発表された API Gateway の WebSocket 対応、ついに利用できるようになりました!
WebSocket が サーバーレスで簡単に利用できるようになるとアプリの幅も広がり、いろいろなことができるようになります。
さっそく API Gateway の WebSocket を 試してみたいと思います。

※ 今回 Serverless Framework の serverless-websockets-plugin を 使いますが 2018年12月現在、暫定の実装になるとのことです。API Gateway の WebSocket 対応 が AWS CloudFormation で 未サポートのため Serverless Framework 本体に含まれず Plugin に なっていること、正式版では構文が変わる可能性があることに注意が必要です。

しかしながら “With all that out of the way, play with our new presents!” ということで、楽しんでみましょう!

環境

開発者の環境は以下となります。

  • Windows 10 64bit + WSL Ubuntu 18.04.1 LTS
  • Visual Studio Code
  • Node.js 8.10.0
  • Yarn 1.12.3
  • TypeScript 3.2.2
  • Serverless Framework 1.35.1
  • Serverless Websockets Plugin 1.0.0

参考情報

WebSocket について

HTTP ベース の Web API では サーバーに対して接続、リクエストを送り、処理結果のレスポンスを受け取り、切断終了という流れになります。
必要に応じて、このリクエスト/レスポンスのやり取りを繰り返す形になります。

それに対して WebSocket は サーバーに接続後、コネクションを維持したまま双方向でメッセージを送ることができます。
これは通常のリクエスト/レスポンスに当たるやり取りのほかに、サーバー側から任意のタイミングでメッセージを送ることができるようになるということです。

例えば私たちがハッカソンで作った「ラップ、タップ、アップ 🎶」というアプリでは、演奏者へのフィードバックとして「👍」を 送ることができ、その数をリアルタイムでカウントする機能があります。

この「👍」を リアルタイムでカウントする部分を HTTP ベース の Web API で 作るとすると、アプリから「👍」の数を取得する API を 繰り返し リクエスト/レスポンス して受け取る必要が出てきます。
仮に数に変化がなかったとしてもアプリ側は知るすべがないので、繰り返し「👍」の数を取得しに行かなければなりません。

WebSocket が 使える場合、コネクションは維持したまま必要な時に「👍」の数をサーバー側がアプリへメッセージを送ることができるようになります。
「👍」の数に変化がなかった場合は維持されているコネクションの中にメッセージが流れないだけでアプリは特に何もする必要はありません。変化があった時だけサーバーが教えてくれるので、それに応じてアプリの表示を変えるだけになります。

これにより不要なリクエスト/レスポンスを減らせるほか、よりリアルタイムに近い状態で変化を受け取ることができるようになります。
HTTP ベースでは リクエスト/レスポンス で 受け取り、次のリクエストを出すまでの間にあった変化は結果しか受け取れません。5だった「👍」を次のリクエスト/レスポンスでは 10になっているかもしれません。

WebSocket では 状態の変化を断続的に返すことも可能になるので、5、6、7… と メッセージを返せます。

これにより、よりスムーズに描画を変えていくことができるようになります。
これはチャットのようなコミュニケーションや金融などの取引の価格情報などに使うことができます。

今回 API Gateway が この WebSocket に 対応したので、その使い方をチャットを実装することで確認していきます。
(WebSocket で チャットは定番すぎますが、「👍」の カウントだとさみしいですからね)

※ 「ラップ、タップ、アップ 🎶」では、API Gateway が まだ WebSocket が 扱えなかったので、 Firebase Realtime Database を 使って実現しています。

Node.js プロジェクト の 準備

Serverless Framework の ボイラープレート を 使って、TypeScript の Node.js プロジェクトを作成します。

プロジェクトのディレクトリを作成しプロジェクトのひな型を作ります。

1
2
3
4
5
6
7
8
9
username@pc:~$ mkdir samples-apigateway-websocket-chat
username@pc:~$ cd samples-apigateway-websocket-chat
username@pc:~/samples-apigateway-websocket-chat$

username@pc:~/samples-apigateway-websocket-chat$ npx serverless create --template aws-nodejs-typescript
Serverless: Generating boilerplate...
(省略)
Serverless: Successfully generated boilerplate for template: "aws-nodejs-typescript"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

続いて Serverless Framework を ローカルで追加し、AWS SDK と WebSocket クライアント wscat、必要なパッケージを最新化してインストールします。
Serverless Framework は 公式では グローバルに追加して使うようですが、複数人開発でグローバルのを使っているとバージョンの違いなどでトラブルということがあったので package.json で 明示して、それを使うようにしているためです。サクッと試すにはグローバルでもよいでしょう。

1
2
3
username@pc:~/samples-apigateway-websocket-chat$ yarn add -D serverless serverless-websockets-plugin wscat
username@pc:~/samples-apigateway-websocket-chat$ yarn upgrade --latest
username@pc:~/samples-apigateway-websocket-chat$ yarn add aws-sdk

package.json を プロジェクトに合わせて修正します。
主に name description author あたりを合わせるとよいでしょう。
また、作成しているのはアプリケーションなのでモジュール公開の防止のために "private": true を 設定しておくとよいでしょう。private の 詳細は こちらの package.json | npm Documentation を ご確認ください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "samples-apigateway-websocket-chat",
"version": "1.0.0",
"private": true,
"dependencies": {
"aws-sdk": "^2.382.0"
},
"devDependencies": {
"@types/aws-lambda": "8.10.17",
"@types/node": "^10.12.18",
"serverless": "^1.35.1",
"serverless-webpack": "^5.1.1",
"serverless-websockets-plugin": "^1.0.0",
"source-map-support": "^0.5.6",
"ts-loader": "^5.3.2",
"typescript": "^3.2.2",
"webpack": "^4.5.0",
"wscat": "^2.2.1"
},
"author": "Riotz.works (https://riotz.works)",
"license": "MIT"
}

Serverless Framework の 設定

serverless.yml を 編集し Serverless Framework の 設定を行います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
service:
name: samples-apigateway-websocket-chat

plugins:
- serverless-webpack
- serverless-websockets-plugin

provider:
name: aws
stage: ${ opt:stage, 'dev' }
region: ${ opt:region, 'us-west-2' }
runtime: nodejs8.10
iamRoleStatements:
- Effect: Allow
Action:
- execute-api:ManageConnections
Resource:
- arn:aws:execute-api:*:*:**/@connections/*
- Effect: Allow
Action:
- dynamodb:Scan
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- Fn::GetAtt: [ ChatConnectionsTable, Arn ]
environment:
DYNAMODB_CONNECTIONS:
Ref: ChatConnectionsTable
websocketApiName: ${self:service.name}-${self:provider.stage}
websocketApiRouteSelectionExpression: $request.body.action

functions:
connect:
handler: handler.connect
events:
- websocket:
routeKey: $connect
disconnect:
handler: handler.disconnect
events:
- websocket:
routeKey: $disconnect
defaultMessage:
handler: handler.defaultMessage
events:
- websocket:
routeKey: $default
sendMessage:
handler: handler.sendMessage
events:
- websocket:
routeKey: sendMessage

resources:
Resources:
ChatConnectionsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:service.name}-connections-${self:provider.stage}
AttributeDefinitions:
- AttributeName: ConnectionId
AttributeType: S
KeySchema:
- AttributeName: ConnectionId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
SSESpecification:
SSEEnabled: True
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES

plugins に API Gateway WebSocket を 使うための serverless-websockets-plugin を 追加します。

iamRoleStatements では、API Gateway の WebSocket API を 呼び出すための execute-api:ManageConnections に 許可を与えます。
また WebSocket に 接続しているクライアントのコネクションを管理するための DynamoDB が 必要なので、DynamoDB に 関する許可も与えます。

30行目、31行目 の websocketApiNamewebsocketApiRouteSelectionExpression は、serverless-websockets-plugin の 設定になります。websocketApiName は 管理用にわかりやすい名前を設定しておくとよいでしょう。

functions は WebSocket の イベントとアクションに合わせて定義を行います。
eventswebsocket が 追加でき、 websocketApiRouteSelectionExpression に 設定された Key の 値と routeKey の 文字列のマッチングによって起動する Lambda を 振り分けています。
$connect $disconnect は WebSocket の 接続と切断に対応します。また $default は マッチするアクションがない場合に呼び出されます。
最後の sendMessage が WebSocket で 受け取るメッセージのキーになります。具体的には { "action":"sendMessage", "data":"hello world" } のような JSON の action に 入る文字列のマッチングになります。

resources は WebSocket の コネクション管理用 DynamoDB を 定義しています。
今回は最低限の ConnectionId だけを管理します。名前など無しの完全に匿名のメッセージだけのチャットになります。(WebSocket の 動きと実装を試すってことで💦)

AWS Lambda の 実装

handler.ts に 処理を実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { APIGatewayEventRequestContext, APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult } from 'aws-lambda';
import { ApiGatewayManagementApi, DynamoDB } from 'aws-sdk';

interface APIGatewayProxyEventWithWebSocket extends APIGatewayProxyEvent {
requestContext: APIGatewayEventRequestContextWithWebSocket
}
interface APIGatewayEventRequestContextWithWebSocket extends APIGatewayEventRequestContext {
domainName: string,
connectionId: string
}


const apigateway = ({ domainName, stage }): ApiGatewayManagementApi => new ApiGatewayManagementApi({ endpoint: `${domainName}/${stage}` });
const dynamodb = new DynamoDB.DocumentClient();

export const connect: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
await dynamodb.put({ TableName: process.env.DYNAMODB_CONNECTIONS, Item: { ConnectionId: event.requestContext.connectionId }}).promise();
return new Result('Connected');
};

export const disconnect: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
await dynamodb.delete({ TableName: process.env.DYNAMODB_CONNECTIONS, Key: { ConnectionId: event.requestContext.connectionId }}).promise();
return new Result('Disconnected');
};

export const defaultMessage: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
const params: ApiGatewayManagementApi.Types.PostToConnectionRequest = {
ConnectionId: event.requestContext.connectionId,
Data: 'Error: Invalid action type'
};
await apigateway(event.requestContext).postToConnection(params).promise();
return new Result('Error: Invalid action type', 500);
}

export const sendMessage: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket, context, callback): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
const connections = await dynamodb.scan({ TableName: process.env.DYNAMODB_CONNECTIONS, ProjectionExpression: 'ConnectionId' }).promise();
await Promise.all(connections.Items.map(async ({ ConnectionId }) => {
try {
const params: ApiGatewayManagementApi.Types.PostToConnectionRequest = {
ConnectionId: ConnectionId,
Data: JSON.parse(event.body).data
};
await apigateway(event.requestContext).postToConnection(params).promise();
} catch (e) {
if (e.statusCode === 410) {
await dynamodb.delete({ TableName: process.env.DYNAMODB_CONNECTIONS, Key: { ConnectionId: ConnectionId }}).promise();
} else {
throw e;
}
}
}));
return new Result('OK');
}


class Result implements APIGatewayProxyResult {
public constructor(public body: string, public statusCode: number = 200) {}
}

4行目~10行目 の interface 宣言ですが、こちらは API Gateway の WebSocket 対応の TypeScript 型定義がまだ入っていないので補完するために宣言しています。 requestContext に入ってくる domainNameconnectionId が 必要なため追加しています。型定義が更新されたら不要となります。

13行目 ApiGatewayManagementApi の インスタンスを取得する関数ですが、API Gateway から WebSocket の メッセージを返す際に endpoint が 必要となり、これが domainNamestage から決まってきます。固定値の場合はよいのですが、今回のように動的に決まってくる場合は requestContext から受け取った domainNamestage が 必要となるため毎回インスタンスを生成しています。

16行目~58行目で serverless.yml に 定義した Lambda の エントリーポイントと実装があります。

connectdisconnect は WebSocket の 接続/切断 の 際に呼び出されます。
接続時に connectionId を DynamoDB へ 保存し、切断時に削除しています。切断は呼び出されないこともあるので、注意が必要です。

defaultMessage は WebSocket で 受け取ったメッセージに対応するアクションがなかった場合に呼び出されます。ここでは “Error: Invalid action type” を クライアントに返しています。
WebSocket で メッセージを返すには ApiGatewayManagementApipostToConnection() を 呼び出します。その際にクライアントの connectionId が 必要となります。
この関数のようにメッセージを送ってきたクライアントだけにメッセージを送る場合は requestContextconnectionId が 使えるので、それを使ってエラーメッセージを返します。

最後の sendMessage は、チャットのコメントを送る処理になります。リアルタイムに複数クライアントへメッセージを送る WebSocket を使う処理の肝となる部分です。
複数クライアントにメッセージを返すには、メッセージを送るべきクライアント全ての connectionId が 必要となり、それぞれに ApiGatewayManagementApi#postToConnection() を 行う必要があります。
つまり API Gateway が 接続中のクライアントを知ってくれてるわけではないので、自前で管理する必要があり、そのために DynamoDB を 用意しているものになります。

今回は全員参加の簡単な実装なので、DynamoDB の コネクション管理テーブルをスキャンし、全件に対して ApiGatewayManagementApi#postToConnection() を 呼び出しています。(なんか、もっとスマートな実装できないかなぁ)

ApiGatewayManagementApi#postToConnection() を 呼び出す際に、コネクションが切断されているクライアントがありえます。先ほど「切断は呼び出されないこともあるので、注意が必要です。」と書きました通り、クライアントが切断されてもイベントが呼び出されないケースもあるため、DynamoDB への 削除処理が行われず connectionId が 残っているケースがありえます。その場合 statusCode410 の エラーが投げられるので、そのエラーが投げられた場合は DynamoDB から該当する connectionId を 削除しておき再発防止しておきます。

デプロイ & 実行!

デプロイは Serverless Framework が しっかりやってくれるので、以下のコマンドで行えます。
あらかじめ AWS の Access Key の用意とプロファイルを設定しておきます。(デフォルト・プロファイルでない場合は --aws-profile [your profile name] と 利用するプロファイル名を --aws-profile で 指定します)

1
2
3
4
5
6
username@pc:~/samples-apigateway-websocket-chat$ yarn serverless deploy
(省略)
Serverless: Deploying Websockets API named "samples-apigateway-websocket-chat-dev"...
Serverless: Websockets API named "samples-apigateway-websocket-chat-dev" with ID "6ovkt8XX" has been deployed.
Serverless: Websocket URL: wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
Done in 137.90s.

デプロイが完了すると、コマンドの実行結果に WebSocket の URL が 出力されます。
その URL に対して wscat で 接続し API Gateway WebSocket の 動きを確認します。

1
2
3
username@pc:~/samples-apigateway-websocket-chat$ yarn wscat -c wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
connected (press CTRL+C to quit)
>

接続できると > で 入力待ちになります。 { "action":"sendMessage", "data":"hello world" } と メッセージを送ると、チャットのコメントが帰ってきます。

1
2
3
4
5
username@pc:~/samples-apigateway-websocket-chat$ yarn wscat -c wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
connected (press CTRL+C to quit)
> { "action":"sendMessage", "data":"hello world" }
< hello world
>

複数のコンソールから接続すると、送ったコメントが全てのコンソールに流れてきます。
WebSocket で リアルタイムに複数クライアントへメッセージが遅れていることが確認できます。

チャットとは名ばかりのコメントだけを送りあうだけの実装(しかも wscat によるコマンドライン)でしたが、API Gateway WebSocket の 実装がつかめたかと思います。

Serverless Framework は 今後の AWS CloudFormation 対応によって変わってくる部分がありますが、こんなに簡単に設定できるのでとても助かります。

WebSocket が 簡単に利用できるようになったので、いろいろなアプリづくりに生かせそうで楽しみです。


では、ハッピー・サーバーレス・ライフ! ハッピー・ホリデー!!

Author: lulzneko

Serverless Framework と TypeScript で Hello と Version の Web API を 実装

前回サーバーレスなアプリケーション の ひな形を作りました。
今回は、ひな形で作られた AWS Lambda の ソースを Hello World にし、また新しくアプリケーションのバージョンを返す Version Web API を 追加します。

シリーズの記事

環境

開発者の環境は以下となります。

  • Windows 10 64bit
  • Visual Studio Code
  • Node.js 9
  • TypeScript 2.7
  • Serverless Framework 1.26.0

主な実行環境について、また全部稼働まではいきませんが以下を想定しています。
※ Amazon API Gateway などは、Serverless Framework が 自動設定するので省略、明示的に使うものとしてリストになります。

  • Amazon S3
  • AWS Lambda

ベースとなるソースコード

前回の続きとなりますので、こちら https://github.com/riotz-works/samples-hello-serverless/tree/0.0.1 を もとに追加開発します。

本記事と一緒に作成する場合は 前回のソース もしくは タグを指定してチェックアウトしたソース を お使いください。

1
2
3
c:\Temp\nlog>git clone --depth 1 -b 0.0.1 https://github.com/riotz-works/samples-hello-serverless.git
Cloning into 'samples-hello-serverless'...
(省略)

Hello Web API の 改修

Serverless Framework の ボイラープレート で 生成した Lambda の プログラム は handler.js で 以下のようになっています。
これを Hello World の Web API へ 改修するにあたり、このままで responsebody を 変えるだけでよさそうです。今回は message'Hello Serverless !!' にし、input は 削除することにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda';

export const hello: Handler = (event: APIGatewayEvent, context: Context, cb: Callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!',
input: event,
}),
};

cb(null, response);
}

そしてプロジェクトのディレクトリ直下で汎用的な名前の handler.js だと、このあと追加する Version Web API の 配置などで困ります。
まずはディレクトリ配置を見直し、Lambda の ハンドラ・ファンクションのソースが入っていることがわかるように src/handler 配下に置くことにします。
続いて Hello Web API の ハンドラに対応したファンクションのファイル名として greetings.ts とすることにします。

ファイル名と配置を変えたので Lambda の 定義をしている serverless.yml を 修正します。
hello ファンクション の ハンドラ は handler.hello と 定義されていましたが、greetings ファクション src/handler/greetings.hello ハンドラ に 変更します。

Hello Web API が できました。
この時点で serverless deploy コマンドでデプロイすることもできます。(–aws-profile [profilename] を 忘れずに)

Version Web API の 作成

Hello Web API が 作れましたがボイラープレートのままだったので、新しく Web API を 追加したいと思います。
とりあえず、アプリケーションのバージョンを返す Version Web API を 作ることにします。
仕様は「HTTP GET /versionpackage.jsonversion を 返す」にします。

まずは、Lambda の ハンドラのソースを配置する src/handlersystems.ts を 作ります。
他にシステム関連の Web API の 想定はありませんが、システム関連 Web API の ハンドラを配置する systems.tsversion の ハンドラを追加するイメージにしました。

コードは以下のようにします。(このコードを使う場合は、1行目の Copyright は 書き換えてください)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Copyright 2018 Riotz Works. */
import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda';
import { version } from '../../package.json';

/**
* System Web API's AWS Lambda handler function.
*
* @param event – event data.
* @param context – runtime information of the Lambda function that is executing.
* @param callback – optional callback to return information to the caller, otherwise return value is null.
* @see http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
*/
export const handle: Handler = (event: APIGatewayEvent, context: Context, cb?: Callback): void => {

const response = {
'body': JSON.stringify({
'version': version
}),
'statusCode': 200
};

if (cb !== undefined) {
cb(null, response); // tslint:disable-line
} else {
context.succeed(response);
}
};

主なキー・ポイントは以下になります。 先の Hello Web API と 若干異なる部分 (context.succeed() とか) が ありますが詳細は後日の記事として、基本的には変わりありません。

  • 3行目で、バージョンのもとになる package.jsonsystems.ts の 相対パスで指定し version 要素をインポートします
  • 17行目で、インポートした version 属性の値 を レスポンス・ボディとしてセットします

Visual Studio Code の 環境によってはエラーが出ないかもしれませんが、3行目 の インポート文でエラーにあります。

何も表示されていなくても serverless package を 実行するとエラーが出力されます。

1
2
3
4
5
C:\Temp\samples-hello-serverless> serverless package
Serverless: Bundling with Webpack...
(省略)
ERROR in C:\Develop\repos\riotz\samples-hello-serverless\src\handler\systems.ts
(3,25): error TS2307: Cannot find module '../../package.json'.

これは package.json の モジュール定義が存在しないためになります。
このように型定義などを確認してくれるのが TypeScript のありがたいところです。
一方で今回のは若干無茶な実装でした。標準モジュールには存在しませんし、適切なモジュール定義をとってくることも難しいでしょう。さりとて package.json と 何か別ファイルで version の ダブルメンテはしたくないです。。。 ということで、モジュール定義を追加することにします。
ソースディレクトリ の srctypes.d.ts を 追加します。.d.ts ファイルでしたら特に命名規則はなく typing.d.ts も よく見かけます。

コードは以下のようにします。(1行目の Copyright は 書き換えてください)

1
2
3
4
5
6
7
8
9
10
/* Copyright 2018 Riotz Works. */

/**
* Module declaration for JSON file.
*/
declare module '*.json' {

/** version element of package.json using Version API. */
const version: string | undefined;
}

*.json なので、モジュール定義が見つからなかった JSON ファイル の 型定義になります。
その中に version が 文字列として存在することを定義しますが、これは 全ての JSON ファイルに当てはまることではないので、型定義は string | undefined とし ドキュメントで注釈しました。
頑張ると package.json 固有のモジュール定義もできたのですが version を取得するだけにしては複雑になりすぎたので、このあたりを落としどころとしました。

最後に serverless.yml に Version Web API の Lambda 定義を追加します。
functions: greetings: の 下に追加します。

1
2
3
4
5
6
systems:
handler: src/handler/systems.handle
events:
- http:
method: get
path: version

Version Web API が できました。

デプロイ

AWS 環境へデプロイします。前回の デプロイ と 稼働テスト 同様に、AWS の プロファイを参照して serverless deploy --aws-profile [profilename] を 実行します。

endpointshelloversion の URL が 出力されるので、それぞれブラウザでアクセスすると、プログラムした JSON が 返ってきます。

ソースコード

今回作成した部分までのソース を GitHub へ アップしました。
https://github.com/riotz-works/samples-hello-serverless/tree/0.0.2


Hello Web API は ボイラープレート の レスポンスを改修しただけだったので特に大きな変化はありませんでした。一方で Version Web API は 新しく追加となりましたし、両方のプログラムを配置するためにプロジェクトの構造も変化させました。

Hello と Version で 実装レベルが異なっている部分はありますが、これについては次の記事で確認しながら合わせこみをしていきたいと思います。できれば TypeScript の コンパイラ設定 や Lint にまでふれられたらと思います。

Author: lulzneko

Serverless Framework と TypeScript で サーバレス開発事始め

前回の記事から時間が空いてしまいましたが、ちょうど新しいプロダクトの開発を始めるところなので Serverless FrameworkTypeScript で 開発する際の事始めについてまとめます。
例によって Hello World になりますが、こんな感じで作り始めますというところを お伝えできればと思います。

シリーズの記事

環境

開発者の環境は以下となります。

  • Windows 10 64bit
  • Visual Studio Code
  • Node.js 9
  • TypeScript 2.7
  • Serverless Framework 1.26.0

主な実行環境について、今回は準備なので全部稼働まではいきませんが以下を想定しています。
※ Amazon API Gateway などは、Serverless Framework が 自動設定するので省略、明示的に使うものとしてリストになります。

  • Amazon S3
  • AWS Lambda

想定アプリケーション

ブラウザでアクセスするウェブサイトで、アクセス時に JavaScript で Web API を 呼び出し “Hello World” の 挨拶を取得します。 まずは動作させるところを目標にシンプルな形で進めます。

ウェブサイト は Amazon S3 に HTML を 配置し 静的ウェブサイトのホスティングを使います。
本格稼働するには Amazon CloudFrontAmazon Route 53 などが必要となりますが、まずは稼働を目指し S3 だけで進めます。

Web API は サーバーレスで作りたいので AWS Lambda を 使います。
インスタンス や コンテナ の 管理が不要で、純粋にアプリケーションの開発やメンテに集中できるのサーバーレスにこだわりたいです。
こちらも本格稼働にあたっては Amazon API Gateway に カスタム・ドメインを割り当てたりしますが、まずは稼働を目指し自動割り当てで進めます。

開発環境の構築

コーディングにためのエディタを用意します。こちらは手慣れたもので大丈夫です。今回は Visual Studio Code を 使いました。
こちら https://code.visualstudio.com から取得できます。

続いて Node.js を インストールします。こちら https://nodejs.org から ダウンロードしてインストールします。今回は 9.5.0 Current を インストールしました。

プロジェクト の 作成

Node.js が インストールできたら、プロジェクトのディレクトリを作成します。
今回は C:\Temp\hello-serverless を プロジェクトのディレクトリとしました。

続いて Serverless Framework を 導入します。今回は Visual Studio Code の ターミナルを使っていますが、コマンド プロンプト からも同様のコマンドになります。
今回はプロジェクトごとに Serverless Framework を 導入したいので、-g なしで npm install serverless としました。

1
2
3
4
C:\Temp\hello-serverless> npm install serverless
(省略)
+ serverless@1.26.0
added 302 packages in 44.148s

Serverless の モジュール が 導入され、node_modulespackage-lock.json が 作られています。

Serverless の AWS/TypeScript ボイラープレート から プロジェクト の ひな形を作ります。
※ 今回はプロジェクト・ローカル に Serverless Framework を 導入しているため node_modules\.bin\serverless コマンドになります。node_modules\.bin に パスを通しておくか、めんどくさい場合は npm install -g serverless-g を つけてグローバルに入れてしまうのも手です。

1
2
3
4
C:\Temp\hello-serverless> node_modules\.bin\serverless create --template aws-nodejs-typescript
(省略)
Serverless: Successfully generated boilerplate for template: "aws-nodejs-typescript"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

Node.js/npm プロジェクト関連のファイルが追加されます。

package.jsondevDependencies に Serverless Framework が 入っていないので、もう一度 --save-dev を 付けて npm install --save-dev serverless を 実行します。
※ 最初から --save-dev しないのは package.json が 作られているとボイラープレートが展開できないためです。

他のモジュールもインストールするため、npm install を 実行します。

プロジェクト の 設定

自動生成された設定が入っているので、プロジェクトに合わせた設定を行います。

package.json は、最小限 name description author あたりを変更しておきます。
また、作成しているのはアプリケーションなのでモジュール公開の防止のために "private": true を 設定しておくとよいでしょう。private の 詳細は こちら package.json | npm Documentation を ご確認ください。

serverless.yml は、service: name: の 値を変更しておきます。

tsconfig.jsonlibesnext を 追加します。
2018年2月現在、これを追加しておかないとビルド時に参照しているモジュールで以下のようなエラーが発生するためです。

1
2
3
4
5
6
7
C:\Temp\hello-serverless> node_modules\.bin\serverless package

ERROR in C:\Temp\hello-serverless\node_modules\@types\graphql\subscription\subscribe.d.ts
(17,4): error TS2304: Cannot find name 'AsyncIterator'.

ERROR in C:\Temp\hello-serverless\node_modules\@types\graphql\subscription\subscribe.d.ts
(29,4): error TS2304: Cannot find name 'AsyncIterable'.

プロジェクト の ビルド

serverless package コマンド で ビルドします。

1
2
3
4
5
6
7
8
9
C:\Temp\hello-serverless> node_modules\.bin\serverless package
Serverless: Bundling with Webpack...
ts-loader: Using typescript@2.6.2 and C:\Temp\hello-serverless\tsconfig.json
Time: 2085ms
Asset Size Chunks Chunk Names
handler.js 2.94 kB 0 [emitted] handler
handler.js.map 3.18 kB 0 [emitted] handler
[0] ./handler.ts 350 bytes {0} [built]
Serverless: Packaging service...

TypeScript が コンパイルされ、JavaScript と ソースマップ が 作られ、.serverless ディレクトリに AWS CloudFormation の テンプレート と Lambda の デプロイ Zip が 作られます。

デプロイ と 稼働テスト

ビルドに成功したら serverless deploy コマンド で AWS 環境 へ デプロイします。
デプロイにあたっては AWS IAM ユーザー の アクセス・キー が 必要となります。あらかじめ作成アクセス・キーを取得し、%USERPROFILE%\.aws\credentials (e.g. C:\Users\username\.aws\credentials) に 記述しておきます。
IAM の アクセス権 は PowerUserAccess では足りず IAM 周りの権限追加が必要です。まだ絞り込みきれておらず結局 AdministratorAccess を 使ってしまっています。頑張らないと。。。

1
2
3
4
[hello]
region = us-west-2
aws_access_key_id = ZDEJREC4D1GM3DXXXX
aws_secret_access_key = ce4FH4Dcyh5DGh2dDGG4hDk6DYfhDAjrFhXXXX

デプロイを実行します。
serverless deploy --aws-profile hello--aws-profilecredentials[] で 指定したプロファイル名を指定します。

1
2
3
4
5
6
C:\Temp\hello-serverless> node_modules\.bin\serverless deploy --aws-profile hello
(省略)
endpoints:
GET - https://ca3kg0hrXX.execute-api.us-east-1.amazonaws.com/dev/hello
functions:
hello: hello-serverless-dev-hello

無事にデプロイできると 自動生成された API Gateway の エンドポイントが出力されます。

ブラウザでアクセスすると、handler.ts の 実装の通り「Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!」の メッセージ と HTTP リクエストの内容が表示されます。

お掃除

serverless remove で AWS 環境をクリーンアップすることができます。

1
2
3
4
5
6
7
C:\Temp\hello-serverless> node_modules\.bin\serverless remove --aws-profile hello
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
..........
Serverless: Stack removal finished...

ソースコード

今回作成した部分までのソース を GitHub へ アップしました。
https://github.com/riotz-works/samples-hello-serverless/tree/0.0.1


初期設定に多少の作業がありましたが、Serverless Framework を 使うことで簡単にデプロイとクリーンアップができました。

アプリケーションとしては Lambda で メッセージを返すレベルではありますが、インフラ面を考えると、これを全て AWS マネジメントコンソール ではかなりの手間がかかります。それを Serverless Framework が 補ってくれるので、サーバレス開発のインフラ運用が削減できるメリットに加えて、インフラ構築も格段と楽になるのではないでしょうか。

また Try & Error を 繰り返すうちに AWS 環境 が ついつい散かってしまい、よくわからないリソースが放置されるケースが出てきたりします。開発環境とはいえ Serverless Framework で 環境を作るようにすると片付けも簡単ですね。

引き続き、このプロジェクトに設定やコードを加えて もう少し発展させていきたいと思います。

Author: lulzneko

CSV ファイル の バッチ連携 も AWS Lambda で サーバーレス

この記事は Serverless Advent Calendar 2017 の 7日目になります。

Serverlessconf Tokyo 2017 で 発表させていただく機会をいただき、 Java チームが選択した TypeScript による AWS Lambda 開発 というタイトルで お話をさせていただきました。

今回は そのシステムの裏手側、CSV ファイル を 連携するバッチ を サーバーレスで実現したアーキテクチャについて ご紹介します。

システム全体の概略図

ざっくりと下図のようなシステムで AWS 上に作られています。
スマートフォン などから IoT 機器を操作するようなクラウド・サービスがあり、そのバックグラウンド・プラットフォームになります。認証や機器のデータ管理を行うシステムです。
このシステムは、図の Amazon API GatewayAWS Lambda が ペアになっているアイコン毎が1つ1つのマイクロサービスとして作られています。つまり 10を超えるマイクロ・サービスの集合体になります!

今回の話は、この図の右上部分 “Traditional DC”、企業の伝統的なデータセンターからデータを受ける部分です。
この部分は伝統とシキタリにのっとり CSV ファイル を 受け取り、処理する仕組みが必要となります。

※ CSV の C は Comma と 信じてましたが、Character や Column 説 (e.g. Wikipedia) が あり 広義には Comma に 限らず特定の文字でデータを区切るファイルらしい。どうでもいいけど。。。

なぜ AWS Lambda ?

このようなシステム を AWS で 実装するには、AWS BatchAWS Glue などを使うかと思います。しかしながら、今回は Lambda で 実装することにしました。

背景としては、以下のような点があります。

  • 少人数の DevOps チームであり、AWS の マネージド度合いが高いほど嬉しかった
  • データ量や処理量から想定してコスパが優れていた
  • 1回に連携するデータ量 が Lambda の 処理時間におさまる可能性が持てた

特に2番目のコストについては、Glue に対して圧倒的によかったというのが大きかったです。今回の処理は ETL に近いとはいえ、DWH 連携ではなく、DB の マスター・データ登録だったので Glue を 活かしきれないという点がありました。

なお Lambda の 実行ランタイムは Java に なります。
(Serverlessconf Tokyo 2017 の 発表資料 の 通り、Java チーム なので)

CSV ファイル 連携 の アーキテクチャ概要図


“Traditional DC” からは、Amazon S3 に CSV を おいてもらうことにします。FTP/SFTP とのリクエストがありましたが、サーバーレス厨 とは言わずとも ここは S3 へのアップロードへお願いしたいところ、何としてでも承諾いただきます。(いただきました)

S3 からは Amazon SNS へ イベント通知をし、Lambda を 起動します。その Lambda で CSV を パースして DynamoDB へ データを登録します。

複雑なデータの加工 や 外部の API/データ を 参照するような場合は、DynamoDB Streams から Lambda を 呼び出して後続の処理として実装します。このようにすることで、データの登録に特化させて処理数を稼ぐことができ、また DynamoDB Streams の 後続処理は、登録されたデータ1件ごとの処理になるので時間的な余裕が生まれます。

ここでのポイントは S3 ⇒ SNS からの Lambda は DynamoDB への登録だけに特化し、他の処理をしないことです。このようにすることで、なるべく CSV ファイルの対応に処理を振り分けるようにし、時間内で処理できる量を増やすようにしています。

処理能力 と アーキテクチャの改良

このような形にすることで、CSV を Lambda で 処理できるようになります。
このアーキテクチャの処理能力は、CSV ファイル 1行のデータ量や、カラム数によって変わってくる部分があるかと思いますが、今回のケースでは 1ファイル で 約 800行のレコードが処理できました!
て、まったく処理できてません。。。

これでは役に立たないので対応が必要となります。
Lambda は 設定するメモリの使用量によって処理速度が変わるという話もあり、最大に設定してみましたが設定による差は特にありませんでした。ファイルを読み込みながらの順次処理なので、ここでの処理性能はあまり変わらないのでしょう。また DynamoDB へ アクセスするオーバーヘッドも処理性能では大きく変わらないはずです。

では、どうするのか。


S3 に 置かれたファイルを DynamoDB へ 登録する前に、ファイル分割する処理をはさみます。
1回の Lambda で DynamoDB へ 登録できるのは 余裕を見て 500件までとして、CSV ファイルを 500行ごとのファイルに分割して S3 へ 再アップロードします。その 500行ごとのファイルを Lambda で DynamoDB へ 登録する形にしました。

これにより、30,000行まで処理できるようになり現実的なラインまで持っていけるようになりました。S3 からの Lambda に 変わりはないので、サーバーレスの形態も維持できます。

まとめ

サーバーレスでシステムを作ろうとしても、往々にして発生してしまう既存システムとのバッチ連携。そのために FTP/SFTP やら、CSV パースするための処理やら と どうしても サーバ・インスタンスが欲しくなってしまい、せっかくの サーバーレス が サーバー有り(サーバーレスの反対語って何だろう)になってしまいます。

Glue に 見合う処理であればよいのですが、今回のように小規模なデータ登録となるとオーバースペック気味にもなります。そんな時には S3 からの Lambda で 処理することで、サーバーレスでバッチ連携をするのも手ではないでしょうか。

ポイントとしては以下になります。

  • ファイルは S3 に 置いてもらう
  • S3 ⇒ SNS から Lambda を 起動し DynamoDB へ データ登録に特化する
  • 1回の Lambda で処理できるデータ量は少ない、必要に応じてファイル分割の Lambda を はさむ

Serverless Advent Calendar 2017 、楽しく、そして勉強になる記事がたくさんです。

昨日 6日目 は @RyoheiMorimotoさん の AWS LambdaをTest Runnerとして使ってみる でした. ユーザ管理のシステムをサーバーレスで 34歳 タローさん が ハナコさん に なれるかをテストしています。サーバーレス・テスト、面白いですね!

明日 8日目 は @narikeiさん です。何の記事か楽しみです!


では、ハッピー・サーバーレス・ライフ! ハッピー・ホリデー!!

Author: lulzneko

Hello World !!

こんにちは、世界!
こんにちは、みなさん!!

わたしたち は Riotz Works です。

“a cheerful engineering team” を 標榜する、わたしたちは
IT を 中心に 技術的なこと や さまざまな挑戦 が 大好きで 陽気で愉快な エンジニアの集団です。

これまで学んできたこと、今挑戦していること、先々やってみたいこと など、を 面白おかしく、まるで お祭り騒ぎ のように アウトプットしていきたい、そんな思いから、この『 Articles | Riotz Works 』という場を作りました。

またエンジニアにとっての最初の挨拶は、何といっても “Hello World !” ですね。
ということで最初のポストのタイトルも “Hello World !!” に しました。

この記念すべき Hello World は プログラム言語でいうと、どんな感じだろうかと「Hello worldプログラムの一覧 - Wikipedia」を眺めていたら、これかな!というのがありました。

1
import __hello__

Python の コードで、”プログラマーに必要な機能をすべて標準ライブラリーとして提供する「バッテリー同梱 (batteries included)」の思想を具現化するジョーク - Wikipedia」なのだとか。

さすがに「すべて」とまではいかないですが、エンジニアにとって必要なものが たくさんアウトプットされている場にしていきたいと考えています。

わたしたち の アウトプット が わずかでもお役に立てれれば、勉強させていただいているコミュニティへ少しでも還元できれば、そして 新たな出会いと挑戦につながればと考えております。

どうぞ よろしくお願いいたします!!

Author: lulzneko