AWS CDK で Redash の環境を構築してみた

記事タイトルとURLをコピーする

CI部の宮本です。在宅勤務で毎朝のコーヒーを淹れるのが面倒くさくなってきました。全自動のコーヒーメーカーが欲しいのですが、中々のお値段なのでためらっています。

さて、今回は AWS CDK を使って Redash の環境を構築してみました。

AWS CDK とは

AWS クラウド開発キット (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースをモデル化およびプロビジョニングするためのオープンソースのソフトウェア開発フレームワークです。 引用元: https://aws.amazon.com/jp/cdk/

内部的には CloudFormation が生成され、リソースの作成が行われます。対応言語は TypeScript、Python、Java、C#等が使用出来ます。TypeScriptなどの静的型言語で、型に守られながらリソースを書けるところが良さそうです。

Redash とは

Redash はオープンソースで開発されているダッシュボードツールです。様々なデータソースと接続可能で、SQLと簡単な設定をすることでダッシュボードを作ることが出来ます。

接続可能なデータベースが豊富で、MySQLやPostgreSQLなどの一般的なRDBMSはもちろん、SnowflakeやSalesforce などのSaaSにも接続出来る優れものです。

完成イメージ

AWS CDK で以下の様な構成をAWS上に構築してみたいと思います。

Redash は Flask や Redis 、PostgreSQL などで構築されている様ですが、公式から全部入りのAMI が提供されているので、今回はこれを使用します。

AWS CDK の開発環境の準備

今回はTypeScriptにて開発を行います。以下が準備済みの前提で進めます。

  • AWS CLI (2.0.19)
  • Node.js (12.18.0)

AWS CDK のインストール

以下コマンドでインストールし、バージョンが確認できればインストール成功です。

$ npm install -g aws-cdk

$ cdk --version
1.51.0 (build 8c2d53c)

 

CDKプロジェクトの作成

早速CDKプロジェクトの作成をしていきましょう。--language オプションの後に使用したい言語を指定します。

$ mkdir redash-cdk && cd redash-cdk # プロジェクトディレクトリの作成
$ cdk init --language typescript # プロジェクトの初期化
... 中略...
✅ All done!
**************************************************
*** Newer version of CDK is available [1.51.0] ***
*** Upgrade recommended                        ***
**************************************************

お好みのエディタでプロジェクトを開いてみましょう。初期のプロジェクト構成はこの様になっています。

lib/redash-cdk-stack.ts にリソースを定義するコードを書いて行きます。

依存ライブラリのインストール

AWS CDK では作成するリソース毎にライブラリが分けられており、使用したい場合は以下の様にインストールする必要があります。今回は EC2、IAM、ALBを使用するのでそれぞれインストールします。作成できるリソースは API Reference を参照してください。

$ npm install @aws-cdk/aws-ec2 @aws-cdk/aws-iam @aws-cdk/aws-elasticloadbalancingv2 @aws-cdk/aws-elasticloadbalancingv2-targets

スタックの実装

結論からですが、以下の様なコードで実現することが出来ました。

// lib/redash-cdk-stack.ts

import * as cdk from "@aws-cdk/core";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as iam from "@aws-cdk/aws-iam";
import * as elbv2 from "@aws-cdk/aws-elasticloadbalancingv2";
import * as targets from "@aws-cdk/aws-elasticloadbalancingv2-targets";

export class RedashCdkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // (1)
    const vpc = new ec2.Vpc(this, "redash-vpc", {
      cidr: "10.100.0.0/16",
      enableDnsHostnames: true,
      enableDnsSupport: true,
      maxAzs: 2,
      natGateways: 1,
      subnetConfiguration: [
        {
          name: "public",
          subnetType: ec2.SubnetType.PUBLIC,
          cidrMask: 24,
        },
        {
          name: "private",
          subnetType: ec2.SubnetType.PRIVATE,
          cidrMask: 24,
        },
      ],
    });

    // (2)
    const role = new iam.Role(this, "redash-instance-role", {
      assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "AmazonSSMManagedInstanceCore"
        ),
      ],
    });

    // (3)
    const albSg = new ec2.SecurityGroup(this, "redash-alb-sg", {
      vpc: vpc,
      allowAllOutbound: true,
    });

    // (4)
    const instanceSg = new ec2.SecurityGroup(this, "redash-instance-sg", {
      vpc: vpc,
      allowAllOutbound: true,
    });
    instanceSg.addIngressRule(albSg, ec2.Port.tcp(80));

    // (5)
    const instance = new ec2.Instance(this, "redash", {
      vpc,
      instanceType: new ec2.InstanceType("t2.small"),
      machineImage: ec2.MachineImage.genericLinux({
        "us-east-1": "ami-0d915a031cabac0e0",
        "us-east-2": "ami-0b97435028ca44fcc",
        "us-west-1": "ami-068d0753a46192935",
        "us-west-2": "ami-0c457f229774da543",
        "eu-west-1": "ami-046c6a0123bf94619",
        "eu-west-2": "ami-0dbe8ba0cd21ea12b",
        "eu-west-3": "ami-041bf9180061ce7ea",
        "eu-central-1": "ami-0f8184e6f30cc0c33",
        "eu-north-1": "ami-08dd1b893371bcaac",
        "ap-south-1": "ami-0ff23052091536db2",
        "ap-southeast-1": "ami-0527e82bae7c51958",
        "ap-southeast-2": "ami-0bae8773e653a32ec",
        "ap-northeast-1": "ami-060741a96307668be",
        "ap-northeast-2": "ami-0d991ac4f545a6b34",
        "sa-east-1": "ami-076f350d5a5ec448d",
        "ca-central-1": "ami-0071deaa12b66d1bf",
      }),
      role,
      blockDevices: [
        {
          deviceName: "/dev/sda1",
          volume: ec2.BlockDeviceVolume.ebs(30),
        },
      ],
      securityGroup: instanceSg,
    });

    // (6)
    const alb = new elbv2.ApplicationLoadBalancer(this, "redash-alb", {
      vpc,
      internetFacing: true,
      securityGroup: albSg,
    });

    // (7)
    const listener = alb.addListener("redash-alb-listener", {
      port: 443,
    });

    // (8)
    listener.addTargets("redash-alb-target", {
      port: 80,
      targets: [new targets.InstanceTarget(instance)],
      healthCheck: {
        path: "/status.json",
      },
    });
  }
}


