こんにちは。 エキサイト株式会社で内定者アルバイトをしています。
今回も、実際のリソースの作成を行いたいと思います。第7回は、OpenSearchです。
前の記事
OpenSearchとは?
OpenSearchは、高速検索が可能な全文検索・分析エンジンです。
大量のデータへの高速なアクセスと応答が提供され、高度なスケール化も容易に行えます。
また、検索機能に加え、データ蓄積や分析環境の構築も容易なため、ビッグデータを利用する場合などの大規模なシステムに向いています。
OpenSearchは(これまで作成したRDSやRedisのように)クラスタ化が可能で、そのクラスタはドメインと呼ばれます。
ドメインは指定した設定、インスタンスタイプ、インスタンス数、ストレージリソースを持ちます。
実際に作成してみる
今回作成するのは以下のような設定を持つドメイン(OpenSearchクラスタ)です。
項目 | 設定 |
---|---|
バージョン | OpenSearch 1.0 |
EBS ボリュームタイプ | gp2 |
EBS ボリュームサイズ | 150GiB |
暗号化:HTTPS | 要求 |
暗号化:ノード間 | 有効 |
暗号化:保管時 | 有効 |
アベイラビリティゾーン数 | 2 |
データノードの数 | 2 |
データノードのインスタンスタイプ | t3.medium.search |
マスターノードの数 | 3 |
マスターノードのインスタンスタイプ | m6g.large.search |
前回までで作成したVPCおよびサブネット上に作成していきます。
なお、マスターノードはクラスタ管理タスクを行い、データの保持やデータのアップロードリクエストには応答しません。 マスターノードを存在させることによってクラスタの安定性が向上するようです。
検索およびクエリリクエストを処理するのはデータノードです。
補足
- OpenSearchの最新バージョンは1.3です
- EBS(Amazon Elastic Block Store)は、ブロックストレージサービスです。EBSについては以下の記事がわかりやすいかと思います
- EBSでは新たにgp3というボリュームが登場したようです。こちらでは既存のものよりコスト的に効率で最適なパフォーマンスが実現できるそうです。
- 「暗号化:ノード間」はノード間の転送中に暗号化(TLS 1.2)を使用するかどうかの設定です。
前回までのコード
前回はElastiCacheを作成しましたが、今回はそれらを参照しませんので、VPCおよびサブネットを作成した部分だけを再掲します。
package com.myorg; import software.amazon.awscdk.CfnTag; import software.amazon.awscdk.services.ec2.CfnInternetGateway; import software.amazon.awscdk.services.ec2.CfnVPCGatewayAttachment; import software.amazon.awscdk.services.ec2.PrivateSubnet; import software.amazon.awscdk.services.ec2.PublicSubnet; 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(); } }
OpenSearchのドメインを作成するコード
// OpenSearch // OpenSearch用のセキュリティグループ ① SecurityGroup openSearchSecurityGroup = SecurityGroup.Builder.create(this, "OpenSearchSG") .securityGroupName("sample-open-search-sg") .description("security-group-for-sample-open-search") .vpc(vpc) .allowAllOutbound(true) .build(); openSearchSecurityGroup.addIngressRule(Peer.ipv4(privateSubnetA.getIpv4CidrBlock()), Port.tcp(80), "private-subnet-a"); openSearchSecurityGroup.addIngressRule(Peer.ipv4(privateSubnetA.getIpv4CidrBlock()), Port.tcp(443), "private-subnet-a"); openSearchSecurityGroup.addIngressRule(Peer.ipv4(privateSubnetB.getIpv4CidrBlock()), Port.tcp(80), "private-subnet-c"); openSearchSecurityGroup.addIngressRule(Peer.ipv4(privateSubnetB.getIpv4CidrBlock()), Port.tcp(443), "private-subnet-c"); // ドメイン ② Domain domain = Domain.Builder.create(this, "SampleOpenSearch") .domainName("sample-open-search") .version(EngineVersion.OPENSEARCH_1_0) .vpc(vpc) .securityGroups(List.of(openSearchSecurityGroup)) .enforceHttps(true) .nodeToNodeEncryption(true) .encryptionAtRest(EncryptionAtRestOptions.builder() .enabled(true) .build()) .vpcSubnets(List.of(SubnetSelection.builder() .subnets(List.of(privateSubnetA, privateSubnetB)) .build())) .capacity(CapacityConfig.builder() .masterNodes(3) .masterNodeInstanceType("m6g.large.search") .dataNodes(2) .dataNodeInstanceType("t3.medium.search") .build()) .ebs(EbsOptions.builder() .enabled(true) .volumeType(EbsDeviceVolumeType.GP2) .volumeSize(150) .build()) .zoneAwareness(ZoneAwarenessConfig.builder() .enabled(true) .availabilityZoneCount(2) .build()) .build(); // アクセスポリシーの追加 ③ domain.addAccessPolicies(PolicyStatement.Builder.create() .effect(Effect.ALLOW) .principals(List.of(new AnyPrincipal())) .actions(List.of("es:*")) .resources(List.of(domain.getDomainArn() + "/*")) .build());
少し長くなりましたので以下で少し説明を加えます。
まず、①ではOpenSearchのドメイン用のセキュリティグループを作成しています。
セキュリティグループについては以下で解説しているので、興味がある方はこちらをご覧ください。
ちなみに、addIngressRule
の第3引数はdescription
ですので、特別な設定をしているわけではありません。ただの説明です。
次に、②では実際にドメインを作成しています。
設定項目はほとんどメソッド名通りですので、細かい説明は省きます。
zoneAwareness
について、zone awareness(ゾーン認識)という機能を有効にすると、同じリージョン内の2つまたは3つのアベイラビリティゾーンにわたって(データ)ノードとレプリカを割り当てるようで、ダウンタイムやデータ損失を防ぐのに役立つそうです。 (ノード数はアベイラビリティゾーンの数の倍数でなければなりません。これはマネジメントコンソール上から作成する際にもエラーメッセージとして出ますよね。)
今回は、2つのアベイラビリティゾーンにそれぞれ一つずつのノードを設置しています。
ただし、耐障害性を高めるためには、少なくとも3つのノードを作成することが推奨されているようです。
最後に、③ではドメインのアクセスポリシーを追加しています。 ここでは、以下のようなアクセスポリシーとなります。
このアクセスポリシーは、任意のAWSアカウント、ユーザまたはロールがこのドメイン内の任意のノードに任意のアクション("ESHttpDelete", "es:ESHttpGet", "es:ESHttpHead", "es:ESHttpPost", "es:ESHttpPut", "es:ESHttpPatch")を実行できることを表しています(ほぼ何も設定していないのと同じです)。
特にこの部分は必要に応じてカスタマイズしてください。
アクセスポリシーについては以下のドキュメントを参考にしてください。
Identity and Access Management in Amazon OpenSearch Service - Amazon OpenSearch Service
デプロイ
ここまで、記述できたらいつものようにデプロイします。
cdk deploy
エラーなくデプロイが完了したらOKです(作成には少し時間がかかります)。
終わりに
今回は、AWS CDKを用いてOpenSearchのドメインを作成しました。
前回のElastiCacheのようなややこしい設定はないので作成自体は比較的簡単にできました。
では、また次回。
次の記事