Tutorial 3: comunicações entre serviços

Importante

O recurso de trabalho do Snowpark Container Services está atualmente em versão preliminar privada e sujeito aos Termos de versão preliminar em https://snowflake.com/legal. Entre em contato com seu representante Snowflake para obter mais informações.

Introdução

Neste tutorial, você cria um trabalho do Snowpark Container Services que se comunica com o serviço Echo criado no Tutorial 1. Quando o trabalho é executado, ele envia uma solicitação POST ao URL do serviço Echo (que você fornece na especificação do trabalho) com uma cadeia de caracteres «Hello» no corpo da solicitação. O serviço Echo retorna uma resposta com a cadeia de caracteres»Bob disse Olá» no corpo da resposta. Você acessa os logs do contêiner de trabalho para verificar se as comunicações foram bem-sucedidas.

Existem duas partes neste tutorial:

  • Parte 1: Criar e testar um trabalho. Faça download do código fornecido para este tutorial e siga as instruções passo a passo:

    1. Baixe o código do trabalho para este tutorial.

    2. Crie uma imagem Docker para Snowpark Container Services e carregue a imagem em um repositório em sua conta.

    3. Prepare o arquivo de especificação, que fornece ao Snowflake as informações de configuração do contêiner. Além do nome da imagem a ser usada para iniciar um contêiner, a especificação define a variável de ambiente (SERVICE_URL) para o URL do serviço Echo. O código do aplicativo lê esta variável de ambiente para enviar solicitações ao serviço Echo.

    4. Execute o trabalho. Usando o comando EXECUTE SERVICE, você pode executar o trabalho fornecendo o arquivo de especificação e o pool de computação onde o Snowflake pode executar o contêiner. E, por fim, acesse os logs do contêiner de trabalho para verificar se a comunicação entre o trabalho e o serviço foi bem-sucedida.

  • Parte 2: Entender o código do trabalho. Esta seção fornece uma visão geral do código de serviço e destaca como diferentes componentes colaboram.

Pré-requisitos

Conclua o Tutorial 1 e verifique se o serviço Echo está em execução.

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

1: Baixe o código de serviço

O código (um aplicativo Python) é fornecido para criar um trabalho.

  1. Faça download do arquivo zip em um diretório.

  2. Descompacte o conteúdo, que inclui um diretório para cada tutorial. O diretório Tutorial-3 possui os seguintes arquivos:

    • service_to_service.py

    • Dockerfile

    • service_to_service_spec.yaml

2: Crie e carregue uma imagem

Crie uma imagem para a plataforma Linux/AMD64 compatível com o Snowpark Container Services e, em seguida, faça upload da imagem para o repositório de imagens da sua conta (consulte Configuração comum).

Você precisará de informações sobre o repositório (o URL do repositório e o nome do host do registro) antes de poder construir e fazer upload da imagem. Para obter mais informações, consulte Registro e repositórios.

Obter informações sobre o repositório

  1. Para obter o URL do repositório, execute o comando SHOW IMAGE REPOSITORIES SQL.

    SHOW IMAGE REPOSITORIES;
    
    Copy
    • A coluna repository_url na saída fornece o URL. Abaixo um exemplo:

      <orgname>-<acctname>.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository
      
    • O nome do host no URL do repositório é o nome do host do registro. Abaixo um exemplo:

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

Criar a imagem e carregá-la no repositório

  1. Abra uma janela de terminal e mude para o diretório que contém os arquivos que você descompactou.

  2. Para criar uma imagem do Docker, execute o seguinte comando docker build usando o Docker CLI. Observe que o comando especifica o diretório de trabalho atual (.) como PATH para arquivos a serem usados na construção da imagem.

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

    Exemplo

    docker build --rm --platform linux/amd64 -t myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest .
    
    Copy
  3. Faça upload da imagem para o repositório em sua conta Snowflake. Para que o Docker carregue uma imagem em seu nome para o seu repositório, você deve primeiro autenticar o Docker com Snowflake.

    1. Para autenticar o Docker com o registro Snowflake, execute o seguinte comando.

      docker login <registry_hostname> -u <username>
      
      Copy
      • Para username, especifique seu nome de usuário do Snowflake. O Docker solicitará sua senha.

    2. Para fazer upload da imagem, execute o seguinte comando:

      docker push <repository_url>/<image_name>
      
      Copy

      Exemplo

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