上から解説していきます。

(1) VPCを作成しています。cidr や enableDnsHostnames など、見慣れたオプションがありますね。maxAzs はサブネットを作成するアベイラビリティーゾーンの数です。デフォルトだと3AZにサブネットを展開してしまうので、2に設定しています。また、natGateways は作成する NatGatewayの数です。最後の subnetConfiguration はその名の通り、作成するサブネットの設定です。subnetType に PUBLIC 、PRIVATE を設定することで、ルートテーブルをよしなに作成してくれます。

(2) EC2インスタンスにアタッチするIAMロールを作成しています。セッションマネージャーにてログインする為に、AmazonSSMManagedInstanceCore のマネージドポリシーを設定しています。

(3) ALBにアタッチするセキュリティグループを作成しています。

(4) EC2インスタンスにアタッチするセキュリティグループを作成しています。作成後、ALBからの ポート80 へのインバウンドアクセスを許可するルールを追加しています。

(5) EC2インスタンスを作成しています。ec2.MachineImage.genericLinux のパラメータでリージョンとAMIのマッピングを設定しています。blockDevices でEBSの設定も可能です。

(6) ALBを作成しています。

(7) ALBのリスナーを追加しています。説明のし易さの為、ポート80 (HTTP) としていますが、現実的にはポート443 (HTTPS) を受け付ける様にしましょう。その際はACMで証明書を発行し、certificates プロパティに設定するなどしましょう。

(8) ターゲットを追加しています。EC2インスタンスのポート80 をターゲットとしています。また、ヘルスチェックのパスとして /status.json を設定しています。こちらはRedashにて提供されるステータスチェック用のAPIのパスです。

// bin/redash-cdk.ts

#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "@aws-cdk/core";
import { RedashCdkStack } from "../lib/redash-cdk-stack";

