Tutoriel 3 : communications de service à service

Important

La fonction de tâches Snowpark Container Services est actuellement disponible en avant-première privée et est soumise aux conditions d’utilisation de l’avant-première disponibles à https://snowflake.com/legal. Contactez votre représentant Snowflake pour plus d’informations.

Introduction

Dans ce tutoriel, vous créez une tâche Snowpark Container Services qui communique avec le service echo que vous avez créé dans le tutoriel 1. Lorsque la tâche s’exécute, elle envoie une requête POST à l’URL de service echo (que vous avez fournie dans la spécification de la tâche) avec une chaîne « Hello » dans le corps de la requête. Le service echo renvoie une réponse contenant la chaîne « Bob said Hello » dans le corps de la réponse. Vous accédez aux journaux du conteneur de tâches pour vérifier que les communications ont réussi.

Ce tutoriel comporte deux parties :

  • Partie 1 : Créer et tester une tâche. Vous téléchargez le code fourni pour ce tutoriel et suivez les instructions étape par étape :

    1. Téléchargez le code de la tâche pour ce tutoriel.

    2. Créez une image Docker pour Snowpark Container Services, et chargez l’image dans un référentiel de votre compte.

    3. Mettez en zone de préparation le fichier de spécification, qui donne à Snowflake les informations de configuration du conteneur. En plus du nom de l’image à utiliser pour démarrer un conteneur, la spécification définit la variable d’environnement (SERVICE_URL) sur l’URL de service echo. Le code de l’application lit cette variable d’environnement pour envoyer des demandes au service echo.

    4. Exécutez la tâche. En utilisant la commande EXECUTE SERVICE, vous pouvez exécuter la tâche en fournissant le fichier de spécification et le pool de calcul où Snowflake peut exécuter le conteneur. Enfin, accédez aux journaux du conteneur de tâches pour vérifier que la communication entre la tâche et le service s’est déroulée correctement.

  • Partie 2 : comprendre le code de la tâche. Cette section donne une vue d’ensemble du code de service et met en évidence la façon dont les différentes composantes collaborent.

Conditions préalables

Effectuez le tutoriel 1 et vérifiez que le service echo fonctionne.

SELECT SYSTEM$GET_SERVICE_STATUS('echo_service', 10);
Copy

1 : Télécharger le code de service

Un code (une application Python) est fourni pour créer une tâche.

  1. Téléchargez le fichier zip dans un répertoire.

  2. Décompressez le contenu, qui comprend un répertoire pour chaque tutoriel. Le répertoire Tutorial-3 contient les fichiers suivants :

    • service_to_service.py

    • Dockerfile

    • service_to_service_spec.yaml

2 : Construire et charger une image

Construisez une image pour la plateforme linux/amd64 prise en charge par Snowpark Container Services, puis chargez l’image dans le référentiel d’images de votre compte (voir Configuration commune).

Vous aurez besoin d’informations sur le référentiel (l’URL du référentiel et le nom d’hôte du registre) avant de pouvoir construire et charger l’image. Pour plus d’informations, voir Registre et référentiels.

Obtenir des informations sur le référentiel

  1. Pour obtenir l’URL du référentiel, exécutez la commande SQL SHOW IMAGE REPOSITORIES.

    SHOW IMAGE REPOSITORIES;
    
    Copy
    • La colonne repository_url de la sortie fournit l’URL. En voici un exemple :

      <orgname>-<acctname>.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository
      
    • Le nom d’hôte dans l’URL du référentiel est le nom d’hôte du registre. En voici un exemple :

      <orgname>-<acctname>.registry.snowflakecomputing.com
      

Construire l’image et la charger dans le référentiel

  1. Ouvrez une fenêtre de terminal et accédez au répertoire contenant les fichiers que vous avez décompressés.

  2. Pour créer une image Docker, exécutez la commande docker build suivante à l’aide de la CLI Docker. Notez que la commande spécifie le répertoire de travail actuel (.) comme PATH pour les fichiers à utiliser pour la construction de l’image.

    docker build --rm --platform linux/amd64 -t <repository_url>/<image_name> .
    
    Copy
    • Pour image_name, utilisez service_to_service:latest.

    Exemple

    docker build --rm --platform linux/amd64 -t myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest .
    
    Copy
  3. Chargez l’image dans le référentiel de votre compte Snowflake. Pour que Docker puisse charger une image en votre nom dans votre référentiel, vous devez d’abord authentifier Docker avec Snowflake.

    1. Pour authentifier Docker auprès du registre Snowflake, exécutez la commande suivante.

      docker login <registry_hostname> -u <username>
      
      Copy
      • Pour username, indiquez votre nom d’utilisateur Snowflake. Docker vous demandera votre mot de passe.

    2. Pour charger l’image, exécutez la commande suivante :

      docker push <repository_url>/<image_name>
      
      Copy

      Exemple

      docker push myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest
      
      Copy

