【Railway】プライベートネットワーキング

Railwayのプライベートネットワーキングについてすべて学びます。

Railwayはこちら (←このリンクから登録すると20ドル分のクレジットがもらえます)

プライベートネットワーキング

プライベートネットワーキングは、サービス間のプライベートネットワークを持つことを可能にするRailway内の機能であり、APIのパブリックゲートウェイを持ちたいが、内部通信はプライベートに保ちたい場合に役立ちます。

デフォルトでは、すべてのプロジェクトでプライベートネットワーキングが有効になっており、サービスは railway.internal ドメインの下に新しいDNS名を取得します。このDNS名は、プロジェクト内のサービスの内部IPv6アドレスに解決されます。

プライベートネットワーク経由での通信

プライベートネットワーク経由で通信するには、成功するために知っておくべき特定のことがいくつかあります。

IPv6でリッスン

プライベートネットワークはIPv6のみのネットワークであるため、プライベートネットワーク経由でリクエストを受信するアプリケーションは、IPv6でリッスンするように設定する必要があります。ほとんどのWebフレームワークでは、ホスト :: にバインドすることでこれを行うことができます。

以下にいくつかの例を示します -

Node / Express

:: でリッスンして、IPv4とIPv6の両方にバインドします。

const port = process.env.PORT || 3000;
 
app.listen(port, '::', () => {
    console.log(`Server listening on [::]${port}`);
});
Node / Nest

:: でリッスンして、IPv4とIPv6の両方にバインドします。

const port = process.env.PORT || 3000;
 
async function bootstrap() {
  await app.listen(port, '::');
}
Node / Next

開始コマンドを更新して、IPv4とIPv6の両方にバインドします。

next start --hostname :: --port ${PORT-3000}

または、カスタムサーバーを使用している場合は、next() 関数に渡される構成オブジェクトで hostname:: に設定します。

const port = process.env.PORT || 3000;
 
const app = next({
  // ...
  hostname: '::',
  port: port
});

これらのオプションのいずれも実行できない場合は、HOSTNAME サービス変数を値 :: で設定して、IPv4とIPv6の両方でリッスンできます。

Python / Gunicorn

開始コマンドを更新して、IPv4とIPv6の両方にバインドします。

gunicorn app:app --bind [::]:${PORT-3000}
Python / Hypercorn

開始コマンドを更新して、IPv4とIPv6の両方にバインドします。

hypercorn app:app --bind [::]:${PORT-3000}
Python / Uvicorn

開始コマンドを更新して、IPv6にバインドします。

uvicorn app:app --host :: --port ${PORT-3000}

注: アプリケーションがプライベートネットワークとパブリックネットワークの両方でアクセスできる必要がある場合、アプリケーションサーバーはデュアルスタックバインディングをサポートする必要があります。ほとんどのサーバーは :: でリッスンするときにこれを自動的に処理しますが、Uvicornなどの一部は処理しません。

内部ホスト名とポートの使用

プライベートネットワーク経由でサービスにリクエストを行うアプリケーションでは、サービスの内部DNS名と、サービスがリッスンしている PORT を使用する必要があります。

たとえば、ポート3000でリッスンしている api というサービスがあり、別のサービスから通信したい場合は、ホスト名として api.railway.internal を使用し、ポートを指定します -

app.get('/fetch-secret', async (req, res) => {
    axios.get('http://api.railway.internal:3000/secret')
    .then(response => {
        res.json(response.data);
    })
})

アドレスに http を使用する必要があることに注意してください。

参照変数の使用

参照変数を使用すると、上記の例と同じ目的を達成できます。

api サービスと通信するためにフロントエンドサービスを設定しているとします。フロントエンドサービスで、次の変数を設定します -

BACKEND_URL=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}}

上記の api.PORT は、手動で設定する必要があるサービス変数を参照します。サービスがリッスンしているポートに自動的に解決されることも、実行時にサービスに挿入される PORT 環境変数に解決されることもありません。

次に、フロントエンドコードで、BACKEND_URL 環境変数を参照するだけです -

app.get('/fetch-secret', async (req, res) => {
    axios.get(`${process.env.BACKEND_URL}/secret`)
    .then(response => {
        res.json(response.data);
    })
})

プライベートネットワークコンテキスト

プライベートネットワークはプロジェクトと環境のコンテキストに存在し、パブリックインターネット経由ではアクセスできません。言い換えれば -

  • クライアント側のリクエストを行うWebアプリケーションは、プライベートネットワーク経由で別のサービスと通信できません
  • あるプロジェクト/環境のサービスは、プライベートネットワーク経由で別のプロジェクト/環境のサービスと通信できません

詳細については、FAQセクションを確認してください。

IPv6の既知の構成要件

一部のライブラリとコンポーネントでは、IPv6経由でリッスンまたは接続を確立するときに明示的に指定する必要があります。

ioredis

ioredis はnode.js用のRedisクライアントであり、nodeアプリケーションからRedisに接続するためによく使用されます。

