Private Space DNS Service Discovery
最終更新日 2020年04月13日(月)
Table of Contents
Heroku Private Space で実行されているプロセスは、同じスペース内の他の dyno の IP アドレスを DNS を使用して取得することによって、容易に相互通信できます。これにより、マイクロサービスの作成とデプロイが容易になります。たとえば、次のような複数の小さなサービスで構成される画像処理アプリを作成するとします。
- ジョブを受け付ける Web プロセス
- 受け取った画像を処理するワーカープロセス
- バックオフィスの対話を処理するエージェントプロセス
DNS Service Discovery を使用すれば、このようなシステム内のプロセス同士が簡単な方法で通信してタスクを実行できます。新しいジョブを受け付けた Web プロセスは、新しいジョブが到着したことを、その DNS 名によってバックオフィスサービスに通知できます。その後、同じくその DNS 名によってワーカープロセスにジョブを送信できます。
Common Runtime 内の dyno と違って、Private Space 内の dyno はプライベートネットワーク上で TCP および UDP トラフィックを自由に交換できます。あらゆる種類 (Web またはワーカー) のプロセスタイプが任意の利用可能なポートでリッスンすることを選択でき、Space 内の他の dyno は dyno ホスト上でそのポートに接続できます。
別のプロセスと通信するには、プロセスが実行されている dyno の IP アドレスと、プロセスがリッスンしているポート番号を知っている必要があります。サーバープロセスは固定のポート番号でリッスンするため、通常であればポート番号は事前にわかっています。ただし、dyno の IP アドレスを事前に知ることは不可能です。これを解決するために、Heroku では、DNS ベースの命名体系を dyno 用に提供しています。したがって、次の情報を指定すれば、Private Space 内の任意の dyno を特定して接続することができます。
- プロセスに関連付けられた Heroku アプリの名前
- 接続先プロセスのプロセスタイプ (
web
やworker
など) - (オプション) 接続先の dyno 番号 (プロセスが複数の dyno で実行されている場合に有用)
セットアップ: DNS ルックアップの有効化
2017 年 5 月 31 日よりも後に作成されたすべてのアプリケーションでは、DNS Service Discovery がデフォルトで有効です。 既存のアプリケーションでは、次のように実行して有効化する必要があります。
$ heroku features:enable spaces-dns-discovery --app <your app>
アプリが実行中の場合、この設定を有効にするにはアプリを再起動する必要があります。
$ heroku restart --app <your app>
この機能を有効にした後は、アプリの dyno で DNS 設定が少し変更され、DNS ルックアップが可能になります。この変更が原因でアプリケーションに問題が発生するわずかなリスクがあります。後述する既知の技術的な考慮事項を参照してください。何か問題が発生した場合は、次のようにして、機能を無効化してアプリを再起動してください。
$ heroku features:disable spaces-dns-discovery --app <your app>
$ heroku restart --app <your app>
使用法
プライベートネットワークへのバインド
Private Space 内での dyno 間通信はすべて、プライベートネットワーク経由で行われます。プライベートネットワーク経由で通信するには、プロセスがその dyno のプライベート IP アドレスに 1024
~ 65535
の範囲内のポートでバインドする必要があります。dyno のプライベート IP アドレスは HEROKU_PRIVATE_IP
環境変数に含まれています。
(web
だけでなく) すべてのプロセスがプライベートネットワーク上のポートにバインドできます
Private Space Service Discovery を使用するアプリとプロセスでは、$PORT
環境変数の値を使用してはなりません。$PORT
は、同じプロセスタイプであっても実行する dyno によって異なり、dyno を再起動した場合にも値が変わるからです。代わりに、5000
のような静的ポートを選んで使用してください。Node.js と Express を使用する場合の例を示します。
const express = require('express')
const PORT = 5000
express()
.get('/', (req, res) => res.send('Hello World!'))
.listen(PORT, () => console.log(`Listening on ${ PORT }`))
これは、次の Procfile
を使用して foo
プロセスタイプとしてデプロイできます。
foo: node index.js
プライベート IP アドレスにバインドした後のプロセスとは、選択したポートでその DNS 名とポートを介して通信できます。上記の例には次の URLでアクセスできます。
http://foo.[APP_NAME].app.localspace:5000/
他のプロセスの解決
DNS Service Discovery では、次の命名体系を使用します。
[DYNO_NUMBER (optional)].[PROCESS_TYPE].[APP_NAME].app.localspace
たとえば、次の nslookup
を One-off dyno から実行すると、sushi
というアプリの web
プロセスを実行しているすべての dyno の IP アドレスが返されます。
$ nslookup web.sushi.app.localspace
web.sushi.app.localspace. 0 IN A 10.10.10.11
web.sushi.app.localspace. 0 IN A 10.10.10.10
web.sushi.app.localspace. 0 IN A 10.10.10.9
上記の形式の DNS 名にプロセスが接続した場合、DNS レジストリにより、関連付けられたプロセスの dyno のいずれかにラウンドロビン方式でルーティングされます。そうではなく、関連付けられたプロセスを実行している特定の dyno に接続したい場合、その dyno 番号を DNS 名の先頭で指定できます。
次の例では、sushi
アプリの web
プロセスを実行している 2 番目の dyno の IP アドレスを指定して nslookup
を実行しています。
$ nslookup 2.web.sushi.app.localspace
2.web.sushi.app.localspace. 0 IN A 10.10.10.10
命名体系の最後 2 つの要素 (app
と localspace
) はすべての DNS 名に共通であることに注意してください。
環境変数
DNS Service Discovery が有効な dyno では、次の環境変数が設定されています。
名前 | 内容 |
---|---|
HEROKU_DNS_FORMATION_NAME |
dyno のプロセスタイプのラウンドロビン DNS 名 |
HEROKU_DNS_DYNO_NAME |
dyno の DNS 名 |
HEROKU_DNS_APP_NAME |
dyno のアプリケーション DNS 名 |
HEROKU_PRIVATE_IP |
dyno のプライベート IP |
HEROKU_DNS_DYNO_NAME
や HEROKU_DNS_FORMATION_NAME
と違って、HEROKU_DNS_APP_NAME
は単体では解決しません。dyno のアプリケーションレベルのホスト名の決定を簡素化するために提供されます。
DNS レジストリの詳細
更新頻度
dyno の場所の DNS レジストリのセットは 10 秒おきに更新されます。DNS Service Discovery を使用するアプリを設計するときは、この時間枠を考慮に入れてください。これらのレジストリ更新を監視するタイミングには dyno ごとにわずかな差がある可能性がありますが、約 10 秒後には結果は収束します。
TTL
DNS Service Discovery レコードの存続時間 (TTL) は常にゼロ秒であるため、リクエスト元で独自に情報をキャッシュしてはなりません。DNS 応答内の TTL を考慮し、これらのローカルリクエストをキャッシュしないようにアプリケーションが適切に設定されていることは重要です。
技術的な考慮事項
ルーティング
Private Space DNS Service Discovery を使用したネットワーク処理では、生の TCP/IP を使用します。HTTP サービスを実行している場合でも、Heroku ルーティングレイヤー、ルーターのログまたは測定値、ポートバインディング関連のブートタイムアウトはありません。これは、非 Web プロセスとしてデプロイされた HTTP サービスのトラブルシューティングの妨げになる可能性がありますが、Heroku Private Space で非 HTTP サービスを実行できる利点もあります。
IPv6
アプリで DNS Service Discovery を有効にすると、アプリの dyno で IPv6 が無効になります。Private Space では IPv4 経由の接続しか提供しませんが、それでも IPv6 が dyno で利用できなくなるとアプリの動作が変わる可能性があります。たとえば、Go アプリは tcp
ではなく tcp4
経由でリッスンする必要があります。次のようなコードがあるとします。
conn, err := net.Dial("tcp", "golang.org:80")
ln, err := net.Listen("tcp", ":8080")
これは、次のように置き換える必要があります。
conn, err := net.Dial("tcp4", "golang.org:80")
ln, err := net.Listen("tcp4", ":8080")