3 : Mettre en zone de préparation le fichier de spécification

  • Pour charger votre fichier de spécification de tâche (service_to_service_spec.yaml) sur la zone de préparation, utilisez l’une des options suivantes :

    La commande définit OVERWRITE=TRUE afin que vous puissiez charger le fichier à nouveau, si nécessaire (par exemple, si vous avez corrigé une erreur dans votre fichier de spécification). Si la commande PUT est exécutée avec succès, les informations relatives au fichier chargé sont affichées.

4 : Exécuter la tâche

Vous êtes maintenant prêt à tester la tâche Snowflake que vous avez créée. Lorsque la tâche est exécutée, Snowflake collecte tout ce que votre code dans le conteneur envoie à la sortie standard ou à l’erreur standard en tant que journaux. Vous pouvez utiliser la fonction système SYSTEM$GET_JOB_LOGS pour accéder aux journaux. Pour plus d’informations, voir Snowpark Container Services : considérations supplémentaires pour les services et les tâches.

  1. Pour démarrer une tâche, exécutez la commande EXECUTE SERVICE :

    EXECUTE SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      FROM @tutorial_stage
      SPEC='service_to_service_spec.yaml';
    
    Copy

    Remarques :

    • FROM et SPEC indiquent le nom de la zone de préparation et le nom du fichier de spécification de la tâche.

    • COMPUTE_POOL fournit les ressources informatiques où Snowflake exécute la tâche.

    Snowflake exécute le conteneur identifié dans le fichier de spécification. Le conteneur lit la valeur de la variable d’environnement SERVICE_URL (http://echo-service:8000/echo) et envoie une requête au service echo sur le port 8000 au chemin HTTP /echo.

    Snowflake démarre la tâche et renvoie un ID de tâche en sortie :

    +------------------------------------------------------------------------+
    | status                                                                 |
    |------------------------------------------------------------------------|
    | Execution 01af7ee6-0001-cb52-0020-c5870077223a completed successfully. |
    +------------------------------------------------------------------------+
    

    Notez que la réponse comprend un ID de tâche de requête attribué par Snowflake.

  2. (facultatif) Une fois la tâche terminée, vous pouvez obtenir plus d’informations à son sujet. Ceci est utile pour déboguer l’échec d’une tâche.

    1. Facultatif : pour capturer l’ID d’une tâche de la commande EXECUTE SERVICE précédente dans une variable de session afin de pouvoir y faire référence ultérieurement, exécutez la commande suivante :

      SET job_id = last_query_id();
      
      Copy

      Notez que vous devez capturer l’ID de la tâche immédiatement après sa création, sinon vous capturerez une valeur erronée.

    2. Pour obtenir le statut d’une tâche, utilisez l’une des options suivantes pour appeler la fonction SYSTEM$GET_JOB_STATUS :

      • En utilisant l’ID d’une tâche renvoyé par EXECUTE SERVICE :

        CALL SYSTEM$GET_JOB_STATUS('<job_id returned by EXECUTE SERVICE>');
        
        Copy
      • Utilisation de la variable de session :

        CALL SYSTEM$GET_JOB_STATUS($job_id);
        
        Copy

      Exemple de sortie :

      [
        {
          "status":"DONE",
          "message":"Container finished",
          "containerName":"main",
          "instanceId":"0",
          "serviceName":"JOB_01ABD9E5000046DF00000E99000BC01E",
          "image":"myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest",
          "restartCount":0,
          "startTime":"2023-01-01T00:00:00Z"
        }
      ]
      
  3. Pour lire les journaux des tâches, utilisez l’une des options suivantes :

    • Utiliser l’ID de tâche d’une requête renvoyé par EXECUTE SERVICE :

      CALL SYSTEM$GET_JOB_LOGS('<job_id returned by EXECUTE SERVICE>', 'main');
      
      Copy
    • Utiliser la variable de session :

      CALL SYSTEM$GET_JOB_LOGS($job_id, 'main');
      
      Copy

    main est le nom du conteneur à partir duquel vous récupérez le journal. Vous définissez ce nom de conteneur pour le conteneur dans le fichier de spécification de la tâche.

    Exemple de journal :

    +--------------------------------------------------------------------------------------------------------------------------+
    | 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 : Nettoyage

Snowflake facture les nœuds du pool de calcul qui sont actifs pour votre compte. (Voir Utilisation des pools de calcul). Pour éviter les frais non voulus, arrêtez d’abord tous les services en cours d’exécution sur un pool de calcul. Ensuite, suspendez le pool de calcul (si vous avez l’intention de le réutiliser plus tard) ou supprimez-le.

  1. Arrêtez tous les services et toutes les tâches sur le pool de calcul.

    ALTER COMPUTE POOL tutorial_compute_pool STOP ALL;
    
    Copy
  2. Supprimez le pool de calcul.

    DROP COMPUTE POOL tutorial_compute_pool;
    
    Copy

Vous pouvez également nettoyer le registre des images (supprimer toutes les images) et la zone de préparation interne (supprimer les spécifications).

DROP IMAGE REPOSITORY tutorial_repository;
DROP STAGE tutorial_stage;
Copy

6 : Vérification du code de tâche

Cette section couvre les sujets suivants :

Vérification des fichiers fournis

Le fichier zip que vous avez téléchargé comprend les fichiers suivants :

  • service_to_service.py

  • Dockerfile

  • service_to_service_spec.yaml

Cette section donne un aperçu de la manière dont le code met en œuvre la tâche.

Fichier 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)
Copy

