SnowflakeのQuickstart「Build a Snowflake Native App with Snowpark Container Services」をやってみた
さがらです。
SnowflakeのQuickstart「Build a Snowflake Native App with Snowpark Container Services」をやってみたので、その内容をまとめてみます。
検証環境
- Ubuntu 24.04LTS(WSL2上で動作)
- Rancher Desktop 1.14.2
1.Overview
このQuickstartの概要についてまとめられています。
このQuickstartを通すことで、Snowpark Container Servicesを用いたSnowflake Native App Frameworkに沿ったアプリケーションをSnowflakeアカウントにデプロイすることが出来ます。
アプリケーションの内容としては、TPC-Hのデータセットを照会して上位の販売員を返し、表示する販売データや販売員の数をGUI上で変更することができるアプリケーションとなっています。アーキテクチャとしては、VueベースのJavaScriptのフロントエンド、FlaskベースのPythonのバックエンド、ルーターとしてのnginx、となっています。
2.Snowflake Application Code
ここでは、Snowflake社が用意している下記のリポジトリをローカルにクローンします。
git clone https://github.com/Snowflake-Labs/sfguide-build-a-native-app-with-spcs
3.Native App Provider Setup
次は、Snowflake側でNative Appの開発・デプロイに必要なオブジェクトの作成をしていきます。
まず、操作用のロールとしてnaspcs_role
というロールを作成します。create application package
など、必要な権限を付与します。
use role accountadmin;
create role if not exists naspcs_role;
grant role naspcs_role to role accountadmin;
grant create integration on account to role naspcs_role;
grant create compute pool on account to role naspcs_role;
grant create warehouse on account to role naspcs_role;
grant create database on account to role naspcs_role;
grant create application package on account to role naspcs_role;
grant create application on account to role naspcs_role with grant option;
grant bind service endpoint on account to role naspcs_role;
次に、アプリケーション用のファイルやコンテナイメージを保存するためのデータベースなどを作成していきます。
use role naspcs_role;
create database if not exists spcs_app;
create schema if not exists spcs_app.napp;
create stage if not exists spcs_app.napp.app_stage;
create image repository if not exists spcs_app.napp.img_repo;
create warehouse if not exists wh_nap with warehouse_size='xsmall';
4.Consumer Privilege Setup
次に、デプロイされたアプリケーションを用いて分析をするためのロール、分析用のデータを格納するデータベース、などのオブジェクトを作成します。
まずは分析用のロールとしてnac
というロールを作成します。
use role accountadmin;
create role if not exists nac;
grant role nac to role accountadmin;
create warehouse if not exists wh_nac with warehouse_size='xsmall';
grant usage on warehouse wh_nac to role nac with grant option;
grant imported privileges on database snowflake_sample_data to role nac;
grant create database on account to role nac;
grant bind service endpoint on account to role nac with grant option;
grant create compute pool on account to role nac;
grant create application on account to role nac;
分析用のデータを格納するデータベース・スキーマ・テーブルを作成します。
use role nac;
create database if not exists nac_test;
create schema if not exists nac_test.data;
use schema nac_test.data;
create view if not exists orders as select * from snowflake_sample_data.tpch_sf10.orders;
5. Build and Upload Container Images
これまでの工程で格納場所は出来たので、コンテナイメージをビルドしてSnowflake上のイメージリポジトリにプッシュしていきます。
5.1 Get Image Repository URL
まず、Snowflake上で下記のクエリを実行して、コンテナイメージのアップロード先を確認し、コピーしておきます。
use role naspcs_role;
show image repositories in schema spcs_app.napp;
5.2 Build and Push Images
次に、コンテナイメージをビルドし、Snowflakeのイメージリポジトリにプッシュしていきます。
このチュートリアルでは2種類の方法が提示されているのですが、Step 5.2.2 - Individual Docker Commands
の方法に沿ってやっていきます。
※ここから、<SNOWFLAKE_REPO>
は先程コピーしたイメージリポジトリのURLに書き換えて各コマンドを実行していきます。
まず、Snowflake上のイメージリポジトリにログインします。
docker login <SNOWFLAKE_REPO>
次に、バックエンドに関するコンテナイメージをビルドし、Snowflakeのイメージリポジトリにプッシュします。
cd backend
docker build --platform linux/amd64 -t eap_backend .
cd ..
docker tag eap_backend <SNOWFLAKE_REPO>/eap_backend
docker push <SNOWFLAKE_REPO>/eap_backend
次に、フロントエンドに関するコンテナイメージをビルドし、Snowflakeのイメージリポジトリにプッシュします。
cd frontend
docker build --platform linux/amd64 -t eap_frontend .
cd ..
docker tag eap_frontend <SNOWFLAKE_REPO>/eap_frontend
docker push <SNOWFLAKE_REPO>/eap_frontend
最後に、ルーターに関するコンテナイメージをビルドし、Snowflakeのイメージリポジトリにプッシュします。
cd router
docker build --platform linux/amd64 -t eap_router .
cd ..
docker tag eap_router <SNOWFLAKE_REPO>/eap_router
docker push <SNOWFLAKE_REPO>/eap_router
あとはQuickstartにも載っていないおまけですが、以下のクエリを実行するとプッシュしたイメージの一覧が確認できます。
show images in image repository spcs_app.napp.img_repo;
5.3 Upload Native App Code
次に、App packageの構築に使用するコードをSPCS_APP.NAPP.APP_STAGE
ステージにアップロードします。
クローンしたリポジトリの/app/src
フォルダ内にあるsetup.sql
、fullstack.yaml
、manifest.yml
、readme.md
を全てSPCS_APP.NAPP.APP_STAGE
ステージにアップロードします。
アップロード後、SPCS_APP.NAPP.APP_STAGE
ステージは下図のようになります。
参考までに、各ファイルの内容は下記のようになっています。
setup.sql
:アプリケーションに関連するロールやスキーマの作成と、アプリケーションの起動や停止に使用するストアドプロシージャを定義するSQLが記述されたファイル。setup scriptに関して詳細は公式Docもご覧ください。- 下記の内容はサンプルコードをそのまま貼り付けていますが、個人的にはロールのベストプラクティスに沿って、各ロールをSYSADMINにGRANTして各オブジェクトをSYSADMIN・ACCOUNTADMINも見れるようにした方が良いと思います。
CREATE APPLICATION ROLE app_admin;
CREATE APPLICATION ROLE app_user;
CREATE SCHEMA IF NOT EXISTS app_public;
GRANT USAGE ON SCHEMA app_public TO APPLICATION ROLE app_admin;
GRANT USAGE ON SCHEMA app_public TO APPLICATION ROLE app_user;
CREATE OR ALTER VERSIONED SCHEMA v1;
GRANT USAGE ON SCHEMA v1 TO APPLICATION ROLE app_admin;
CREATE PROCEDURE v1.register_single_callback(ref_name STRING, operation STRING, ref_or_alias STRING)
RETURNS STRING
LANGUAGE SQL
AS $$
BEGIN
CASE (operation)
WHEN 'ADD' THEN
SELECT system$set_reference(:ref_name, :ref_or_alias);
WHEN 'REMOVE' THEN
SELECT system$remove_reference(:ref_name);
WHEN 'CLEAR' THEN
SELECT system$remove_reference(:ref_name);
ELSE
RETURN 'Unknown operation: ' || operation;
END CASE;
RETURN 'Operation ' || operation || ' succeeds.';
END;
$$;
GRANT USAGE ON PROCEDURE v1.register_single_callback( STRING, STRING, STRING) TO APPLICATION ROLE app_admin;
CREATE OR REPLACE PROCEDURE app_public.start_app(poolname VARCHAR, whname VARCHAR)
RETURNS string
LANGUAGE sql
AS $$
BEGIN
EXECUTE IMMEDIATE 'CREATE SERVICE IF NOT EXISTS app_public.st_spcs
IN COMPUTE POOL Identifier(''' || poolname || ''')
FROM SPECIFICATION_FILE=''' || '/fullstack.yaml' || '''
QUERY_WAREHOUSE=''' || whname || '''';
GRANT USAGE ON SERVICE app_public.st_spcs TO APPLICATION ROLE app_user;
GRANT SERVICE ROLE app_public.st_spcs!ALL_ENDPOINTS_USAGE TO APPLICATION ROLE app_user;
RETURN 'Service started. Check status, and when ready, get URL';
END;
$$;
GRANT USAGE ON PROCEDURE app_public.start_app(VARCHAR, VARCHAR) TO APPLICATION ROLE app_admin;
CREATE OR REPLACE PROCEDURE app_public.stop_app()
RETURNS string
LANGUAGE sql
AS
$$
BEGIN
DROP SERVICE IF EXISTS app_public.st_spcs;
END
$$;
GRANT USAGE ON PROCEDURE app_public.stop_app() TO APPLICATION ROLE app_admin;
CREATE OR REPLACE PROCEDURE app_public.app_url()
RETURNS string
LANGUAGE sql
AS
$$
DECLARE
ingress_url VARCHAR;
BEGIN
SHOW ENDPOINTS IN SERVICE app_public.st_spcs;
SELECT "ingress_url" INTO :ingress_url FROM TABLE (RESULT_SCAN (LAST_QUERY_ID())) LIMIT 1;
RETURN ingress_url;
END
$$;
GRANT USAGE ON PROCEDURE app_public.app_url() TO APPLICATION ROLE app_admin;
GRANT USAGE ON PROCEDURE app_public.app_url() TO APPLICATION ROLE app_user;
fullstack.yaml
:上述のsetup.sql内で定義しているストアドプロシージャapp_public.start_app
内で使用する、作成するServiceの仕様をまとめたファイル。
spec:
containers:
- name: eap-frontend
image: /spcs_app/napp/img_repo/eap_frontend
env:
VUE_APP_API_URL: /api/snowpark
- name: eap-backend
image: /spcs_app/napp/img_repo/eap_backend
- name: eap-router
image: /spcs_app/napp/img_repo/eap_router
env:
FE_SERVER: 127.0.0.1:8080
BE_SERVER: 127.0.0.1:8081
endpoints:
- name: app
port: 8000
public: true
manifest.yml
:Application Packageがアプリケーションを作成・管理するために必要な情報を定義している。セットアップスクリプト(今回でいうとsetup.sql
)の場所、readmeファイルの場所、バージョン定義、アプリの構成情報が含まれます。manifest fileに関しては公式Docも併せてご覧ください。
#version identifier
manifest_version: 1
version:
name: V1
label: "Version One"
comment: "The first version of our Native Application that includes SPCS"
#artifacts that are distributed from this version of the package
artifacts:
readme: readme.md
setup_script: setup.sql
container_services:
images:
- /spcs_app/napp/img_repo/eap_frontend
- /spcs_app/napp/img_repo/eap_backend
- /spcs_app/napp/img_repo/eap_router
privileges:
- CREATE COMPUTE POOL:
description: "Enable application to create its own compute pool(s)"
- BIND SERVICE ENDPOINT:
description: "Enables application to expose service endpoints"
- CREATE WAREHOUSE:
description: "Enables application to create its own warehouse(s)"
references:
- ORDERS_TABLE:
label: "Orders View"
description: "View created on Orders table from TPC-H samples"
privileges:
- SELECT
object_type: VIEW
multi_valued: false
register_callback: v1.register_single_callback
readme.md
:Snowsightからアプリケーションの詳細を確認した際に表示されるテキスト(Markdownで記述)
# build-a-native-app-with-spcs
How to Build a Native App that includes Snowpark Container Services
6.Create Application Package
次に、Application Packageを作成し、アプリ利用者でインストール出来るようにnac
ロールに必要な権限の付与も行います。alter application
コマンドは30秒ほど要するためご注意ください。
use role naspcs_role;
create application package spcs_app_pkg;
alter application package spcs_app_pkg add version v1 using @spcs_app.napp.app_stage;
grant install, develop on application package spcs_app_pkg to role nac;
このコマンドが完了すると、SPCS_APP_PKG
というApplication Packageが作られて、Databases
から確認できます。
また、ステージに置いたmanifest.yml
を参照して実行しているので、show versions in application
を実行すると下図のようにmanifest.yml
を参照した内容で新しいバージョンV1が作成されます。
show versions in application package spcs_app_pkg;
Snowsightからも、Projects
のApp Packages
から作成したApplication Packageが確認できます。
7.Install & Run Application
Snowflake上にApplication Packageは構築できたので、あとはこのApplication Packageを用いてアプリケーションをインストールしてSnowpark Container Services上で起動していきます。
7.1 Install App as the Consumer
今回アプリを利用するロールであるnac
ロールを使って、Application Packageからアプリケーションをインストールします。
use role nac;
create application spcs_app_instance from application package spcs_app_pkg using version v1;
7.2 Create Compute Pool and Grant Privileges
インストールしたアプリケーション用のSnowpark Container ServicesのCompute Poolを作成し、必要な権限を付与します。
use database nac_test;
use role nac;
create compute pool pool_nac for application spcs_app_instance
min_nodes = 1 max_nodes = 1
instance_family = cpu_x64_s
auto_resume = true;
grant usage on compute pool pool_nac to application spcs_app_instance;
grant usage on warehouse wh_nac to application spcs_app_instance;
grant bind service endpoint on account to application spcs_app_instance;
CALL spcs_app_instance.v1.register_single_callback(
'ORDERS_TABLE' , 'ADD', SYSTEM$REFERENCE('VIEW', 'NAC_TEST.DATA.ORDERS', 'PERSISTENT', 'SELECT'));
7.3 Start App Service
これでアプリケーションを動かす準備は整ったので、実際にアプリケーションを起動してみます。
まず、下記のストアドプロシージャを実行して、作成したCompute Poolとウェアハウスを利用してアプリケーションを起動します。
call spcs_app_instance.app_public.start_app('POOL_NAC', 'WH_NAC');
その後、下記の別のストアドプロシージャを実行して、アプリケーションのURLを確認します。
call spcs_app_instance.app_public.app_url();
起動には数分かかるため、準備が整っていないと下図のように結果が返ってきます。
無事に準備が整った上でこのストアドプロシージャを実行すると、下図のようにURLが返ってきます。
このURLをブラウザで貼り付けてEnterを押してみると、下図のように認証の画面が表示されます。
認証を終えてサインインすると、下図のようにアプリケーションが表示されました。
また、SnowsightのApps欄からも同じようにインストールしたアプリケーションを確認できます。
右側の「…」からView details
を押すことで、アプリケーションに関する情報を得ることが出来ます。例えば、About the app
タブでは、ステージにアップロードしたreadme.md
の内容が表示されています。(右上のLaunch app
を押してもワークシートに移動するだけでアプリケーションの画面には遷移しないためご注意ください。)
8.Cleanup
このままアプリケーションを起動したまま放置するとコストがかなりかかってしまいますので、下記のクエリを実行してクリーンアップします。
※Quickstartに記載のあったdrop application spcs_app_instance
はそのまま実行するとエラーとなったので、cascade
オプションを追加しています。
--clean up consumer objects
use role nac;
drop application spcs_app_instance cascade;
drop compute pool pool_nac;
drop database nac_test;
--clean up provider objects
use role naspcs_role;
drop application package spcs_app_pkg;
drop database spcs_app;
drop warehouse wh_nap;
--clean up prep objects
use role accountadmin;
drop warehouse wh_nac;
drop role naspcs_role;
drop role nac;
最後に
SnowflakeのQuickstart「Build a Snowflake Native App with Snowpark Container Services」をやってみました。
最後のクリーンアップ時のcascade
オプションの追加以外は詰まることなく、Quickstartに記載されたコマンドを実行していくだけでSnowpark Container Servicesを用いたアプリケーションのデプロイが出来ました!Snowpark Container Servicesの取っ掛かりとしてはちょうどよいチュートリアルだと思います。