3: Prepare o arquivo de especificação

  • Para fazer upload do arquivo de especificação do trabalho (service_to_service_spec.yaml) para o estágio, use uma das seguintes opções:

    O comando define OVERWRITE=TRUE para que você possa fazer upload do arquivo novamente, se necessário (por exemplo, se você corrigiu um erro em seu arquivo de especificação). Se o comando PUT for executado com sucesso, as informações sobre o arquivo carregado serão impressas.

4: Execute o trabalho

Agora você está pronto para testar o trabalho Snowflake que criou. Quando o trabalho é executado, o Snowflake coleta tudo o que seu código no contêiner gera como saída padrão ou erro padrão como logs. Você pode usar a função do sistema SYSTEM$GET_JOB_LOGS para acessar os logs. Para obter mais informações, consulte Snowpark Container Services: considerações adicionais sobre serviços e tarefas.

  1. Para iniciar um trabalho, execute o comando EXECUTE SERVICE:

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

    Observe o seguinte:

    • FROM e SPEC fornecem o nome do estágio e o nome do arquivo de especificação do trabalho.

    • COMPUTE_POOL fornece os recursos de computação onde o Snowflake executa o trabalho.

    Snowflake executa o contêiner identificado no arquivo de especificação. O contêiner lê o valor da variável de ambiente SERVICE_URL (http://echo-service:8000/echo) e envia uma solicitação ao serviço Echo na porta 8000 no caminho /echo HTTP.

    Snowflake inicia o trabalho e retorna um ID de trabalho na saída:

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

    Observe que a resposta inclui um ID do trabalho de consulta atribuído pelo Snowflake.

  2. (opcional) Após a conclusão do trabalho, você poderá obter mais informações sobre o trabalho que foi executado. Isso é útil para depurar falhas de trabalho.

    1. Opcional: para capturar o ID do trabalho do comando EXECUTE SERVICE anterior em uma variável de sessão para que você possa consultá-la posteriormente, execute o seguinte comando:

      SET job_id = last_query_id();
      
      Copy

      Observe que você precisa capturar o ID do trabalho imediatamente após ele ser criado; caso contrário, você capturará o valor errado.

    2. Para obter o status do trabalho, use uma das seguintes opções para chamar a função SYSTEM$GET_JOB_STATUS:

      • Usando o ID do trabalho retornado por EXECUTE SERVICE:

        CALL SYSTEM$GET_JOB_STATUS('<job_id returned by EXECUTE SERVICE>');
        
        Copy
      • Usando uma variável de sessão:

        CALL SYSTEM$GET_JOB_STATUS($job_id);
        
        Copy

      Exemplo de saída:

      [
        {
          "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. Para ler os logs do trabalho, use uma das seguintes opções:

    • Use o ID do trabalho de consulta retornado por EXECUTE SERVICE:

      CALL SYSTEM$GET_JOB_LOGS('<job_id returned by EXECUTE SERVICE>', 'main');
      
      Copy
    • Use uma variável de sessão:

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

    main é o nome do contêiner do qual você recupera o log. Você configura esse nome de contêiner no arquivo de especificação do trabalho.

    Log de amostra:

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

O Snowflake cobra pelos nós do pool de computação que estão ativos para sua conta. (Consulte Como trabalhar com pools de computação). Para evitar cobranças indesejadas, primeiro interrompa todos os serviços que estão atualmente em execução em um pool de computação. Em seguida, suspenda o pool de computação (se você pretende usá-lo novamente mais tarde) ou descarte-o.

  1. Pare todos os serviços e trabalhos no pool de computação.

    ALTER COMPUTE POOL tutorial_compute_pool STOP ALL;
    
    Copy
  2. Exclua o pool de computação.

    DROP COMPUTE POOL tutorial_compute_pool;
    
    Copy

Você também pode limpar o registro da imagem (remover todas as imagens) e o estágio interno (remover especificações).

DROP IMAGE REPOSITORY tutorial_repository;
DROP STAGE tutorial_stage;
Copy

6: Análise do código do trabalho

Esta seção cobre os seguintes tópicos:

Análise dos arquivos fornecidos

O arquivo zip que você baixou inclui os seguintes arquivos:

  • service_to_service.py

  • Dockerfile

  • service_to_service_spec.yaml

Esta seção fornece uma visão geral de como o código implementa o trabalho.

arquivo 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

Quando o trabalho é executado:

  1. Snowflake usa o valor fornecido no arquivo de especificação para definir a variável de ambiente SERVICE_URL no contêiner.

  2. O código lê a variável de ambiente.

    SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo').
    
    Copy
  3. A função call_service() usa SERVICE_URL para se comunicar com o serviço Echo.

Arquivo Docker

Este arquivo contém todos os comandos para criar uma imagem usando 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

Arquivo service_to_service_spec.yaml (especificação do trabalho)

Snowflake usa as informações fornecidas nesta especificação para configurar e executar seu serviço.

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

Esta especificação fornece informações ao Snowflake para configurar e executar seu trabalho. Para se comunicar com o serviço Echo, o trabalho precisa do seguinte:

  • Nome DNS do serviço Echo para o qual enviar solicitações.

  • Porta HTTP na qual o serviço Echo está escutando.

  • Caminho HTTP onde o serviço Echo espera que a solicitação seja enviada.

Para obter essas informações:

  1. Para obter o nome DNS do serviço Echo (Tutorial 1), execute o comando DESCRIBE SERVICE SQL:

    DESCRIBE SERVICE echo_service;
    
    Copy

    Nome DNS resultante para o serviço Echo:

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

    Observe que, neste tutorial, você cria o trabalho no mesmo esquema de banco de dados (data-schema) onde o serviço Echo (Tutorial 1) é criado. Portanto, você só precisa da parte “serviço-echo” do nome DNS anterior para criar o SERVICE_URL.

  2. Obtenha o número da porta (8000) onde o serviço Echo está escutando no arquivo de especificação do serviço Echo (Tutorial 1).

Em seguida, você cria o arquivo de especificação anterior (service_to_service_spec.yaml). Além dos campos obrigatórios containers.name e containers.image, você também inclui o campo opcional containers.env.

Criação e teste de uma imagem localmente

Você pode testar a imagem do Docker localmente antes de carregá-la em um repositório em sua conta Snowflake. Nos testes locais, seu contêiner é executado de forma independente (não é um trabalho executado pelo Snowflake).

Nota

O código Python fornecido neste tutorial usa a biblioteca requests para enviar solicitações a outro serviço Snowpark Containers. Se você não tiver esta biblioteca instalada, execute pip (por exemplo, pip3 install requests).

Use as etapas a seguir para testar a imagem Docker do Tutorial 3:

  1. Você precisa do serviço Echo em execução (Tutorial 1). Para iniciar o serviço Echo do Tutorial 1, em uma janela de terminal, execute o seguinte comando Python:

    SERVER_PORT=8000 python3 echo_service.py
    
    Copy
  2. Abra outra janela de terminal e execute o código Python fornecido para este tutorial:

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

    Observe que SERVICE_URL é uma variável de ambiente. Para testes locais, você precisa definir explicitamente esta variável. Este URL corresponde à porta e ao caminho HTTP especificados explicitamente quando você iniciou o serviço Echo.

    Quando o trabalho é executado, ele envia uma solicitação POST ao serviço Echo que escuta na porta 8080 com a cadeia de caracteres “Olá” no corpo da solicitação. O serviço Echo repete a entrada e retorna uma resposta - «Eu disse Olá».

    Exemplo de resposta:

    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
    

    Revise o log para verificar se a comunicação serviço a serviço foi bem-sucedida.

Qual é o próximo passo?

Agora que concluiu este tutorial, você pode retornar aos tutoriais avançados para explorar outros tópicos.