Tutoriel 3 : communications de service à service

Introduction

Dans ce tutoriel, vous créez un service de tâche Snowpark Container Services qui communique avec le service echo que vous avez créé dans le tutoriel 1. Lorsque le service de tâche s’exécute, il envoie une requête POST à l’URL de service echo (que vous avez fournie dans la spécification du service) 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 services de tâches pour vérifier que les communications ont réussi.

Ce tutoriel comporte deux parties :

  • Partie 1 : créez et testez un service de 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 service de 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 le service de tâche. En utilisant la commande EXECUTE JOB SERVICE, vous pouvez exécuter le service de 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 service de tâches pour vérifier que la communication entre le service de tâche et le service s’est déroulée correctement.

  • Partie 2 : comprendre le code du service de 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 un service de tâche.

  1. Téléchargez SnowparkContainerServices-Tutorials.zip.

  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 le registre.

    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 service (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écutez le service de tâche

Vous êtes maintenant prêt à tester le service de tâche Snowflake que vous avez créé. Lorsque le service de tâche est exécuté, 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_SERVICE_LOGS pour accéder aux journaux. Pour plus d’informations, voir Snowpark Container Services : considérations supplémentaires pour les services.

  1. Pour démarrer un service de tâche, exécutez la commande 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';
    
    Copy

    Remarques :

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

    • COMPUTE_POOL fournit les ressources de calcul où Snowflake exécute le service de 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 le service de tâche et renvoie le résultat suivant :

    +------------------------------------------------------------------------+
    | status                                                                 |
    |------------------------------------------------------------------------|
    | Job TUTORIAL3_JOB_SERVICE completed successfully with status: DONE     |
    +------------------------------------------------------------------------+
    

    Notez que la réponse comprend le nom du service de tâche.

  2. (facultatif) Une fois le service de tâche terminé, vous pouvez obtenir plus d’informations au sujet de son exécution. Ceci est utile pour déboguer l’échec du service de tâche. Pour obtenir le statut du service de tâche, appelez la fonction SYSTEM$GET_SERVICE_STATUS — Obsolète :

    CALL SYSTEM$GET_SERVICE_STATUS('TUTORIAL3_JOB_SERVICE');
    
    Copy

    Exemple de sortie :

    [
      {
        "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"
      }
    ]
    
  3. Pour consulter les journaux des services de tâche, appelez SYSTEM$GET_SERVICE_LOGS :

    CALL SYSTEM$GET_SERVICE_LOGS('tutorial_3_job_service', 0, '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 du service.

    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 tous les services de 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 : Révisez le code du service 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 le service de 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 le service de tâche s’exécute :

  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 service)

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.fsvv.svc.spcs.internal
    
    Copy

    Notez que, dans ce tutoriel, vous créez le service de 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 pouvez également utiliser la commande SHOW ENDPOINTS SQL.

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 pour spécifier des variables d’environnement utilisées par le service.

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’un service de tâche exécuté 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 8000 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 ?

Tutoriel 4 : créer un service avec un volume de stockage en bloc monté