ioredis を使用してRedisクライアントを初期化する場合、IPv6とIPv4の両方のエンドポイントへの接続をサポートするために、接続文字列に family=0 を指定する必要があります。

import Redis from 'ioredis';
 
const redis = new Redis(process.env.REDIS_URL + '?family=0');
 
const ping = await redis.ping();

ioredis docs

bullmq

bullmq はnode.js用のメッセージキューおよびバッチ処理ライブラリであり、キュー内のジョブを処理するためによく使用されます。

bullmqクライアントを初期化する場合、IPv6とIPv4の両方のRedisエンドポイントへの接続をサポートするために、接続オブジェクトに family: 0 を指定する必要があります。

import { Queue } from "bullmq";
 
const redisURL = new URL(process.env.REDIS_URL);
 
const queue = new Queue("Queue", {
    connection: {
        family: 0,
        host: redisURL.hostname,
        port: redisURL.port,
        username: redisURL.username,
        password: redisURL.password
    }
});
 
const jobs = await queue.getJobs();
 
console.log(jobs);

bullmq docs

Mongo Dockerイメージ

Docker Hubの公式Mongo Dockerイメージを使用してサービスを作成し、プライベートネットワーク経由で接続したい場合は、MongoインスタンスにIPv6でリッスンするように指示するいくつかのオプションを指定してコンテナを起動する必要があります。たとえば、これは開始コマンドで設定されます。

docker-entrypoint.sh mongod --ipv6 --bind_ip ::,0.0.0.0

Railwayが提供する公式テンプレートは、既にこの開始コマンドでデプロイされていることに注意してください。

hot-shots

hot-shots はnode.js用のStatsDクライアントであり、たとえばDataDogエージェントにメトリックを送信するために使用できます。hot-shots を使用してStatsDクライアントを初期化する場合、IPv6経由で接続するように指定する必要があります。

const StatsD = require('hot-shots');
 
const statsdClient = new StatsD({
  host: process.env.AGENT_HOST,
  port: process.env.AGENT_PORT,
  protocol: 'udp',
  cacheDns: true,
  udpSocketOptions: {
    type: 'udp6',
    reuseAddr: true,
    ipv6Only: true,
  },
});

hot-shots docs

Go Fiber

fiber はGo用のWebフレームワークです。Fiberアプリを構成するときは、ネットワークフィールドを tcp に設定して、IPv4だけでなくIPv6でもリッスンするようにする必要があります。

app := fiber.New(fiber.Config{
    Network:       "tcp",
    ServerHeader:  "Fiber",
    AppName: "Test App v1.0.1",
})

Fiber docs

DNSのサービス名の変更

サービス設定内で、参照するサービス名を変更できます(例:api-1.railway.internal -> api-2.railway.internal)。

ドメインのルート railway.internal は静的であり、変更できません

注意事項

機能開発プロセス中に、注意すべきいくつかの注意点が見つかりました。

  • プライベートネットワーキングは、ビルドフェーズでは利用できません。
  • プライベートネットワークでトラフィックを受信するには、IPv6ポートにバインドする必要があります。
  • IPv4プライベートネットワーキングはサポートしていません

FAQ

クライアントサイドアプリ、サーバーサイドアプリとは何ですか?また、私が実行しているアプリはどの種類ですか?

プライベートネットワーキングのコンテキストでは、クライアントサイドとサーバーサイドの主な違いは、リクエストがどこから行われるかです。

  • クライアントサイドアプリケーションでは、他のリソース(他のRailwayサービスなど)へのリクエストは、プライベートネットワークの外部のパブリックネットワークに存在するブラウザから行われます。
  • サーバーサイドアプリケーションでは、他のリソースへのリクエストは、アプリケーションをホストしているサーバーから行われます。これは、(アプリをホストしているサーバーがRailwayにあると仮定して)プライベートネットワーク内に存在します。

アプリケーションがクライアントサイドまたはサーバーサイドのリクエストを行っているかどうかを判断する1つの方法は、DevToolsのネットワークタブでリクエストを検査することです。RequestURLがリクエストが行われているリソース(バックエンドサーバーなど)である場合、これはブラウザ自体がリクエストを行っている(クライアントサイド)ことを示す良い兆候です。

Vercelからサーバーサイドでリクエストを行っている場合はどうなりますか?

VercelでホストされているアプリケーションはRailwayのプライベートネットワークの外部に存在するため、Vercelサーバーからのリクエストはプライベートネットワーク経由では行えません。

Railwayはこちら (←このリンクから登録すると20ドル分のクレジットがもらえます)

Read more

リアルタイム投票アプリ5選【ライブ配信やイベントで】

リアルタイム投票アプリ5選【ライブ配信やイベントで】

