Glue CrawlerをAurora MySQLへ向けて実行してみる

Glue CrawlerをAurora MySQLへ向けて実行してみる

2025.04.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、データ事業本部のキタガワです。
Glue CrawlerをAurora MySQLに対して実行し、テーブル情報をGlue Data Catalogに登録する手順をまとめました。

前提条件

この記事を理解するには、以下の知識と権限が必要です。

  • AWSの基本的な知識(VPC、IAM、RDS、Glueなど)
  • IAMユーザーに適切な権限(CloudFormation、RDS、Glue、VPC、IAMの操作権限)
  • MySQLの基本的な知識

稼働中のAurora MySQLがすでにある状態を想定しています。
前提としては以下の通りです。

  • Aurora MySQLクラスターが稼働していること
  • VPCとサブネットが設定済みであること
  • 以下の情報が手元にあること
    • Aurora MySQLのエンドポイント
    • データベース名
    • 接続ユーザー名
    • 接続パスワード
    • VPCのID
    • プライベートサブネットのID

今回やりたいことの簡単なイメージ図はこんな感じです。

alt text

CloudFormationテンプレートの概要

今回は前提となるAurora MySQLのデータベースとその他のリソースをCloudFormationを用いて作成します。
このテンプレートでは以下のリソースを作成します。

  1. ネットワークリソース

    • VPC: Aurora MySQLとGlue Crawlerを実行するためのネットワーク環境
    • プライベートサブネット: Aurora MySQLとGlue Crawlerを配置するためのサブネット
    • ルートテーブル: プライベートサブネットのルーティング設定
    • VPCエンドポイント: S3、SSM、SSMメッセージング用のエンドポイント
  2. セキュリティリソース

    • セキュリティグループ: Aurora MySQL、SSM、SSM Bastion用のセキュリティグループ
    • IAMロール: SSM Bastion用のIAMロール
  3. データベースリソース

    • Aurora MySQLクラスター: メインのデータベース
    • パラメータグループ: データベースの設定
    • Secrets Manager: データベースの認証情報
  4. Glueリソース

    • Glueデータベース: クローリング結果を格納するデータベース
  5. 踏み台サーバ

    • SSM Bastion: プライベートサブネット内の踏み台サーバ
    • セッションマネージャー経由でアクセス: 踏み台サーバへのアクセスはSSMセッションマネージャーを使用します

以下が使用したテンプレートです。

template-infra.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template for Aurora MySQL and related resources for Glue Crawler