const app = new cdk.App();
new RedashCdkStack(app, "RedashCdkStack", {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION,
  },
});

こちらがエントリポイントとなるコードです。環境変数からアカウントとリージョンを設定しています。こちらはAMIの選択の為に追加をしています。デプロイ前に環境変数として設定しておきましょう。

CDK スタックのデプロイ

初めてデプロイする場合は以下の cdk bootstrap を実行する必要があります。CFnテンプレートを保存するためのバケットの作成が行われます。

$ cdk bootstrap
⏳  Bootstrapping environment aws://XXXXXXXXXXXX/ap-northeast-1...
✅  Environment aws://XXXXXXXXXXXX/ap-northeast-1 bootstrapped (no changes).

早速デプロイしてみましょう。

$ cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬─────────────────────────────┬────────┬────────────────┬───────────────────────────┬───────────┐
│   │ Resource                    │ Effect │ Action         │ Principal                 │ Condition │
├───┼─────────────────────────────┼────────┼────────────────┼───────────────────────────┼───────────┤
│ + │ ${redash-instance-role.Arn} │ Allow  │ sts:AssumeRole │ Service:ec2.amazonaws.com │           │
└───┴─────────────────────────────┴────────┴────────────────┴───────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────┬────────────────────────────────────────────────────────────────────┐
│   │ Resource                │ Managed Policy ARN                                                 │
├───┼─────────────────────────┼────────────────────────────────────────────────────────────────────┤
│ + │ ${redash-instance-role} │ arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore │
└───┴─────────────────────────┴────────────────────────────────────────────────────────────────────┘
Security Group Changes
┌───┬───────────────────────────────┬─────┬────────────┬──────────────────────────┐
│   │ Group                         │ Dir │ Protocol   │ Peer                     │
├───┼───────────────────────────────┼─────┼────────────┼──────────────────────────┤
│ + │ ${redash-alb-sg.GroupId}      │ In  │ TCP 80     │ Everyone (IPv4)          │
│ + │ ${redash-alb-sg.GroupId}      │ Out │ Everything │ Everyone (IPv4)          │
├───┼───────────────────────────────┼─────┼────────────┼──────────────────────────┤
│ + │ ${redash-instance-sg.GroupId} │ In  │ TCP 80     │ ${redash-alb-sg.GroupId} │
│ + │ ${redash-instance-sg.GroupId} │ Out │ Everything │ Everyone (IPv4)          │
└───┴───────────────────────────────┴─────┴────────────┴──────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
RedashCdkStack: deploying...
RedashCdkStack: creating CloudFormation changeset...













 ✅  RedashCdkStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/RedashCdkStack/021bbd00-c807-11ea-8ab6-06255f79192b

デプロイが出来ました!デプロイ前にセキュリティ関連の変更を表示してくれるのが親切です。

動作確認

マネジメントコンソールで作成されたALBのエンドポイントを確認し、ブラウザでアクセスしてみましょう。以下の様な初期画面が表示されればOKです。

生成されるテンプレート

冒頭で内部的には CloudFormation のテンプレートが生成されると書きましたが、 cdk synth コマンドで確認できます。

