見出し画像

AWS CDK + TypeScript で Route 53 にサブドメインのホストゾーンを作成してレコード追加する方法と やってみてハマったところ、分かったこと

やったこと

 Route 53 にサブドメイン cdk.dafujii.ga のホストゾーンを作成し、A レコードで 127.0.0.1 を追加します。

 その後すでに Route 53 で管理している dafujii.ga のホストゾーンに NS レコードを追加し、cdk.dafujii.ga 作成時に自動生成された NS レコードを設定します。

 先日投稿した下記記事の2つ目のパターンをやろうとしています。

できたもの

 コード全体は以下のリポジトリに置いています。ちゃんとテストも書きました💪

./lib/route53-stack.ts

import * as route53 from "@aws-cdk/aws-route53";
import * as cdk from "@aws-cdk/core";
import { Duration } from "@aws-cdk/core";

const env = {
 region: process.env.CDK_DEFAULT_REGION,
 account: process.env.CDK_DEFAULT_ACCOUNT
};

export class Route53Stack extends cdk.Stack {
 constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
   super(scope, id, props ? props : { env });

   const hostedZone = new route53.PublicHostedZone(this, "HostedZone", {
     zoneName: "cdk.dafujii.ga",
     comment: "Created from cdk"
   });

   new route53.ARecord(this, "Record", {
     zone: hostedZone,
     recordName: "www",
     target: {
       values: ["127.0.0.1"]
     },
     ttl: Duration.seconds(300),
     comment: "Created from cdk"
   });

   const parent = route53.HostedZone.fromLookup(this, "ParentHostedZone", {
     domainName: "dafujii.ga."
   });

   if (!hostedZone.hostedZoneNameServers) {
     throw new Error("NS record is undefined.");
   }

   new route53.ZoneDelegationRecord(this, "NS", {
     zone: parent,
     recordName: "cdk",
     nameServers: hostedZone.hostedZoneNameServers,
     comment: "Created from cdk"
   });
 }
}

./test/route53.test.ts

import { expect as expectCDK, haveResource } from "@aws-cdk/assert";
import * as cdk from "@aws-cdk/core";
import Route53 = require("../lib/route53-stack");

const env = {
 region: "1234567890123",
 account: "ap-northeast-1"
};

test("cdk.dafujii.ga のホストゾーンが作成できているか", () => {
 const app = new cdk.App();
 const stack = new Route53.Route53Stack(app, "MyTestStack", { env });

 expectCDK(stack).to(
   haveResource("AWS::Route53::HostedZone", {
     Name: "cdk.dafujii.ga.",
     HostedZoneConfig: {
       Comment: "Created from cdk"
     }
   })
 );
});

test("cdk.dafujii.ga のホストゾーン内にサブドメインwwwの127.0.0.1の値を持ったAレコードが追加されているか", () => {
 const app = new cdk.App();
 const stack = new Route53.Route53Stack(app, "MyTestStack", { env });

 expectCDK(stack).to(
   haveResource("AWS::Route53::RecordSet", {
     Comment: "Created from cdk",
     HostedZoneId: {
       Ref: "HostedZoneDB99F866"
     },
     Name: "www.cdk.dafujii.ga.",
     ResourceRecords: ["127.0.0.1"],
     TTL: "300",
     Type: "A"
   })
 );
});

test("dafujii.ga のホストゾーン内にcdkのNSレコードが追加されているか", () => {
 const app = new cdk.App();
 const stack = new Route53.Route53Stack(app, "MyTestStack", { env });

 expectCDK(stack).to(
   haveResource("AWS::Route53::RecordSet", {
     Name: "cdk.dafujii.ga.",
     Type: "NS",
     Comment: "Created from cdk",
     HostedZoneId: "DUMMY",
     ResourceRecords: {
       "Fn::GetAtt": ["HostedZoneDB99F866", "NameServers"]
     },
     TTL: "172800"
   })
 );
});

ハマったところ

 CDK では recordName: "www" とだけ定義しても、CloudFormation テンプレート(テストも)では "www.cdk.dafujii.ga." と FQDN 表記となります。特に末尾ピリオド忘れがち。

 テストで下記のように HostedZoneId を HostedZoneDB99F866 で固定にするところも、AWS CDK 自体のテストを見て知りました。なぜ DB99F866 ?

     HostedZoneId: {
       Ref: "HostedZoneDB99F866"
     },

 既存の Route 53 上のホストゾーンに対して AWS CDK で作成したサブドメインのホストゾーンの NS レコード追加方法だけで3時間悩みました。

 下記のようにhostedZoneNameServers で作成した NS レコードを取得し、それを ZoneDelegationRecord の nameServers に設定してやるだけみたいです。Null 安全のためチェックは必須です。

   const parent = route53.HostedZone.fromLookup(this, "ParentHostedZone", {
     domainName: "dafujii.ga."
   });

   if (!hostedZone.hostedZoneNameServers) {
     throw new Error("NS record is undefined.");
   }

   new route53.ZoneDelegationRecord(this, "NS", {
     zone: parent,
     recordName: "cdk",
     nameServers: hostedZone.hostedZoneNameServers,
     comment: "Created from cdk"
   });

 また fromLookup などを使うと、スタック作成時に AWS アカウントIDとリージョンを渡してあげる必要があります。テストはダミーの文字列で大丈夫でした。

super(scope, id, props ? props : { env });

分かったこと

 AWS CDK は CloudFormation テンプレートを作って実行するので、CloudFormation の知識は必須ということ。

 AWS CDK で作成する単体テストは CloudFormation テンプレートのテストになるので、単体テストを書くすなわち CloudFormation テンプレートを書くみたいなことになる。

 コード補完や型があるのである程度はググらなくてもエディタ内で調査が完結できること。TypeScript最高! VS Code 最高!

 テストが書けるのでデプロイせずに結果が分かる。でも TDD やるには CloudFormation 力が低すぎてできませんでした😥

感想

 TypeScript チョット分かれば CloudFormation 全く知らずでも何とかなった。逆にみんなよく今まで CloudFormation テンプレート書けているのがすごい。どうやってるのか不思議。でも AWS CDK には CloudFormation 力も必須なので、AWS CDK 触りつつ高めていきたいです。

 オライリーの TypeScript 本買ったし、TypeScript ちゃんと勉強する!

 技術書典の AWS CDK + TypeScript 本も勧められたし、買って勉強する!

 技術書典では他にも、様々な技術同人誌が頒布されています。イベント自体は中止になっても、本はネットで買えます。先日 note に投稿した「エンジニアの心を整える技術」も技術書典で出されていたもので、現在では続編も出ています。みんなも技術書典でお気に入りの技術について探してみよう!


😉