ウェビナーやセミナー、社内研修を実施する際、「参加者が受け身になってしまう」「質問がなかなか出てこない」といった課題を感じたことはないでしょうか。 オンラインでの情報発信が当たり前になった今、一方的な配信だけでは参加者の満足度を高めることが難しくなっています。そこで注目されているのが、リアルタイムで参加者の意見を集約し、その場で結果を共有できる投票・質問ツールです。 本記事では、ライブ配信やイベント、研修などで活用できるリアルタイム投票アプリを5つ厳選してご紹介します。 リアルタイム投票でつながる参加者とイベント リアルタイム投票やQ&A機能を使うと、視聴者や参加者の意見を即座に集計・表示できます。講義や会議の進行を妨げず、参加者全員が自分の意見を簡単に表明できる仕組みです。 従来の挙手による質疑応答では、発言しづらいと感じる参加者も少なくありません。特にオンラインイベントでは、カメラがオンになっていることへの抵抗感や、大人数の前で質問することへのハードルが存在します。 しかし、スマートフォンから匿名で投票やコメントができる仕組みがあれば、参加者は気軽に自分の意見を伝えら

By 阿部 隼也
質問受付ツールの選び方とおすすめ5選を紹介

質問受付ツールの選び方とおすすめ5選を紹介

セミナーや講演会、社内研修などで「質問はありませんか?」と投げかけても、なかなか手が挙がらない経験はないでしょうか。参加者に有益な情報を提供しても、疑問や意見が共有されないまま終わってしまうのは、主催者にとっても参加者にとっても大きな機会損失です。 こうした課題を解決するために注目されているのが「質問受付ツール」です。参加者がスマートフォンから匿名で質問を投稿できるため、発言への抵抗感が下がり、活発なコミュニケーションが生まれます。 本記事では、質問受付ツールの基本機能から、実際に役立つおすすめツール5選、そして選定時に押さえておきたいポイントまで、実務に活かせる情報をまとめて解説します。 質問受付の現場課題 イベントやセミナーの運営で最も頭を悩ませる問題の一つが、参加者からの質問をいかに引き出すかという点です。質問タイムを設けても、会場がシーンと静まり返ってしまい、仕方なく「それでは時間になりましたので」と締めくくる光景は珍しくありません。 この背景には、日本特有の文化的要因も関係しています。大勢の前で発言することへの恥ずかしさ、自分の質問が的外れではないかという不安、他

By 阿部 隼也
オンラインセミナーアプリの選び方。参加者エンゲージメントを高めるポイント

オンラインセミナーアプリの選び方。参加者エンゲージメントを高めるポイント

近年、オンラインセミナーの活用が急速に広がっています。会場のコストや移動時間を気にすることなく、全国・世界中から参加者を集められる点は大きな魅力です。 しかし、せっかく開催しても 「参加者が途中で離脱してしまう」 「ただ見ているだけで反応が薄い」 といった課題を抱えている企業も少なくありません。 本記事では、参加者のエンゲージメントを高め、成果につながるオンラインセミナーアプリの選び方と、実務に役立つ具体的なポイントを解説します。 参加者とのつながりを生むオンライン環境の設計 オンラインセミナーにおける最大の課題は、画面越しの距離感です。会場で直接顔を合わせる機会がないからこそ、参加者が「ただ見ているだけ」にならないような仕組みが求められます。適切なツールと機能選びが、参加者のエンゲージメントを左右します。 従来のオフラインセミナーでは、会場の雰囲気や参加者同士の反応が自然と生まれましたが、オンラインではそうした「空気感」が伝わりにくくなります。だからこそ、双方向のコミュニケーション機能や、参加者の行動データを活用した設計が重要になるのです。 エンゲージメントを高

By 阿部 隼也
参加者の質問を効率的に管理!ZoomウェビナーQ&A機能の使い方を徹底解説

参加者の質問を効率的に管理!ZoomウェビナーQ&A機能の使い方を徹底解説

オンラインでのセミナーやイベントが日常化する中で、Zoomウェビナーを活用している企業が増えています。しかし、ウェビナーの開催で意外と頭を悩ませるのが「参加者からの質問をどう管理するか」という点ではないでしょうか。 セミナーが盛り上がり、次々と質問が寄せられるのは嬉しいことです。一方で、質問が多すぎて整理しきれない、どの質問に優先的に答えるべきか判断に迷う、といった課題も生じます。こうした問題を解決するために役立つのが、ZoomウェビナーのQ&A機能です。 本記事では、ZoomウェビナーのQ&A機能の基本的な使い方から、参加者の質問を効率的に管理する実践的なテクニックまで、詳しく解説していきます。 ZoomウェビナーのQ&A機能とは ZoomウェビナーのQ&A機能は、ウェビナー開催中に参加者が質問を投稿し、主催者側が回答を行うための専用機能です。この機能を使うことで、質問と回答がスレッド形式で整理され、効率的なコミュニケーションが可能になります。 チャット機能との違い Zoomには「チャット機能」もあるため、「Q&A機能とチャット機能の違いは何か」と疑問に思う方も多いで

By 阿部 隼也