Tutorial 3: Dienst-zu-Dienst-Kommunikation

Einführung

In diesem Tutorial erstellen Sie einen Snowpark Container Services-Jobdienst, der mit dem Echo-Dienst kommuniziert, den Sie in Tutorial 1 erstellt haben. Wenn der Jobdienst ausgeführt wird, sendet er eine POST-Anforderung an die Echo-Dienst-URL (die Sie in der Dienstspezifikation angeben) mit einer „Hello“-Zeichenfolge im Anforderungstext. Der Echo-Dienst gibt eine Antwort mit der Zeichenfolge „Bob said Hello“ (Bob sagte Hallo) im Antworttext zurück. Sie greifen auf die Protokolle des Jobdienstcontainers zu, um zu überprüfen, ob die Kommunikation erfolgreich war.

Dieses Tutorial besteht aus zwei Teilen:

  • Teil 1: Jobdienst erstellen und testen. Sie laden den für dieses Tutorial bereitgestellten Code herunter und befolgen die schrittweise Anleitung:

    1. Jobdienstcode für dieses Tutorial herunterladen

    2. Docker-Image für Snowpark Container Services erstellen und Image in Repository im eigenen Konto hochladen

    3. Job-Spezifikationsdatei mit den Container-Konfigurationsinformationen für Snowflake im Stagingbereich bereitstellen. Neben dem Namen des Images, das zum Starten eines Containers verwendet werden soll, enthält die Spezifikationsdatei auch die Umgebungsvariable (SERVICE_URL) für die Echo-Dienst-URL. Der Anwendungscode liest diese Umgebungsvariable, um Anforderungen an den Echo-Dienst zu senden.

    4. Jobdienst ausführen. Mit dem Befehl EXECUTE JOB SERVICE können Sie den Jobdienst ausführen, indem Sie die Spezifikationsdatei und den Computepool angeben, in dem Snowflake den Container ausführen kann. Und schließlich können Sie auf die Protokolle des Jobdienstcontainers zugreifen, um zu überprüfen, ob die Kommunikation zwischen Jobdienst und Dienst erfolgreich war.

  • Teil 2: Erläuterungen zum Jobdienstcode. Dieser Abschnitt bietet eine Übersicht zum Dienstcode und zeigt auf, wie die verschiedenen Komponenten zusammenarbeiten.

Voraussetzungen

Schließen Sie Tutorial 1 ab, und überprüfen Sie, ob der Echo-Dienst ausgeführt wird.

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

1: Dienstcode herunterladen

Zum Erstellen eines Jobdienstes wird ein Code (eine Python-Anwendung) bereitgestellt.

  1. Laden Sie SnowparkContainerServices-Tutorials.zip herunter.

  2. Entpacken Sie den Inhalt, der ein Verzeichnis für jedes Tutorial enthält. Das Verzeichnis Tutorial-3 enthält die folgenden Dateien:

    • service_to_service.py

    • Dockerfile

    • service_to_service_spec.yaml

2: Image erstellen und hochladen

Erstellen Sie ein Image für die linux/amd64-Plattform, die von Snowpark Container Services unterstützt wird, und laden Sie das Image dann in das Image-Repository in Ihrem Konto hoch (siehe Grundlegende Einrichtung).

Sie benötigen Informationen zum Repository (die Repository-URL und den Hostnamen der Registry), bevor Sie das Image erstellen und hochladen können. Weitere Informationen dazu finden Sie unter Registry und Repositorys.

Informationen zum Repository abrufen

  1. Um die Repository-URL zu erhalten, führen Sie den SQL-Befehl SHOW IMAGE REPOSITORIES aus.

    SHOW IMAGE REPOSITORIES;
    
    Copy
    • Die URL ist in der Spalte repository_url der Ausgabe enthalten. Siehe folgendes Beispiel:

      <orgname>-<acctname>.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository
      
    • Der Hostname in der Repository-URL ist der Name des Registry-Hosts. Siehe folgendes Beispiel:

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

Image erstellen und in das Repository hochladen

  1. Öffnen Sie ein Terminalfenster, und wechseln Sie in das Verzeichnis, das die entpackten Dateien enthält.

  2. Um ein Docker-Image zu erstellen, führen Sie den folgenden Befehl docker build mithilfe der Docker-CLI aus. Beachten Sie, dass der Befehl das aktuelle Arbeitsverzeichnis (.) als PATH für die Dateien angibt, die für das Erstellen des Images verwendet werden sollen.

    docker build --rm --platform linux/amd64 -t <repository_url>/<image_name> .
    
    Copy
    • Für image_name verwenden Sie service_to_service:latest:

    Beispiel

    docker build --rm --platform linux/amd64 -t myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest .
    
    Copy
  3. Laden Sie das Image in das Repository in Ihrem Snowflake-Konto hoch. Damit Docker ein Image in Ihrem Namen in Ihr Repository hochladen kann, müssen Sie zunächst Docker mit der Registry authentifizieren.

    1. Um Docker bei der Snowflake-Registrierung zu authentifizieren, führen Sie den folgenden Befehl aus.

      docker login <registry_hostname> -u <username>
      
      Copy
      • Geben Sie dabei für username Ihren Snowflake-Benutzernamen an. Docker fordert Sie zur Eingabe Ihres Kennworts auf.

    2. Führen Sie den folgenden Befehl aus, um das Image hochzuladen:

      docker push <repository_url>/<image_name>
      
      Copy

      Beispiel

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

