Snowflakeオープンカタログをはじめるにあたり

概要

SnowflakeオープンカタログはApache Iceberg™のオープンカタログです。オープンカタログは、Snowflake上で管理される SaaS サービスとして利用できます。また、オープンソースコードとして提供されており、自分でビルドしてデプロイすることもできます。オープンカタログは、ロールベースのアクセス制御によるクロスエンジンセキュリティを備えたApache Iceberg REST カタログの実装を提供します。

このチュートリアルでは、Snowflakeで管理されるオープンカタログを使い始める方法を学びます。

学習内容

  • 新しいオープンカタログアカウントの作成方法

  • オープンカタログアカウントで新しいIcebergカタログを作成し、 RBAC を使用してセキュリティ保護する方法。

  • カタログでテーブルを作成し、クエリを実行するためにApache Spark™を使用する方法。

  • Snowflakeを使用してカタログ内のテーブルに対してクエリを実行する方法。

  • SnowflakeでマネージドIcebergテーブルをオープンカタログにミラーリングまたは公開する方法。

次が必要になります

  • Snowflake組織の ORGADMIN 権限(新しいオープンカタログアカウントを作成するため)。

  • Snowflake組織の ACCOUNTADMIN 権限(オープンカタログアカウントに接続するため)。このSnowflakeアカウントは、Snowflake組織アカウントと同じである必要はありません。

作業内容

2つのユースケースを完成させます。

  • ユースケース1: オープンカタログでカタログを作成し、Apache Sparkを使用してテーブルを作成し、Apache SparkとSnowflakeを使用してテーブルにクエリを実行する。

    画像1: ダイアグラム

  • ユースケース2: Snowflakeを使用してSnowflake DB アカウントにApache Icebergテーブルを作成し、それをオープンカタログに公開してApache Sparkがそれに対してクエリを実行できるようにする。

    画像2: ダイアグラム

環境の設定

ノートパソコンへのConda、Spark、Jupyterのインストール

このチュートリアルでは、簡単に開発環境を作成し、必要なパッケージをダウンロードするためにCondaを使用できます。これは、Apache Spark™を使用してSnowflakeが管理するApache Iceberg™のテーブルを読み取るためにユースケース2に従う場合にのみ必要です。これは、Snowflake上でIcebergテーブルを作成または使用するために必要ではありません。

  1. Condaをインストールするには、 OS 固有の手順を使用してください。

  2. environment.yml というファイルを以下の内容で作成します。

    name: iceberg-lab
    channels:
      - conda-forge
    dependencies:
      - findspark=2.0.1
      - jupyter=1.0.0
      - pyspark=3.5.0
      - openjdk=11.0.13
    
    Copy
  3. 必要な環境を作成するには、シェルで以下を実行します。

    conda env create -f environment.yml
    
    Copy

オープンカタログアカウントの作成

オープンカタログアカウントは、 ORGADMIN によってのみ作成できます。

  1. Snowsightのナビゲーションペインで、 管理者 > アカウント を選択します。

  2. +アカウント ドロップダウンで、 Snowflakeオープンカタログアカウントを作成 を選択します。

  3. Snowflake オープンカタログアカウント ダイアログを完了します。

    • クラウド: Apache Iceberg™テーブルを保管するクラウドプロバイダー。

    • リージョン: Icebergテーブルを保管するリージョン。

    • エディション: オープンカタログアカウントのエディション。

  4. 次へ を選択します。

  5. 新規アカウントを作成のダイアログで、アカウント名、ユーザー名、パスワード、およびメールフィールドを入力します。

  6. アカウントを作成 を選択します。新しいオープンカタログアカウントが作成され、確認ボックスが表示されます。

  7. 確認ボックスで、 アカウントロケーター URL を選択し、ウェブブラウザでアカウントロケーター URL を開きます。

  8. アカウントロケーター URL をブックマークします。オープンカタログにサインインする際には、アカウントロケーター URL を指定する必要があります。

オープンカタログのウェブインターフェイスにサインイン

  1. アカウント作成後にメールで届いたアカウント URL をクリックする、 OR https://app.snowflake.comに移動します。

  2. 別のアカウントにサインイン をクリックし、先ほど作成したオープンカタログアカウントでサインインします。

ユースケース1: Apache Spark™を使用してテーブルを作成する

S3ロケーションへのアクセスを許可するIAMポリシーを作成する

