Criação de um serviço do Snowpark Container Services que use os direitos do chamador¶
Introdução¶
Neste tutorial, você explorará a criação de um serviço, apresentando uma UI da Web, que usa o recurso de direitos do chamador ao executar consultas SQL em nome dos usuários.
Você cria um serviço (chamado query_service
) que executa uma consulta fornecida na solicitação. Por padrão, os contêineres de aplicativos se conectam ao Snowflake como o usuário do serviço usando a função de proprietário do serviço. Mas esse aplicativo usa o recurso de direitos do chamador para se conectar ao ponto de extremidade do serviço como o usuário final e usar os privilégios concedidos a esse usuário.
Ao testar, você usa o serviço de um navegador da Web porque o recurso de direitos do chamador só é suportado ao acessar um serviço usando o ingresso na rede. O recurso de direitos do chamador não está disponível ao acessar um serviço usando uma função de serviço.
O serviço faz o seguinte:
Expõe um ponto de extremidade público.
Quando um usuário faz login no ponto de extremidade, o serviço fornece uma UI da Web para fazer uma consulta. O serviço executa a consulta no Snowflake e retorna os resultados. Neste tutorial, você executa o seguinte comando SQL:
SELECT CURRENT_USER(), CURRENT_ROLE();
O comando retorna o nome do usuário conectado no momento e a função ativa no momento, sendo que ambos dependem do uso dos direitos do chamador.
Quando os direitos do chamador são usados, o serviço se conecta ao Snowflake como o usuário chamador e a função padrão do usuário. O comando retorna seu nome de usuário e função padrão.
Quando os direitos do chamador não são usados, o comportamento padrão entra em ação, em que o serviço se conecta ao Snowflake como o usuário do serviço e a função de proprietário do serviço. Portanto, o comando retorna o nome do usuário do serviço no formato:
SF$SERVICE$unique-id
,TEST_ROLE
.
Existem duas partes neste tutorial:
Parte 1: Criar e testar um serviço. 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 deste tutorial.
Crie uma imagem Docker para Snowpark Container Services e carregue a imagem em um repositório em sua conta.
Crie um serviço.
Comunique-se com o serviço usando o ingresso na rede para se conectar ao ponto de extremidade público que o serviço expõe. Usando um navegador da Web, você faz login no ponto de extremidade público e executa o comando SELECT CURRENT_USER();. Verifique a saída do comando para garantir que o contêiner executou o comando como o usuário conectado.
Parte 2: Entender o serviço. Esta seção fornece uma visão geral do código de serviço e destaca como o código do aplicativo usa os direitos do chamador.
Preparação¶
Siga Configuração comum para configurar pré-requisitos e criar recursos do Snowflake que são necessários para todos os tutoriais do Snowpark Container Services fornecidos nesta documentação.
Download do código de serviço¶
O código (um aplicativo Python) é fornecido para criar o serviço de consulta.
Descompacte o conteúdo, que inclui um diretório para cada tutorial. O diretório
Tutorial-6-callers-rights
possui os seguintes arquivos:Dockerfile
main.py
templates/basic_ui.html
Criação e carregamento de 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 de 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 (.
) como oPATH
para os arquivos a serem usados para criar a imagem.docker build --rm --platform linux/amd64 -t <repository_url>/<image_name> .
Para
image_name
, usequery_service:latest
:
Exemplo
docker build --rm --platform linux/amd64 -t myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/query_service:latest .
Faça upload da imagem para o repositório em sua conta Snowflake. Para que o Docker faça upload de uma imagem em seu nome para o repositório, você deve primeiro autenticar o Docker com o Snowflake.
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/query_service:latest
Criação de um serviço¶
Nesta seção, você cria um serviço (query_service).
Verifique se o pool de computação está pronto e se você está no contexto certo para criar o serviço.
Anteriormente, você definiu o contexto na etapa Configuração comum. Para garantir que você esteja no contexto correto para as declarações do SQL nesta etapa, execute o seguinte:
USE ROLE test_role; USE DATABASE tutorial_db; USE SCHEMA data_schema; USE WAREHOUSE tutorial_warehouse;
Para garantir que o pool de computação que você criou na configuração comum esteja pronto, execute
DESCRIBE COMPUTE POOL
e verifique se ostate
éACTIVE
ouIDLE
. Sestate
forSTARTING
, será necessário aguardar até questate
mude paraACTIVE
ouIDLE
.
DESCRIBE COMPUTE POOL tutorial_compute_pool;
Para criar o serviço, execute o seguinte comando usando
test_role
:CREATE SERVICE query_service IN COMPUTE POOL tutorial_compute_pool FROM SPECIFICATION $$ spec: containers: - name: main image: /tutorial_db/data_schema/tutorial_repository/query_service:latest env: SERVER_PORT: 8000 readinessProbe: port: 8000 path: /healthcheck endpoints: - name: execute port: 8000 public: true capabilities: securityContext: executeAsCaller: true serviceRoles: - name: ui_usage endpoints: - execute $$;
Nota
Se já existir um serviço com esse nome, use o comando DROP SERVICE para excluir o serviço criado anteriormente e, em seguida, crie esse serviço.
Execute os seguintes comandos SQL para obter informações detalhadas sobre o serviço que você acabou de criar. Para obter mais informações, consulte Snowpark Container Services: como trabalhar com serviços.
Para listar os serviços da sua conta, execute o comando SHOW SERVICES:
SHOW SERVICES;
Para obter o status do seu serviço, execute o comando SHOW SERVICE CONTAINERS IN SERVICE:
SHOW SERVICE CONTAINERS IN SERVICE query_service;
Para obter informações sobre seu serviço, execute o comando DESCRIBE SERVICE:
DESCRIBE SERVICE query_service;
Uso do serviço¶
Nesta seção, verifique se os direitos do chamador configurados para o serviço funcionam. Você faz login no ponto de extremidade público a partir de um navegador, executa uma consulta e verifica se a sessão do Snowflake que o serviço criou opera como o usuário que chama, em vez de como o usuário do serviço.
Primeiro, para configurar o contexto das declarações do SQL nesta seção, execute o seguinte:
USE ROLE test_role;
USE DATABASE tutorial_db;
USE SCHEMA data_schema;
USE WAREHOUSE tutorial_warehouse;
O serviço expõe um ponto de extremidade público (consulte a especificação inline fornecida no comando CREATE SERVICE); portanto, primeiro faça login no ponto de extremidade usando um navegador da Web e, em seguida, use a UI da Web que o serviço expõe à Internet para enviar solicitações de consulta ao ponto de extremidade do serviço.
Encontre o URL do endereço do ponto de extremidade público que o serviço expõe:
SHOW ENDPOINTS IN SERVICE query_service;
A coluna
ingress_url
na resposta fornece o URL.Exemplo
p6bye-myorg-myacct.snowflakecomputing.app
Anexe
/ui
ao URL do ponto de extremidade e cole-o no navegador da web. Isso faz com que o serviço execute a funçãoui()
(consultemain.py
).Observe que na primeira vez que você acessar o URL do ponto de extremidade, será solicitado a fazer login no Snowflake.
Use o mesmo usuário que você usou para criar o serviço. Após o login bem-sucedido, o serviço mostra a seguinte UI da Web.
Digite o seguinte comando na caixa de texto e pressione Enter para ver os resultados.
SELECT CURRENT_USER(), CURRENT_ROLE()DONE;
Como você incluiu o recurso
executeAsCaller
na especificação do serviço, quando uma solicitação chega, o Snowflake insere o cabeçalhoSf-Context-Current-User-Token
na solicitação e, em seguida, encaminha a solicitação para o ponto de extremidade do serviço.Para fins de ilustração, o código de serviço neste tutorial executa a consulta tanto como chamador quanto como usuário do serviço.
Executa a consulta em nome do chamador (usuário de entrada): nesse caso, o código usa o token de usuário que o Snowflake fornece para construir um token de login para conexão com o Snowflake. Assim, o serviço usa os direitos do chamador. O Snowflake executa a consulta em nome do chamador, exibindo o nome do chamador e o nome da função ativa no resultado de consulta. Por exemplo:
['TESTUSER, PUBLIC']
Executa a consulta em nome do usuário do serviço: nesse caso, o código não usa o token de usuário que o Snowflake fornece na solicitação ao construir o token de login para se conectar ao Snowflake. Assim, o serviço não utiliza os direitos do chamador, fazendo com que o Snowflake execute a consulta em nome do usuário do serviço. O resultado de consulta mostra o nome do usuário do serviço (que é o mesmo que o nome do serviço) e a função ativa.
['QUERY_SERVICE, TEST_ROLE']
Quando o serviço executa a consulta (SELECT CURRENT_USER(), CURRENT_ROLE();
) em nome do chamador, o Snowflake não precisa do warehouse do usuário para executar essa consulta simples. Portanto, o serviço não precisava de nenhuma concessão do chamador. Na próxima seção, o serviço executa uma consulta não trivial em nome do usuário chamador que exige que você conceda concessões do chamador ao serviço.
Nota
Você pode acessar o ponto de extremidade de entrada programaticamente. Para obter um código de amostra, consulte Acesso de ponto de extremidade público de fora do Snowflake e autenticação. Observe que é necessário anexar /ui
ao URL do ponto de extremidade no código para que o Snowflake possa rotear a solicitação para a função ui()
no código de serviço.
Uso do serviço com concessões do chamador¶
Nesta seção, o serviço executa a seguinte consulta em nome do chamador (o usuário que faz login no ponto de extremidade de entrada do serviço).
SELECT * FROM ingress_user_db.ingress_user_schema.ingress_user_table;
O serviço não tem permissões para acessar a tabela e não tem permissão para executar a consulta no warehouse padrão. Para permitir que o serviço execute essa consulta em nome do chamador, você concede a concessão do chamador necessária ao serviço.
Para demonstrar o cenário, você cria uma nova função (ingress_user_role
) e uma tabela (ingress_user_table
) que é acessível à nova função, mas não à função de proprietário do serviço (test_role
). Portanto, quando o serviço tenta executar a consulta usando as credenciais do serviço, o Snowflake retorna um erro. Mas quando o serviço executa a consulta em nome do usuário, o Snowflake executa a consulta e retorna o resultado.
Criação de funções e recursos¶
Crie uma função (
ingress_user_role
) e um banco de dados (ingress_user_db
) que somente essa função possa acessar. Em seguida, você concede essa função ao seu usuário, para que ele possa fazer login no ponto de extremidade público do serviço e consultar essa tabela.USE ROLE accountadmin; CREATE ROLE ingress_user_role; GRANT ROLE ingress_user_role TO USER <your_user_name>; GRANT USAGE ON WAREHOUSE tutorial_warehouse TO ROLE ingress_user_role; CREATE DATABASE IF NOT EXISTS ingress_user_db; GRANT OWNERSHIP ON DATABASE ingress_user_db TO ROLE ingress_user_role COPY CURRENT GRANTS;
Crie uma tabela (
ingress_user_table
) que somente a funçãoingress_user_role
possa acessar.USE ROLE ingress_user_role; CREATE SCHEMA IF NOT EXISTS ingress_user_db.ingress_user_schema; USE WAREHOUSE tutorial_warehouse; CREATE TABLE ingress_user_db.ingress_user_schema.ingress_user_table (col string) AS ( SELECT 'this table is only accessible to the ingress_user_role' );
Observe que quando o serviço tenta consultar a tabela em nome do chamador, o serviço opera somente como
test_role
, a função que foi usada para criar o serviço (a função de proprietário do serviço). Essa função não tem permissão para acessar a tabela de usuários.Concede concessões do chamador à função de proprietário do serviço (
test_role
) para consultar tabelas no banco de dadosingress_user_db
. Esse privilégio permite que o serviço consulte tabelas nesse banco de dados somente se o seguinte for verdadeiro:O serviço está usando uma sessão de direitos do chamador.
Na sessão, o chamador também tem permissão para executar essas consultas.
USE ROLE accountadmin; GRANT CALLER USAGE ON DATABASE ingress_user_db TO ROLE test_role; GRANT INHERITED CALLER USAGE ON ALL SCHEMAS IN DATABASE ingress_user_db TO ROLE test_role; GRANT INHERITED CALLER SELECT ON ALL TABLES IN DATABASE ingress_user_db TO ROLE test_role; GRANT CALLER USAGE ON WAREHOUSE tutorial_warehouse TO ROLE test_role; SHOW CALLER GRANTS TO ROLE test_role;
Configure o warehouse padrão e as funções secundárias padrão.
Quando uma sessão é criada para um usuário, o Snowflake ativa a função primária padrão, as funções secundárias padrão e o warehouse padrão do usuário conectado. Neste tutorial,
Você define
DEFAULT_SECONDARY_ROLES
como ALL para que, quando uma sessão for criada para o usuário atual, o Snowflake defina as funções secundárias atuais como todas as funções concedidas ao usuário.Você também define o warehouse padrão como
tutorial_warehouse
, onde as consultasingress_user_table
são executadas.
ALTER USER SET DEFAULT_SECONDARY_ROLES = ('ALL'); ALTER USER SET DEFAULT_WAREHOUSE = TUTORIAL_WAREHOUSE;
Observe o seguinte:
Neste tutorial, você faz login no ponto de extremidade público do serviço. O usuário tem
test_role
como função principal eingress_user_role
como função secundária. Isso permite que a sessão faça tudo o que oingress_user_role
permite.A função padrão e o warehouse padrão afetam apenas a função e o warehouse ativados quando o serviço estabelece uma sessão em nome do usuário. Após o estabelecimento de uma sessão de direitos do chamador, você não pode alterar a função, mas pode alterar o warehouse.
Uso do serviço e teste das concessões do chamador¶
Encontre o URL do endereço do ponto de extremidade público que o serviço expõe:
SHOW ENDPOINTS IN SERVICE tutorial_db.data_schema.query_service;
A coluna
ingress_url
na resposta fornece o URL.Exemplo
p6bye-myorg-myacct.snowflakecomputing.app
Anexe
/ui
ao URL do ponto de extremidade e cole-o no navegador da web. Isso faz com que o serviço execute a funçãoui()
(consulteecho_service.py
): observe que, na primeira vez que acessar o URL do ponto de extremidade, você será solicitado a fazer login no Snowflake. Para esse teste, use o mesmo usuário que você usou para criar o serviço para garantir que o usuário tenha os privilégios necessários:Use o mesmo usuário que você usou para criar o serviço. Após o login bem-sucedido, o serviço mostra a seguinte UI da Web.
Digite o seguinte comando na caixa de texto e pressione Enter para ver os resultados.
SELECT * FROM ingress_user_db.ingress_user_schema.ingress_user_table;
Para fins de ilustração, o código de serviço neste tutorial executa a consulta tanto como chamador quanto como usuário do serviço.
Executa a consulta em nome do chamador (usuário de entrada): nesse caso, o código usa o token de usuário fornecido pelo Snowflake para construir um token de login para conexão com o Snowflake. Assim, o serviço usa os direitos do chamador. O Snowflake executa a consulta em nome do chamador. Como o chamador está usando o
ingress_user_role role
que tem o privilégio de consultar a tabelaingress_user_table
, a consulta retorna uma linha no resultado:['this table is only accessible to ingress_user_role']
Executa a consulta em nome do usuário do serviço: nesse caso, o código não usa o token de usuário que o Snowflake fornece na solicitação ao construir o token de login para se conectar ao Snowflake. Assim, o Snowflake executa a consulta em nome do usuário do serviço. Como o proprietário do serviço usa o endereço padrão
test_role
, que não tem permissão para consultar a tabela, você vê um erro:Encountered an error when executing query:... SQL compilation error: Database 'INGRESS_USER_DB' does not exist or not authorized.
Limpeza¶
Você deve remover os recursos faturáveis que criou. Para obter mais informações, consulte a Etapa 5 no Tutorial 3.
Revisão do código de serviço¶
Esta seção cobre os seguintes tópicos:
Revisão do código do tutorial: analise os arquivos de código que implementam o serviço de consulta.
Revisão do código do tutorial¶
O arquivo zip baixado na etapa 1 inclui os seguintes arquivos:
Dockerfile
main.py
templates/basic_ui.html
Você também usa a especificação de serviço ao criar o serviço. A seção a seguir explica como esses componentes de código funcionam juntos para criar o serviço.
arquivo main.py¶
Esse arquivo Python contém o código que implementa um servidor HTTP mínimo que executa uma consulta na solicitação e retorna os resultados de consulta. O código fornece uma interface de usuário da Web (UI) para o envio de solicitações de eco.
from flask import Flask
from flask import request
from flask import render_template
import logging
import os
import sys
from snowflake.snowpark import Session
from snowflake.snowpark.exceptions import *
# Environment variables below will be automatically populated by Snowflake.
SNOWFLAKE_ACCOUNT = os.getenv("SNOWFLAKE_ACCOUNT")
SNOWFLAKE_HOST = os.getenv("SNOWFLAKE_HOST")
SNOWFLAKE_DATABASE = os.getenv("SNOWFLAKE_DATABASE")
SNOWFLAKE_SCHEMA = os.getenv("SNOWFLAKE_SCHEMA")
# Custom environment variables
SNOWFLAKE_USER = os.getenv("SNOWFLAKE_USER")
SNOWFLAKE_PASSWORD = os.getenv("SNOWFLAKE_PASSWORD")
SNOWFLAKE_ROLE = os.getenv("SNOWFLAKE_ROLE")
SNOWFLAKE_WAREHOUSE = os.getenv("SNOWFLAKE_WAREHOUSE")
SERVICE_HOST = os.getenv("SERVER_HOST", "0.0.0.0")
SERVER_PORT = os.getenv("SERVER_PORT", 8080)
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
def get_login_token():
"""
Read the login token supplied automatically by Snowflake. These tokens
are short lived and should always be read right before creating any new connection.
"""
with open("/snowflake/session/token", "r") as f:
return f.read()
def get_connection_params(ingress_user_token=None):
"""
Construct Snowflake connection params from environment variables.
"""
if os.path.exists("/snowflake/session/token"):
if ingress_user_token:
logger.info("Creating a session on behalf of user.")
token = get_login_token() + "." + ingress_user_token
else:
logger.info("Creating a session as service user.")
token = get_login_token()
return {
"account": SNOWFLAKE_ACCOUNT,
"host": SNOWFLAKE_HOST,
"authenticator": "oauth",
"token": token,
"warehouse": SNOWFLAKE_WAREHOUSE,
"database": SNOWFLAKE_DATABASE,
"schema": SNOWFLAKE_SCHEMA,
}
else:
return {
"account": SNOWFLAKE_ACCOUNT,
"host": SNOWFLAKE_HOST,
"user": SNOWFLAKE_USER,
"password": SNOWFLAKE_PASSWORD,
"role": SNOWFLAKE_ROLE,
"warehouse": SNOWFLAKE_WAREHOUSE,
"database": SNOWFLAKE_DATABASE,
"schema": SNOWFLAKE_SCHEMA,
}
logger = get_logger("query-service")
app = Flask(__name__)
@app.get("/healthcheck")
def readiness_probe():
return "I'm ready!"
@app.route("/ui", methods=["GET", "POST"])
def ui():
"""
Main handler for providing a web UI.
"""
if request.method == "POST":
# get ingress user token
ingress_user = request.headers.get("Sf-Context-Current-User")
ingress_user_token = request.headers.get("Sf-Context-Current-User-Token")
if ingress_user:
logger.info(f"Received a request from user {ingress_user}")
# getting input in HTML form
query = request.form.get("query")
if query:
logger.info(f"Received a request for query: {query}.")
query_result_ingress_user = (
run_query(query, ingress_user_token)
if ingress_user_token
else "Token is missing. Can't execute as ingress user."
)
query_result_service_user = run_query(query)
return render_template(
"basic_ui.html",
query_input=query,
query_result_ingress_user=query_result_ingress_user,
query_result_service_user=query_result_service_user,
)
return render_template("basic_ui.html")
@app.route("/query", methods=["GET"])
def query():
"""
Main handler for providing programmatic access.
"""
# get ingress user token
query = request.args.get("query")
logger.info(f"Received query request: {query}.")
if query:
ingress_user = request.headers.get("Sf-Context-Current-User")
ingress_user_token = request.headers.get("Sf-Context-Current-User-Token")
if ingress_user:
logger.info(f"Received a request from user {ingress_user}")
res = run_query(query, ingress_user_token)
return str(res)
return "DONE"
def run_query(query, ingress_user_token=None):
# start a Snowflake session as the ingress user
try:
with Session.builder.configs(
get_connection_params(ingress_user_token)
).create() as session:
logger.info(
f"Snowflake connection established (id={session.session_id}). Now executing query: {query}."
)
try:
res = session.sql(query).collect()
logger.info(f"Query execution done: {query}.")
return (
"[Empty Result]"
if len(res) == 0
else [", ".join(row) for row in res]
)
except Exception as e:
return "Encountered an error when executing query: " + str(e)
except Exception as e:
return "Encountered an error when connecting to Snowflake: " + str(e)
if __name__ == '__main__':
app.run(host=SERVICE_HOST, port=SERVER_PORT)
No código:
A função
ui
exibe o seguinte formulário da Web e trata as solicitações de consulta enviadas pelo formulário da Web.Esta função usa o decorador
@app.route()
para especificar que as solicitações de/ui
serão tratadas por esta função:@app.route("/ui", methods=["GET", "POST"]) def ui():
O serviço de consulta expõe publicamente o ponto de extremidade
execute
(consulte a especificação de serviço em linha que você forneceu ao criar o serviço), permitindo a comunicação com o serviço pela Web. Quando você carrega o URL do ponto de extremidade público com /ui anexado em seu navegador, o navegador envia uma solicitação HTTP GET para esse caminho e o servidor encaminha a solicitação para essa função. A função é executada e retorna um formulário HTML simples para o usuário inserir uma consulta.Depois que o usuário insere uma consulta e envia o formulário, o navegador envia uma solicitação HTTP POST para esse caminho. Como a especificação do serviço inclui o recurso
executeAsCaller
, o Snowflake adiciona o cabeçalhoSf-Context-Current-User-Token
à solicitação de entrada e encaminha a solicitação para essa mesma função (consulte Conexão com o Snowflake usando os direitos do chamador).O código executa a função
run_query
duas vezes:Como usuário de entrada. Nesse caso, o token de login é a concatenação do token do OAuth e do token de usuário de ingresso.
token = get_login_token() + "." + ingress_user_token
Como usuário do serviço. Nesse caso, o token de login é apenas o token do OAuth.
token = get_login_token()
A função
readiness_probe
usa o decorador@app.get()
para especificar que as solicitações de/healthcheck
serão tratadas por esta função:@app.get("/healthcheck") def readiness_probe():
Esta função permite que o Snowflake verifique a prontidão do serviço. Quando o contêiner é iniciado, o Snowflake deseja confirmar se o aplicativo está funcionando e se o serviço está pronto para atender às solicitações. O Snowflake envia uma solicitação HTTP GET com esse caminho (como uma análise de integridade, análise de prontidão) para garantir que apenas contêineres íntegros tenham tráfego. A função pode fazer o que você quiser.
A função
get_logger
ajuda a configurar a geração de registros.
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 main.py ./
COPY templates/ ./templates/
RUN pip install --upgrade pip && pip install flask snowflake-snowpark-python
CMD ["python", "main.py"]
O Dockerfile contém instruções para instalar a biblioteca do Flask no contêiner do Docker. O código em main.py
depende da biblioteca Flask para lidar com solicitações HTTP.
/template/basic_ui.html¶
O serviço de consulta expõe publicamente o ponto de extremidade echoendpoint
(consulte a especificação do serviço), permitindo a comunicação com o serviço pela Web. Quando você carrega o URL do ponto de extremidade público com /ui
anexado em seu navegador, o serviço de consulta exibe esse formulário.

