AnsibleでAmazon Linux 2023にdbt-athena環境を構築してみた

dbt-athenaの実行環境を構築するために、Amazon Linux 2023のEC2インスタンスにAnsibleで必要なソフトウェアをインストールする例をご紹介します。
2023.08.14

データアナリティクス事業本部 機械学習チームの鈴木です。

データマート作成に、dbt-athenaを使いたく、環境をどこに構築するか考えていました。

ローカル環境上に準備してもいいのですが、今後のことを考えてAnsibleでAmazon Linux 2023のインスタンス上に準備をしてみました。

EC2のあるVPC内からエンドポイント経由でAthenaに通信する必要もあるため、ネットワークも含めたCloudFormationテンプレート例も合わせてご紹介します。

この記事の内容について

Amazon Linux 2023のインスタンス上にdbt-athena環境を構築し、動作確認を行いました。構築は再現できるようAnsibleで行いました。

dbtのドキュメントのAthena setupページで以下のdbt-athena-communityを使うように案内があったため、このアダプタを使いました。

dbt Coreの利用は初めてだったので、設定と動作確認は以下の資料を参考に進めました。

なお、Amazon Linux 2023にAnsibleで環境構築する例は、以前に以下のブログを公開していました。Ansibleの実行も記事内で行いますが、手順はこのブログを踏襲しています。

やってみる

1. AWSのリソース作成

キーペアの作成

まず、EC2にSSH接続するためのキーペアを作成しました。CloudFormationテンプレートでまとめて作ってもいいのですが、検証中作成の旅にキーファイルをローカルに配置し直すのが手間なので分けて作成しました。

名前はなんでもいいですが、今回は分かりやすいのでcm-nayuts-dbt-athenaとしました。

キーペアの作成

作成するとキーファイルが自動的にダウンロードされるので、~/.ssh/dbt-athena/cm-nayuts-dbt-athena.pemのように分かる場所に配置しました。

IAMロールの作成

以下のymlファイルを使って、IAMロール用のCloudFormationスタックを作成しました。この後に作成するEC2インスタンスおよびネットワークのテンプレートに混ぜてもよいのですが、ネットワークは料金の関係でこまめに消したかった一方で、IAMロールはそうではなかったので別にしました。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  EnvironmentName:
    Type: String

Resources:
  EC2IAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${EnvironmentName}-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/AmazonAthenaFullAccess
        - arn:aws:iam::aws:policy/AmazonS3FullAccess

ポリシーは検証のため強めの権限をアタッチしています。設計時には必要なものに絞って頂ければと思います。

EC2およびネットワークの作成

以下のymlファイルを使って、EC2インスタンスおよびネットワークのCloudFormationスタックを作成しました。

少し長いのでトグルに隠しておきます。(※ ▶️を押すと開きます。)

EC2インスタンスおよびネットワークのテンプレート
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  EnvironmentName:
    Type: String

  VPCCIDR:
    Type: String
    Default: 10.192.0.0/16

  PublicSubnetCIDR:
    Type: String
    Default: 10.192.1.0/24

  PrivateSubnetCIDR:
    Type: String
    Default: 10.192.0.0/24

  Ec2ImageId:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64

  Ec2InstanceType:
    Type: String
    Default: t3.micro

  KeyPair:
    Type: String
    Default: xxxxx-key

  EC2RoleName:
    Type: String

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-VPC

  # InternetGateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-igw

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-ngw

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  # Public Subnetのネットワーク設定
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Ref PublicSubnetCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PublicSubnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PublicRouteTable

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  # Private Subnetのネットワーク設定
  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Ref PrivateSubnetCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PrivateSubnet

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PrivateRouteTable

  PrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

  # エンドポイントの設定
  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EndpointSecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-EndpointSecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VPCCIDR

  EndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EndpointSSMMessages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EndpointAthena:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.athena
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EndpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref PrivateRouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VPC

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - Ref: EC2RoleName
      InstanceProfileName: !Sub ${EnvironmentName}-EC2InstanceProfile

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2SecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-EC2SecurityGroup

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref Ec2InstanceType
      SubnetId: !Ref PrivateSubnet
      ImageId: !Ref Ec2ImageId
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 50
            VolumeType: gp3
      EbsOptimized: true
      SourceDestCheck: true
      KeyName: !Ref KeyPair
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-EC2Instance