まだ持っていない場合は、S3ロケーションへのアクセスを許可する IAM ポリシーを作成することから始めます。このポリシーを作成する手順については、S3ロケーションへのアクセスを許可する IAM ポリシーの作成 を参照してください。

IAMロールを作成する

まだ持っていない場合は、オープンカタログ用の AWS IAM ロールを作成して、S3バケットに権限を付与します。手順については、IAM ロールの作成 を参照してください。ポリシーを選択するよう促されたら、S3ロケーションへのアクセスを許可する IAM ポリシーを選択します。

オープンカタログでの内部カタログの作成

オープンカタログアカウントの内部カタログを使用してテーブルを作成し、クエリを実行し、Apache Spark™またはその他のクエリエンジンを使用してテーブルに対して DML を実行することができます。

  1. 新しいオープンカタログアカウントにサインインします。

  2. 新しいカタログを作成するには、左側のペインで カタログ を選択します。

  3. 右上の +カタログ を選択します。

  4. カタログを作成 ダイアログで、以下の詳細を入力します。

    • デフォルトのベースロケーション: テーブルデータが保管される場所。

    • 追加のロケーション(オプション): 複数のストレージ場所をカンマ区切りで指定します。これは主に、このカタログの異なる場所からテーブルをインポートする必要がある場合に使用されます。空白のままにできます。

    • S3ロール ARN: ストレージ場所への読み書きアクセスを持つ AWS ロール。オープンカタログ用に作成した IAM ロールの ARN を入力します。

    • 外部 ID: (オプション): カタログユーザーとストレージアカウントの信頼関係を作成する際に提供したい秘密。これをスキップすると自動生成されます。このチュートリアルでは、 abc123 のような単純な文字列を使用します。

  5. 作成 を選択します。カタログが作成され、以下の値がカタログに追加されます。

    • オープンカタログアカウントの IAM ユーザー名

    • 外部 ID を自分で入力しなかった場合、 外部 ID がカタログ用に自動生成されます。

    この値は、次のセクションで信頼関係を作成するときに必要になります。

信頼関係の構築

カタログを作成したら、上記の構成で指定したS3ロールがストレージ場所のデータを読み書きできるように、信頼関係を設定する必要があります。このタスクを完了するには、カタログのS3 IAM ユーザーと外部 ID が必要になります。

  1. カタログが作成された後、カタログをリストで選択すると、カタログのS3 IAM ユーザー名と外部 ID が表示されます。

  2. 信頼関係を構築するには、ステップ5: IAM ユーザーにバケットへのアクセス許可を付与する を完了します。

これらの手順に表示されている JSON オブジェクトには:

  • <open_catalog_user_arn> の場合、オープンカタログ UI の IAM ユーザーARN の下にある値を使用します。

  • <open_catalog_external_id> の場合、オープンカタログ UI の 外部 ID の下にある値を使用します。

Apache Spark™用の新しい接続の作成

作成したカタログに対してクエリを実行するために、Apache Spark用の新しい接続(client_id/client_secretペア)を作成します。

  1. オープンカタログの左ペインで、 接続 タブを選択し、右上の +接続 を選択します。

  2. サービス接続を構成 ダイアログで、新しいプリンシパルロールを作成するか、利用可能なロールの1つから選択します。

  3. 作成 を選択します。

  4. サービス接続を構成 ダイアログから、クライアント ID とクライアントシークレットをテキストエディタにコピーするには、 <CLIENT ID>:<SECRET>として フィールド内で コピー を選択します。

    重要

    これらのテキスト文字列を後でオープンカタログサービスから取り出すことはできないため、今すぐコピーしておく必要があります。これらのテキスト 文字列は、Sparkを設定する際に使用します。

接続のためのカタログ権限の設定

ここでは、サービス接続に権限を与え、カタログにアクセスできるようにします。アクセス権限がないと、サービス接続はカタログ上でクエリを実行できません。

  1. ナビゲーションペインで、 カタログ を選択し、リストからカタログを選択します。

  2. 新しいロールを作成するには、 ロール タブを選択します。

  3. +カタログロール を選択します。

  4. カタログロールを作成 ダイアログで、 名前spark_catalog_role と入力します。

  5. 権限 では、 CATALOG_MANAGE_CONTENT を選択し、 作成 を選択します。

    このロールには、テーブルの作成、読み取り、書き込みの権限が与えられます。

  6. プリンシパルロールへに付与 を選択してします。

  7. カタログロールを付与 ダイアログの 付与するプリンシパルロールmy_spark_admin_role を選択します。

  8. 付与するカタログロール では、 spark_catalog_role を選択し、 付与 を選択します。