Parameters:
  VpcCIDR:
    Description: CIDR block for the VPC
    Type: String
    Default: 10.0.0.0/16

  PrivateSubnet1CIDR:
    Description: CIDR block for Private Subnet 1
    Type: String
    Default: 10.0.1.0/24

  PrivateSubnet2CIDR:
    Description: CIDR block for Private Subnet 2
    Type: String
    Default: 10.0.2.0/24

  DBName:
    Description: Database name
    Type: String
    Default: mydb

  DBUsername:
    Description: Database admin username
    Type: String
    Default: admin
    NoEcho: true

  DBInstanceClass:
    Description: Database instance class
    Type: String
    Default: db.t3.medium

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

  # Subnets
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 0
        - !GetAZs ''
      CidrBlock: !Ref PrivateSubnet1CIDR
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PrivateSubnet1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 1
        - !GetAZs ''
      CidrBlock: !Ref PrivateSubnet2CIDR
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PrivateSubnet2

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

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet2

  # Security Groups
  AuroraSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Aurora MySQL
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-AuroraSecurityGroup

  SSMSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for SSM endpoints
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VpcCIDR
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SSMSecurityGroup

  SSMBastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for SSM Bastion
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SSMBastionSecurityGroup

  # Security Group Rules
  AuroraIngressFromSSMBastion:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref AuroraSecurityGroup
      IpProtocol: tcp
      FromPort: 3306
      ToPort: 3306
      SourceSecurityGroupId: !Ref SSMBastionSecurityGroup
      Description: Allow MySQL access from SSM Bastion

  AuroraIngressSelfReference:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref AuroraSecurityGroup
      IpProtocol: tcp
      FromPort: 0
      ToPort: 65535
      SourceSecurityGroupId: !Ref AuroraSecurityGroup
      Description: Allow all inbound traffic from the same security group

  # IAM Roles
  SSMInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref SSMInstanceRole

  SSMInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy

  # Secrets Manager
  AuroraSecret:
    Type: AWS::SecretsManager::Secret
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Properties:
      Name: !Sub ${AWS::StackName}/aurora/credentials
      Description: Aurora database credentials
      GenerateSecretString:
        SecretStringTemplate: !Sub '{"username": "${DBUsername}"}'
        GenerateStringKey: "password"
        PasswordLength: 32
        ExcludeCharacters: '"@/\'

  # Aurora Subnet Group
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for Aurora MySQL
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-DBSubnetGroup

  # Aurora Parameter Groups
  AuroraClusterParameterGroup:
    Type: AWS::RDS::DBClusterParameterGroup
    Properties:
      Description: Parameter group for Aurora MySQL cluster
      Family: aurora-mysql8.0
      Parameters:
        character_set_server: utf8mb4
        collation_server: utf8mb4_unicode_ci

  AuroraInstanceParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Parameter group for Aurora MySQL instances
      Family: aurora-mysql8.0
      Parameters:
        max_connections: 1000

  # Aurora Cluster
  AuroraCluster:
    Type: AWS::RDS::DBCluster
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Properties:
      Engine: aurora-mysql
      EngineVersion: 8.0.mysql_aurora.3.08.1
      DatabaseName: !Ref DBName
      MasterUsername: !Sub '{{resolve:secretsmanager:${AuroraSecret}:SecretString:username}}'
      MasterUserPassword: !Sub '{{resolve:secretsmanager:${AuroraSecret}:SecretString:password}}'
      DBSubnetGroupName: !Ref DBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AuroraSecurityGroup
      DBClusterParameterGroupName: !Ref AuroraClusterParameterGroup
      BackupRetentionPeriod: 1
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-AuroraCluster

  AuroraPrimaryInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Properties:
      Engine: aurora-mysql
      DBClusterIdentifier: !Ref AuroraCluster
      DBInstanceClass: !Ref DBInstanceClass
      DBParameterGroupName: !Ref AuroraInstanceParameterGroup
      DBSubnetGroupName: !Ref DBSubnetGroup
      PubliclyAccessible: false
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-AuroraPrimaryInstance

  # Glue Resources
  GlueDatabase:
    Type: AWS::Glue::Database
    Properties:
      CatalogId: !Ref AWS::AccountId
      DatabaseInput:
        Name: !Join ['_', !Split ['-', !Sub '${AWS::StackName}_db']]

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

  SSMVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      VpcId: !Ref VPC
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      SecurityGroupIds:
        - !Ref SSMSecurityGroup

  SSMMessagesVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      VpcId: !Ref VPC
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      SecurityGroupIds:
        - !Ref SSMSecurityGroup

  # SSM Bastion
  SSMBastionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
      SubnetId: !Ref PrivateSubnet1
      IamInstanceProfile: !Ref SSMInstanceProfile
      SecurityGroupIds:
        - !Ref SSMBastionSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SSMBastion

またこのテンプレートをデプロイ後にAurora MySQLのデータベースに接続して、テーブルとGlue Crawlerのためのユーザーを作成しておきます。

簡単に手順を記します。
作成されたEC2にセッションマネージャー経由で接続して、以下のコマンドを実行してください。

  1. mysqlクライアントのインストール
sudo dnf -y update
sudo dnf -y install mariadb105
  1. データベースに接続
mysql -h <Aurora MySQLクラスターエンドポイント> -u admin -p

その後パスワードの入力を求められるので、先程のテンプレートで作成したAuroraSecretのパスワードを入力してください。

  1. テーブルの作成
USE mydb;

CREATE TABLE employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    department VARCHAR(100)
);
INSERT INTO employees (name, department) VALUES 
    ('山田太郎', '営業部'),
    ('鈴木花子', '開発部'),
    ('佐藤一郎', '人事部'),
    ('田中美咲', '営業部'),
    ('高橋健一', '開発部'),
    ('伊藤香澄', '経理部'),
    ('渡辺翔太', '人事部'),
    ('小林優子', '開発部');

CREATE TABLE departments (
    id INT AUTO_INCREMENT PRIMARY KEY,
    department_name VARCHAR(100),
    location VARCHAR(100)
);
INSERT INTO departments (department_name, location) VALUES
    ('営業部', '東京本社'),
    ('開発部', '大阪支社'),
    ('人事部', '東京本社'),
    ('経理部', '名古屋支社');
  1. Glue Crawlerのためのユーザーの作成

