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:
Baixe o código de serviço de trabalho deste tutorial.
Crie uma imagem Docker para Snowpark Container Services e carregue a imagem em um repositório em sua conta.
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.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);
1: Baixe o código de serviço¶
O código (um aplicativo Python) é fornecido para criar um serviço de trabalho.
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
Para obter o URL do repositório, execute o comando SHOW IMAGE REPOSITORIES SQL.
SHOW IMAGE REPOSITORIES;
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
Abra uma janela de terminal e mude para o diretório que contém os arquivos que você descompactou.
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 (.) comoPATH
para arquivos a serem usados na construção da imagem.docker build --rm --platform linux/amd64 -t <repository_url>/<image_name> .
Para
image_name
, useservice_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 .
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.
Para autenticar o Docker com o registro Snowflake, execute o seguinte comando.
docker login <registry_hostname> -u <username>
Para
username
, especifique seu nome de usuário do Snowflake. O Docker solicitará sua senha.
Para fazer upload da imagem, execute o seguinte comando:
docker push <repository_url>/<image_name>
Exemplo
docker push myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/service_to_service:latest
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:A interface da web do Snowsight. Para obter instruções, consulte Escolha de um estágio interno para os arquivos locais.
O SnowSQL CLI. Execute o seguinte comando PUT:
PUT file://<absolute-path-to-spec.yaml> @tutorial_stage AUTO_COMPRESS=FALSE OVERWRITE=TRUE;
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.
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';
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.
(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');
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" } ]
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');
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.
Interrompa todos os serviços e serviços de trabalho no pool de computação.
ALTER COMPUTE POOL tutorial_compute_pool STOP ALL;
Exclua o pool de computação.
DROP COMPUTE POOL tutorial_compute_pool;
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;
6: Revisando o código do serviço de trabalho¶
Esta seção cobre os seguintes tópicos:
Análise dos arquivos fornecidos: revise vários arquivos de código que implementam o serviço de trabalho.
Criação e teste de uma imagem localmente. Aprenda como testar localmente a imagem do Docker antes de carregá-la em um repositório em sua conta Snowflake.
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)
Quando o serviço de trabalho é executado:
Snowflake usa o valor fornecido no arquivo de especificação para definir a variável de ambiente SERVICE_URL no contêiner.
O código lê a variável de ambiente.
SERVICE_URL = os.getenv('SERVICE_URL', 'http://localhost:8080/echo').
A função
call_service()
usaSERVICE_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"]
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"
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:
Para obter o nome DNS do serviço Echo (Tutorial 1), execute o comando DESCRIBE SERVICE SQL:
DESCRIBE SERVICE echo_service;
Nome DNS resultante para o serviço Echo:
echo-service.fsvv.svc.spcs.internal
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 oSERVICE_URL
.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:
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
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
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