この記事は スマートスピーカー2 Advent Calendar 2018 8日目 の穴埋め記事です。
ngrokとは
httpトンネリングサービスです。
ローカルPCで立ち上げているプログラムをポート開放したりせず、ngrokが発行するURLを経由して外部公開することができます。
さらにhttpsや他のtcpプロトコルにも対応しています。
私はスマートスピーカースキル開発でngrokを使用しており、シミュレーターや実機テストの際にLambda等FaaSへデプロイせずにngrokでローカルでスキルのプログラムを動かしテスト/デバッグを行っています。
なぜngrokを使うのか
理由は3つあります。
1. デプロイが手間
まずスマートスピーカースキルのデプロイ先としてはAWS LambdaやFirebase Functionsが一般的ですが、ソース修正する度にソース固めてデプロイするのが手間である点です。
シェルやバッチ組めばコマンドで一発ですが、その一発も手間です。
対してngrokはローカルで動いているのでデプロイもクソもありません。
ここで「プログラムの再起動でコマンド叩くだろ」と思われるでしょうが、後述するnodemonとの組み合わせで何もする必要がありません。
2. ログ反映が遅い
1つ目に関連しますが、クラウドではログの反映が遅いことです。
ここはぶっちゃけ、AWS(CloudWatch)は半年ぐらい前は1~2分はかかりほんと我慢ならなかったのですが、最近はわりとすぐにログ出てくれてます。
しかしラグは当然あります。
Firebaseも半年ぐらい前は同じぐらいログ反映に時間かかっていました。
(最近触ってないので今どうかはわかりません…)
対してngrokではプログラムはローカルで動いているので、当然ログは即出ます。
3. nodemon/ts-nodeとの組み合わせがすこぶる便利
「nodemon」とは、プログラムを実行しつつ、ソースに修正があったら自動でプロセスを再起動してくれるNode.jsツールです。
これを組み合わせることでCtrl + S
で修正が即反映されます。
「ts-node」は.tsファイルを自動でコンパイル実行してくれるツールです。
TypeScriptを使っている場合はこれも組み合わせることで爆速ローカル開発ができます。
(コンパイルは多少重いのでマシンスペックに依存します)
参考
Node.jsのソース修正後、nodemonで自動再起動
ts-nodeでCLI上でのtypescriptの検証がめっちゃ楽になった話
【ホットリロード】nodejs + TypeScriptでサーバーサイドを開発している時に、コードを編集したら自動リロードさせる。
ngrok(無料版)の弱点
ngrokの素晴らしさは分かって頂けたかと思いますが、そんなngrokにも1点弱点があります。
ngrokには無料版/有料版があり、無料版ではURLが固定できないという点です。
ngrokのコマンド実行時に払い出されるURLのドメイン部が毎回乱数となるのです。
以下はngrokコマンド実行結果になりますが、Forwarding
にあるURLのドメイン部が実行するたび変わります。
$ ngrok http 3000
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account Miso Tanaka (Plan: Free)
Version 2.2.8
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://xxxxxxxx.ngrok.io -> localhost:3000
Forwarding https://xxxxxxxx.ngrok.io -> localhost:3000
Connections ttl opn rt1 rt5 p50 p90
26 0 0.00 0.00 5.05 9.54
HTTP Requests
-------------
無料プランでURL固定する方法
「無料プランでURL固定化」自体が限りなく黒いグレーな行為であるため、以下自己責任でお願い致します。
ちなみにURLを固定化しても1点、有料版には届かない点があります。
それは起動から8時間が経過するとトンネリングが無効化されるという点です。
しかしこれは開発やデバッグで使う分には不都合ないと思います。
結論はAmazon API Gateway(AWS)とAWS CLI
方法は至って簡単で、AWSのAPI Gatewayでngrokが生成したURLをパススルーさせます。
そしてngrokをNode.jsから実行し、同時にAWS CLIでAPI Gatewayを更新するコマンドを叩くだけです。
以下細かい手順になります。
API GatewayからAPIを作成
AWSコンソールよりAmazon API Gatewayを開き、「APIをの作成」ボタンを押します。
「API名」に「ngrok」とでも入れて(なんでもいいです)、「APIの作成」ボタンを押します。
このような画面になるので、「アクション」ボタン > 「メソッドの作成」と選択します。
リソースの「/」の下にセレクトボックスが出てくるのでとりあえず「ANY」を選択し、すぐ右にあるチェックマークを押します。
※ここは必要なメソッドに絞ってもいいです。例えばスマートスピーカースキルならPOSTを選択すれば十分でしょうし。
この画面まできたらコンソールの操作は完了です。
2箇所の赤枠部分にそれぞれ乱数のIDが入っているので、メモっておきます。
ngrok URL固定スクリプトを実行
以下のNode.jsプログラムを実行します。
前提として、Node.js、AWS CLIがインストールされていることです。
ngrokもNode.js版をインストールしていなければ入れます。
npm i -g ngrok
実行プログラムは以下になります。
先頭のconfig
オブジェクトをいじります。
restApiId
には先ほどメモしたngrok(xxxxxxxx)
の乱数部を入れます。
resourceId
には先ほどメモした/(xxxxxxxx)
の乱数部を入れます。
httpMethod
には先ほどANYを指定していればそのままで、ANY以外ならそれを指定してください。
port
はローカル実行させるプログラムのポート番号を指定してください。
const config = {
restApiId: "xxxxxxxx",
resourceId: "xxxxxxxx",
httpMethod: "ANY",
port: 3000,
}
const execSync = require('child_process').execSync
const ngrok = require('ngrok')
const main = async () => {
const ngrokUrl = await ngrok.connect(config.port)
console.log(ngrokUrl)
execSync(`aws apigateway put-integration --rest-api-id ${config.restApiId} --resource-id ${config.resourceId} --http-method ${config.httpMethod} --type HTTP_PROXY --integration-http-method ${config.httpMethod} --uri ${ngrokUrl}`)
execSync(`aws apigateway create-deployment --rest-api-id ${config.restApiId} --stage-name prod`)
console.log(`https://${config.restApiId}.execute-api.ap-northeast-1.amazonaws.com/prod`)
}
main()
あとは実行するだけです。
$ node index.js
https://xxxxxxxx.ngrok.io
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod
返ってくる結果のうち、上の行がngrokが生成する乱数URLです。
これは一応表示していますが気にしなくていいです。
下の行が固定化されたURLになります。
xxxxxxxxxx
の部分はrestApiId
が入ってきます。
あとは下の行のURLを開発やテストで使い回せばおっけーです。
ngrokを使う時にnodemonとあわせ上記のプログラムを実行しておきます。
以上、シェルやバッチ置いてパス通してすぐ実行できるようにしてもいいと思います。