Outputs:
  VPC:
    Value: !Ref VPC
    Export:
      Name: !Sub ${EnvironmentName}-VPC

  VPCCIDR:
    Value: !Ref VPCCIDR
    Export:
      Name: !Sub ${EnvironmentName}-VPCCIDR

  PrivateSubnet:
    Value: !Ref PrivateSubnet
    Export:
      Name: !Sub ${EnvironmentName}-PrivateSubnet

  PrivateRouteTable:
    Value: !Ref PrivateRouteTable
    Export:
      Name: !Sub ${EnvironmentName}-PrivateRouteTable

  SecurityGroup:
    Value: !Ref EndpointSecurityGroup
    Export:
      Name: !Sub ${EnvironmentName}-EndpointSecurityGroup

  EndpointSSM:
    Value: !Ref EndpointSSM
    Export:
      Name: !Sub ${EnvironmentName}-EndpointSSM

  EndpointSSMMessages:
    Value: !Ref EndpointSSMMessages
    Export:
      Name: !Sub ${EnvironmentName}-EndpointSSMMessages

  EndpointEC2Messages:
    Value: !Ref EndpointEC2Messages
    Export:
      Name: !Sub ${EnvironmentName}-EndpointEC2Messages

  EndpointS3:
    Value: !Ref EndpointS3
    Export:
      Name: !Sub ${EnvironmentName}-EndpointS3

  EndpointAthena:
    Value: !Ref EndpointAthena
    Export:
      Name: !Sub ${EnvironmentName}-EndpointAthena

  EC2SecurityGroup:
    Value: !Ref EC2SecurityGroup
    Export:
      Name: !Sub ${EnvironmentName}-EC2SecurityGroup

  EC2Instance:
    Value: !Ref EC2Instance
    Export:
      Name: !Sub ${EnvironmentName}-EC2Instance

今回のポイントはAthenaのエンドポイントをVCPに作成したことでした。Glueのエンドポイントも必要かなと考えていましたが、以下のドキュメントで具体的に記載されていたのはAthenaエンドポイントのみでしたので、Athenaに直接関係するエンドポイントはこれのみ作成しました。今回試した内容ではこれで問題ありませんでした。

EC2インスタンスへのSSH接続確認

デプロイしたEC2インスタンスはセッションマネージャー経由でSSH接続できるので、初回接続しました。

.ssh/configに以下を追記しました。ただし、インスタンスIDプロファイル名秘密鍵のパスは作成したインスタンスやローカル環境に設定しているものに置き換えました。

host cm-nayuts-dbt-athena
    ProxyCommand sh -c "aws ssm start-session --target <インスタンスID> --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --profile <プロファイル名> --region ap-northeast-1"
    User ec2-user
    IdentityFile <秘密鍵のパス>

sshコマンドで接続すると、ログインできました。

ssh cm-nayuts-dbt-athena
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
Last login: Mon Aug 14 05:17:01 2023 from 127.0.0.1

AthenaおよびGlueのリソース作成

dbt-athenaからのAthenaでの処理実行に必要な、以下のリソースを作成しました。

  • Glueデータベース
  • 動作確認に使うGlueテーブル
  • dbtから実行したAthenaのクエリ結果を保存するS3バケット
  • dbtが使うAthenaのワークグループ

このリソースは説明と動作確認に使いたいだけなので、詳細はこだわりません。

特に動作確認に使うGlueテーブルは、よく検証で使っているUCI Machine Learning RepositoryのIris Data Setが入ったirisテーブルを作成して使いました。

なお、データセットのリンクは以下になります。

  • https://archive.ics.uci.edu/ml/datasets/iris

Athenaのエディタで見るとこのようになる状態にしました。

Glueまわりの準備

2. Ansibleによるインスタンスの環境構築

先ほどインスタンスを作成したので、Ansibleを使って環境を構築していきます。

Ansible用のファイルの作成

ローカルでansibleディレクトリを作成し、以下のようにファイルを作成しました。

ansibleディレクトリを作成し、以下のようにファイルを作成しました。

tree ansible
# .
# ├── ansible.cfg
# ├── hosts
# ├── playbook.yml
# └── ssh_config

プレイブックの作成

playbook.ymlファイルは以下のようにしました。

ansible/playbook.yml

- hosts: cm-nayuts-dbt-athena
  tasks:
  - name: Install python3
    ansible.builtin.dnf:
      name: python3.11-3.11.2-2.amzn2023.0.7.x86_64
      state: present
  - name: Install python3-pip
    ansible.builtin.dnf:
      name: python3.11-pip-22.3.1-2.amzn2023.0.2.noarch
      state: present
  - name: Install Git
    ansible.builtin.dnf:
      name: git-2.40.1-1.amzn2023.0.1.x86_64
      state: present
  - name: pip dbt-athena
    ansible.builtin.pip:
      name:
        - dbt-athena-community==1.5.1
      executable: pip3.11

Amazon Linux2023にはシステムPythonとしてPython3.9が入っていますが、dbtのインストールに使うためにPython3.11をインストールしました。

