チュートリアル3: サービス間通信¶
概要¶
このチュートリアルでは、 チュートリアル1 で作成したEchoサービスと通信するSnowpark Container Servicesジョブサービスを作成します。ジョブサービスが実行されると、リクエスト本文に「Hello」文字列を含む POST リクエストをEchoサービス URL (サービス仕様で提供したもの)に送信します。Echoサービスは、応答本文に「Bob said Hello」という文字列を含む応答を返します。ジョブサービスコンテナのログにアクセスして、通信が成功したことを確認します。
このチュートリアルには2つのパートがあります。
パート1: ジョブサービスを作成してテストする。 このチュートリアルで提供されるコードをダウンロードし、ステップバイステップの手順に従います。
このチュートリアルのジョブサービスコードをダウンロードします。
Snowpark Container Services用のDockerイメージをビルドし、アカウントのリポジトリにイメージをアップロードします。
Snowflakeにコンテナー構成情報を与える仕様ファイルをステージします。この仕様では、コンテナーの起動に使用するイメージの名前に加えて、仕様は、Echoサービス URL に環境変数(
SERVICE_URL
)を設定します。アプリケーションコードはこの環境変数を読み取り、Echoサービスにリクエストを送信します。ジョブサービスを実行します。EXECUTE JOBSERVICE コマンドを使用して、仕様ファイルとSnowflakeがコンテナを実行できるコンピューティングプールを指定すると、ジョブサービスを実行できます。そして最後に、ジョブサービスとサービス間の通信が成功したことを確認するために、ジョブサービスコンテナからログにアクセスします。
パート2: ジョブサービスコードを理解する。このセクションでは、サービスコードの概要を説明し、さまざまなコンポーネントがどのように連携しているかを明らかにします。
前提条件¶
チュートリアル1 を完了し、Echoサービスが実行されていることを確認します。
SELECT SYSTEM$GET_SERVICE_STATUS('echo_service', 10);
1: サービスコードをダウンロードする¶
ジョブサービスを作成するためのコード(Pythonアプリケーション)が提供されます。
ダウンロード:
SnowparkContainerServices -Tutorials.zip </samples/spcs/SnowparkContainerServices-Tutorials.zip>
をダウンロードします。ファイルを解凍します。チュートリアルごとに1つのディレクトリが含まれています。
Tutorial-3
ディレクトリには以下のファイルがあります。service_to_service.py
Dockerfile
service_to_service_spec.yaml
2: イメージをビルドしてアップロードする¶
Snowpark Container Servicesがサポートするlinux/amd64プラットフォーム用のイメージをビルドし、アカウントのイメージリポジトリにイメージをアップロードします(共通セットアップ を参照)。
イメージをビルドしてアップロードする前に、リポジトリに関する情報(リポジトリ URL とレジストリのホスト名)が必要です。詳細については、 レジストリおよびリポジトリ をご参照ください。
リポジトリに関する情報を取得する
リポジトリ URL を取得するには、 SHOW IMAGE REPOSITORIES SQL コマンドを実行します。
SHOW IMAGE REPOSITORIES;
出力の
repository_url
列は、 URL を提供します。以下に例を示します。<orgname>-<acctname>.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository
リポジトリ URL のホスト名はレジストリのホスト名です。以下に例を示します。
<orgname>-<acctname>.registry.snowflakecomputing.com
イメージをビルドし、リポジトリにアップロードする
ターミナルウィンドウを開き、解凍したファイルのあるディレクトリに移動します。
Dockerイメージをビルドするには、Docker CLI を使用して以下の
docker build
コマンドを実行します。このコマンドは、イメージのビルドに使用するファイルのPATH
として、現在の作業ディレクトリ(.)を指定していることに注意してください。docker build --rm --platform linux/amd64 -t <repository_url>/<image_name> .
image_name
には、service_to_service:latest
を使用します。
例
docker build --rm --platform linux/amd64 -t myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest .
Snowflakeアカウントのリポジトリにイメージをアップロードします。Dockerがあなたの代わりにリポジトリにイメージをアップロードするには、まず レジストリでDockerを認証する 必要があります。
SnowflakeレジストリでDockerを認証するには、以下のコマンドを実行します。
docker login <registry_hostname> -u <username>
username
には、Snowflakeのユーザー名を指定します。Dockerは、パスワードの入力を求めるプロンプトを表示します。
イメージをアップロードするには、以下のコマンドを実行します。
docker push <repository_url>/<image_name>
例
docker push myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest
3: 仕様ファイルをステージする¶
サービス仕様ファイル(
service_to_service_spec.yaml
)をステージにアップロードするには、以下のオプションのいずれかを使用します。Snowsightウェブインターフェイス。手順については、 ローカルファイルに対する内部ステージの選択 をご参照ください。
SnowSQL CLI。 次の PUT コマンドを実行します。
PUT file://<absolute-path-to-spec.yaml> @tutorial_stage AUTO_COMPRESS=FALSE OVERWRITE=TRUE;
このコマンドは OVERWRITE=TRUE を設定するため、必要な場合(例: 仕様ファイルのエラーを修正した場合)は、ファイルを再度アップロードすることができます。PUT コマンドが正常に実行されると、アップロードされたファイルに関する情報がプリントアウトされます。
4: ジョブサービスを実行する¶
これで、作成したSnowflakeジョブサービスをテストする準備が整いました。ジョブサービスが実行されると、Snowflakeは、コンテナ内のコードが標準出力または標準エラーに出力したものをログとして収集します。 SYSTEM$GET_SERVICE_LOGS
システム関数を使用して、ログにアクセスできます。詳細については、 Snowpark Container Services: サービスのその他の考慮事項 をご参照ください。
ジョブサービスを開始するには、 EXECUTE JOBSERVICE コマンドを実行します。
EXECUTE JOB SERVICE IN COMPUTE POOL tutorial_compute_pool NAME=tutorial_db.data_schema.tutorial3_job_service FROM @tutorial_stage SPEC='service_to_service_spec.yaml';
次の点に注意してください。
FROM と SPEC は、ステージ名とサービス仕様ファイル名を提供します。
COMPUTE_POOL は、Snowflakeがジョブサービスを実行するコンピューティングリソースを提供します。
Snowflakeは、仕様ファイルで特定されたコンテナーを実行します。コンテナーは
SERVICE_URL
環境変数値(http://echo-service:8000/echo
)を読み取り、/echo
HTTP パスのポート8000でEchoサービスにリクエストを送信します。Snowflakeはジョブサービスを開始し、以下の出力を返します。
+------------------------------------------------------------------------+ | status | |------------------------------------------------------------------------| | Job TUTORIAL3_JOB_SERVICE completed successfully with status: DONE | +------------------------------------------------------------------------+
応答にはジョブサービス名が含まれることに注意してください。
(オプション)ジョブサービスの完了後に、実行されたジョブサービスに関する詳細情報を取得できます。これはジョブサービスの失敗をデバッグするのに便利です。ジョブサービスのステータスを取得するには、 SYSTEM$GET_SERVICE_STATUS --- 非推奨 関数を呼び出します。
CALL SYSTEM$GET_SERVICE_STATUS('TUTORIAL3_JOB_SERVICE');
サンプル出力:
[ { "status":"DONE", "message":"Container finished", "containerName":"main", "instanceId":"0", "serviceName":"TUTORIAL3_JOB_SERVICE", "image":"myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest", "restartCount":0, "startTime":"2023-01-01T00:00:00Z" } ]
ジョブサービスのログを読むには、 SYSTEM$GET_SERVICE_LOGS を呼び出します。
CALL SYSTEM$GET_SERVICE_LOGS('tutorial_3_job_service', 0, 'main');
main
は、ログを取得するコンテナーの名前です。このコンテナ名は、サービス仕様ファイルでコンテナに設定します。サンプルログ:
+--------------------------------------------------------------------------------------------------------------------------+ | SYSTEM$GET_JOB_LOGS | |--------------------------------------------------------------------------------------------------------------------------| | service-to-service [2023-04-29 21:52:09,208] [INFO] Calling http://echo-service:8000/echo with input Hello | | service-to-service [2023-04-29 21:52:09,212] [INFO] Received response from http://echo-service:8000/echo: Bob said Hello | +--------------------------------------------------------------------------------------------------------------------------+
5: クリーンアップする¶
Snowflakeは、お客様のアカウントでアクティブなコンピューティングプールノードに対して課金します。(コンピューティングプールの操作 を参照。)不要な課金を防ぐには、まず、コンピューティングプールで現在実行中のサービスをすべて停止します。そして、コンピューティングプールを中断するか(後ほど再度使用する予定の場合)、ドロップします。
コンピューティングプール上のすべてのサービスとジョブサービスを停止します。
ALTER COMPUTE POOL tutorial_compute_pool STOP ALL;
コンピューティングプールを削除します。
DROP COMPUTE POOL tutorial_compute_pool;
イメージレジストリ(すべてのイメージを削除)と内部ステージ(仕様を削除)をクリーンアップすることもできます。
DROP IMAGE REPOSITORY tutorial_repository;
DROP STAGE tutorial_stage;
6: ジョブサービスコードを見直す¶
このセクションでは、以下のトピックを取り上げます。
提供されたファイルの調査: ジョブサービスを実装するさまざまなコードファイルを確認します。
ローカルでのイメージの構築とテスト。DockerイメージをSnowflakeアカウントのリポジトリにアップロードする前に、ローカルでテストする方法について説明します。
提供されたファイルの調査¶
ダウンロードしたzipファイルには以下のファイルが含まれています。
service_to_service.py
Dockerfile
service_to_service_spec.yaml
このセクションでは、コードがジョブサービスを実装する方法の概要を説明します。
service_to_service.pyファイル¶
import json
import logging
import os
import requests
import sys
SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo')
ECHO_TEXT = 'Hello'
def get_logger(logger_name):
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
handler.setFormatter(
logging.Formatter(
'%(name)s [%(asctime)s] [%(levelname)s] %(message)s'))
logger.addHandler(handler)
return logger
logger = get_logger('service-to-service')
def call_service(service_url, echo_input):
logger.info(f'Calling {service_url} with input {echo_input}')
row_to_send = {"data": [[0, echo_input]]}
response = requests.post(url=service_url,
data=json.dumps(row_to_send),
headers={"Content-Type": "application/json"})
message = response.json()
if message is None or not message["data"]:
logger.error('Received empty response from service ' + service_url)
response_row = message["data"][0]
if len(response_row) != 2:
logger.error('Unexpected response format: ' + response_row)
echo_reponse = response_row[1]
logger.info(f'Received response from {service_url}: ' + echo_reponse)
if __name__ == '__main__':
call_service(SERVICE_URL, ECHO_TEXT)
ジョブサービスの実行時:
Snowflakeは、コンテナー内の SERVICE_URL 環境変数を設定するために、指定ファイルで提供された値を使用します。
コードは環境変数を読み取ります。
SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo').
call_service()
関数は、SERVICE_URL
を使用してEchoサービスと通信します。
Dockerfile¶
このファイルには、Dockerを使用してイメージを構築するためのすべてのコマンドが含まれています。
ARG BASE_IMAGE=python:3.10-slim-buster
FROM $BASE_IMAGE
COPY service_to_service.py ./
RUN pip install --upgrade pip && \
pip install requests
CMD ["python3", "service_to_service.py"]
service_to_service_spec.yamlファイル(サービス仕様)¶
Snowflakeは、この仕様で提供された情報を使用して、サービスを構成および実行します。
spec:
container:
- name: main
image: /tutorial_db/data_schema/tutorial_repository/service_to_service:latest
env:
SERVICE_URL: "http://echo-service:8000/echo"
この仕様は、ジョブの構成と実行用の情報をSnowflakeに提供します。Echoサービスと通信するために、このジョブには次が必要です。
リクエストを送信するEchoサービスの DNS 名前。
Echoサービスがリッスンしている HTTP ポート。
Echoサービスが予期しているリクエストを送信する HTTP パス。
この情報を得るには、
Echoサービスの DNS 名(チュートリアル1)を取得するには、 DESCRIBE SERVICE SQL コマンドを実行します。
DESCRIBE SERVICE echo_service;
Echoサービス用に得られる DNS名:
echo-service.fsvv.svc.spcs.internal
このチュートリアルでは、Echoサービス(チュートリアル1)が作成されるのと同じデータベーススキーマ(
data-schema
)にジョブサービスを作成することに注意してください。したがって、前述の DNS 名の「echo-service」部分のみがSERVICE_URL
の構成に必要です。Echoサービス仕様ファイル(チュートリアル1)から、Echoサービスがリッスンしているポート番号(8000)を取得します。 SHOW ENDPOINTS SQL コマンドを使用することもできます。
次に、先行する仕様ファイル(service_to_service_spec.yaml
)を作成します。必須フィールドの containers.name
と containers.image
に加えて、オプションの containers.env
フィールドも含めて、サービスで使用する環境変数を指定します。
ローカルでのイメージの構築とテスト¶
Snowflakeアカウントのリポジトリにアップロードする前に、ローカルでDockerイメージをテストすることができます。ローカルテストでは、コンテナはスタンドアロンで実行されます(Snowflakeが実行するジョブサービスではありません)。
注釈
このチュートリアルで提供されるPythonコードは、 requests
ライブラリを使用して別のSnowpark Containersサービスにリクエストを送信します。このライブラリがインストールされていない場合は、pipを実行します(例: pip3 install requests
)。
以下のステップを使用して、チュートリアル3Dockerイメージをテストします。
Echoサービスを実行状態にする必要があります(チュートリアル1)。チュートリアル1のEchoサービスを開始するには、ターミナルウィンドウで次のPythonコマンドを実行します。
SERVER_PORT=8000 python3 echo_service.py
別のターミナルウィンドウを開き、このチュートリアルで提供されるPythonコードを実行します。
SERVICE_URL=http://localhost:8000/echo python3 service_to_service.py
SERVICE_URL
は環境変数であることに注意してください。ローカルテストでは、この変数を明示的に設定する必要があります。この URL は、Echoサービスを開始したときに明示的に指定したポートと HTTP パスに一致します。ジョブが実行されると、リクエスト本文に「Hello」文字列を含む POST リクエストをポート8000でリッスンしているEchoサービスに送信します。Echoサービスは入力をエコーして、「I said Hello」という応答を返します。
サンプル応答:
service-to-service [2023-04-23 22:30:41,278] [INFO] Calling http://localhost:8000/echo with input Hello service-to-service [2023-04-23 22:30:41,287] [INFO] Received response from http://localhost:8000/echo: I said Hello
ログをレビューして、サービス間通信が成功したことを確認します。