$ cdk synth
Resources:
  redashvpc787F192D:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.100.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/Resource
  redashvpcpublicSubnet1Subnet3D390376:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.100.0.0/24
      VpcId:
        Ref: redashvpc787F192D
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: aws-cdk:subnet-name
          Value: public
        - Key: aws-cdk:subnet-type
          Value: Public
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/Subnet
  redashvpcpublicSubnet1RouteTableE975F80B:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: redashvpc787F192D
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/RouteTable
  redashvpcpublicSubnet1RouteTableAssociationD0578F24:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: redashvpcpublicSubnet1RouteTableE975F80B
      SubnetId:
        Ref: redashvpcpublicSubnet1Subnet3D390376
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/RouteTableAssociation
  redashvpcpublicSubnet1DefaultRoute3F4FA9A9:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: redashvpcpublicSubnet1RouteTableE975F80B
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: redashvpcIGW7813B7C8
    DependsOn:
      - redashvpcVPCGWD937466E
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/DefaultRoute
  redashvpcpublicSubnet1EIPCC704A65:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/EIP
  redashvpcpublicSubnet1NATGatewayE9CE305C:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - redashvpcpublicSubnet1EIPCC704A65
          - AllocationId
      SubnetId:
        Ref: redashvpcpublicSubnet1Subnet3D390376
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet1/NATGateway
  redashvpcpublicSubnet2Subnet4F70832C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.100.1.0/24
      VpcId:
        Ref: redashvpc787F192D
      AvailabilityZone: ap-northeast-1c
      MapPublicIpOnLaunch: true
      Tags:
        - Key: aws-cdk:subnet-name
          Value: public
        - Key: aws-cdk:subnet-type
          Value: Public
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet2
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet2/Subnet
  redashvpcpublicSubnet2RouteTableCECFFA67:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: redashvpc787F192D
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/publicSubnet2
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet2/RouteTable
  redashvpcpublicSubnet2RouteTableAssociationD50DF0BC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: redashvpcpublicSubnet2RouteTableCECFFA67
      SubnetId:
        Ref: redashvpcpublicSubnet2Subnet4F70832C
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet2/RouteTableAssociation
  redashvpcpublicSubnet2DefaultRouteEDB2F883:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: redashvpcpublicSubnet2RouteTableCECFFA67
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: redashvpcIGW7813B7C8
    DependsOn:
      - redashvpcVPCGWD937466E
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/publicSubnet2/DefaultRoute
  redashvpcprivateSubnet1Subnet8CAD3737:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.100.2.0/24
      VpcId:
        Ref: redashvpc787F192D
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: false
      Tags:
        - Key: aws-cdk:subnet-name
          Value: private
        - Key: aws-cdk:subnet-type
          Value: Private
        - Key: Name
          Value: RedashCdkStack/redash-vpc/privateSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet1/Subnet
  redashvpcprivateSubnet1RouteTableAE169A43:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: redashvpc787F192D
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/privateSubnet1
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet1/RouteTable
  redashvpcprivateSubnet1RouteTableAssociation11192046:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: redashvpcprivateSubnet1RouteTableAE169A43
      SubnetId:
        Ref: redashvpcprivateSubnet1Subnet8CAD3737
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet1/RouteTableAssociation
  redashvpcprivateSubnet1DefaultRouteAAEFF0DE:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: redashvpcprivateSubnet1RouteTableAE169A43
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: redashvpcpublicSubnet1NATGatewayE9CE305C
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet1/DefaultRoute
  redashvpcprivateSubnet2Subnet5B47BA0C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.100.3.0/24
      VpcId:
        Ref: redashvpc787F192D
      AvailabilityZone: ap-northeast-1c
      MapPublicIpOnLaunch: false
      Tags:
        - Key: aws-cdk:subnet-name
          Value: private
        - Key: aws-cdk:subnet-type
          Value: Private
        - Key: Name
          Value: RedashCdkStack/redash-vpc/privateSubnet2
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet2/Subnet
  redashvpcprivateSubnet2RouteTable2FA16BB7:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: redashvpc787F192D
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc/privateSubnet2
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet2/RouteTable
  redashvpcprivateSubnet2RouteTableAssociation523D6F0E:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: redashvpcprivateSubnet2RouteTable2FA16BB7
      SubnetId:
        Ref: redashvpcprivateSubnet2Subnet5B47BA0C
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet2/RouteTableAssociation
  redashvpcprivateSubnet2DefaultRouteABA00E61:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: redashvpcprivateSubnet2RouteTable2FA16BB7
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: redashvpcpublicSubnet1NATGatewayE9CE305C
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/privateSubnet2/DefaultRoute
  redashvpcIGW7813B7C8:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash-vpc
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/IGW
  redashvpcVPCGWD937466E:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: redashvpc787F192D
      InternetGatewayId:
        Ref: redashvpcIGW7813B7C8
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-vpc/VPCGW
  redashinstanceroleCA5CD152:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/AmazonSSMManagedInstanceCore
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-instance-role/Resource
  redashalbsgFF5DACBB:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: RedashCdkStack/redash-alb-sg
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          Description: Allow from anyone on port 80
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80
      VpcId:
        Ref: redashvpc787F192D
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-alb-sg/Resource
  redashinstancesg749BCA92:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: RedashCdkStack/redash-instance-sg
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      VpcId:
        Ref: redashvpc787F192D
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-instance-sg/Resource
  redashinstancesgfromRedashCdkStackredashalbsg26A403EF8046A50BB9:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: from RedashCdkStackredashalbsg26A403EF:80
      FromPort: 80
      GroupId:
        Fn::GetAtt:
          - redashinstancesg749BCA92
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - redashalbsgFF5DACBB
          - GroupId
      ToPort: 80
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-instance-sg/from RedashCdkStackredashalbsg26A403EF:80
  redashInstanceProfile17725B73:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - Ref: redashinstanceroleCA5CD152
    Metadata:
      aws:cdk:path: RedashCdkStack/redash/InstanceProfile
  redashE2FE35A2:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: ap-northeast-1a
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 30
      IamInstanceProfile:
        Ref: redashInstanceProfile17725B73
      ImageId: ami-060741a96307668be
      InstanceType: t2.small
      SecurityGroupIds:
        - Fn::GetAtt:
            - redashinstancesg749BCA92
            - GroupId
      SubnetId:
        Ref: redashvpcprivateSubnet1Subnet8CAD3737
      Tags:
        - Key: Name
          Value: RedashCdkStack/redash
      UserData:
        Fn::Base64: "#!/bin/bash"
    DependsOn:
      - redashinstanceroleCA5CD152
    Metadata:
      aws:cdk:path: RedashCdkStack/redash/Resource
  redashalbE9806DDF:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      SecurityGroups:
        - Fn::GetAtt:
            - redashalbsgFF5DACBB
            - GroupId
      Subnets:
        - Ref: redashvpcpublicSubnet1Subnet3D390376
        - Ref: redashvpcpublicSubnet2Subnet4F70832C
      Type: application
    DependsOn:
      - redashvpcpublicSubnet1DefaultRoute3F4FA9A9
      - redashvpcpublicSubnet2DefaultRouteEDB2F883
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-alb/Resource
  redashalbredashalblistenerA15C76FF:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - TargetGroupArn:
            Ref: redashalbredashalblistenerredashalbtargetGroupEEFC3BEE
          Type: forward
      LoadBalancerArn:
        Ref: redashalbE9806DDF
      Port: 80
      Protocol: HTTP
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-alb/redash-alb-listener/Resource
  redashalbredashalblistenerredashalbtargetGroupEEFC3BEE:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckPath: /status.json
      Port: 80
      Protocol: HTTP
      Targets:
        - Id:
            Ref: redashE2FE35A2
      TargetType: instance
      VpcId:
        Ref: redashvpc787F192D
    Metadata:
      aws:cdk:path: RedashCdkStack/redash-alb/redash-alb-listener/redash-alb-targetGroup/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.51.0,@aws-cdk/aws-cloudwatch=1.51.0,@aws-cdk/aws-ec2=1.51.0,@aws-cdk/aws-elasticloadbalancingv2=1.51.0,@aws-cdk/aws-elasticloadbalancingv2-targets=1.51.0,@aws-cdk/aws-events=1.51.0,@aws-cdk/aws-iam=1.51.0,@aws-cdk/aws-kms=1.51.0,@aws-cdk/aws-logs=1.51.0,@aws-cdk/aws-s3=1.51.0,@aws-cdk/aws-ssm=1.51.0,@aws-cdk/cloud-assembly-schema=1.51.0,@aws-cdk/core=1.51.0,@aws-cdk/cx-api=1.51.0,@aws-cdk/region-info=1.51.0,jsii-runtime=node.js/v12.18.0

一気にスクロールしましたね? AWS CDK の強力さがお分かりいただけたと思います。

スタック削除をする場合は cdk destroy を実行します。

おわりに

AWS CDK で Redash 環境を構築しました。次回は Snowflake へ接続してダッシュボードを作ってみたいと思います。