Snowpark Container Services: サービスの操作

Snowpark Container Services を使用すると、コンテナー化されたアプリケーションを簡単に展開、管理、スケーリングできるようになります。アプリケーションを作成し、Snowflakeアカウントのリポジトリにアプリケーションイメージをアップロードしたら、アプリケーションコンテナをサービスとして実行できます。

サービスは、疑似マシン (VM) ノードのコレクションである コンピューティングプール 上でコンテナ化されたアプリケーションを実行するSnowflakeを表します。サービスには2つのタイプがあります。

  • 長時間実行サービス。 自動的に終了しないウェブサービスのようなものです。サービスを作成した後、Snowflakeは実行中のサービスを管理します。たとえば、何らかの理由でサービスコンテナーが停止した場合、Snowflakeはそのコンテナーを再起動し、サービスが中断されることなく実行されるようにします。

  • ジョブサービス。 ストアドプロシージャと同じように、コードが終了すると終了します。すべてのコンテナが終了すると、ジョブサービスは完了します。

Snowpark Container Servicesは、サービスの作成と管理に使用できる SQL コマンドのセットを提供します。これらには次が含まれます。

サービスの開始

サービスの開始に最低限必要な情報には以下が含まれます。

  • 名前: サービス名。

  • サービス仕様: この 仕様 は、サービスの実行に必要な情報をSnowflakeに提供します。仕様は YAML ファイルです。

  • コンピューティングプール: Snowflakeは、指定された コンピューティングプール でサービスを実行します。

長時間実行サービスの作成

CREATE SERVICE を使用して長時間実行サービスを作成します。

  • インライン仕様を使用してサービスを作成します。以下に示すように、開発中はほとんどのケースでインライン仕様を選ぶことができます。

    CREATE SERVICE echo_service
       IN COMPUTE POOL tutorial_compute_pool
       FROM SPECIFICATION $$
       spec:
         containers:
         - name: echo
           image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:tutorial
           readinessProbe:
             port: 8000
             path: /healthcheck
         endpoints:
         - name: echoendpoint
           port: 8000
           public: true
       $$;
    
    Copy
  • ステージ情報を使用してサービスを作成します。サービスを実稼働環境に展開する際には、懸念事項の分離という設計原則を適用し、仕様をステージにアップロードし、以下に示すように、ステージ情報の CREATE SERVICE コマンドを提供することをお勧めします。

    CREATE SERVICE echo_service
      IN COMPUTE POOL tutorial_compute_pool
      FROM @tutorial_stage
      SPECIFICATION_FILE='echo_spec.yaml';
    
    Copy

ジョブサービスの実行

EXECUTE JOB SERVICE を使用してジョブサービスを作成します。このコマンドは同期的に実行され、ジョブ・サービスのすべてのコンテナーが終了した後に応答を返します。

  • インライン仕様を使用してジョブサービスを実行します。

    EXECUTE JOB SERVICE
       IN COMPUTE POOL tutorial_compute_pool
       NAME = example_job_service
       FROM SPECIFICATION $$
       spec:
         container:
         - name: main
           image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
           env:
             SNOWFLAKE_WAREHOUSE: tutorial_warehouse
           args:
           - "--query=select current_time() as time,'hello'"
           - "--result_table=results"
       $$;
    
    Copy
  • ステージ情報を使用してジョブサービスを実行します。

    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service
      FROM @tutorial_stage
      SPECIFICATION_FILE='my_job_spec.yaml';
    
    Copy

仕様テンプレートの使用

同じ仕様で複数のサービスを作成したいが、構成が異なる場合があります。たとえば、サービス仕様で 環境変数 を定義し、同じ仕様で環境変数の値が異なる複数のサービスを作成したいとします。

仕様テンプレートのサポートにより、仕様内でフィールド値の変数を定義することができます。サービスを作成するときに、これらの変数に値を指定します。

仕様テンプレートの使用は、2段階のプロセスからなります。

  1. さまざまな仕様フィールドの値として変数を使用して仕様を作成します。これらの変数を指定するには、 {{ variable_name }} 構文を使用します。例えば、以下の指定では、イメージタグ名に「tag_name」という変数を使い、サービスごとに異なるイメージタグを指定します。

    spec:
      containers:
      - name: echo
        image: myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:{{ tag_name }}
        ...
      endpoints:
      
    
    Copy
  2. CREATE SERVICE コマンドで仕様テンプレートを提供してサービスを作成します。テンプレートの指定には SPECIFICATION_TEMPLATE または SPECIFICATION_TEMPLATE_FILE を使用します。変数の値を指定するには、 USING パラメーターを使用します。例えば、次のステートメントはSnowflakeステージの仕様テンプレートを使用しています。USING パラメーターは、変数 tag_name に値 'latest' を設定します。

    CREATE SERVICE echo_service
       IN COMPUTE POOL tutorial_compute_pool
       FROM @STAGE SPECIFICATION_TEMPLATE_FILE='echo.yaml'
       USING (tag_name=>'latest');
    
    Copy

仕様で変数を定義するためのガイドライン

  • 仕様でフィールド値として変数を定義するには、 {{ variable_name }} 構文を使用します。

  • これらの変数はデフォルト値を持つことができます。デフォルト値を指定するには、変数宣言で default 関数を使用します。たとえば、以下の仕様では2つの変数(character_nameendpoint_name)をデフォルト値で定義しています。

    spec:
      containers:
      - name: echo
        image: <image_name>
        env:
          CHARACTER_NAME: {{ character_name | default('Bob') }}
          SERVER_PORT: 8085
      endpoints:
      - name: {{ endpoint_name | default('echo-endpoint') }}
        port: 8085
    
    Copy

    default 関数にオプションのブール値パラメーターを指定すると、変数に空白値が渡されたときにデフォルト値を使用するかどうかを指定できます。次の仕様を検討します。

    spec:
      containers:
      - name: echo
        image: <image_name>
        env:
          CHARACTER_NAME: {{ character_name | default('Bob', false) }}
          SERVER_PORT: 8085
      endpoints:
      - name: {{ endpoint_name | default('echo-endpoint', true) }}
        port: 8085
    
    Copy

    仕様で、

    • 変数 character_name の場合、ブール値パラメーターは false に設定されます。したがって、このパラメータに空の文字列値('')が設定されている場合、値は空白のままであり、デフォルト値("Bob")は使用されません。

    • 変数 echo_endpoint の場合、ブール値パラメーターは true に設定されます。したがって、このパラメーターに空白値を渡すと、デフォルト値(「echo-endpoint」)が使用されます。

    デフォルトでは、 default 関数のブール値パラメーターは false です。