Você pode inserir uma consulta no formulário e enviar o formulário, e o serviço retorna os resultados em uma resposta de HTTP.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Welcome to the query service!</title>
</head>
<body>
<h1>Welcome to the query service!</h1>
<form action="{{ url_for("ui") }}" method="post">
<label for="query">query:<label><br>
<input type="text" id="query" name="query" size="50"><br>
</form>
<h2>Query:</h2>
{{ query_input }}
<h2>Result (executed on behalf of ingress user):</h2>
{{ query_result_ingress_user }}
<h2>Result (executed as service user):</h2>
{{ query_result_service_user }}
</body>
</html>
Especificação de serviço¶
Snowflake usa as informações fornecidas nesta especificação para configurar e executar seu serviço.
spec:
containers:
- name: main
image: /tutorial_db/data_schema/tutorial_repository/query_service:latest
env:
SERVER_PORT: 8000
readinessProbe:
port: 8000
path: /healthcheck
endpoints:
- name: execute
port: 8000
public: true
capabilities:
securityContext:
executeAsCaller: true
serviceRoles:
- name: ui_usage
endpoints:
- execute
Na especificação do serviço, spec
, capabilities
e serviceRoles
são os campos de nível superior.
spec
fornece detalhes de especificação (consulte Referência de especificação de serviço). Observe que o serviço expõe um ponto de extremidade público (execute
) que permite o acesso de entrada ao serviço a partir da Web pública.capabilities
Especifica o recursoexecuteAsCaller
. Isso informa ao Snowflake que o aplicativo pretende usar os direitos do chamador.serviceRoles
especifica uma função de serviço (ui_usage
) e um nome de ponto de extremidade (execute
) para conceder o privilégio USAGE.O campo
readinessProbe
identificaport
epath
que o Snowflake pode usar para enviar uma solicitação HTTP GET à análise de prontidão para verificar se o serviço está pronto para lidar com o tráfego.O código de serviço (
echo_python.py
) implementa a sonda de prontidão da seguinte forma:@app.get("/healthcheck") def readiness_probe():
Portanto, o arquivo de especificação inclui o campo
container.readinessProbe
adequadamente.
Para obter mais informações sobre especificações de serviço, consulte Referência de especificação de serviço.
Qual é o próximo passo?¶
Agora que você concluiu este tutorial, você pode retornar para Como trabalhar com serviços para explorar outros tópicos.