このプロシージャの結果、spark_catalog_roleロールがmy_spark_admin_roleに付与され、前のプロシージャで作成したSpark接続の管理者権限が付与されます。

Sparkの設定

ターミナルから以下のコマンドを実行して、設定で作成した仮想環境をアクティブにし、Jupyter Notebooksを開きます。

conda activate iceberg-lab
jupyter notebook
Copy

Sparkの構成

Sparkを構成するには、Jupyter Notebooksで以下のコマンドを実行します。

パラメータの説明を含む詳細については、Sparkにサービス接続を登録する をご参照ください。

import os
os.environ['SPARK_HOME'] = '/Users/<username>/opt/anaconda3/envs/iceberg-lab/lib/python3.12/site-packages/pyspark'

import pyspark
from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('iceberg_lab') \
.config('spark.jars.packages', 'org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.4.1,software.amazon.awssdk:bundle:2.20.160,software.amazon.awssdk:url-connection-client:2.20.160') \
.config('spark.sql.extensions', 'org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions') \
.config('spark.sql.defaultCatalog', 'opencatalog') \
.config('spark.sql.catalog.opencatalog', 'org.apache.iceberg.spark.SparkCatalog') \
.config('spark.sql.catalog.opencatalog.type', 'rest') \
.config('spark.sql.catalog.opencatalog.header.X-Iceberg-Access-Delegation','vended-credentials') \
.config('spark.sql.catalog.opencatalog.uri','https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog') \
.config('spark.sql.catalog.opencatalog.credential','<client_id>:<client_secret>') \
.config('spark.sql.catalog.opencatalog.warehouse','<catalog_name>') \
.config('spark.sql.catalog.opencatalog.scope','PRINCIPAL_ROLE:<principal_role_name>') \
.getOrCreate()

#Show namespaces
spark.sql("show namespaces").show()

#Create namespace
spark.sql("create namespace spark_demo")

#Use namespace
spark.sql("use namespace spark_demo")

#Show tables; this will show no tables since it is a new namespace
spark.sql("show tables").show()

#create a test table
spark.sql("create table test_table (col1 int) using iceberg");

#insert a record in the table
spark.sql("insert into test_table values (1)");

#query the table
spark.sql("select * from test_table").show();
Copy

オプション: S3クロスリージョン

ストレージアカウントがSparkクライアントと異なるリージョンにある場合、追加のSpark構成設定を提供する必要があります。

.config('spark.sql.catalog.opencatalog.client.region','<region_code>') \
Copy

リージョンコードのリストについては、 AWS ドキュメントのリージョンエンドポイントをご参照ください。

以下のコード例は、s3リージョンを含むように修正されています。

import pyspark
from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('iceberg_lab') \
.config('spark.jars.packages', 'org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.4.1,software.amazon.awssdk:bundle:2.20.160,software.amazon.awssdk:url-connection-client:2.20.160') \
.config('spark.sql.extensions', 'org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions') \
.config('spark.sql.defaultCatalog', 'opencatalog') \
.config('spark.sql.catalog.opencatalog', 'org.apache.iceberg.spark.SparkCatalog') \
.config('spark.sql.catalog.opencatalog.type', 'rest') \
.config('spark.sql.catalog.opencatalog.header.X-Iceberg-Access-Delegation','vended-credentials') \
.config('spark.sql.catalog.opencatalog.uri','https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog') \
.config('spark.sql.catalog.opencatalog.credential','<client_id>:<secret>') \
.config('spark.sql.catalog.opencatalog.warehouse','<catalog_name>') \
.config('spark.sql.catalog.opencatalog.scope','PRINCIPAL_ROLE:<principal_role_name>') \
.config('spark.sql.catalog.opencatalog.client.region','<region_code>') \
.getOrCreate()
Copy

Snowflakeを使用したテーブルのクエリ

Snowflakeでカタログ統合オブジェクトを作成し、Snowflakeでオープンカタログのテーブルを表すApache Iceberg™テーブルを作成することができます。次の例では、SnowflakeにIcebergテーブルを作成し、これはSparkによってオープンカタログの内部カタログに作成されたばかりのIcebergテーブルです。