Lorsque la tâche est exécutée :

  1. Snowflake utilise la valeur fournie dans le fichier de spécification pour définir la variable d’environnement SERVICE_URL dans le conteneur.

  2. Le code lit la variable d’environnement.

    SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo').
    
    Copy
  3. La fonction call_service() utilise la fonction SERVICE_URL pour communiquer avec le service echo.

Dockerfile

Ce fichier contient toutes les commandes pour construire une image en utilisant 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"]
Copy

Fichier service_to_service_spec.yaml (spécification de la tâche)

Snowflake utilise les informations que vous fournissez dans cette spécification pour configurer et faire fonctionner votre service.

spec:
container:
   - name: main
      image: /tutorial_db/data_schema/tutorial_repository/service_to_service:latest
      env:
      SERVICE_URL: "http://echo-service:8000/echo"
Copy

Cette spécification fournit des informations à Snowflake pour la configuration et l’exécution de votre tâche. Pour communiquer avec le service echo, la tâche a besoin des éléments suivants :

  • Nom DNS du service echo auquel envoyer les requêtes.

  • Port HTTP sur lequel le service echo écoute.

  • Chemin HTTP où le service echo s’attend à ce que la requête soit envoyée.

Pour obtenir ces informations :

  1. Pour obtenir le nom DNS du service echo (tutoriel 1), exécutez la commande DESCRIBE SERVICE SQL :

    DESCRIBE SERVICE echo_service;
    
    Copy

    Nom DNS résultant pour le service echo :

    echo-service.data-schema.tutorial-db.snowflakecomputing.internal
    
    Copy

    Notez que, dans ce tutoriel, vous créez la tâche dans le même schéma de base de données (data-schema) où le service echo (tutoriel 1) est créé. Par conséquent, vous n’avez besoin que de la partie « echo-service » du nom DNS précédent pour construire la SERVICE_URL.

  2. Obtenez le numéro de port (8000) où le service echo écoute à partir du fichier de spécification de service echo (tutoriel 1).

Vous créez ensuite le fichier de spécification précédent (service_to_service_spec.yaml). Outre les champs obligatoires containers.name et containers.image, vous incluez également le champ containers.env facultatif.

Construire et tester une image localement

Vous pouvez tester l’image Docker localement avant de la charger vers un référentiel dans votre compte Snowflake. Dans les tests locaux, votre conteneur fonctionne de manière autonome (il ne s’agit pas d’une tâche exécutée par Snowflake).

Note

Le code Python fourni pour ce tutoriel utilise la bibliothèque requests pour envoyer des requêtes à un autre service Snowpark Containers. Si cette bibliothèque n’est pas installée, lancez pip (par exemple, pip3 install requests).

Suivez les étapes suivantes pour tester l’image Docker du tutoriel 3 :

  1. Il faut que le service echo fonctionne (tutoriel 1). Pour démarrer le service echo du tutoriel 1, dans une fenêtre de terminal, exécutez la commande Python suivante :

    SERVER_PORT=8000 python3 echo_service.py
    
    Copy
  2. Ouvrez une autre fenêtre de terminal et exécutez le code Python fourni pour ce tutoriel :

    SERVICE_URL=http://localhost:8000/echo python3 service_to_service.py
    
    Copy

    Notez que la SERVICE_URL est une variable d’environnement. Pour les tests locaux, vous devez définir explicitement cette variable. Cette URL correspond au port et au chemin HTTP explicitement spécifiés lorsque vous avez démarré le service echo.

    Lorsque la tâche est exécutée, elle envoie une requête POST au service echo écoutant sur le port 8080 avec la chaîne « Hello » dans le corps de la requête. Le service echo renvoie l’écho de l’entrée et renvoie une réponse, « I said Hello ».

    Exemple de réponse :

    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
    

    Examinez le journal pour vérifier que la communication de service à service a réussi.

Quelle est la prochaine étape ?

Maintenant que vous avez terminé ce tutoriel, vous pouvez retourner à Tutoriels avancés pour explorer d’autres sujets.