LoginSignup
3
1

More than 1 year has passed since last update.

cdk-remote-stack と AWS Edge Networking Services を使ったクロスリージョンアプリケーション の補足

Posted at

こちらは CDK Advent Calendar 2021 の 19 日目の記事です。

こんにちは。 藤原 @twingo-b です。

2021/11/20-21 に開催された JAWS PANKRATION 2021 にて cdk-remote-stackとAWS Edge Networking Servicesを使ったクロスリージョンアプリケーション のセッション発表を行いました。発表時間の都合上概念説明がメインで、実際の CDK コードを交えたお話をもっとしたかったなーと思いましたので、この記事で補足します。

セッション発表の後に 「こちら」や「こちら」でも cdk-remote-stack の詳しい解説が行われていますので、ぜひご参照ください。

Amazon CloudFront を使用したクロスリージョンアプリケーション

お題のアーキテクチャ図です。
cross-regional-archi.png

CDK コードのディレクトリ構成はこちらです。

├── README.md
├── bin
│   └── cross-region-app.ts
├── cdk.json
├── jest.config.js
├── lib
│   ├── canary
│   │   └── nodejs
│   │       └── node_modules
│   │           └── screen-canary.js
│   ├── cloudfront-stack.ts
│   ├── origin-stack.ts
│   ├── parameter-stack.ts
│   └── synthetics-stack.ts
├── package-lock.json
├── package.json
└── tsconfig.json

CDK で定義した Stack は以下のように分けました。

  • AWS Systems Manager Parameter Store 関連の ParameterStack: ap-northeast-3
  • Application Load Balancer, Amazon ECS on AWS Fargate 関連の OsakaOriginStack: ap-northeast-3, TokyoOriginStack: ap-northeast-1
  • Amazon CloudFront, AWS WAF 関連の CloudFrontStack: us-east-1
  • Amazon CloudWatch Synthetics 関連の SyntheticsStack: us-west-2

CDK コードで実現していることを改めて説明します。

Stack 間の依存関係を定義

add-dependencies.png

OsakaOriginStack, TokyoOriginStack で出力した ALB Domain Name を CloudFrontStack で参照

alb-domainname.png

CloudFrontStack で出力した CloudFront Distribution Domain Name を SyntheticsStack で参照

cloudfront-distribution-domainname.png

ParameterStack で事前共有キーを定義し CloudFront origin custom header で追加した x-pre-shared-key を ALB の custom rule で評価し、 ALB へのダイレクトアクセスを拒否する

x-pre-shard-key.png

bin/cross-region-app.ts

上記を定義したコード全体像を下に記載しています。 v2.2.0 で動作確認しています。
クロスリージョンの Stack 間の依存関係、パラメータ参照をシンプルなコードで実現できていることがわかります。

※ Stack 内での RemoteOutputs, RemoteParameters 利用方法は発表内で解説していますので こちら をご確認ください。

  • RemoteOutputsCloudFrontStack, SyntheticsStack で利用しますので、引数で依存する Stack を参照しています。
    • CfnOutput は Stack 内で定義するのではなく、エントリポイント側で定義したほうが全体の見通しが良いですね。
  • RemoteParametersOsakaOriginStack, TokyoOriginStack, CloudFrontStack で利用しますが、こちらは ParameterStack で定義したリージョンとパスを引数として渡しています。
bin/cross-region-app.ts
#!/usr/bin/env node
import 'source-map-support/register';
import {
  App,
  CfnOutput,
} from 'aws-cdk-lib';
import { ParameterStack } from '../lib/parameter-stack';
import { OriginStack } from '../lib/origin-stack';
import { CloudFrontStack } from '../lib/cloudfront-stack';
import { SyntheticsStack } from '../lib/synthetics-stack';

const app = new App();
const appName = app.node.tryGetContext('appName');
const parameterRegion = 'ap-northeast-3';
const parameterPath = `/${appName}`;
const hostedZoneId = process.env.CDK_HOSTED_ZONE_ID ?? "";
const hostedZoneName = process.env.CDK_HOSTED_ZONE_NAME ?? "";
const cpu = 512;
const memory = 1024;

// Osaka Parameter resources
const parameterStack = new ParameterStack(app, 'ParameterStack', {
  env: {region: parameterRegion},
  appName: appName,
  parameterPath: parameterPath,
});

// Osaka Origin resources 
const osakaOriginStack = new OriginStack(app, 'OsakaOriginStack', {
  env: {region: 'ap-northeast-3'},
  appName: appName,
  parameterRegion: parameterRegion,
  parameterPath: parameterPath,
  hostedZoneId: hostedZoneId,
  hostedZoneName: hostedZoneName,
  cpu: cpu,
  memory: memory
});
new CfnOutput(osakaOriginStack, "AlbDomainName", {      
  value: osakaOriginStack.domainName
});
osakaOriginStack.addDependency(parameterStack);

// Tokyo Origin resources
const tokyoOriginStack = new OriginStack(app, 'TokyoOriginStack', {
  env: {region: 'ap-northeast-1'},
  appName: appName,
  parameterRegion: parameterRegion,
  parameterPath: parameterPath,
  hostedZoneId: hostedZoneId,
  hostedZoneName: hostedZoneName,
  cpu: cpu,
  memory: memory
});
new CfnOutput(tokyoOriginStack, "AlbDomainName", {      
  value: tokyoOriginStack.domainName
});
tokyoOriginStack.addDependency(parameterStack);

// N.Virginia CloudFront related resources
const cloudFrontStack = new CloudFrontStack(app, 'CloudFrontStack', {
  env: {region: 'us-east-1'},
  appName: appName,
  parameterRegion: parameterRegion,
  parameterPath: parameterPath,
  hostedZoneId: hostedZoneId,
  hostedZoneName: hostedZoneName,
  primaryOriginStack: osakaOriginStack,
  fallbackOriginStack: tokyoOriginStack,
});
new CfnOutput(cloudFrontStack, 'CloudFrontDistributionDomainName', {
  value: cloudFrontStack.domainName
});
cloudFrontStack.addDependency(parameterStack);
cloudFrontStack.addDependency(osakaOriginStack);
cloudFrontStack.addDependency(tokyoOriginStack);

// Oregon Synthetics resources
const syntheticsStack = new SyntheticsStack(app, 'SyntheticsStack', {
  env: {region: 'us-west-2'},
  appName: appName,
  cloudFrontStack: cloudFrontStack,
});
syntheticsStack.addDependency(cloudFrontStack);

まとめ

私が cdk-remote-stack を初めて利用したときに感じたシンプルさと便利さを、皆さんにも感じていただければ幸いです。

そして、クロスリージョンアプリを作るときは、大阪リージョンをプライマリリージョンにできることを思い出してくださいね!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1