同じSpark接続認証情報を使用することも、新しいSnowflake接続を作成することもできます。新しい接続を作成する場合は、それに応じてロールと権限を設定する必要があります。

  1. カタログ統合オブジェクトの作成:

    CREATE OR REPLACE CATALOG INTEGRATION demo_open_catalog_int 
    CATALOG_SOURCE=POLARIS 
    TABLE_FORMAT=ICEBERG 
    CATALOG_NAMESPACE='<catalog_namespace>' 
    REST_CONFIG = (
    CATALOG_URI ='https://<account>.snowflakecomputing.com/polaris/api/catalog' 
    WAREHOUSE = <catalog_name>
    )
    REST_AUTHENTICATION = (
    TYPE=OAUTH 
    OAUTH_CLIENT_ID='<client_id>' 
    OAUTH_CLIENT_SECRET='<secret>' 
    OAUTH_ALLOWED_SCOPES=('PRINCIPAL_ROLE:ALL') 
    ) 
    ENABLED=true;
    
    # the <catalog_namespace> created in previous step is spark_demo.
    # the <catalog_name> created in previous step is demo_catalog.
    
    Copy
  2. 上記で作成したカタログ統合を使用してSnowflakeでテーブル表現を作成し、テーブルにクエリを実行します。

    create or replace iceberg table test_table
      catalog = 'demo_open_catalog_int'
      external_volume = '<external_volume>'
      catalog_table_name = 'test_table'
    
    select * from test_table;
    
    Copy

ユースケース2: Apache Iceberg™テーブルをSnowflakeからオープンカタログに同期する

SnowflakeにIcebergテーブルがある場合、それをオープンカタログに同期することで、他のエンジンがそれらのテーブルをクエリできます。

オープンカタログでの外部カタログの作成

SnowflakeのIcebergテーブルは、オープンカタログアカウントの外部カタログで同期できます。

  1. 新しいオープンカタログアカウントにサインインします。

  2. 新しいカタログを作成するには、左側のペインで カタログ を選択します。

  3. 右上の +カタログ を選択します。

  4. カタログを作成 ダイアログで、以下の詳細を入力します。

    • 名前: カタログに demo_catalog_ext という名前を付けます。

    • 外部 のトグルを オン に設定します。

    • デフォルトのベースロケーション: テーブルデータが保管される場所。

      注意

      このチュートリアルのユースケース1で作成した内部カタログとは異なるストレージ場所を使用する必要があります。カタログに定義されたアクセス権限が正しく実施されるようにするため、2つの異なるカタログに重複する場所を指定できません。

    • 追加のロケーション(オプション): 複数のストレージ場所をカンマ区切りで指定します。これは主に、このカタログの異なる場所からテーブルをインポートする必要がある場合に使用されます。空白のままにできます。

    • S3ロール ARN: ストレージ場所への読み書きアクセスを持つ AWS ロール。

    • 外部 ID: (オプション): カタログユーザーとストレージアカウントの信頼関係を作成する際に提供したい秘密。これをスキップすると自動生成されます。このチュートリアルでは、 abc123 のような単純な文字列を使用します。

  5. 作成 を選択します。以下の値がカタログに追加されます。

    • オープンカタログアカウントの IAM ユーザー名

    • 外部 ID を自分で入力しなかった場合、 外部 ID がカタログ用に自動生成されます。

Snowflake用接続の作成

  1. オープンカタログの左ペインで、 接続 タブを選択し、右上の +接続 を選択します。

  2. サービス接続を構成 ダイアログで、新しいプリンシパルロールを作成するか、利用可能なロールの1つから選択します。

  3. 作成 を選択します。

  4. サービス接続を構成 ダイアログから、クライアント ID とクライアントシークレットをテキストエディタにコピーするには、 <CLIENT ID>:<SECRET>として フィールド内で コピー を選択します。

    重要

    これらのテキスト文字列を後でオープンカタログサービスから取り出すことはできないため、今すぐコピーしておく必要があります。これらのテキスト 文字列は、Sparkを設定する際に使用します。

カタログ権限の設定

