こんにちは。 エキサイト株式会社で内定者アルバイトをしています。
今回も、実際のリソースの作成を行いたいと思います。第5回は、Route 53です。
前の記事 tech.excite.co.jp
Route 53とは?
AWSの公式ドキュメントによると、可用性と拡張性に優れたクラウドのドメインネームシステム(DNS)Webサービスであり、www.example.comのような名前を、IPアドレスに変換するシステムです。デベロッパや企業がエンドユーザをインターネットアプリケーションにルーティングする、信頼性が高く、効率の良い方法になるように設計されているようです。
そして、Amazon EC2インスタンス、Elastic Balancing ロードバランサー、Amazon S3バケットなどのAWSで実行するインフラストラクチャにユーザリクエストを効率的に接続してくれるようです。
Route 53にはDNSのエントリをレコードとして追加していきます。これらのレコードを保持するコンテナをホストゾーンと呼び、インターネットでどのようにルーティングするかを指定するレコードを保持するホストゾーンをパブリックホストゾーン、VPC内でどのようにルーティングするかを指定するレコードを保持するホストゾーンをプライベートホストゾーンと呼びます。
レコードの種類として多くのものがありますが、よく使われるのは以下の5つかと思います。
- A record type
- Webサーバのようなリソースに対するルーティングのためのレコードで、ドット付き10進記法でIPv4アドレスを指定します。
- AAAA record type
- Webサーバのようなリソースに対するルーティングのためのレコードで、colon-separated hexadecimal format(コロン区切り16進記法)でIPv6アドレスを指定します。
- CNAME record type
- NS record type
- ホストゾーンのためのネームサーバを特定するために使用します。(自動で作成されます)
- SOA record type
実際に作成してみる
ここでは、プライベートホストゾーンを作成し、そこに2つのEC2インスタンスに対するA recordを作成します。
前回までのコード
前回は、RDSのデータベースクラスタとデータベースインスタンスを作成しました。
ただし、今回はRDS関連のリソースは使用しませんので、第3回までのコードを示します。
package com.myorg; import software.amazon.awscdk.CfnTag; import software.amazon.awscdk.Duration; import software.amazon.awscdk.services.ec2.CfnInternetGateway; import software.amazon.awscdk.services.ec2.CfnVPCGatewayAttachment; import software.amazon.awscdk.services.ec2.IMachineImage; import software.amazon.awscdk.services.ec2.Instance; import software.amazon.awscdk.services.ec2.InstanceClass; import software.amazon.awscdk.services.ec2.InstanceSize; import software.amazon.awscdk.services.ec2.InstanceType; import software.amazon.awscdk.services.ec2.MachineImage; import software.amazon.awscdk.services.ec2.Peer; import software.amazon.awscdk.services.ec2.Port; import software.amazon.awscdk.services.ec2.PrivateSubnet; import software.amazon.awscdk.services.ec2.PublicSubnet; import software.amazon.awscdk.services.ec2.SecurityGroup; import software.amazon.awscdk.services.ec2.SubnetSelection; import software.amazon.awscdk.services.ec2.Vpc; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import java.util.List; public class MyProjectStack extends Stack { public MyProjectStack(final Construct scope, final String id) { this(scope, id, null); } public MyProjectStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Vpc vpc = Vpc.Builder.create(this, "SampleVPC") .vpcName("sample-vpc") .cidr("cidr") .subnetConfiguration(List.of()) .build(); // Availability zone: ap-northeast-1a PrivateSubnet privateSubnetA = PrivateSubnet.Builder.create(this, "PrivateSubnetA") .availabilityZone("ap-northeast-1a") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); PublicSubnet publicSubnetA = PublicSubnet.Builder.create(this, "PublicSubnetA") .availabilityZone("ap-northeast-1a") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); // Availability zone: ap-northeast-1c PrivateSubnet privateSubnetB = PrivateSubnet.Builder.create(this, "PrivateSubnetB") .availabilityZone("ap-northeast-1c") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); PublicSubnet publicSubnetB = PublicSubnet.Builder.create(this, "PublicSubnetB") .availabilityZone("ap-northeast-1c") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); // NAT gatewayの追加 publicSubnetA.addNatGateway(); publicSubnetB.addNatGateway(); // Internet Gateway CfnInternetGateway internetGateway = CfnInternetGateway.Builder.create(this, "InternetGateway") .tags(List.of(CfnTag.builder() .key("Name") .value("sample-internet-gateway") .build())) .build(); // Internet gatewayをVPCにattachする CfnVPCGatewayAttachment.Builder.create(this, "VpcGateAwayAttachment") .vpcId(vpc.getVpcId()) .internetGatewayId(internetGateway.getAttrInternetGatewayId()) .build(); SecurityGroup securityGroup = SecurityGroup.Builder.create(this, "SampleSecurityGroup") .securityGroupName("sample-security-group") .vpc(vpc) .build(); IMachineImage machineImage = MachineImage.latestAmazonLinux(); Instance instance01 = Instance.Builder.create(this, "ec2-instance-01") .instanceName("ec2-instance-01") .vpcSubnets(SubnetSelection.builder().subnets(List.of(privateSubnetA)).build()) .machineImage(machineImage) .vpc(vpc) .availabilityZone("ap-northeast-1a") .instanceType(InstanceType.of(InstanceClass.T2, InstanceSize.SMALL)) .securityGroup(securityGroup) .build(); Instance instance02 = Instance.Builder.create(this, "ec2-instance-02") .instanceName("ec2-instance-02") .vpcSubnets(SubnetSelection.builder().subnets(List.of(privateSubnetB)).build()) .machineImage(machineImage) .vpc(vpc) .availabilityZone("ap-northeast-1c") .instanceType(InstanceType.of(InstanceClass.T2, InstanceSize.SMALL)) .securityGroup(securityGroup) .build(); // Load Balancer // Load Balancer用のSecurity Group SecurityGroup securityGroupEC2LB = SecurityGroup.Builder.create(this, "SecurityGroupEC2LoadBalancer") .securityGroupName("ec2-lb-security-group") .vpc(vpc) .description("security-group-of-ec2-load-balancer") .allowAllOutbound(true) .build(); securityGroupEC2LB.addIngressRule(Peer.ipv4("0.0.0.0/0"), Port.tcp(80)); ApplicationLoadBalancer applicationLoadBalancer = ApplicationLoadBalancer.Builder.create(this, "SampleEC2ApplicationLoadBalancer") .loadBalancerName("sample-ec2-load-balancer") .deletionProtection(false) .vpc(vpc) .vpcSubnets(SubnetSelection.builder().subnets(List.of(privateSubnetA, privateSubnetB)).build()) .securityGroup(securityGroupEC2LB) .ipAddressType(IpAddressType.IPV4) .idleTimeout(Duration.seconds(120)) .http2Enabled(true) .build(); ApplicationTargetGroup ec2TargetGroup = ApplicationTargetGroup.Builder.create(this, "EC2TargetGroup") .targetGroupName("ec2-target-group") .targetType(TargetType.INSTANCE) .port(80) .vpc(vpc) .targets(List.of(new InstanceTarget(instance01, 80), new InstanceTarget(instance02, 80))) .protocol(ApplicationProtocol.HTTP) .protocolVersion(ApplicationProtocolVersion.HTTP1) .healthCheck(HealthCheck.builder() .enabled(true) .path("/") .healthyThresholdCount(3) .unhealthyThresholdCount(2) .interval(Duration.seconds(60)) .timeout(Duration.seconds(5)) .protocol(Protocol.HTTP) .port("80") .build()) .build(); ApplicationListener applicationListener = ApplicationListener.Builder.create(this, "ApplicationListener") .loadBalancer(applicationLoadBalancer) .protocol(ApplicationProtocol.HTTP) .port(80) .defaultAction(ListenerAction.forward(List.of(ec2TargetGroup))) .build(); } }
Route 53リソースとそれにレコードを追加するコード
PrivateHostedZone privateHostedZone = PrivateHostedZone.Builder.create(this, "SamplePrivateHostedZone") .zoneName("your.zone.name") .vpc(vpc) .comment("private-sample") .build(); ARecord.Builder.create(this, "EC2ARecord01") .zone(privateHostedZone) .recordName("ec2-instance-01.your.zone.name") .target(RecordTarget.fromIpAddresses(instance01.getInstancePrivateIp())) .ttl(Duration.seconds(3600)) .build(); ARecord.Builder.create(this, "EC2ARecord02") .zone(privateHostedZone) .recordName("ec2-instance-02.your.zone.name") .target(RecordTarget.fromIpAddresses(instance02.getInstancePrivateIp())) .ttl(Duration.seconds(3600)) .build();
your.zone.name
には、ご自身が使用するドメイン名を指定してください。
今回はかなりシンプルですね。
参考
同様にCNAME recordも以下のように登録できます。
CnameRecord.Builder.create(this, "CnameRecord") .zone(privateHostedZone) .recordName("sample-cname.your.zone.name") .domainName("other-domain.co.jp") .ttl(Duration.seconds(600)) .build();
デプロイ
ここまで、記述できればあとはデプロイするだけです。
cdk deploy
エラーなくデプロイできれば成功です。
終わりに
今回は、AWS CDKを用いてRoute 53のホストゾーンとレコードを作成しました。
では、また次回。
次の記事 tech.excite.co.jp