同じくインストールしたpip3.11を使ってdbt-athena-communityをインストールしました。dbt-coreをはじめとした依存するパッケージはdbt-athena-communityと一緒にインストールされる旨が以下のガイドに記載されていました。

nameにはバージョンまで記載しましたが、dnf search--showduplicatesオプションでバージョンまで表示して確認しました。特定バージョンをインストールできれば良かったのでstatepresentとしました。

プレイブック以外のファイルの作成

ansible.cfgファイルは以下のようにしました。

ansible/ansible.cfg

[defaults]
inventory = hosts

[privilege_escalation]
become = True

[ssh_connection]
control_path = %(directory)s/%%h-%%r
ssh_args = -o ControlPersist=15m -F ssh_config -q
scp_if_ssh = True

ssh_configファイルは以下のようにしました。ただし、インスタンスIDプロファイル名秘密鍵のパスは作成したインスタンスやローカル環境に設定しているものに置き換えました。

ansible/ssh_config

host cm-nayuts-dbt-athena
    ProxyCommand sh -c "aws ssm start-session --target <インスタンスID> --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --profile <プロファイル名> --region ap-northeast-1"
    User ec2-user
    IdentityFile <秘密鍵のパス>

hostsファイルは以下のようにしました。

ansible/hosts

[cm-nayuts-dbt-athena]
cm-nayuts-dbt-athena

プレイブックの実行

以下のようにプレイブックを実行しました。

# playbook.ymlのあるディレクトリに移動
cd ansible

# プレイブックの実行
ansible-playbook ./playbook.yml
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
[WARNING]: Found both group and host with same name: cm-nayuts-dbt-athena

PLAY [cm-nayuts-dbt-athena] ***************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************
[WARNING]: Platform linux on host cm-nayuts-dbt-athena is using the discovered Python interpreter at /usr/bin/python3.11, but
future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.14/reference_appendices/interpreter_discovery.html for more information.
ok: [cm-nayuts-dbt-athena]

TASK [Install python3] ********************************************************************************************************
ok: [cm-nayuts-dbt-athena]

TASK [Install python3-pip] ****************************************************************************************************
ok: [cm-nayuts-dbt-athena]

TASK [Install Git] ************************************************************************************************************
ok: [cm-nayuts-dbt-athena]

TASK [pip dbt-athena] *********************************************************************************************************
ok: [cm-nayuts-dbt-athena]

PLAY RECAP ********************************************************************************************************************
cm-nayuts-dbt-athena       : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

EC2にログインしてdnf historyを実行すると、インストールが実行されていることが確認できました。

また、pipでインストールしたdbtのバージョンは以下でした。

pip3.11 freeze | grep -e "dbt-core" -e "dbt-athena-community" -e "dbt-extractor"
# dbt-athena-community==1.5.1
# dbt-core==1.5.4
# dbt-extractor==0.4.1

3. dbtの初期設定

dbt initの実行

インスタンスにログインし、dbt initを実行しました。ログにあるようにいくつか質問をされるので答えていきました。

dbt init test_project
07:51:21  Running with dbt=1.5.4
Which database would you like to use?
[1] athena

