Service Connectの落とし穴とAWS CDKでECSの名前解決をCloudMapに設定する方法

April 27, 2024
tag icon
cdk
tag icon
ecs
tag icon
cloudmap

先日AWS CDKでAmazon ECSの名前解決をAWS CloudMapに設定する方法を調べたのですが1週間くらいかかったので紹介します。

動機(Service Connectの落とし穴)

そもそも改造することになったECSは名前解決にService Connectを使っていました。AWS的にはメトリクス取得と機能が両立していてイチオシらしいのですが、実装に/etc/hostsを使っていて、新しいサービスを追加したときに、既存サービスは再デプロイしないと新しいサービスの名前解決ができない、ということが分かりました1

通常はそれでよいのでしょうが、今回は1つ共通リソースになっているコンテナが存在し、裏方のコンテナのデプロイにあわせて共通リソースコンテナを再デプロイしてしまうと既存の利用者に影響が出てしまう状態でした。

裏方コンテナのデプロイの時には、共通リソースコンテナは名前解決だけできれば良いため、Service Connectの利用をやめて、動的に名前解決のできるCloudMapの利用に切り替えました。

ECSのサービスでCloudMapを使うよう指定する

コードのスニペットではまず新しいCloudMapの名前空間を作って、それをECSのサービスに紐づける例を記載しています。CloudMapはCDKではservicediscoveryで呼び出せます。

// ポイントのみの記載のため、このままでは動きません。

import { aws_ecs as ecs } from 'aws-cdk-lib';
import { aws_servicediscovery as servicediscovery } from 'aws-cdk-lib';

// 新規にCloudMapのNameSpaceを作る場合のコード
const namespace = new servicediscovery.PrivateDnsNamespace(this, 'Namespace', {
  name: 'domain.local',
  vpc,
});

const service = new ecs.FargateService(this, 'Service', {
  cluster,
  taskDefinition,
  // CloudMapとECSのサービスを紐づけるにはcloudMapOptionsを使う
  cloudMapOptions: {
    cloudMapNamespace: namespace,
    name: "newone" //この例だと newone.domain.local になる
    dnsRecordType: servicediscovery.DnsRecordType.A,
  },
});

問題はこのとき既存のCloudMapの名前空間に追加したいときどうかけばよいか?がわからずはまりました2

既存のCloudMapを指定してサービスを紐づける

1週間の調査と試行錯誤でわかったのは、servicediscovery.PrivateDnsNamespaceクラスにfromPrivateDnsNamespaceAttributesメソッドがあるので、そこで既存のCloudMapを指定することができます。下記にコードスニペットを記載します。

// ポイントのみの記載のため、このままでは動きません。

import { aws_ecs as ecs } from 'aws-cdk-lib';
import { aws_servicediscovery as servicediscovery } from 'aws-cdk-lib';

// 既存のCloudMapをインスタンスにするコード。
const namespace = servicediscovery.PrivateDnsNamespace.fromPrivateDnsNamespaceAttributes(this, 'Namespace', {
  namespaceArn: `arn:aws:servicediscovery:region:accountId:namespace/ns-xxxxxxxxx`,
  namespaceId: "ns-xxxxxxxxx",
  namespaceName: "domain.local",
});

const service = new ecs.FargateService(this, 'Service', {
  cluster,
  taskDefinition,
  // CloudMapとECSのサービスを紐づけるにはcloudMapOptionsを使う
  cloudMapOptions: {
    cloudMapNamespace: namespace,
    name: "newone" //この例だと newone.domain.local になる
    dnsRecordType: servicediscovery.DnsRecordType.A,
  },
});

なお、CDKでECSのサービス全体を立てるのは、参考文献6が分かりやすいと思うのでご紹介します(Service Connectのケースの書き方ですが、serviceConnectConfigurationの設定の代わりにcloudMapOptionsを指定)。

どなたかのお役に立てば幸いです。

参考文献

  1. ECS Service ConnectをCDKでデプロイしてみた | DevelopersIO
  2. Service Connect の概念
  3. interface CloudMapOptions AWS CDK
  4. class PrivateDnsNamespace (construct) AWS CDK
  5. interface PrivateDnsNamespaceAttributes AWS CDK
  6. Service Connect を使用した ECS サービスにオートスケーリングを設定してみる
  7. 【AWS】CDKでECSサービスディスカバリを設定する方法 - Qiita

  1. わかりづらいのですがドキュメント(参考文献2)に「このエンドポイントを解決して接続できるのは、(中略)、このデプロイ後に実行を開始した新しい Amazon ECS タスクだけです」とあります。実機を見ても再デプロイしない限り/etc/hostsを書き換える動きをしません。動きは参考文献1が分かりやすいです。
  2. ChatGPTにきいても「できません」とか言うし(苦笑)。

Profile picture

i氏 システムのデザインが好きな自称システムアーキテクト。データサイエンティスト見習い。Jamstackのアーキテクチャーに感動して、Gatsbyでブログを始めました。