仕様変数に値を渡す際のガイドライン

CREATE SERVICE コマンドで USING パラメーターを指定して、変数の値を提供します。USING の一般的な構文は次のとおりです。

USING( var_name=>var_value, [var_name=>var_value, ... ] );
Copy

条件

  • var_name は大文字小文字を区別し、有効なSnowflake識別子でなければなりません(識別子の要件 を参照)。

  • var_value には英数字か有効な JSON 値を指定します。

    例:

    -- Alphanumeric string and literal values
    USING(some_alphanumeric_var=>'blah123',
          some_int_var=>111,
          some_bool_var=>true,
          some_float_var=>-1.2)
    
    -- JSON string
    USING(some_json_var=>' "/path/file.txt" ')
    
    -- JSON map
    USING(env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' );
    
    -- JSON list
    USING (ARGS='["-n", 2]' );
    
    Copy
  • CREATE SERVICE の USING パラメーターは、仕様変数(仕様がデフォルト値を提供する変数を除く)の値を提供しなければなりません。それ以外の場合、エラーが返されます。

次の例は、仕様テンプレートを使用してサービスを作成する方法を示しています。これらの例の CREATE SERVICE コマンドはインライン仕様を使っています。

例1: 単純な値を提供する

チュートリアル1 では、インライン仕様を提供してサービスを作成します。以下の例は同じものを修正したバージョンで、 image_urlSERVER_PORT の2つの変数を定義します。変数 SERVER_PORT が3箇所で繰り返されていることに注意してください。これは、同じ値を持つことが期待されるすべてのフィールドが同じ値を持つことを保証する変数を使用することの利点です。

CREATE SERVICE echo_service
   IN COMPUTE POOL tutorial_compute_pool
   MIN_INSTANCES=1
   MAX_INSTANCES=1
   FROM SPECIFICATION_TEMPLATE $$
      spec:
         containers:
         - name: echo
           image: {{ image_url }}
           env:
             SERVER_PORT: {{SERVER_PORT}}
             CHARACTER_NAME: Bob
           readinessProbe:
             port: {{SERVER_PORT}}
             path: /healthcheck
         endpoints:
         - name: echoendpoint
           port: {{SERVER_PORT}}
           public: true
         $$
      USING (image_url=>' "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest" ', SERVER_PORT=>8000 );
Copy

この CREATE SERVICE コマンドでは、 USING パラメーターが2つの仕様変数の値を提供します。1つの image_url 値にはスラッシュとコロンが含まれます。英数字ではありません。そのため、この例では値を二重引用符で囲み、有効な JSON 文字列値にしています。テンプレート仕様は以下の仕様を拡張したものです。

spec:
  containers:
  - name: echo
    image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
    env:
      SERVER_PORT: 8000
      CHARACTER_NAME: Bob
    readinessProbe:
      port: 8000
      path: /healthcheck
    endpoints:
    - name: echoendpoint
      port: 8000
      public: true
Copy

例2: JSON 値を提供する

チュートリアル1では、以下のように2つの環境変数(SERVER_PORTCHARACTER_NAME)を定義しています。

spec:
 containers:
 - name: echo
   image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
   env:
     SERVER_PORT: 8000
     CHARACTER_NAME: Bob
   
Copy

この指定をテンプレート化するには、 env フィールドに変数を使用します。これにより、環境変数の値を変えて複数のサービスを作ることができます。以下の CREATE SERVICE コマンドは、envフィールドに変数(env_values)を使用しています。

CREATE SERVICE echo_service
  IN COMPUTE POOL tutorial_compute_pool
  MIN_INSTANCES=1
  MAX_INSTANCES=1
  FROM SPECIFICATION_TEMPLATE $$
     spec:
       containers:
       - name: echo
         image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
         env: {{env_values}}
         readinessProbe:
           port: {{SERVER_PORT}}    #this and next tell SF to connect to port 8000
           path: /healthcheck
       endpoints:
       - name: echoendpoint
         port: {{SERVER_PORT}}
         public: true
        $$
     USING (env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' );
Copy

CREATE SERVICE の USING パラメーターは、 env_values 変数の値を提供します。値は JSON マップで、両方の環境変数の値を提供します。

例3: 変数値としてリストを提供する

チュートリアル2 では、仕様に2つの引数を含む args フィールドが含まれています。

spec:
  container:
  - name: main
    image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
    env:
      SNOWFLAKE_WAREHOUSE: tutorial_warehouse
    args:
    - "--query=select current_time() as time,'hello'"
    - "--result_table=results"
Copy

仕様書のテンプレートバージョンでは、以下のように、これらの引数を JSON リストとして提供することができます:

spec:
  container:
  - name: main
    image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
    env:
      SNOWFLAKE_WAREHOUSE: tutorial_warehouse
    args: {{ARGS}}
  $$
  USING (ARGS=$$["--query=select current_time() as time,'hello'", "--result_table=results"]$$ );
Copy

サービスのスケーリング

デフォルトでは、Snowflakeは指定したコンピューティングプールでサービスのインスタンスを1つ実行します。重いワークロードを管理するには、 MIN_INSTANCES と MAX_INSTANCES プロパティを設定して、複数のサービスインスタンスを実行できます。このプロパティは、サービスの最小インスタンス数から開始し、必要に応じてSnowflakeがスケールできる最大インスタンス数を指定します。

CREATE SERVICE echo_service
   IN COMPUTE POOL tutorial_compute_pool
   FROM @tutorial_stage
   SPECIFICATION_FILE='echo_spec.yaml'
   MIN_INSTANCES=2
   MAX_INSTANCES=4;
Copy

複数のサービスインスタンスが実行されている場合、Snowflakeは自動的にロードバランサーを提供し、受信するリクエストを分散します。

Snowflakeは、少なくとも2つのインスタンスが利用可能になるまで、サービスを READY だと考えません。サービスが準備できていない間は、Snowflakeはそのサービスへのアクセスをブロックします。つまり、準備完了が確認されるまで、関連するサービス機能やイングレス・リクエストは拒否されます。

場合によっては、利用可能なインスタンスが指定した最小数に満たない場合でも、Snowflakeにサービスの準備ができたと判断させたい(受信リクエストを転送させたい)場合があります。これは、 MIN_READY_INSTANCES プロパティを設定することで実現できます。

別のシナリオを考えてみましょう。メンテナンス中またはサービスのローリングアップグレード中に、Snowflakeは1つまたは複数のサービスインスタンスを終了する可能性があります。このため、利用可能なインスタンス数が指定された MIN_INSTANCES より少なくなり、サービスが READY の状態にならない可能性があります。このような場合、 MIN_READY_INSTANCES を MIN_INSTANCES よりも小さい値に設定し、サービスがリクエストを受け入れ続けられるようにしたいとします。

CREATE SERVICE echo_service
   IN COMPUTE POOL tutorial_compute_pool
   FROM @tutorial_stage
   SPECIFICATION_FILE='echo_spec.yaml'
   MIN_INSTANCES=2
   MAX_INSTANCES=4
   MIN_READY_INSTANCES=1;
Copy

詳細については、 CREATE SERVICE をご参照ください。

注釈

ジョブ・サービスの複数のインスタンスを実行することはできません。

オートスケールの有効化

実行中のサービスインスタンス数を自動スケールするようにSnowflakeを構成するには、以下のステップに従います。

  1. サービス仕様ファイルで、サービスインスタンスに必要なメモリと CPU を指定します。詳細については、 container.resources フィールドをご参照ください。

    resources:
      requests:
       cpu: <cpu-units>
    
    Copy
  2. CREATE SERVICE コマンドを実行する場合は、 MIN_INSTANCES と MAX_INSTANCES パラメーターを設定します。また、 ALTER SERVICE を使用してこれらの値を変更することもできます。オートスケーリングは、指定された MAX_INSTANCES が MIN_INSTANCES より大きい場合に発生します。

Snowflakeは、指定されたコンピューティングプール上に最小数のサービスインスタンスを作成することから開始します。その後、Snowflakeは80% CPU の使用しきい値に基づいて、サービスインスタンス数をスケールアップまたはスケールダウンします。Snowflakeは、現在実行中のすべてのサービスインスタンスの使用データを集約し、コンピュートプール内の CPU 使用率を継続的に監視します。

Snowflakeは、(すべてのサービスインスタンスを合計した) CPU の使用率が80%を超えると、コンピュートプール内に追加のサービスインスタンスをデプロイします。CPU の使用率が 80% を下回ると、Snowflake は実行中のサービスインスタンスを削除してスケールダウンします。Snowflakeは5分間の安定化ウィンドウを使用して、頻繁なスケーリングを防止します。

以下のスケーリング動作に注意してください。

  • サービスインスタンスのスケーリングは、サービス用に構成された MIN_INSTANCES と MAX_INSTANCES パラメーターによって制約されます。

  • スケールアップが必要で、コンピューティングプールノードが別のサービスインスタンスを起動するために必要なリソース容量が不足している場合は、コンピューティングプールの自動スケールをトリガーできます。詳細については、 コンピューティングプールノードの自動スケーリング をご参照ください。

  • サービスの作成時に MAX_INSTANCES と MIN_INSTANCES パラメーターを指定しても、サービス仕様ファイルでサービスインスタンスのメモリと CPU 要件を指定しない場合は、自動スケーリングは実行されません。Snowflakeは MIN_INSTANCES パラメーターで指定されたインスタンスの数で開始され、数は自動スケーリングされません。

  • 長時間稼働しているサービスは、コンピュートプールのリソースを消費し、コストを発生させますが、意味のある作業を行っていない場合には、サービスを一時停止することができます(ALTERSERVICE ... SUSPEND を参照)。どのコンピュートプールノードでもサービスやジョブがアクティブでない場合、Snowflakeの自動一時停止メカニズムがプールを一時停止してコストを削減します。

サービスの変更とドロップ

サービス作成後:

  • サービスを作成した後、 DROP SERVICE を使用してスキーマからサービスを削除できます(Snowflakeはすべてのサービスコンテナを終了します)。

  • ALTER SERVICE を使ってサービスを変更します(たとえば、サービスを一時停止または再開し、実行中のインスタンス数を変更し、新しいサービス仕様を使用してサービスを再展開するようにSnowflakeに指示します)。

    注釈

    • ジョブサービスを変更することはできません。

サービスの終了

サービスを一時停止 (ALTERSERVICE... SUSPEND) またはサービスを停止 (DROP SERVICE) すると、Snowflake はすべてのサービスインスタンスを終了します。同様に、サービスコードをアップグレードする場合(ALTER SERVICE...<fromSpecification> )、Snowflake は、一度に 1 つのサービスインスタンスを終了して再デプロイすることで、 ローリングアップグレード を適用します。

サービスインスタンスを終了する際、Snowflakeはまず各サービスコンテナに SIGTERM シグナルを送信します。コンテナーには、シグナルを処理し、30秒のウィンドウで優雅にシャットダウンするオプションがあります。そうでない場合は、猶予期間の後、Snowflake はコンテナー内のすべてのプロセスを終了します。

サービスコードの更新とサービスの更新

サービス作成後、 ALTER SERVICE...<fromSpecification> コマンドを使用してサービスコードを更新し、サービスを再デプロイします。

まず、修正したアプリケーションコードをイメージリポジトリにアップロードし、インラインまたはSnowflakeステージの仕様ファイルへのパスを指定して、サービス仕様を提供する ALTER SERVICE を呼び出します。例:

ALTER SERVICE echo_service
FROM SPECIFICATION $$
spec:
  
  
$$;
Copy

リクエストを受信すると、Snowflakeは新しいコードを使用してサービスを再展開します。

CREATESERVICE...<from-Specification> コマンドを実行すると、Snowflake は提供されたイメージの特定のバージョンを記録します。Snowflakeは、リポジトリ内のイメージが更新された場合でも、以下のシナリオで同じイメージバージョンをデプロイします。

  • 中断されたサービスが再開された場合(ALTERSERVICE... RESUMEを使用)。

  • オートスケールがさらにサービス・インスタンスを追加する場合。

  • クラスタメンテナンス中にサービスインスタンスが再起動された場合。

しかし、 ALTER SERVICE...<fromSpecification> を呼び出すと、Snowflakeがそのイメージのリポジトリにある最新バージョンを使用するトリガーとなります。

あなたがサービス・オーナーである場合、 DESCRIBE SERVICE コマンドの出力にはサービス仕様が含まれ、下図のようにイメージ・ダイジェスト(仕様の sha256 フィールドの値)が含まれます。

spec:
containers:
- name: "echo"
    image: "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest"
    sha256: "@sha256:8d912284f935ecf6c4753f42016777e09e3893eed61218b2960f782ef2b367af"
    env:
      SERVER_PORT: "8000"
      CHARACTER_NAME: "Bob"
    readinessProbe:
      port: 8000
      path: "/healthcheck"
endpoints:
- name: "echoendpoint"
    port: 8000
    public: true
Copy

ALTER SERVICE は、サービスとの通信( サービスの使用 を参照)に影響を与える可能性があります。

  • ALTER SERVICE...<fromSpecification> でエンドポイントが削除されたり、エンドポイントを使用するために必要な関連するパーミッションが削除されたりした場合(仕様リファレンスの serviceRoles を参照)、サービスへのアクセスは失敗します。詳しくは、 Using Service をご参照ください。

  • アップグレード中は、新しい接続が新しいバージョンにルーティングされる可能性があります。新しいサービス・バージョンに後方互換性がない場合、有効なサービス利用は中断されます。例えば、サービス・ファンクションを使った継続的なクエリは失敗するかもしれません。

注釈

ネイティブアプリの一部であるサービスコードをコンテナで更新する場合、 SYSTEM$WAIT_FOR_SERVICES システム機能を使用してネイティブアプリのセットアップスクリプトを一時停止し、サービスを完全にアップグレードできるようにします。詳細については、 アプリをアップグレードする をご参照ください。

ローリングアップグレードの監視

複数のサービスインスタンスが実行されている場合、Snowflakeはサービスインスタンスの ID に基づいて降順にローリングアップグレードを実行します。サービスのアップグレードを監視するには、以下のコマンドを使用します。

  • DESCRIBE SERVICE および SHOW SERVICES:

    • サービスがアップグレードされている場合、出力の is_upgrading 列の表示は TRUE です。

    • 出力の spec_digest 列は、現在のサービス仕様の仕様ダイジェストを表します。このコマンドは定期的に実行することができます。; spec_digest の値が変化した場合は、サービスのアップグレードがトリガーされたことを示しています。 SHOW SERVICE INSTANCES IN SERVICE コマンドを使用して、以下の説明に従って、すべてのインスタンスが最新バージョンにアップグレードされているかどうかを確認します。

  • SHOW SERVICE INSTANCES IN SERVICE:

    • 出力の status 列は、ローリングアップグレードの進行中に、個々のサービスインスタンスのステータスを提供します。アップグレード中、 TERMINATING から PENDING 、 PENDING から READY のように、各サービス・インスタンスの移行ステータスが表示されます。

    • サービス・アップグレード中、 SHOW SERVICE INSTANCES IN SERVICE コマンドは、 spec_digest 出力カラムに、常に最新のスペックダイジェストを返す SHOWSERVICES とは異なる値を返すかもしれません。これは単に、サービスのアップグレードが進行中であり、サービスインスタンスがまだ古いバージョンのサービスを実行していることを示しています。

サービスについての情報の取得

これらのコマンドを使うことができます。

  • サービスのプロパティとステータスを取得するには、 DESCRIBE SERVICE コマンドを使用します。

  • SHOW SERVICES コマンドを使用して、あなたが権限を持っている現在のサービス(ジョブ・サービスを含む)をリストアップします。各サービスについて、出力はサービスのプロパティとステータスを提供します。デフォルトでは、現在のデータベースとスキーマのサービスが出力されます。また、以下のスコープを指定することもできます。例:

    • 特定のデータベース、または特定のスキーマでアカウントのサービスをリストする: 例えば、 IN ACCOUNT フィルタを使用して、サービスがどのデータベースまたはスキーマに属しているかに関係なく、Snowflake アカウントのサービスを一覧表示します。これは、アカウント内の複数のデータベースとスキーマにSnowflakeサービスが作成されている場合に便利です。他のコマンドと同様に、 SHOW SERVICES IN ACCOUNTS は権限によって制限され、使用しているロールが表示権限を持っているサービスのみを返します。

      IN DATABASE または IN SCHEMA を指定して、現在の(または指定した)データベースまたはスキーマのサービスを一覧表示することもできます。

    • コンピューティングプールで実行されているサービスをリストする: 例えば、 IN COMPUTE POOL フィルターを使用して、コンピューティングプールで実行されているサービスをリストします。

    • プレフィックスで始まる、またはパターンに一致するサービスをリストする: LIKE と STARTS WITH フィルタを適用して、名前でサービスをフィルタリングすることができます。

    • ジョブ・サービスのみをリストアップする、またはジョブ・サービスをリストから除外する: SHOW JOB SERVICES または SHOW SERVICES EXCLUDE JOBS を使用します。

    これらのオプションを組み合わせて、 SHOW SERVICES 出力をカスタマイズすることもできます。

  • サービス・インスタンスのプロパティを取得するには、 SHOW SERVICE INSTANCES IN SERVICE コマンドを使用します。

  • サービスインスタンスのプロパティとステータスを取得するには、 SHOW SERVICE CONTAINERS IN SERVICE コマンドを使用します。

サービスのモニタリング

Snowpark Container Servicesは、アカウント内のコンピューティングプールとその上で実行されているサービスを監視するためのツールを提供します。詳細については、 Snowpark Container Services: Monitoring Services をご参照ください。

サービスエンドポイントへのアクセス管理

サービス 所有者 ロール(サービスを作成するために使用するロール)は、サービスとサービスが公開するエンドポイントへのフルアクセス権を持っています。その他のロールは、サービスと通信するためにエンドポイントで USAGE 権限が必要です。例:

  • クライアントの所有者ロールは、エンドポイントで USAGE 権限が必要です。 クライアント とは、サービス関数またはサービスが他のサービスのエンドポイントにリクエストを行うことを指します。

    • エンドポイントを参照する サービス関数 を作成するには、エンドポイントへのアクセス権が必要です。つまり、サービス関数の所有者ロールは、 CREATE FUNCTION で参照されるエンドポイントで USAGE 権限が必要です。

    • サービス間通信 では、(相手サービスのエンドポイントを呼び出している)クライアントサービスの所有者ロールは、エンドポイントで USAGE 権限が必要です。

  • Snowflakeの外部からパブリックエンドポイントに イングレス リクエストを行うユーザーは、エンドポイントで USAGE 権限が必要です。

ロールがサービスエンドポイントにアクセスできるようにするには、そのロールに次のようにグラントします。

  • サービスが作成されるデータベースおよびスキーマに対する USAGE 権限。

  • エンドポイントへのアクセス許可を持つサービスロール (GRANT SERVICE ROLE を参照)。 サービスロール は、サービスエンドポイントの権限を他のロールに付与する仕組みです。以下のようなオプションがあります。

    • デフォルトサービスロールを使用する: Snowflakeはまた、サービスが公開するすべてのエンドポイントに USAGE 権限を付与するデフォルトサービスロール(ALL_ENDPOINTS_USAGE)を定義し、このデフォルトサービスロールをサービスの所有者ロールに付与します。このため、所有者ロールはサービスが公開するずべてのエンドポイントにアクセスすることができます。このデフォルトのサービス・ロールを他のロールに付与することができます。

      図のように、パブリックエンドポイント (echoendpoint) を持つサービスを作成したとします。

      use database my_db;
      use schema my_schema;
      create service my_service
      in compute pool tutorial_pool
      from specification $$
      spec:
        containers:
        - name: echo
          image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
        endpoints:
        - name: echoendpoint
          port: 8000
          public: true
      $$
      
      Copy

      ロール (custom_role) にエンドポイントへのアクセスを付与するには、以下のコマンドを実行します。

      grant usage on database my_db to role custom_role;
      grant usage on schema my_schema to role custom_role;
      grant service role my_service!all_endpoints_usage to role custom_role;
      
      Copy
    • サービス・ロールの作成: デフォルトのサービス・ロールを使用してすべてのエンドポイントに権限を付与する代わりに、 サービス仕様 で1つ以上のサービス・ロールを定義することができます。定義内では、ロールに USAGE 権限が付与される特定のエンドポイントを示します。 GRANT SERVICE ROLEREVOKE SERVICE ROLE コマンドを使用して、サービス・ロールを他のロールに付与(または取り消し)できます。 SHOW ROLES IN SERVICE, SHOW GRANTS コマンドを使用して、付与についての情報を表示することもできます。

      Snowflakeはサービスの作成時にサービスロールを作成し、サービスの削除時にそれを削除します。

      カスタム・サービス・ロールを作成することで、シナリオごとに異なるアクセス許可を付与することができます。例えば、サービス機能で使用するために、エンドポイントにサービス・ロール権限を付与することができます。ウェブ UI で使用されるパブリック・エンドポイントへの権限を持つ別のサービス・ロールを作成することになるかもしれません。

      例: 図のように、2つのパブリックエンドポイント(ep1ep2)と、エンドポイント ep1 へのアクセスを持つサービスロール(ep1_role)を持つサービスを作成したとします。

      use database my_db;
      use schema my_schema;
      create service my_service
      in compute pool tutorial_pool
      from specification $$
      spec:
        containers:
        - name: echo
          image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
        endpoints:
        - name: ep1
          port: 8000
          public: true
        - name: ep2
          port: 8082
          public: true
      serviceRoles:
      - name: ep1_role
        endpoints:
        - ep1
      $$
      
      Copy

      ロール (custom_role) にエンドポイント ep1 へのアクセスのみを許可するには、以下のコマンドを実行します。

      grant usage on database my_db to role custom_role;
      grant usage on schema my_schema to role custom_role;
      grant service role my_service!ep1_role to role custom_role;
      
      Copy

次の点に注意してください。

  • 同じロールを使用して複数のサービスを作成する場合、所有者ロールはすべてのエンドポイントへのアクセス権を持っているため、余分な構成を行わなくても、それらのサービスはシームレスに相互に通信できます。

  • サービスに複数のコンテナがある場合、それらのコンテナーはlocalhostを介して相互に通信することができ、これらの通信は各サービスインスタンス内でローカルであり、ロールベースのアクセス制御の対象ではないことに注意してください。

以下のセクションで詳細を説明します。また、この機能をステップバイステップで説明するチュートリアル(サービスエンドポイント権限を構成してテストする)を試すこともできます。

デフォルトのサービス・ロールを使用するすべてのエンドポイントで USAGE 権限を付与します。

サービス(ジョブサービスを含む)を作成すると、Snowflakeは ALL_ENDPOINTS_USAGE という名前のデフォルトサービスロールも作成します。このロールはサービスが公開するすべてのエンドポイントに対して USAGE の権限を持ちます。 GRANT SERVICE ROLE コマンドを使用して、このデフォルトサービスロールを他のロールに付与できます。

GRANT SERVICE ROLE my_echo_service_image!ALL_ENDPOINTS_USAGE TO ROLE some_other_role;
Copy

some_other_role を使用しているユーザーは、すべてのサービスエンドポイントで USAGE 権限を持ちます。

サービスをドロップすると、Snowflakeはサービスに関連付けられたすべてのサービスロール(デフォルトサービスロールおよびサービス仕様で定義されたサービスロール)をドロップし、すべてのサービスロールの付与を無効にします。

仕様で定義されたサービス・ロールを使用して、特定のエンドポイントに USAGE 権限を付与します。

サービスロールを使用して、サービスエンドポイントへのきめ細かなアクセスを管理します。サービスロールは、サービス仕様で USAGE 権限を付与されたエンドポイントのリストとともに定義します。

サービスの特定のエンドポイントに権限を付与するには、2段階のプロセスがあります。

  1. サービスロールを定義する: ロール名と、 USAGE 権限を付与したい1つ以上のエンドポイントのリストを提供することによって、サービスロールを定義するためにサービス仕様を使用します。たとえば、以下の仕様の断片では、最上位 serviceRoles フィールドは、特定のエンドポイントで USAGE 権限を持つ2つのサービスロールを定義しています。

    spec:
    ...
    serviceRoles:                 # Optional list of service roles
    - name: <svc_role_name1>
      endpoints:                  # endpoints that role can access
      - <endpoint_name1>
      - <endpoint_name2>
    - name: <svc_role_name2>
      endpoints:
      - <endpoint_name3>
      - <endpoint_name4>
    
    Copy
  2. 他のロールにサービスロールを付与する: GRANT SERVICE ROLE コマンドを使用して、サービスロールを他のロール(アカウントロール、アプリケーションロール、データベースロール)に付与します。例:

    GRANT SERVICE ROLE <service-name>!<svc_role_name1> TO ROLE <another-role>
    
    Copy

サービスの使用

サービスを作成した後、同じアカウント(サービスを作成したアカウント)のユーザーは、次の3つのサポートされている方法のいずれかを使用してサービスを使用することができます。ユーザーは、必要な権限を持つロールにアクセスする必要があります。

  • SQL クエリからサービスを使用する: (サービス関数): サービスに関連付けられたユーザー定義関数(UDF)であるサービス関数を作成し、 SQL クエリで使用してサービスと通信します。例については、 チュートリアル1 をご参照ください。

  • Snowflake の外部からサービスを使用する (Ingress): 1つまたは複数のサービスエンドポイントをパブリックとして宣言し、サービスへのネットワークイングレスアクセスを許可することができます。例については、 チュートリアル1 をご参照ください。

  • 他のサービスのサービスを使用する (サービス間通信): サービス間通信のために Snowflake が割り当てたサービス DNS 名を使用して、サービス間で通信することができます。例については、 チュートリアル 3 を参照してください。

注釈

  • ジョブサービスはジョブのように実行され、ジョブ完了時に終了します。ジョブ・サービスとの通信にサービス関数またはイングレスを使用することはサポートされていません。

    • ジョブ・サービスのどのエンドポイントにもサービス関数を関連付けることはできません。

    • パブリック・エンドポイントを定義する仕様では、ジョブ・サービスを作成できません。

  • ジョブ・サービスとのサービス間通信はサポート対象です。つまり、サービスとジョブ・サービスは互いに通信することができます。

以下のセクションで詳細を説明します。

サービス関数: SQL クエリからのサービスの使用

サービス関数とは、 CREATE FUNCTION (Snowpark Container Services) を使用して作成するユーザー定義関数(UDF)のことです。しかし、 UDF のコードを直接記述する代わりに、 UDF をサービスエンドポイントに関連付けます。サービス機能は、 HTTP または HTTPS プロトコルをサポートするサービスエンドポイントにのみ関連付けることができます。

たとえば、 チュートリアル1 では、サービス仕様で定義された1つのエンドポイント(echoendoint)を公開する echo_service という名前のサービスを作成します。

spec:

  endpoints:
  - name: echoendpoint
    port: 8080
Copy

echoendpoint は、対応するポート(8080)を表す分かりやすいエンドポイント名です。このサービスエンドポイントと通信するには、次に示すように SERVICE と ENDPOINT パラメーターを指定してサービス関数を作成します。

CREATE FUNCTION my_echo_udf (text varchar)
   RETURNS varchar
   SERVICE=echo_service
   ENDPOINT=echoendpoint
   AS '/echo';
Copy

AS パラメーターは、サービスコードへの HTTP パスを提供します。このパス値はサービスコードから取得します(例: チュートリアル 1 のservice.pyを参照)。例えば、以下のコード行は チュートリアル 1service.py にあります。

@app.post("/echo")
def echo():
...
Copy

サービス関数を呼び出すと、Snowflakeは関連するサービスエンドポイントとパスにリクエストを誘導します。

注釈

サービス関数は、ジョブとではなく、サービスと通信するために使用されます。つまり、サービスのみ(ジョブではなく)をサービス関数に関連付けることができます。

サービスにデータを送信する際にバッチサイズを指定し、同時実行性を高める

サービスの複数のインスタンスを実行する場合は、オプションの MAX_BATCH_ROWS パラメーターを指定してサービス関数を作成し、 バッチサイズ (Snowflakeがサービスにバッチで送信する最大行数)を制限することができます。たとえば、 MAX_BATCH_ROWS が10で、 my_echo_udf サービス関数を100入力行で呼び出したとします。Snowflakeは入力行をバッチに分割し、各バッチは最大10行を持ち、リクエスト本文にバッチ行を持つ一連のリクエストをサービスに送信します。処理に多くの時間がかかる場合は、バッチサイズを設定すると役に立ちます。行を利用可能なサーバー全体に分散することも役に立ちます。

サービス関数を変更するには、 ALTER FUNCTION を使用します。次の ALTER FUNCTION コマンドは、関連付けるサービスエンドポイントとバッチサイズを変更します。

ALTER FUNCTION my_echo_udf(VARCHAR)
   SET SERVICE=other_service
   ENDPOINT=otherendpoint
   MAX_BATCH_ROWS=100
Copy

データ交換形式

サービス関数とコンテナー間のデータ交換では、Snowflakeは外部関数が使用するのと同じ形式に従います( データ形式 を参照)。たとえば、テーブル(input_table)にデータ行が格納されているとします。

"Alex", "2014-01-01 16:00:00"
"Steve", "2015-01-01 16:00:00"

このデータをサービスに送信するには、これらの行をパラメーターとして渡してサービス関数を呼び出します。

SELECT service_func(col1, col2) FROM input_table;
Copy

Snowflakeは、一連のリクエストをリクエスト本文のデータ行のバッチと合わせて次の形式でコンテナーに送信します。

{
   "data":[
      [
         0,
         "Alex",
         "2014-01-01 16:00:00"
      ],
      [
         1,
         "Steve",
         "2015-01-01 16:00:00"
      ],
      …
      [
         <row_index>,
         "<column1>",
         "<column2>"
      ],
   ]
}
Copy

そして、コンテナーは次の形式で出力を返します。

{
   "data":[
      [0, "a"],
      [1, "b"],
      …
      [ row_index,  output_column1]
   ]
}
Copy

上記の出力例では、行(「a」、「b」)を持つ1列のテーブルを想定しています。

複数のサービスインスタンスが稼働している場合は、 MAX_BATCH_ROWS パラメーターを使用してサービス関数を作成し、利用可能なすべてのサーバーに入力行を分散して処理することができます。詳細については、 サービスにデータを送信する際にバッチサイズを指定し、同時実行性を高める をご参照ください。

サービス関数の作成および管理に必要な権限

サービス関数を作成して管理するには、ロールに以下の権限が必要です。

  • サービス関数を作成するには: 現在のロールは、参照されるサービスに対する USAGE 権限を持っている必要があります。

  • **サービス関数を変更するには

  • サービス関数を使用するには: 現在のロールには、サービス関数に対する USAGE 権限が必要であり、サービス関数所有者ロールには、関連するサービスに対する USAGE 権限が必要です。

次のスクリプト例では、サービス関数の権限を付与する方法を示します。

USE ROLE service_owner;
GRANT USAGE ON service service_db.my_schema.my_service TO ROLE func_owner;

USE ROLE func_owner;
CREATE OR REPLACE test_udf(v VARCHAR)
  RETURNS VARCHAR
  SERVICE=service_db.my_schema.my_service
  ENDPOINT=endpointname1
  AS '/run';

SELECT test_udf(col1) FROM some_table;

ALTER FUNCTION test_udf(VARCHAR) SET
  SERVICE = service_db.other_schema.other_service
  ENDPOINT=anotherendpoint;

GRANT USAGE ON FUNCTION test_udf(varchar) TO ROLE func_user;
USE ROLE func_user;
SELECT my_test_udf('abcd');
Copy

イングレス: Snowflake外部からのサービスの使用

サービスは、1つまたは複数のエンドポイントを パブリック として公開して、ユーザーがパブリックウェブからサービスを使用できるようにします。この場合は、Snowflakeがアクセス制御を管理します。イングレスは HTTP または HTTPS のエンドポイントでのみ許可されます。

サービス仕様ファイルでエンドポイントをパブリックとしてマークします。

spec
  ...
  endpoints
  - name: <endpoint name>
    port: <port number>
    public: true
Copy

Snowflake外部からのパブリック エンドポイントアクセスと認証

サービスによって公開された公開エンドポイントには、誰もがアクセスできるわけではありません。サービスと同じ Snowflake アカウントで、パブリックエンドポイントの USAGE 権限を持つユーザーのみがパブリックエンドポイントにアクセスできます。この権限を付与するには、 サービス・ロール を使用します。

パブリックエンドポイントには、ブラウザーまたはプログラムを使用してアクセスできます。Snowflake はこれらのリクエストの認証に OAuth を使用します。

  • ブラウザーの使用によるパブリックエンドポイントのアクセス: ブラウザーを使用してパブリックエンドポイントにアクセスすると、Snowflakeはユーザー認証のために自動的にリダイレクトします。ユーザーはサインインする必要があり、その裏側で、ユーザーのサインインによりSnowflakeから OAuth トークンが生成されます。そして、 OAuth トークンを使用してサービスエンドポイントにリクエストが送信されます。

  • プログラムによるパブリック・エンドポイントへのアクセス: アプリケーションでは、 キーペア認証 を使って、パブリック・エンドポイントへのリクエストを認証することができます。コードでは、キーペアから JSON Web Token (JWT) を生成し、 JWT トークンを Snowflake と交換して OAuth トークンを生成し、 OAuth トークンを使用してサービスのパブリックエンドポイントへのリクエストを認証します。

チュートリアル 1 は、公開エンドポイント・アクセスをテストするための手順をステップ・バイ・ステップで説明します。

チュートリアル 1 に示すキーペア認証は、公開エンドポイントにアクセスする際にリクエストを認証するための推奨方法です。以下のコードは、キーペアを使用する代わりに認証に使用することができます。しかし、このコードが Python用Snowflake Connector の将来のバージョンで動作する保証はありません。この Python コードでは、まず Python コネクタを使って、あなたの ID を表すセッショントークンを生成します。その後、コードはセッショントークンを使用してパブリックエンドポイントにログインします。

import snowflake.connector
import requests

ctx = snowflake.connector.connect(
   user="<username>",# username
   password="<password>", # insert password here
   account="<orgname>-<acct-name>",
   session_parameters={
      'PYTHON_CONNECTOR_QUERY_RESULT_FORMAT': 'json'
   })

# Obtain a session token.
token_data = ctx._rest._token_request('ISSUE')
token_extract = token_data['data']['sessionToken']

# Create a request to the ingress endpoint with authz.
token = f'\"{token_extract}\"'
headers = {'Authorization': f'Snowflake Token={token}'}
# Set this to the ingress endpoint URL for your service
url = 'http://<ingress_url>'

# Validate the connection.
response = requests.get(f'{url}', headers=headers)
print(response.text)

# Insert your code to interact with the application here
Copy

コードで、

  • アカウント情報(<組織名>-<アカウント名>)が分からない場合は、チュートリアルの 共通セットアップ をご参照ください。

  • SHOW ENDPOINTS を使用すると、サービスが公開しているパブリックエンドポイントの ingress_url を取得できます。

イングレスリクエストのユーザー固有ヘッダー

Snowflakeは、イングレスエンドポイントのリクエストを受信すると、自動的に HTTP リクエストとともに以下のヘッダーをコンテナに渡します。

Sf-Context-Current-User: <user_name>
Copy

コンテナコードにより、オプションでこれらのヘッダーを読み取り、呼び出し元が誰であるかを把握し、異なるユーザーに対してコンテキスト固有のカスタマイズを適用することができます。さらに、Snowflakeではオプションで Sf-Context-Current-User-Email ヘッダーを含めることができます。このヘッダーを含めるには、 Snowflakeサポート までご連絡ください。

サービス間通信

サービス・インスタンスは、 TCP (HTTP/HTTPSを含む)を介して相互に直接通信することができます。これは、同じサービスに属するインスタンスにも、異なるサービスに属するインスタンスにも当てはまります。

インスタンスは で宣言されたエンドポイント でのみ通信(リクエスト)を受け取ることができます。クライアント(リクエストを送信するサービス)は、そのエンドポイントに接続するために必要なロールとグラントを持っていなければなりません。

  • デフォルトでは、サービスインスタンスは宣言されたエンドポイントで同じサービスの他のインスタンスに接続できます。広い意味では、サービスの 所有者ロール は、同じオーナーロールを持つサービスのエンドポイントに接続する権限を持っています。

  • クライアントサービスが異なる所有者ロールを持つサービスのエンドポイントに接続するには、エンドポイントに関連付けられた サービスロール が、クライアントサービスの 所有者ロール に付与されている必要があります。例:

    GRANT SERVICE ROLE my_service!all_endpoints_usage TO ROLE custom_role;
    
    Copy
  • サービス同士が通信できないようにする場合(セキュリティなどの理由により)は、異なるSnowflakeロールを使用してこれらのサービスを作成します。

サービス・インスタンスには、サービス・アドレス(IP)またはサービス・インスタンス・アドレス(IP)のいずれかを使用してアクセスできます。

  • サービス IP アドレスを使ったリクエストはロードバランサーにルーティングされ、ロードバランサーはランダムに選ばれたサービスインスタンスにリクエストをルーティングします。

  • サービスインスタンス IP アドレスを使用したリクエストは、特定のサービスインスタンスに直接ルーティングされます。portRange フィールドを使用して定義されたエンドポイントに接続する場合は、サービスインスタンス IP を使用する必要があります( spec.endpoints フィールド(オプション) を参照)。

どちらの IP アドレスも、Snowflake が各サービスに自動的に割り当てる DNS 名を使用して検出可能です。なお、 DNS を使って特定のインスタンスに接続することはできません。例えば、サービスインスタンス DNS 名を使用して URL を構築することは意味がありません。なぜなら、サービスインスタンス DNS 名を使用して特定のサービスインスタンスをリファレンスする方法がないからです。

2025_01 動作変更バンドル が有効な場合、 SHOW SERVICE INSTANCES IN SERVICE コマンドの出力にサービスインスタンス IP アドレスが表示されます。

サービス間通信の例については、 チュートリアル3 をご参照ください。

サービス間の通信を可能にするためだけにサービスエンドポイントを作成する場合は、 TCP プロトコルを使用する必要があることに注意してください(spec.endpoints フィールド(オプション) を参照)。

サービス DNS 名

DNS 名形式は以下のとおりです。

<service-name>.<hash>.svc.spcs.internal

サービスの DNS 名を取得するには、 SHOW SERVICES (または DESCRIBE SERVICE )を使用します。直前の DNS 名は完全修飾名です。同じスキーマで作成されたサービスでは、 <サービス名> を使用するだけで通信できます。異なるスキーマまたはデータベースにあるサービスは、 <service-name>.<hash> のようにハッシュを提供するか、完全修飾名 (<service-name>.<hash>.svc.spcs.internal) を提供する必要があります。

SYSTEM$GET_SERVICE_DNS_DOMAIN 関数を使用して、指定されたスキーマの DNS ドメインを検索します。DNS ハッシュ・ドメインは、スキーマの現在のバージョンに固有のものです。次の点に注意してください。

  • スキーマやそのデータベースの名前が変わっても、ハッシュは変わりません。

  • スキーマが削除され、(例えば CREATE OR REPLACE SCHEMA を使って)再作成された場合、新しいスキーマは新しいハッシュを持つことになります。スキーマを UNDROP しても、ハッシュは変わりません。

DNS 名には以下の制限があります。

  • サービス名は有効な DNS ラベルでなければなりません。(https://www.ietf.org/rfc/rfc1035.html#section-2.3.1 もご参照ください)。それ以外の場合は、サービスの作成に失敗します。

  • Snowflakeは、サービス名のアンダースコア(_)を DNS のダッシュ(-)に置き換えます。

  • DNS 名は、同じアカウントで実行されているサービス間のSnowflake内部での通信にのみ使用されます。インターネットからはアクセスできません。

サービスインスタンス DNS 名

サービスインスタンス DNS 名の形式は次のとおりです。

instances.<service-name>.<hash>.svc.spcs.internal

これは、サービスのインスタンスごとに1つずつ、サービスインスタンス IP アドレスのリストに解決されます。DNS が返す IP アドレスのリストには順番が保証されていないことに注意してください。この DNS 名は DNS APIs でのみ使用し、 URL のホスト名としては使用しないでください。アプリケーションはこのホスト名を DNS APIs によって、サービスインスタンス IPs のセットを収集し、それらのインスタンス IPs にプログラムで直接接続することを想定しています。

この IP アドレスのリストは、特定のサービスインスタンス間で直接通信するためのメッシュネットワークの作成を可能にします。

どの DNS 名を選ぶべきか

サービス間通信でサービスに接続する際に、どの DNS 名を使用するかを選択する際には、以下の点を考慮する必要があります。

以下のいずれかに該当する場合は、サービス名(DNS)を使用してください。

  • 特定の宛先ポートにできるだけ簡単な方法でアクセスする必要があります。

  • 各リクエストがランダムに選択されたサービスインスタンスに送られるようにします。

  • アプリケーションフレームワークがどのようにパフォーマンスし、 DNS レスポンスをキャッシュしているかはわかりません。

以下のいずれかに該当する場合は、サービスインスタンス DNS 名またはサービスインスタンス IP を使用します。

  • すべてのサービス・インスタンスの IP アドレスを発見したいとします。

  • 中間のロードバランサーをスキップしたい場合。

  • RayやCassandraなど、IDとしてサービスインスタンス IP アドレスを使用する分散フレームワークやデータベースを使用しています。

権限

権限

使用状況

メモ

USAGE

サービスと通信するには、 USAGE 権限がサービスエンドポイントで 必要になります。サービス関数の作成、パブリックエンドポイントの使用、他のサービスからの接続に必要です。

MONITOR

サービスをモニターし、ランタイムのステータスを取得します。

OPERATE

サービスを中断または再開します。

OWNERSHIP

サービスを包括的に制御します。特定のオブジェクトに対して一度にこの権限を保持できるのは、1つのロールのみです。

ALL [ PRIVILEGES ]

OWNERSHIP を除く、サービスに対するすべての権限を付与します。

ガイドラインと制約

詳細については、 ガイドラインと制約 をご参照ください。