Azure Blob Storage を外部ステージに設定し COPY コマンドによるデータロードを試してみる #SnowflakeDB
はじめに
Snowflake で Azure の Blob Storage を外部ステージに設定し、COPY コマンドによる基本的なデータロードを試してみましたので、その内容をまとめてみます。
前提条件
以下の環境で検証しています。
- Snowflake
- クラウドサービス:Microsoft Azure
- リージョン:japaneast
- ストレージ アカウントのリージョン:japaneast
- リソースグループは作成済み
Blob Storage の作成
ストレージ アカウントの作成
Azure ポータルから下図の内容でストレージ アカウントを作成しました。
コンテナーの追加
作成したストレージ アカウントの「ストレージ ブラウザー」メニューから「BLOB コンテナー > コンテナーの追加」をクリックします。
下図の表示となるので、コンテナー名を指定し作成します。
作成したコンテナーの「アップロード」タブよりファイルをアップロードできます。
ストレージアカウントの「セキュリティとネットワーク > ネットワーク」メニューをクリックするとデフォルトでは下図の表示となっていました。
ここでは試しに「パブリックネットワークアクセス スコープ」を「Enabled from selected networks」に変更し、自分の接続元 IP アドレスを指定しました。
Snowflake:データロードの構成
ここから Snowflake 側もあわせて外部ステージ経由のデータロードのための構成を試してみます。
VNet サブネット IDs の許可
先の手順で、このストレージ アカウントでは、特定のIPアドレスからのアクセスのみを許可するよう構成されているため、Snowflake アカウントがアクセスできるように、その VNet サブネットIDを許可リストに追加します。
はじめに Snowflake で以下を実行し、Snowflake アカウント側の VNet サブネット IDs を取得します。
USE ROLE ACCOUNTADMIN;
SELECT SYSTEM$GET_SNOWFLAKE_PLATFORM_INFO();
出力は以下のようになり、ここではsnowflake-vnet-subnet-id
として/subscription
から始まる2つのサブネット ID が返ってきました。
{
"snowflake-vnet-subnet-id":
["/subscriptions/xxxxx",
"/subscriptions/xxxxx"],
"storage-account-resource-id":"/subscriptions/xxxxx"
}
Azure 側で Snowflake サブネットID ごとにネットワークルールを追加します。
Azure ポータルで Cloud shell を起動し ID ごとに以下を実行します。
az storage account network-rule add --resource-group "<リソースグループ名>" --account-name "<ストレージアカウント名>" --subnet "Snowflakeアカウント側のサブネットID"
こちらの手順は、以下を参考にしました。
設定を確認します。すでに設定済みの IP アドレスとあわせて新たに追加した Snowflake アカウント側の Vnet のサブネット ID が追加されています。
$ az storage account show --name "<ストレージアカウント名>" --resource-group "<リソースグループ名>" --query 'networkRuleSet'
{
"bypass": "AzureServices",
"defaultAction": "Deny",
"ipRules": [
{
"action": "Allow",
"ipAddressOrRange": "xx.xx.xx.xx"
}
],
"ipv6Rules": [],
"resourceAccessRules": [],
"virtualNetworkRules": [
{
"action": "Allow",
"state": "Succeeded",
"virtualNetworkResourceId": "/subscriptions/xxxxx"
},
{
"action": "Allow",
"state": "Succeeded",
"virtualNetworkResourceId": "/subscriptions/xxxxx"
}
]
}
ストレージ統合を作成
Snowflake 側で Azure のストレージへのアクセス権を取得するためのオブジェクトとして、ストレージ統合を作成します。
この際、以下の情報が必要となるので、事前に取得・確認しておきます。
- Microsoft Entra テナントID
- ストレージ アカウント名
- コンテナー名
テナント ID は、Azure ポータルの場合「Microsoft Entra ID > プロパティ > テナントID」より確認できます。
各情報を使用し、Snowflake 側でストレージ統合オブジェクトを作成します。
CREATE STORAGE INTEGRATION my_azure_storage_int
TYPE = EXTERNAL_STAGE
STORAGE_PROVIDER = 'AZURE'
ENABLED = TRUE
AZURE_TENANT_ID = '<Microsoft Entra テナントID>'
STORAGE_ALLOWED_LOCATIONS = ('azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/');
ストレージに Snowflake アクセスを許可する
ストレージ統合を作成したら、Azure 側で Snowflake にアクセス権を付与する作業が必要です。
以下を実行し、Microsoft のアクセス許可リクエストページへの URL とアプリケーション名を取得します。
DESC STORAGE INTEGRATION my_azure_storage_int;
出力のAZURE_CONSENT_URL
が Microsoft のアクセス許可リクエストページへの URL となるので、コピーしてブラウザで開きます。
また、AZURE_MULTI_TENANT_APP_NAME
プロパティの値も後ほど使用するので控えておきます。
管理者アカウントでサインインし、「承諾」をクリックします。
承諾後は、Azure ポータルの「Microsoft Entra ID > エンタープライズ アプリケーション」より Snowflake サービスプリンシパルが作成されていることを確認できます。
続けて、Snowflake サービスプリンシパルにストレージへのアクセス権(ロール)を付与します。
Azure ポータルの対象ストレージ アカウントメニューの「アクセス制御(IAM) > 追加 > ロールの割り当ての追加」をクリックします。
各種ロールが表示されるので「Blob」等で検索フィルタし Snowflake サービスプリンシパルへの付与対象となるロールを表示します。
付与対象となるロールは、以下のいずれかです。
- ストレージ BLOB データ閲覧者
- 読み取りアクセスのみを許可
- ストレージ BLOB データ共同作成者
- 読み取りおよび書き込みアクセスを許可
- データのロードに加え、アンロードや REMOVE コマンドによるファイルの削除も可能になります
ここでは「ストレージ BLOB データ閲覧者」を選択し、「次へ」をクリックします。「+ メンバーを選択する」をクリックし、DESC STORAGE INTEGRATION
で取得したAZURE_MULTI_TENANT_APP_NAME
のアンダースコアより前の文字列を検索します。
検索結果から該当のサービスプリンシパルを選択し、ロールを割り当てます。
割り当て後は「ロールの割り当て」タブより対象のサービスプリンシパルに対して、指定のロールが割り当てられていることを確認できます。
外部ステージの作成
Azure 側の設定が完了したので、Snowflake で外部ステージを作成します。
CREATE STAGE my_azure_stage
STORAGE_INTEGRATION = my_azure_storage_int
URL = 'azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/';
オブジェクトを追加後、ls コマンドでステージ内のファイルを確認します。
>ls @my_azure_stage;
+----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------+
| name | size | md5 | last_modified |
|----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------|
| azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/sample_data_20240412.csv | 297 | 9ac383c69c86628e39bde1e6e0fe8d7f | Thu, 9 Oct 2025 08:22:38 GMT |
+----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------+
サブネット ID の許可がない場合、以下のようなエラーメッセージでした。
>ls @my_azure_stage;
091003 (22000): Failure using stage area. Cause: [This request is not authorized to perform this operation. (Status Code: 40
テーブルを作成し COPY コマンドでロードしてみます。
--ファイルフォーマットを作成
CREATE OR REPLACE FILE FORMAT my_csv_format
TYPE = CSV
FIELD_DELIMITER = ','
PARSE_HEADER = TRUE
EMPTY_FIELD_AS_NULL = true
COMPRESSION = AUTO;
--スキーマ検出機能によりテーブルを定義
>CREATE OR REPLACE TABLE mytable
USING TEMPLATE (
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
FROM TABLE(
INFER_SCHEMA(
LOCATION=>'@my_azure_stage/',
FILE_FORMAT=>'my_csv_format'
)
)
);
+-------------------------------------+
| status |
|-------------------------------------|
| Table MYTABLE successfully created. |
+-------------------------------------+
--コピーコマンドでロード
>COPY INTO mytable
FROM @my_azure_stage
FILE_FORMAT=(FORMAT_NAME = 'my_csv_format')
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE;
+----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
| file | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name |
|----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------|
| azure://<ストレージアカウント>.blob.core.windows.net/<コンテナー名>/sample_data_20240412.csv | LOADED | 10 | 10 | 1 | 0 | NULL | NULL | NULL | NULL |
+----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
>SELECT * FROM MYTABLE;
+----+--------------+----------+-----------+
| ID | Val | Category | Date |
|----+--------------+----------+-----------|
| 1 | 1.114388475 | A | 2024/4/12 |
| 2 | -0.617730236 | B | 2024/4/12 |
| 3 | -1.226039849 | A | 2024/4/12 |
| 4 | -1.249994022 | A | 2024/4/12 |
| 5 | 0.775035178 | A | 2024/4/12 |
| 6 | 0.442294860 | C | 2024/4/12 |
| 7 | 0.819239543 | A | 2024/4/12 |
| 8 | -0.921003054 | B | 2024/4/12 |
| 9 | -0.288820276 | B | 2024/4/12 |
| 10 | 0.752006217 | B | 2024/4/12 |
+----+--------------+----------+-----------+
問題なくデータをロードできました。
さいごに
Snowflake で Azure の Blob Storage を外部ステージに設定し、COPY コマンドによるデータロードを試してみました。
ストレージ統合周りの Azure での設定が必要な箇所は、他のクラウドサービスと設定内容が異なりますが、外部ステージ作成以降は同じ手順でロードできます。
こちらの内容が何かの参考になれば幸いです。