Tutorial 3: comunicações entre serviços

Introdução

Neste tutorial, você cria um serviço de trabalho do Snowpark Container Services que se comunica com o serviço Echo criado no Tutorial 1. Quando o serviço de trabalho é executado, ele envia uma solicitação POST ao URL do serviço Echo (que você fornece na especificação do serviço de 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 serviço de trabalho para verificar se as comunicações foram bem-sucedidas.

Existem duas partes neste tutorial:

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

    1. Baixe o código de serviço de trabalho deste 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 serviço de trabalho. Usando o comando EXECUTE JOB SERVICE, você pode executar o serviço de 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 serviço de trabalho para verificar se a comunicação entre o serviço de trabalho e o serviço foi bem-sucedida.

  • Parte 2: Entender o código do serviço 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 serviço de trabalho.

  1. Baixe SnowparkContainerServices-Tutorials.zip.

  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 seu repositório, é necessário primeiro autenticar o Docker com o registro.

    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 serviço (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 serviço do trabalho

Agora você está pronto para testar o serviço de trabalho Snowflake que criou. Quando o serviço de 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_SERVICE_LOGS para acessar os logs. Para obter mais informações, consulte Snowpark Container Services: considerações adicionais sobre serviços.

  1. Para iniciar um serviço de trabalho, execute o comando EXECUTE JOB SERVICE:

    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

    Observe o seguinte:

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

    • COMPUTE_POOL fornece os recursos de computação onde o Snowflake executa o serviço de 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.

    O Snowflake inicia o serviço de trabalho e retorna a seguinte saída:

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

    Observe que a resposta inclui o nome do serviço de trabalho.

  2. (opcional) Após a conclusão do serviço de trabalho, você poderá obter mais informações sobre o serviço de trabalho que foi executado. Isso é útil para depurar falhas de serviço de trabalho. Para obter o status do serviço de trabalho, chame a função SYSTEM$GET_SERVICE_STATUS — Obsoleto:

    CALL SYSTEM$GET_SERVICE_STATUS('TUTORIAL3_JOB_SERVICE');
    
    Copy

    Exemplo de saída:

    [
      {
        "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. Para ler os logs do serviço de trabalho, chame SYSTEM$GET_SERVICE_LOGS:

    CALL SYSTEM$GET_SERVICE_LOGS('tutorial_3_job_service', 0, '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 serviço.

    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. Interrompa todos os serviços e serviços de trabalho 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: Revisando o código do serviço de 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 serviço de 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 serviço de 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 de serviço)

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

    Observe que, neste tutorial, você cria o serviço de 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). Você também pode usar o comando SHOW ENDPOINTS SQL.

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 para especificar as variáveis de ambiente usadas pelo serviço.

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 serviço de 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 8000 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?

Tutorial 4: Crie um serviço com um volume de armazenamento em bloco montado