(Don't see the one you want? https://docs.getdbt.com/docs/available-adapters)

Enter a number: 1
s3_staging_dir (S3 location to store Athena query results and metadata, e.g. s3://athena_query_result/prefix/): s3://バケット名/dbt-athena-staging/
s3_data_dir (S3 location where to store data/tables, e.g. s3://bucket_name/prefix/): s3://バケット名/dbt-athena-data/
region_name (AWS region of your Athena instance): ap-northeast-1
schema (Specify the schema (Athena database) to build models into (lowercase only)): cm-nayuts-sample-db
database (Specify the database (Data catalog) to build models into (lowercase only)) [awsdatacatalog]: awsdatacatalog
threads (1 or more) [1]: 1
07:52:21  Profile test_project written to /home/ec2-user/.dbt/profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection.
07:52:21  
Your new dbt project "test_project" was created!

For more information on how to configure the profiles.yml file,
please consult the dbt documentation here:

  https://docs.getdbt.com/docs/configure-your-profile

One more thing:

Need help? Don't hesitate to reach out to us via GitHub issues or on Slack:

  https://community.getdbt.com/

Happy modeling!

入力した内容に沿って~/.dbt/profiles.yml~/test_projectが作成されました。Athena実行時にはワークグループを指定したかったため、~/.dbt/profiles.ymlは以下のようにwork_groupを追記しました。

~/.dbt/profiles.yml

test_project:
  outputs:
    dev:
      database: awsdatacatalog
      region_name: ap-northeast-1
      s3_data_dir: s3://バケット名/dbt-athena-data/
      s3_staging_dir: s3://バケット名/dbt-athena-staging/
      schema: cm-nayuts-sample-db
      threads: 1
      type: athena
      work_group: dev
  target: dev

モデルの作成

以下のようにtest_project/models/iris_dbt.sqlを作成しました。

~/test_project/models/iris_dbt.sql

with iris_dbt as (

    select
        sepal_length,
        sepal_width,
        petal_length,
        petal_width,
        class

    from iris

)

select * from iris_dbt

AWSのリソース作成』で記載したテーブルからデータをSELECTするだけのモデルです。

サンプルのモデルは不要だったので削除しておきました。

rm -r test_project/models/example

4. 処理の実行

ビュー・マテリアライゼーションを使う

dbt runを実行し、Athena側にビュー(デフォルト設定なので)が作成されることを確認しました。

dbt run
08:01:44  Running with dbt=1.5.4
08:01:44  Registered adapter: athena=1.5.1
08:01:45  Unable to do partial parsing because profile has changed
08:01:46  [WARNING]: Configuration paths exist in your dbt_project.yml file which do not apply to any resources.
There are 1 unused configuration paths:
- models.test_project.example
08:01:46  Found 1 model, 0 tests, 0 snapshots, 0 analyses, 336 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics, 0 groups
08:01:46  
08:01:47  Concurrency: 1 threads (target='dev')
08:01:47  
08:01:47  1 of 1 START sql view model cm-nayuts-sample-db.iris_dbt ....................... [RUN]
08:01:49  1 of 1 OK created sql view model cm-nayuts-sample-db.iris_dbt .................. [OK -1 in 1.65s]
08:01:49  
08:01:49  Finished running 1 view model in 0 hours 0 minutes and 3.02 seconds (3.02s).
08:01:49  
08:01:49  Completed successfully
08:01:49  
08:01:49  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1

ビューが作成された結果

クエリ履歴からは、以下のようなビュー作成とテーブルプロパティの変更が実施されたことを確認しました。

-- /* {"app": "dbt", "dbt_version": "1.5.4", "profile_name": "test_project", "target_name": "dev", "node_id": "model.test_project.iris_dbt"} */
create or replace view
    "awsdatacatalog"."cm-nayuts-sample-db"."iris_dbt"
  as
    with iris_dbt as (
select
        sepal_length,
        sepal_width,
        petal_length,
        petal_width,
        class
from iris

)

select * from iris_dbt

テーブル・マテリアライゼーションを使う

dbt_project.ymlを開き、モデルのマテリアライズの設定を修正しました。

~/test_project/dbt_project.yml

(略)
models:
  test_project:
    +materialized: table

dbt runを実行し、Athena側にテーブルが作成されることを確認しました。

dbt run
08:23:33  Running with dbt=1.5.4
08:23:33  Registered adapter: athena=1.5.1
08:23:33  Found 1 model, 0 tests, 0 snapshots, 0 analyses, 336 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics, 0 groups
08:23:33  
08:23:35  Concurrency: 1 threads (target='dev')
08:23:35  
08:23:35  1 of 1 START sql table model cm-nayuts-sample-db.iris_dbt ...................... [RUN]
08:23:39  1 of 1 OK created sql table model cm-nayuts-sample-db.iris_dbt ................. [OK 0 in 3.97s]
08:23:39  
08:23:39  Finished running 1 table model in 0 hours 0 minutes and 5.41 seconds (5.41s).
08:23:39  
08:23:39  Completed successfully
08:23:39  
08:23:39  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1

テーブルが作成された結果

クエリ履歴からは、以下のようなテーブル作成とテーブルプロパティの変更が実施されたことを確認しました。

-- /* {"app": "dbt", "dbt_version": "1.5.4", "profile_name": "test_project", "target_name": "dev", "node_id": "model.test_project.iris_dbt"} */

  
    create table "awsdatacatalog"."cm-nayuts-sample-db"."iris_dbt"
  with (
    table_type='hive',
    is_external=true,external_location='s3://バケット名/dbt-athena-data/cm-nayuts-sample-db/iris_dbt/45643a21-ec97-4f08-ab26-62c5e8061024',
    format='parquet'
  )
  as
    with iris_dbt as (
select
        sepal_length,
        sepal_width,
        petal_length,
        petal_width,
        class
from iris

)

select * from iris_dbt
alter table `cm-nayuts-sample-db`.`iris_dbt` set tblproperties ('classification' = 'parquet')

最後に

dbt-athenaの実行環境を構築するために、Amazon Linux 2023のEC2インスタンスにAnsibleで必要なソフトウェアをインストールしました。

また、動作確認として簡単なAthenaへのクエリ実行例を紹介しました。

実行環境としてはEC2ではないことも多いと思いますが、気軽にSSHして動作確認できる開発環境として使うのはいいかもしれないですね。

参考になりましたら幸いです。

そのほかに参考にした文献