この例では、employeesテーブルのみを読み取り専用でアクセスできるユーザーを作成します。
これにより、Glue Crawlerは必要なデータのみにアクセスでき、他のテーブルにはアクセスできません。

CREATE USER 'glue_crawler' IDENTIFIED BY 'password';
GRANT SELECT ON mydb.employees TO 'glue_crawler';

Glue Crawler設定手順

おおきく分けて以下の4つの手順です。

  1. セキュリティグループの設定
  2. VPCエンドポイントの設定
  3. Glue Connectionの作成
  4. Glue Crawlerの作成

それでは詳しく見ていきます。

1. セキュリティグループの設定

Glue Crawlerは複数のコンポーネントで構成されており、それらが相互に通信する必要があります。そのため、セキュリティグループには自己参照ルールが必要です。また、Aurora MySQLへのアクセスも必要です。

1.1 Glue Crawler用セキュリティグループの作成

VPCコンソールからセキュリティグループ作成画面を開いてください。
以下項目を埋めて作成してください。

  • セキュリティグループ名: 任意の名前
  • 説明: 任意の説明
  • VPC: Aurora MySQLが存在するVPCを選択

image.png

続いて、先ほど作成したセキュリティグループに自己参照のインバウンドルールを追加してください。

  • タイプ: すべてのTCP
  • ソース: このセキュリティグループ自身

この自己参照ルールは、Glue Crawlerの各コンポーネントが相互に通信するために必要です。

image copy.png
image copy 2.png

1.2 Aurora MySQL側のセキュリティグループの設定

Aurora MySQLのセキュリティグループにGlue Crawler用セキュリティグループからのインバウンドルールを追加してください。

  • タイプ: MYSQL/Aurora (3306)
  • ソース: Glue Crawler用セキュリティグループ

image copy 3.png

この時、Aurora MySQL自身をソースとする自己参照のインバウンドルールも追加されていることを確認してください。
設定されていなければ上記セキュリティグループに加えて設定してください。

AWS Glue から Amazon RDS データストアに JDBC 接続するための Amazon VPC の設定 - AWS Glue

2. VPCエンドポイントの設定

Glue Crawlerはメタデータや一時ファイルの保存など、内部的にさまざまな理由でS3を使用します。
これらの操作はすべてプライベートネットワーク内で行う必要があるため、S3VPCエンドポイントが必要です。

ただしすでにS3VPCエンドポイントが存在する場合は、このセクションをスキップして次に進むことができます。

冒頭で示したテンプレートにはEC2にパッケージをインストールする必要がある都合上、すでにS3VPCエンドポイントが存在します。
詳しくは以下ページをご覧ください。
インターネットにアクセスせずに AL1 または AL2 EC2 インスタンスの yum を更新する | AWS re:Post

2.1 S3用のVPCエンドポイントの作成

VPCコンソールのエンドポイントセクションを開き、エンドポイント作成画面を開いてください。
以下の項目を入力してエンドポイントを作成してください。

  • サービス: com.amazonaws.region.s3を選択
    • エンドポイントのタイプは Gateway を指定
  • VPC: Aurora MySQLが存在するVPCを選択
  • ルートテーブル: Aurora MySQLのプライベートサブネットに紐づくルートテーブルを選択
  • (オプション)リソースベースポリシーの設定

image copy 4.png

3. Glue Connectionの作成

AWS Glueコンソールを開いてください。左メニューから「Connections」を選択して「Create connection」をクリックしてください。
データソースの選択画面でAmazon Auroraを選択し、接続情報を入力してください。

  • Connection details
    • Database instances: 対象のAuroraクラスタ
    • Database name: Glue Crawlerを実行する対象のデータベース名
    • Credential type: Username and password
    • Username: データベースのユーザー名
    • Password: データベースのパスワード
  • Network options:
    • VPC: Aurora MySQLが存在するVPCを選択
    • Subnet: Aurora MySQLのプライベートサブネットを選択
    • Security groups: Glue Crawler用セキュリティグループを選択

続いてプロパティ情報を入力してください。

  • Name: 任意のコネクション名
  • (オプション) DescriptionやTagの入力

続いてレビュー画面で問題がなければ「Create connection」をクリックしてください。

image copy 5.png
image copy 6.png

4. Glue Crawlerの作成

AWS Glueコンソールを開いてください。左メニューから「Crawlers」を選択して「Create crawler」をクリックしてください。
続いてGlue Crawler情報を入力してください。

  • Name: 任意の名前
  • (オプション) DescriptionやTagの入力