Snowflake接続が外部カタログに適切な権限を持つよう外部カタログの権限を設定するには、以下の手順に従います。

  1. ナビゲーションペインで、 カタログ を選択し、リストで外部カタログを選択します。

  2. 新しいロールを作成するには、 ロール タブを選択します。

  3. +カタログロール を選択します。

  4. カタログロールを作成 ダイアログで、 名前spark_catalog_role と入力します。

  5. 権限 では、 CATALOG_MANAGE_CONTENT を選択し、 作成 を選択します。

    このロールには、テーブルの作成、読み取り、書き込みの権限が与えられます。

  6. プリンシパルロールへに付与 を選択してします。

  7. カタログロールを付与 ダイアログの 付与するプリンシパルロールmy_spark_admin_role を選択します。

  8. 付与するカタログロール では、 spark_catalog_role を選択し、 付与 を選択します。

Snowflakeでのカタログ統合オブジェクトの作成

  1. Snowflakeで、CREATE CATALOG INTEGRATION (Snowflakeオープンカタログ)コマンドを使用して、カタログ統合オブジェクトを作成します。

    CREATE OR REPLACE CATALOG INTEGRATION demo_open_catalog_ext 
      CATALOG_SOURCE=POLARIS 
      TABLE_FORMAT=ICEBERG 
      CATALOG_NAMESPACE='default' 
      REST_CONFIG = (
        CATALOG_URI ='https://<account>.snowflakecomputing.com/polaris/api/catalog' 
        WAREHOUSE = '<catalog_name>'
      )
      REST_AUTHENTICATION = (
        TYPE=OAUTH 
        OAUTH_CLIENT_ID='<client_id>' 
        OAUTH_CLIENT_SECRET='<secret>' 
        OAUTH_ALLOWED_SCOPES=('PRINCIPAL_ROLE:ALL') 
      ) 
      ENABLED=true;
    
    # the <catalog_name> created in previous step is demo_catalog_ext.
    
    Copy

    このコードでは、Snowflakeスキーマ polaris_demo.iceberg 内でマネージドIcebergテーブルが変更されるたびに、他のエンジンがそれらのテーブルにクエリできるようオープンカタログに同期されます。

  2. マネージドIcebergテーブルを作成し、SnowflakeからOpen Catalogに同期します。詳細については、次をご参照ください。

    重要

    外部ボリュームの STORAGE_BASE_URL は、オープンカタログで作成した外部カタログの デフォルトのベースロケーション と一致する必要があります。

    use database polaris_demo;
    use schema iceberg;
    
    # Note that the storage location for this external volume will be different than storage location for external volume in use case 1
    
    CREATE OR REPLACE EXTERNAL VOLUME snowflake_demo_ext
      STORAGE_LOCATIONS =
          (
            (
                NAME = '<storage_location_name>'
                STORAGE_PROVIDER = 'S3'
                STORAGE_BASE_URL = 's3://<s3_location>'
                STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::<aws_acct>:role/<rolename>'
                STORAGE_AWS_EXTERNAL_ID = '<external_id>'
            )
          );
    
    CREATE OR REPLACE ICEBERG TABLE test_table_managed (col1 int)
      CATALOG = 'SNOWFLAKE'
      EXTERNAL_VOLUME = 'snowflake_demo_ext'
      BASE_LOCATION = 'test_table_managed'
      CATALOG_SYNC = 'demo_open_catalog_ext'; 
    
    Copy

注意

テーブルがオープンカタログとの同期に失敗した場合は、 SYSTEM$SEND_NOTIFICATIONS_TO_CATALOG システム関数を実行して、同期失敗の原因を診断してください。詳細については、SYSTEM$SEND_NOTIFICATIONS_TO_CATALOGをご参照ください。

結論

オープンカタログアカウントの内部カタログを使用してテーブルを作成し、クエリを実行し、Apache Spark™またはその他のクエリエンジンを使用してテーブルに対して DML を実行することができます。

Snowflakeでは、オープンカタログのカタログ統合を作成して、以下のタスクを実行できます。

  • オープンカタログのマネージドテーブルに対してクエリを実行する。

  • Snowflakeテーブルをオープンカタログアカウントの外部カタログに同期する。

学習した内容

  • オープンカタログアカウントを作成する。

  • オープンカタログアカウントで内部カタログを作成する。

  • Sparkを使用して内部カタログにテーブルを作成する。

  • Snowflakeを使用してオープンカタログのカタログ統合を作成し、オープンカタログアカウントの内部カタログに作成されたテーブルに対してクエリを実行する。

  • オープンカタログアカウントで外部カタログを作成する。

  • SnowflakeでマネージドApache Iceberg™テーブルを作成し、オープンカタログアカウントの外部カタログに同期する。