CloudMapを使って異なるVPCのECSタスクに名前解決させてみた

CloudMapを使って異なるVPCのECSタスクに名前解決させてみた

Clock Icon2025.07.22

【はじめに】

こんにちは。コンサルティング部の津谷です。
皆さんは、CloudMapというサービスでECSのタスク間通信を実装したことはありますでしょうか。
概要はこちらをご覧ください。

CloudMapの利点はタスクのスケーリングに合わせて、動的にDNSのレコード登録を行ってくれることですね。タスクがスケールイン・アウトすると対応するプライベートIPが変わってしまうので、うれしい機能です。この機能はECSとネイティブに統合しており、コンソール上で簡単に設定可能です。最近ではECS Service Connectというサービスも登場しており、タスク間通信の負荷分散機能やセキュリティ機能も利用することができます。
今回は、VPCが異なるタスク同士の通信は可能なのか気になりましたので検証してみました。

【構成図】

構成は下記になります。
スクリーンショット 2025-07-22 092736
基本構成としては、異なるVPCを用意し、その中に別々のECSクラスターを立てます。
サービスAはサービスBにHTTPアクセスを行うコマンドを定期実行し、その結果をCloudWatchログに転送します。サービスBはシンプルなNginxを立てておきます。
利用するサービスは以下です。

  • ECS
    検証用のサービスA、サービスBを構築します。
  • CloudMap
    サービスBの名前空間を作成します(プライベートホストゾーン)
  • VPCPeering
    VPC間の通信を可能にします。今回の構築手順では割愛します。
  • CloudWatch
    サービスAからサービスBにHTTPアクセスした際の結果をログ出力します。
  • VPCEndpoint
    タスクの実行ログを出力するために、エンドポイント経由でCloudWatchに接続します。
    構築手順は割愛します。
  • NatGateway,InternetGateway
    タスク実行の際のイメージを取得するために使用します。今回は、イメージを外部公開されているDockerレジストリから取得します。構築手順は割愛します。

【構築手順】

以下の手順はVPCPeeringを張った状態からスタートします。
ネットワーク周りの設定(通信許可設定含め)は事前に済ませておきましょう。
スクリーンショット 2025-07-22 093842
基本的にコンソールで作成していきます。
①CloudMapで名前空間を作成します。
スクリーンショット 2025-07-22 094407
名前空間はホストゾーン名になります。今回は「backend.local」としておきました。
DNSクエリを行うので「API呼び出しとVPCのDNSクエリ」を指定しましょう。
DNSはインターネット公開しないので今回は真ん中でOKです。
この後サービスを関連付けることでFQDN名としてドメインが完成します。

②次にサービスも作成させておきましょう。
スクリーンショット 2025-07-22 095212
サービス名は「api」にしておきます。これでECSタスクが名前解決する際のFQDNが「api.backend.local」になりました。タスクがスケールしている場合、複数値回答するようにルーティングポリシーは「MultiValue」にしておきます。TTLは60秒に設定します。
*TTLの設定は注意が必要です。レコードのTTLを長くするとクライアント側のTTLキャッシュとして残ってしまい、タスクがスケールした場合に古いIPにアクセスしてエラーが発生する懸念があります。

忘れてはいけないのがホストゾーンに関連付ける作業です。
今回はサービスA側のVPCが名前解決するので、サービスAのVPCを作成したプライベートホストゾーンに関連付けるのを忘れないようにしましょう。
スクリーンショット 2025-07-22 105611

③ECSのクラスターを作成します。
サービスA・サービスBで両方作成しましょう。
(画像はサービスA側の方)
名前は以下のようにしました。
サービスA:frontend-cluster
サービスB:backend-cluster
(既にクラスターを作成しているのでエラーが出ているのですがご愛嬌で。)
スクリーンショット 2025-07-22 102240
ここでは、Service Connectは使わないのでオフの状態で大丈夫です!サービス側の設定にある「サービス検出」の項目でCloudMapを関連付けます。今回はFargateで起動させます。

④ECSタスク定義を作成します。(サービスはタスク定義を指定する必要があるので先にタスクです)
【サービスA】
スクリーンショット 2025-07-22 102737
ファミリー名は「frontend-task」にします。
スクリーンショット 2025-07-22 102748
インフラストラクチャはデフォルト設定のままで大丈夫です。
スクリーンショット 2025-07-22 102837
コンテナ設定ですが、名前は「frontend-container」にします。イメージは「alpine:latest」を指定します。コンテナで起動するOSとして軽量なLinuxパッケージを使用します。(サービスBヘHTTPアクセスするコマンドを打つだけなので)
スクリーンショット 2025-07-22 102911
あとでログを見てアクセスできているか確認するのでサービスA側のログ出力は有効化します。

スクリーンショット 2025-07-22 102921
サービスBへのAPI接続を行うコマンドを指定しています。
HTTP接続を30秒間隔で行い、成功したらメッセージを出力するという内容です。

【サービスB】
スクリーンショット 2025-07-22 103841
ファミリー名は「backend-task」にします。インフラストラクチャはデフォルトのままで、サービスAと同様なので割愛します。

スクリーンショット 2025-07-22 103959
コンテナ名は「backend-container」にします。Nginxをインストールします。コンテナの待ち受けポートは80です。
ログは特に出力しないので、無効化にします。

⑤ECSサービスを作成します。
【サービスA】
スクリーンショット 2025-07-22 104228
先ほど作成したタスク定義を指定します。
必要なタスクは1で問題ないです。
スクリーンショット 2025-07-22 104317
ここで、ServiceConnectとCloudMapの設定が可能です。
今回はCloudMapのネイティブ機能のみ利用しますが、サービスA側は名前解決する側なので特に関連付けは必要ないです。

【サービスB】
スクリーンショット 2025-07-22 104455
先ほど作成したタスク定義を指定しましょう。
今回はタスクを複数用意し、CloudMapにレコードが複数登録されるか確認したいので2にしておきます。
スクリーンショット 2025-07-22 104704
サービス検出で、作成したCloudMapの名前空間を関連付けます。
サービスは作成した「api」を利用するので「既存のサービス検出サービスを選択」を選びましょう。

【動作確認(ログ)】

タスクが実行中のステータスになったら、CloudMatchログを見てサービスA⇒サービスBに疎通成功しているか確認します。
スクリーンショット 2025-07-22 105317
問題なくいけてますね。これでHTTPアクセスできていることは証明されたのですが、念のためホストゾーンも見ておきます。
スクリーンショット 2025-07-22 105512
レコードが複数値登録されました。
これで検証完了です。

【最後に】

ECSのサービス間接続を別VPCで試してみました。CloudMapだけではなく、いろんなサービスが出ているので機能の比較検証をしてみると、用途を明確にできるのでいずれやってみたいです。ECSとネイティブ統合しているのでかなりコンソール上でも設定しやすいです。お読みいただきありがとうございました。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.