image copy 7.png

続いてデータストアの設定を行ってください。

  • Data source configuration: Not yet
  • Data sources: Add a data sourceをクリック
  • Data source: 「JDBC」を選択
  • Connection: 作成したConnectionを選択
    • Include path: DatabaseName/%を入力(DatabaseNameはConnectionで指定したデータベース名)
    • 「Add a JDBC data source」をクリック
    • 「Next」をクリック

alt text

続いてIAMロールの設定を行ってください。

  • 新規作成または既存のロールを選択
  • 必要な権限:
    • AWSGlueServiceRole: Glue Crawlerの基本的な操作(S3へのアクセス、CloudWatch Logsへのログ出力など)に必要です
    • Aurora MySQLへの接続権限(rds-db:connectの許可): Aurora MySQLに接続するために必要です

alt text

必要な権限は次の公式ドキュメントの通りです。
IAM データベースアクセス用の IAM ポリシーの作成と使用 - Amazon Aurora

どうやらIAMロールでは接続許可までをコントロールし、その後の権限(参照できるデータの範囲の制限など)はデータベースユーザー側で行えるようですね。
今回はAWSマネージドの AWSGlueServiceRole に加え、インラインポリシーで rds-db:connect を設定しています。

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:REGION:ACCOUNT_ID:dbuser:*/glue_crawler"
         ]
      }
   ]
}

続いて出力の設定を行ってください。

  • Database: データを格納するGlue Databaseを選択
  • Prefix added to tables: 任意のプレフィックス(例: aurora_)

alt text

必要であればスケジュールの設定を行い、最後に「Create crawler」をクリックしてください。

alt text

5. Glue Crawlerの実行

作成したGlue Crawlerを選択し、「Run crawler」をクリックしてください。
Glue Crawlerが完了するとGlue Data Catalogで登録されたテーブルを確認できます。

alt text
Glue Data Catalogに登録されたテーブルの一覧。
employeesテーブルのみが登録されていることがわかります。

alt text
employeesテーブルのスキーマ情報。
Glue Crawlerによって正しくメタデータが取得されています。

mydb には employees と departments の2つのテーブルが作成されていますが、Glue Data Catalogには employees のみが登録されています。
接続に使用しているデータベースユーザーの権限が適用された上で、メタデータの取得ができていることがわかりますね。

トラブルシューティング

Glue Crawlerの設定中に発生する可能性のある一般的な問題と解決策をまとめました。

1. VPCエンドポイントの検証に失敗する

症状: Glue Connectionの作成時に「VPC S3 エンドポイントの検証に失敗しました」というエラーが表示される。

原因: S3VPCエンドポイントが正しく設定されていない、またはルートテーブルにS3VPCエンドポイントへのルートが追加されていない。

解決策:

  1. S3VPCエンドポイントが存在することを確認する
  2. プライベートサブネットのルートテーブルにS3VPCエンドポイントへのルートが追加されていることを確認する
  3. 必要に応じて、S3VPCエンドポイントを再作成する

2. データベースへの接続に失敗する

症状: Glue Crawlerの実行時にデータベースへの接続に失敗する。

原因: セキュリティグループの設定が不適切、またはデータベースユーザーの権限が不足している。

解決策:

  1. Aurora MySQLのセキュリティグループにGlue Crawler用セキュリティグループからのインバウンドルールが追加されていることを確認する
  2. データベースユーザーに適切な権限が付与されていることを確認する
  3. 必要に応じて、セキュリティグループの設定やデータベースユーザーの権限を修正する

3. IAMロールの権限が不足している

症状: Glue Crawlerの実行時にIAMロールの権限が不足しているというエラーが表示される。

原因: IAMロールに必要な権限が付与されていない。

解決策:

  1. IAMロールにAWSGlueServiceRoleが付与されていることを確認する
  2. IAMロールにAurora MySQLへの接続権限(rds-db:connect)が付与されていることを確認する
  3. 必要に応じて、IAMロールに必要な権限を追加する

まとめ

この記事ではAurora MySQLに対してGlue Crawlerを実行するための手順をまとめました。
今回は検証していませんがAurora MySQL以外のデータソースに関してもGlue Connectionさえ作成できればCrawlerでは適切な権限の付与のみで対応できると思います。

設定することや考慮事項が多く、煩雑に感じるかもしれませんが、1つずつ確認していけばきちんと設定できます。

それではまた次の記事でお会いしましょう。

参考

この記事をシェアする

関連記事