3: Spezifikationsdatei im Stagingbereich bereitstellen

  • Um Ihre Dienstspezifikationsdatei (service_to_service_spec.yaml) in den Stagingbereich hochzuladen, verwenden Sie eine der folgenden Optionen:

    Der Befehl setzt OVERWRITE=TRUE, sodass Sie die Datei bei Bedarf erneut hochladen können (z. B. wenn Sie einen Fehler in Ihrer Spezifikationsdatei behoben haben). Wenn der PUT-Befehl erfolgreich ausgeführt wurde, werden Informationen zu der hochgeladenen Datei ausgegeben.

4: Jobdienst ausführen

Jetzt sind Sie bereit, den von Ihnen erstellen Snowflake-Jobdienst zu testen. Während der Jobdienst ausgeführt wird, erfasst Snowflake alle Daten, die Ihr Code im Container an die Standardausgabe oder den Standardfehler ausgibt, als Protokolleinträge. Sie können die Systemfunktion SYSTEM$GET_SERVICE_LOGS verwenden, um auf die Protokolleinträge zuzugreifen. Weitere Informationen dazu finden Sie unter Snowpark Container Services: Zusätzliche Hinweise zu Diensten.

  1. Um einen Jobdienst zu starten, führen Sie den Befehl EXECUTE JOB SERVICE aus:

    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

    Beachten Sie Folgendes:

    • FROM und SPEC geben den Namen des Stagingbereichs bzw. den Namen der Dienstspezifikationsdatei an.

    • COMPUTE_POOL stellt die Computeressourcen bereit, auf denen Snowflake den Jobdienst ausführt.

    Snowflake führt den in der Spezifikationsdatei angegebenen Container aus. Der Container liest den Wert der Umgebungsvariablen SERVICE_URL (http://echo-service:8000/echo) und sendet eine Anforderung an den Echo-Dienst an Port 8000 im HTTP-Pfad /echo.

    Snowflake startet den Jobdienst und gibt die folgende Ausgabe zurück:

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

    Beachten Sie, dass die Antwort den Namen des Jobdienstes enthält.

  2. (optional) Nach Beendigung des Jobdienstes können Sie weitere Informationen zu dem ausgeführten Jobdienst abrufen. Dies ist nützlich für die Fehlersuche bei Fehlschlagen des Jobdienstes. Um den Status des Jobdienstes abzurufen, rufen Sie die Funktion SYSTEM$GET_SERVICE_STATUS – Veraltet auf:

    CALL SYSTEM$GET_SERVICE_STATUS('TUTORIAL3_JOB_SERVICE');
    
    Copy

    Beispielausgabe:

    [
      {
        "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. Um die Jobdienst-Protokolle zu lesen, rufen Sie SYSTEM$GET_SERVICE_LOGS auf:

    CALL SYSTEM$GET_SERVICE_LOGS('tutorial_3_job_service', 0, 'main');
    
    Copy

    main ist der Name des Containers, aus dem Sie das Protokoll abrufen. Diesen Containernamen verwenden Sie in der Dienstspezifikationsdatei zur Angabe des Containers.

    Beispielprotokoll:

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

Snowflake erhebt Gebühren für die Computepool-Knoten, die für Ihr Konto aktiv sind. (Siehe Verwenden von Computepools). Um unerwünschte Gebühren zu vermeiden, stoppen Sie zunächst alle Dienste, die derzeit in einem Computepool ausgeführt werden. Anschließend können Sie den Computepool entweder anhalten (wenn Sie ihn später wieder verwenden möchten) oder ihn löschen.

  1. Stoppen Sie alle Dienste und Jobdienste im Computepool.

    ALTER COMPUTE POOL tutorial_compute_pool STOP ALL;
    
    Copy
  2. Löschen Sie den Computepool.

    DROP COMPUTE POOL tutorial_compute_pool;
    
    Copy

Sie können auch die Image-Registry (alle Images entfernen) und den internen Stagingbereich (Spezifikationen entfernen) bereinigen.

DROP IMAGE REPOSITORY tutorial_repository;
DROP STAGE tutorial_stage;
Copy

6: Überprüfen des Jobdienstcodes

In diesem Abschnitt werden die folgenden Themen behandelt:

Untersuchen der bereitgestellten Dateien

Die heruntergeladene ZIP-Datei enthält die folgenden Dateien:

  • service_to_service.py

  • Dockerfile

  • service_to_service_spec.yaml

Dieser Abschnitt bietet eine Übersicht darüber, wie der Code den Jobdienst implementiert.

Datei „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

Wenn der Jobdienst ausgeführt wird:

  1. Snowflake verwendet den in der Spezifikationsdatei angegebenen Wert, um die Umgebungsvariable SERVICE_URL im Container festzulegen.

  2. Der Code liest die Umgebungsvariable.

    SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo').
    
    Copy
  3. Die Funktion call_service() verwendet SERVICE_URL zur Kommunikation mit dem Echo-Dienst.

Datei „Dockerfile“

Diese Datei enthält alle Befehle, um ein Image mit Docker zu erstellen.

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

Datei service_to_service_spec.yaml (Dienstspezifikation)

Snowflake verwendet die von Ihnen in dieser Spezifikation angegebenen Informationen zur Konfiguration und Ausführung Ihres Dienstes.

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

Diese Spezifikation stellt Informationen für Snowflake zum Konfigurieren und Ausführen Ihres Jobs bereit. Um mit dem Echo-Dienst zu kommunizieren, benötigt der Job Folgendes:

  • DNS-Name des Echo-Dienstes, an den Anforderungen gesendet werden.

  • HTTP-Port, der vom Echo-Dienst auf Anforderungen überwacht wird.

  • HTTP-Pfad, wo der Echo-Dienst die zu sendende Anforderung erwartet.

So erhalten Sie diese Informationen:

  1. Um den DNS-Namen des Echo-Dienstes (Tutorial 1) zu erhalten, führen Sie den SQL-Befehl DESCRIBE SERVICE aus:

    DESCRIBE SERVICE echo_service;
    
    Copy

    Resultierender DNS-Name für den Echo-Dienst:

    echo-service.fsvv.svc.spcs.internal
    
    Copy

    Beachten Sie, dass Sie in diesem Tutorial den Jobdienst in demselben Datenbankschema (data-schema) erstellen, in dem auch der Echo-Dienst (Tutorial 1) erstellt wird. Daher benötigen Sie nur den „echo-service“-Teil des obigen DNS-Namens, um den Wert für SERVICE_URL zu konstruieren.

  2. Rufen Sie die Portnummer (8000), der vom Echo-Dienst auf Anforderungen überwacht wird, aus der Dienstspezifikationsdatei des Echo-Dienstes ab (Tutorial 1). Sie können auch den SQL-Befehl SHOW ENDPOINTS verwenden.

Erstellen Sie dann die obige Spezifikationsdatei (service_to_service_spec.yaml). Zusätzlich zu den Pflichtfeldern containers.name und containers.image fügen Sie auch das optionale Feld containers.env hinzu, um die vom Dienst verwendeten Umgebungsvariablen anzugeben.

Lokales Erstellen und Testen eines Images

Sie können das Docker-Image lokal testen, bevor Sie es in ein Repository Ihres Snowflake-Kontos hochladen. Bei lokalen Tests wird Ihr Container eigenständig ausgeführt (er ist kein Jobdienst, der von Snowflake ausgeführt wird).

Bemerkung

Der für dieses Tutorial bereitgestellte Python-Code verwendet die requests-Bibliothek, um Anfragen an einen anderen Snowpark Container Services-Dienst zu senden. Wenn Sie diese Bibliothek nicht installiert haben, führen Sie pip aus (zum Beispiel pip3 install requests).

Führen Sie die folgenden Schritte aus, um das Docker-Image von Tutorial 3 zu testen:

  1. Der Echo-Dienst muss aktiviert sein (Tutorial 1). Zum Starten des Echo-Dienstes aus Tutorial 1 führen Sie in einem Terminalfenster den folgenden Python-Befehl aus:

    SERVER_PORT=8000 python3 echo_service.py
    
    Copy
  2. Öffnen Sie ein weiteres Terminalfenster, und führen Sie den Python-Code aus, der für dieses Tutorial bereitgestellt wurde:

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

    Beachten Sie, dass SERVICE_URL eine Umgebungsvariable ist. Für lokale Tests müssen Sie für diese Variable explizit einen Wert festlegen. Diese URL entspricht dem Port und dem HTTP-Pfad, die beim Starten des Echo-Dienstes explizit angegeben wurden.

    Wenn der Jobdienst ausgeführt wird, sendet er eine POST-Anforderung an den Echo-Dienst, der Port 8000 überwacht, mit der Zeichenfolge „Hello“ im Anforderungstext. Der Echo-Dienst gibt die Eingabe als Echo wieder zurück und antwortet mit „I said Hello“ (Ich sagte Hallo).

    Beispielantwort:

    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
    

    Überprüfen Sie das Protokoll, um sicherzustellen, dass die Kommunikation zwischen den Diensten erfolgreich war.

Nächste Schritte

Tutorial 4: Dienst mit einem eingebundenen Blockspeicher-Volume erstellen