Snowpark Container Services: como trabalhar com serviços

O Snowpark Container Services permite implantar, gerenciar e dimensionar facilmente aplicativos em contêineres. Depois de criar um aplicativo e carregar a imagem do aplicativo em um repositório na sua conta Snowflake, você pode executar os contêineres do aplicativo como um serviço.

Um serviço representa o Snowflake executando seu aplicativo em contêiner em um pool de computação, que é uma coleção de nós de máquinas virtuais (VM). Há dois tipos de serviços:

  • Serviços de longa execução. um serviço de longa execução é como um serviço web que não termina automaticamente. Depois de criar um serviço, o Snowflake gerencia o serviço em execução. Por exemplo, se um contêiner de serviço parar, por qualquer motivo, o Snowflake reinicia esse contêiner para que o serviço seja executado ininterruptamente.

  • Serviços de trabalho. um serviço de trabalho termina quando seu código sai, semelhante a um procedimento armazenado. Quando todos os contêineres saírem, o serviço de trabalho estará concluído.

O Snowpark Container Services fornece um conjunto de comandos SQL que você pode usar para criar e gerenciar um serviço. Isso inclui:

Como iniciar os serviços

As informações mínimas necessárias para iniciar um serviço incluem:

  • Um nome: nome do serviço.

  • Uma especificação de serviço: esta especificação fornece ao Snowflake as informações necessárias para executar seu serviço. A especificação é um arquivo YAML.

  • Um pool de computação: o Snowflake executa seu serviço no pool de computação especificado.

Crie um serviço de longa duração

Use CREATE SERVICE para criar um serviço de longa duração.

  • Crie um serviço usando uma especificação embutida. Na maioria dos casos, durante o desenvolvimento, você pode escolher a especificação embutida, conforme mostrado:

    CREATE SERVICE echo_service
       IN COMPUTE POOL tutorial_compute_pool
       FROM SPECIFICATION $$
       spec:
         containers:
         - name: echo
           image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:tutorial
           readinessProbe:
             port: 8000
             path: /healthcheck
         endpoints:
         - name: echoendpoint
           port: 8000
           public: true
       $$;
    
    Copy
  • Crie um serviço usando informações de estágio. Quando você implementar o serviço em um ambiente de produção, é aconselhável aplicar o princípio de design da separação de interesses e carregar a especificação para um estágio, fornecer o comando CREATE SERVICE de informações de estágio, como mostrado:

    CREATE SERVICE echo_service
      IN COMPUTE POOL tutorial_compute_pool
      FROM @tutorial_stage
      SPECIFICATION_FILE='echo_spec.yaml';
    
    Copy

Execução de um serviço de trabalho

Use EXECUTE JOB SERVICE para criar um serviço de trabalho. Este comando é executado de forma síncrona e retorna uma resposta depois que todos os contêineres do serviço de trabalho saem.

  • Execute um serviço de trabalho usando uma especificação inline:

    EXECUTE JOB SERVICE
       IN COMPUTE POOL tutorial_compute_pool
       NAME = example_job_service
       FROM SPECIFICATION $$
       spec:
         container:
         - name: main
           image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
           env:
             SNOWFLAKE_WAREHOUSE: tutorial_warehouse
           args:
           - "--query=select current_time() as time,'hello'"
           - "--result_table=results"
       $$;
    
    Copy
  • Execute um serviço de trabalho usando informações de estágio:

    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service
      FROM @tutorial_stage
      SPECIFICATION_FILE='my_job_spec.yaml';
    
    Copy

Criação de várias instâncias de serviço e habilitação do dimensionamento automático

Por padrão, o Snowflake executa uma instância do serviço no pool de computação especificado. Para gerenciar cargas de trabalho pesadas, você pode executar várias instâncias de serviço definindo as propriedades MIN_INSTANCES e MAX_INSTANCES, que especificam o número mínimo de instâncias do serviço para começar e o número máximo de instâncias para as quais o Snowflake pode escalar quando necessário.

Exemplo

CREATE SERVICE echo_service
   IN COMPUTE POOL tutorial_compute_pool
   FROM @tutorial_stage
   SPECIFICATION_FILE='echo_spec.yaml'
   MIN_INSTANCES=2
   MAX_INSTANCES=4;
Copy

Quando várias instâncias de serviço estão em execução, o Snowflake fornece automaticamente um balanceador de carga para distribuir as solicitações recebidas.

Nota

Não é possível executar mais de uma instância de um serviço de trabalho.

Para configurar o Snowflake para dimensionar automaticamente o número de instâncias de serviço em execução, siga estas etapas:

  1. Especifique os requisitos de CPU e memória para sua instância de serviço no arquivo de especificação de serviço. Para obter mais informações, consulte a campo container.resources.

    Exemplo

    resources:
      requests:
       memory: <memory-reserved>
       cpu: <cpu-units>
    
    Copy
  2. Ao executar o comando CREATE SERVICE, defina os parâmetros MIN_INSTANCES e MAX_INSTANCES. Você também pode usar ALTER SERVICE para alterar esses valores. O dimensionamento automático ocorre quando o MAX_INSTANCES especificado é maior que o MIN_INSTANCES.

O Snowflake começa criando o número mínimo de instâncias de serviço no pool de computação especificado. O Snowflake então aumenta ou diminui o número de instâncias de serviço usando um limite de 80% (para CPU e memória). O Snowflake monitora continuamente a utilização de recursos (memória ou CPU) no pool de computação, agregando os dados de uso de todas as instâncias de serviço em execução no momento.

Quando o uso de recursos agregados (em todas as instâncias de serviço) ultrapassa 80%, o Snowflake implanta uma instância de serviço adicional no pool de computação. Se o uso de recursos agregados cair abaixo de 80%, o Snowflake reduz a escala removendo uma instância de serviço em execução. Snowflake usa uma janela de estabilização de cinco minutos para evitar o dimensionamento frequente.

Observe os seguintes comportamentos de dimensionamento:

  • O dimensionamento das instâncias de serviço é limitada pelos parâmetros MIN_INSTANCES e MAX_INSTANCES configurados para o serviço.

  • Se o dimensionamento for necessário e os nós do pool de computação não tiverem a capacidade de recursos necessária para iniciar outra instância de serviço, o escalonamento automático do pool de computação poderá ser acionado. Para obter mais informações, consulte Dimensionamento automático de nós do pool de computação.

  • Se você especificar os parâmetros MAX_INSTANCES e MIN_INSTANCES ao criar um serviço, mas não especificar os requisitos de CPU e memória para sua instância de serviço no arquivo de especificação de serviço, nenhum dimensionamento automático ocorrerá; o Snowflake inicia com o número de instâncias especificado pelo parâmetro MIN_INSTANCES e não realiza o dimensionamento automático.

Uso de modelos de especificação

Às vezes, você pode querer criar vários serviços usando a mesma especificação, mas com configurações diferentes. Por exemplo, você supõe que define uma variável de ambiente em uma especificação de serviço e deseja criar vários serviços usando a mesma especificação, mas valores diferentes para a variável de ambiente.

Os modelos de especificação permitem que você defina variáveis para valores de campo na especificação. Ao criar um serviço, você fornece valores para essas variáveis.

O uso de modelos de especificação é um processo de duas etapas:

  1. Crie uma especificação usando variáveis como valores para vários campos de especificação. Use a sintaxe {{ variable_name }} para especificar essas variáveis. Por exemplo, a especificação a seguir usa uma variável chamada “tag_name” para o nome da tag de imagem, para que você especifique uma tag de imagem diferente para cada serviço.

    spec:
      containers:
      - name: echo
        image: myorg-myacct.registry.snowflakecomputing.com/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:{{ tag_name }}
        ...
      endpoints:
      
    
    Copy
  2. Crie um serviço fornecendo o modelo de especificação em um comando CREATE SERVICE. Você usa SPECIFICATION_TEMPLATE ou SPECIFICATION_TEMPLATE_FILE para especificar o modelo. Use o parâmetro USING para especificar o valor da variável. Por exemplo, a instrução a seguir usa um modelo de especificação de um estágio Snowflake. O parâmetro USING define a variável tag_name para o valor 'latest'.

    CREATE SERVICE echo_service
       IN COMPUTE POOL tutorial_compute_pool
       FROM @STAGE SPECIFICATION_TEMPLATE_FILE='echo.yaml'
       USING (tag_name=>'latest');
    
    Copy

Diretrizes para definir variáveis em uma especificação

  • Use a sintaxe {{ variable_name }} para definir variáveis como valores de campo na especificação.

  • Essas variáveis podem ter valores padrão. Para especificar o valor padrão, use a função default na declaração da variável. Por exemplo, a especificação a seguir define duas variáveis (character_name e endpoint_name) com valores padrão.

    spec:
      containers:
      - name: echo
        image: <image_name>
        env:
          CHARACTER_NAME: {{ character_name | default('Bob') }}
          SERVER_PORT: 8085
      endpoints:
      - name: {{ endpoint_name | default('echo-endpoint') }}
        port: 8085
    
    Copy

    Além disso, é possível especificar um parâmetro booliano opcional para a função default para indicar se deseja que o valor padrão seja usado quando um valor em branco for passado para a variável. Considere esta especificação:

    spec:
      containers:
      - name: echo
        image: <image_name>
        env:
          CHARACTER_NAME: {{ character_name | default('Bob', false) }}
          SERVER_PORT: 8085
      endpoints:
      - name: {{ endpoint_name | default('echo-endpoint', true) }}
        port: 8085
    
    Copy

    Na especificação:

    • Para a variável character_name, o parâmetro booleano é definido como false. Portanto, se a variável for definida como um valor de cadeia de caracteres vazia (“”) para este parâmetro, o valor permanecerá em branco; o valor padrão («Bob») não será usado.

    • Para a variável echo_endpoint, o parâmetro booleano é definido como true. Portanto, se você passar um valor em branco para este parâmetro, o valor padrão (“ponto de extremidade-echo”) será usado.

    Por padrão, o parâmetro booleano para a função default é false.

Diretrizes para passagem de valores para variáveis de especificação

Especifique o parâmetro USING no comando CREATE SERVICE para fornecer valores para variáveis. A sintaxe geral para USING é:

USING( var_name=>var_value, [var_name=>var_value, ... ] );
Copy

onde

  • var_name diferencia maiúsculas de minúsculas e deve ser um identificador Snowflake válido (consulte Requisitos para identificadores).

  • var_value pode ser um valor alfanumérico ou um valor JSON válido.

    Exemplos:

    -- Alphanumeric string and literal values
    USING(some_alphanumeric_var=>'blah123',
          some_int_var=>111,
          some_bool_var=>true,
          some_float_var=>-1.2)
    
    -- JSON string
    USING(some_json_var=>' "/path/file.txt" ')
    
    -- JSON map
    USING(env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' );
    
    -- JSON list
    USING (ARGS='["-n", 2]' );
    
    Copy
  • O parâmetro USING em CREATE SERVICE deve fornecer valores para as variáveis de especificação (exceto as variáveis para as quais a especificação fornece valores padrão). Caso contrário, um erro é retornado.

Exemplos

Esses exemplos mostram a criação de serviços usando modelos de especificação. Os comandos CREATE SERVICE nestes exemplos usam especificação inline.

Exemplo 1: forneça valores simples

Em Tutorial 1 você cria um serviço fornecendo uma especificação inline. O exemplo a seguir é uma versão modificada do mesmo, onde a especificação define duas variáveis: image_url e SERVER_PORT. Note que a variável SERVER_PORT é repetida em três lugares. Isso tem o benefício adicional de usar variáveis que garantem que todos esses campos que deveriam ter o mesmo valor tenham o mesmo valor.

CREATE SERVICE echo_service
   IN COMPUTE POOL tutorial_compute_pool
   MIN_INSTANCES=1
   MAX_INSTANCES=1
   FROM SPECIFICATION_TEMPLATE $$
      spec:
         containers:
         - name: echo
           image: {{ image_url }}
           env:
             SERVER_PORT: {{SERVER_PORT}}
             CHARACTER_NAME: Bob
           readinessProbe:
             port: {{SERVER_PORT}}
             path: /healthcheck
         endpoints:
         - name: echoendpoint
           port: {{SERVER_PORT}}
           public: true
         $$
      USING (image_url=>' "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest" ', SERVER_PORT=>8000 );
Copy

Neste comando CREATE SERVICE, o parâmetro USING fornece valores para as duas variáveis de especificação. O valor image_url inclui barras e dois pontos. Estes não são caracteres alfanuméricos. Portanto, o exemplo envolve o valor entre aspas duplas para torná-lo um valor de cadeia de caracteres JSON válido. A especificação do modelo expande a seguinte especificação:

spec:
  containers:
  - name: echo
    image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
    env:
      SERVER_PORT: 8000
      CHARACTER_NAME: Bob
    readinessProbe:
      port: 8000
      path: /healthcheck
    endpoints:
    - name: echoendpoint
      port: 8000
      public: true
Copy

Exemplo 2: forneça um valor JSON

No Tutorial 1, a especificação define duas variáveis de ambiente (SERVER_PORT e CHARACTER_NAME), conforme mostrado:

spec:
 containers:
 - name: echo
   image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
   env:
     SERVER_PORT: 8000
     CHARACTER_NAME: Bob
   
Copy

É possível criar um modelo para essa especificação usando uma variável para o campo env. Isso permite que você crie vários serviços com valores diferentes para as variáveis de ambiente. O seguinte comando CREATE SERVICE usa uma variável (env_values) para o campo env.

CREATE SERVICE echo_service
  IN COMPUTE POOL tutorial_compute_pool
  MIN_INSTANCES=1
  MAX_INSTANCES=1
  FROM SPECIFICATION_TEMPLATE $$
     spec:
       containers:
       - name: echo
         image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
         env: {{env_values}}
         readinessProbe:
           port: {{SERVER_PORT}}    #this and next tell SF to connect to port 8000
           path: /healthcheck
       endpoints:
       - name: echoendpoint
         port: {{SERVER_PORT}}
         public: true
        $$
     USING (env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' );
Copy

O parâmetro USING em CREATE SERVICE fornece valor para a variável env_values. O valor é um mapa JSON que fornece valores para ambas as variáveis de ambiente.

Exemplo 3: fornecer lista como valor variável

Em Tutorial 2, a especificação inclui o campo args que inclui dois argumentos.

spec:
  container:
  - name: main
    image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
    env:
      SNOWFLAKE_WAREHOUSE: tutorial_warehouse
    args:
    - "--query=select current_time() as time,'hello'"
    - "--result_table=results"
Copy

Em uma versão de modelo da especificação, você pode fornecer esses argumentos como uma lista JSON como mostrado:

spec:
  container:
  - name: main
    image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
    env:
      SNOWFLAKE_WAREHOUSE: tutorial_warehouse
    args: {{ARGS}}
  $$
  USING (ARGS=$$["--query=select current_time() as time,'hello'", "--result_table=results"]$$ );
Copy

Modificação e descarte de serviços

Após criar um serviço:

  • Use o comando DROP SERVICE para remover um serviço de um esquema (o Snowflake encerra todos os contêineres de serviço).

  • Use o comando ALTER SERVICE para modificar o serviço (por exemplo, suspender ou retomar o serviço, alterar o número de instâncias em execução e instruir o Snowflake a reimplantar seu serviço usando uma nova especificação de serviço).

    Nota

    • Você não pode alterar um serviço de trabalho.

Término do serviço

Quando você suspende um serviço (ALTER SERVICE … SUSPEND) ou descarta um serviço (DROP SERVICE), o Snowflake encerra todas as instâncias do serviço. Da mesma forma, quando você atualiza o código de serviço (ALTER SERVICE … <fromSpecification>), o Snowflake aplica atualizações contínuas encerrando e reimplementando uma instância de serviço por vez.

Ao encerrar uma instância de serviço, o Snowflake primeiro envia um sinal SIGTERM para cada contêiner de serviço. O contêiner tem a opção de processar o sinal e desligar normalmente em uma janela de 30 segundos. Caso contrário, após o período de carência, o Snowflake encerra todos os processos no contêiner.

Atualização do código de serviço e reimplementação do serviço

Após a criação de um serviço, use o comando ALTER SERVICE … <fromSpecification> para atualizar o código de serviço e reimplementar o serviço.

Primeiro, carregue o código do aplicativo modificado em seu repositório de imagens e, em seguida, chame ALTER SERVICE, fornecendo a especificação do serviço em linha ou especificando o caminho para um arquivo de especificação no estágio Snowflake. Por exemplo:

ALTER SERVICE echo_service
FROM SPECIFICATION $$
spec:
  
  
$$;
Copy

Ao receber a solicitação, o Snowflake reimplanta o serviço usando o novo código.

Quando você executa o comando CREATE SERVICE … <from-Specification>, o Snowflake registra a versão específica da imagem fornecida. O Snowflake implementa a mesma versão de imagem nos seguintes cenários, mesmo que a imagem no repositório tenha sido atualizada:

  • Quando um serviço suspenso é retomado (usando ALTER SERVICE … RESUME).

  • Quando o dimensionamento automático adiciona mais instâncias de serviço.

  • Quando instâncias de serviço são reiniciadas durante a manutenção do cluster.

Mas se você chamar ALTER SERVICE … <fromSpecification>, isso fará com que o Snowflake use a versão mais recente no repositório para essa imagem.

Se você for o proprietário do serviço, a saída do comando DESCRIBE SERVICE incluirá a especificação do serviço, que inclui o resumo da imagem (o valor do campo sha256 na especificação), conforme mostrado abaixo:

spec:
containers:
- name: "echo"
    image: "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest"
    sha256: "@sha256:8d912284f935ecf6c4753f42016777e09e3893eed61218b2960f782ef2b367af"
    env:
      SERVER_PORT: "8000"
      CHARACTER_NAME: "Bob"
    readinessProbe:
      port: 8000
      path: "/healthcheck"
endpoints:
- name: "echoendpoint"
    port: 8000
    public: true
Copy

ALTER SERVICE pode afetar as comunicações (consulte Como usar um serviço) com o serviço.

  • Se ALTER SERVICE … <fromSpecification> remover um ponto de extremidade ou remover permissões relevantes necessárias para usar um ponto de extremidade (consulte serviceRoles na referência de especificação), o acesso ao serviço falhará. Para obter mais informações, consulte Como usar um serviço.

  • Enquanto a atualização estiver em andamento, novas conexões poderão ser roteadas para a nova versão. Se a nova versão do serviço não for compatível com versões anteriores, ela interromperá qualquer uso ativo do serviço. Por exemplo, consultas em andamento usando uma função de serviço podem falhar.

Nota

Ao atualizar o código de serviço que faz parte de um aplicativo nativo com contêineres, você pode usar a função do sistema SYSTEM$WAIT_FOR_SERVICES para pausar o script de configuração do aplicativo nativo para permitir que os serviços sejam atualizados completamente. Para obter mais informações, consulte Atualização de um aplicativo com contêineres.

Monitoramento de atualizações contínuas

Quando várias instâncias de serviço estão em execução, o Snowflake executa uma atualização contínua em ordem decrescente com base no ID das instâncias de serviço. Como usar os seguintes comandos para monitorar as atualizações de serviço:

  • DESCRIBE SERVICE e SHOW SERVICES:

    • A coluna is_upgrading na saída mostra TRUE se o serviço estiver sendo atualizado.

    • A coluna spec_digest na saída representa o resumo da especificação do serviço atual. É possível executar este comando periodicamente; uma alteração no valor spec_digest indica que uma atualização de serviço foi acionada. Use o comando SHOW SERVICE INSTANCES IN SERVICE para verificar se todas as instâncias foram atualizadas para a versão mais recente, conforme explicado abaixo.

  • SHOW SERVICE INSTANCES IN SERVICE:

    • A coluna status na saída fornece o status de cada instância de serviço individual enquanto a atualização contínua está em andamento. Durante a atualização, você observará cada status de transição de instância de serviço, como TERMINATING para PENDING e PENDING para READY.

    • Durante a atualização do serviço, os comandos SHOW SERVICE INSTANCES IN SERVICE podem retornar valores diferentes na coluna spec_digest de saída de SHOW SERVICES, que sempre retorna o resumo de especificações mais recente. Isso simplesmente indica que a atualização do serviço está em andamento e as instâncias do serviço ainda estão executando a versão antiga do serviço.

Obtenção de informações sobre serviços

É possível usar estes comandos:

  • Use o comando DESCRIBE SERVICE para recuperar as propriedades e o status de um serviço.

  • Use o comando SHOW SERVICES para listar os serviços atuais (incluindo serviços de trabalho) para os quais você tem permissões. Para cada serviço, a saída fornece propriedades e status do serviço. Por padrão, a saída lista os serviços no banco de dados e esquema atuais. Como alternativa, é possível especificar qualquer um dos seguintes escopos. Por exemplo:

    • Liste os serviços na conta, em um banco de dados específico ou em um esquema específico: Por exemplo, use o filtro IN ACCOUNT para listar serviços em sua conta Snowflake, independentemente do banco de dados ou esquema ao qual os serviços pertencem. Isso é útil se você tiver serviços Snowflake criados em vários bancos de dados e esquemas em sua conta. Como todos os outros comandos, SHOW SERVICES IN ACCOUNTS é controlado por privilégios, retornando apenas os serviços para os quais a função que você está usando tem permissões de exibição.

      Você também pode especificar IN DATABASE ou IN SCHEMA para listar os serviços no banco de dados ou esquema atual (ou especificado).

    • Liste os serviços em execução em um pool de computação: Por exemplo, use o filtro IN COMPUTE POOL para listar os serviços em execução em um pool de computação.

    • Liste os serviços que começam com um prefixo ou que correspondam a um padrão: É possível aplicar os filtros LIKE e STARTS WITH para filtrar os serviços por nome.

    • Liste os serviços de trabalho ou exclua serviços de emprego da lista: É possível usar SHOW JOB SERVICES ou SHOW SERVICES EXCLUDE JOBS para listar apenas serviços de trabalho ou excluí-los.

    Você também pode combinar essas opções para personalizar a saída de SHOW SERVICES.

  • Use o comando SHOW SERVICE INSTANCES IN SERVICE para recuperar propriedades das instâncias de serviço.

  • Use o comando SHOW SERVICE CONTAINERS IN SERVICE para recuperar as propriedades e o status das instâncias de serviço.

Serviços de monitoramento

O Snowpark Container Services oferece ferramentas para monitorar pools de computação em sua conta e os serviços em execução neles. Para obter mais informações, consulte Snowpark Container Services: Serviços de monitoramento.

Gerenciamento do acesso aos pontos de extremidade do servidor

A função de proprietário do serviço (a função que você usa para criar o serviço) tem acesso total ao serviço e aos pontos de extremidade que o serviço expõe. Outras funções precisarão do privilégio USAGE nos pontos de extremidade para se comunicar com o serviço. Por exemplo,

  • A função de proprietário do cliente precisa do privilégio USAGE no ponto de extremidade. Cliente se refere a uma função de serviço ou a um serviço que faz solicitações a pontos de extremidade de outro serviço.

    • Para criar uma função de serviço ao referenciar um ponto de extremidade, o usuário precisa acessar o ponto de extremidade. Ou seja, a função de proprietário da função de serviço precisa do privilégio USAGE no ponto de extremidade final referenciado no CREATE FUNCTION.

    • Em comunicações de serviço para serviço, a função de proprietário do serviço do cliente (que está chamando o ponto de extremidade do outro serviço) precisa do privilégio USAGE no ponto de extremidade.

  • Um usuário fazendo solicitações de entrada de fora do Snowflake para um ponto de extremidade público precisam do privilégio USAGE no ponto de extremidade.

Uma função de serviço é um mecanismo para conceder privilégios em pontos de extremidade do servidor para outras funções. Você tem estas opções:

  • Use a função de serviço padrão: O Snowflake define uma função de serviço padrão (ALL_ENDPOINTS_USAGE) que concede o privilégio USAGE em todos os pontos de extremidade que o serviço expõe e concede essa função de serviço padrão à função de proprietário do serviço. Assim, a função de proprietário pode acessar todos os pontos de extremidade que o serviço expõe. É possível conceder essa função de serviço padrão a outras funções.

  • Crie uma função de serviço: Em vez de conceder privilégios em todos os pontos de extremidade usando a função de serviço padrão, você pode definir uma ou mais funções de serviço na especificação de serviço. Na definição, indique os pontos de extremidade específicos para os quais a função recebe o privilégio USAGE. É possível conceder (ou revogar) a função de serviço para outras funções usando os comandos GRANT SERVICE ROLE e REVOKE SERVICE ROLE. Você também pode usar os comandos SHOW ROLES IN SERVICE e SHOW GRANTS, para exibir informações sobre as concessões.

    O Snowflake cria as funções de serviço quando você cria um serviço e as exclui quando você exclui o serviço.

    A criação de funções de serviço personalizadas permite que você conceda diferentes permissões de acesso para diferentes cenários. Por exemplo, você pode conceder uma permissão de função de serviço a um ponto de extremidade para uso com uma função de serviço. É possível criar outra função de serviço com permissão para um ponto de extremidade público usado com uma UI para a Web.

Observe o seguinte:

  • Se você usar a mesma função para criar vários serviços, como a função de proprietário tem acesso a todos os pontos de extremidade, esses serviços poderão se comunicar entre si perfeitamente, sem nenhuma alteração extra de configuração.

  • Se um serviço tiver vários contêineres, esses contêineres poderão se comunicar entre si via localhost, e essas comunicações serão locais dentro de cada instância de serviço e não estarão sujeitas ao controle de acesso baseado em função.

As seções a seguir fornecem detalhes. Você também pode tentar um tutorial (Configuração e teste de privilégios de ponto de extremidade do servidor) que fornece instruções passo a passo para explorar esse recurso.

Concessão do privilégio USAGE em todos os pontos de extremidade usando a função de serviço padrão

Quando você cria um serviço (incluindo serviço de trabalho), o Snowflake também cria uma função de serviço padrão, chamada ALL_ENDPOINTS_USAGE. Esta função tem o privilégio USAGE em todos os pontos de extremidade que o serviço expõe. Você pode conceder a outras funções esta função de serviço padrão usando o comando GRANT SERVICE ROLE:

GRANT SERVICE ROLE my_echo_service_image!ALL_ENDPOINTS_USAGE TO ROLE some_other_role;
Copy

Usuários que estão usando some_other_role tem o privilégio USAGE em todos os pontos de extremidade do servidor.

Quando você descarta um serviço, o Snowflake descarta todas as funções de serviço (função de serviço padrão e funções de serviço definidas na especificação do serviço) associadas ao serviço e anula todas as concessões de função de serviço.

Concessão do privilégio USAGE a pontos de extremidade específicos usando funções de serviço definidas na especificação

Use funções de serviço para gerenciar acesso detalhado aos pontos de extremidade do servidor. Você define as funções de serviço, juntamente com a lista de pontos de extremidade que recebem o privilégio USAGE, na especificação do serviço.

A concessão de privilégios em pontos de extremidade específicos de um serviço é um processo de duas etapas:

  1. Defina uma função de serviço: use uma especificação de serviço para definir uma função de serviço fornecendo um nome de função e uma lista de um ou mais pontos de extremidade para os quais você deseja conceder o privilégio USAGE. Por exemplo, no seguinte fragmento de especificação, o campo de nível superior serviceRoles define duas funções de serviço, cada uma com o privilégio USAGE em pontos de extremidade específicos.

    spec:
    ...
    serviceRoles:                 # Optional list of service roles
    - name: <svc_role_name1>
      endpoints:                  # endpoints that role can access
      - <endpoint_name1>
      - <endpoint_name2>
    - name: <svc_role_name2>
      endpoints:
      - <endpoint_name3>
      - <endpoint_name4>
    
    Copy
  2. Conceda a função de serviço a outras funções. usando o comando GRANT SERVICE ROLE, você concede a função de serviço a outras funções (funções de conta, funções de aplicativo ou funções de banco de dados). Por exemplo:

    GRANT SERVICE ROLE <service-name>!<svc_role_name1> TO ROLE <another-role>
    
    Copy

Como usar um serviço

Após criar um serviço, os usuários na mesma conta (que criou o serviço) podem usar qualquer um dos três métodos compatíveis a seguir para usá-lo. O usuário precisará ter acesso a funções com os privilégios necessários.

  • Use o serviço de uma consulta SQL (função de serviço): você cria uma função de serviço, uma função definida pelo usuário (UDF) associada a um serviço, e a usa em uma consulta SQL para se comunicar com o serviço. Para obter um exemplo, consulte Tutorial 1.

  • Use o serviço de fora do Snowflake (Entrada): É possível declarar um ou mais pontos de extremidade do servidor como públicos para permitir o acesso de entrada de rede ao serviço. Para obter um exemplo, consulte Tutorial 1.

  • Use o serviço de outro serviço (Comunicações de serviço para serviço): Os serviços podem se comunicar entre si usando o nome DNS do serviço atribuído pelo Snowflake para comunicação de serviço para serviço. Para ver um exemplo, consulte o Tutorial 3.

Nota

  • Um serviço de trabalho é executado como um trabalho e termina quando concluído. Não há suporte ao uso da função de serviço ou entrada para se comunicar com um serviço de trabalho.

    • Não é possível associar uma função de serviço a nenhum ponto de ponto de extremidade de um serviço de trabalho.

    • Você não pode criar um serviço de trabalho com uma especificação que defina um ponto de extremidade público.

  • Há suporte para comunicações de serviço para serviço com serviços de trabalho. Ou seja, serviços e serviços de trabalho podem se comunicar entre si.

As seções a seguir fornecem detalhes.

Funções de serviço: como usar um serviço de uma consulta SQL

Uma função de serviço é uma função definida pelo usuário (UDF) que você cria usando CREATE FUNCTION (Snowpark Container Services). No entanto, em vez de escrever o código UDF diretamente, você associa a UDF ao seu ponto de extremidade do servidor. Observe que é possível associar uma função de serviço somente a um ponto de extremidade do servidor que ofereça suporte ao protocolo HTTP ou HTTPS.

Por exemplo, no Tutorial 1, você cria um serviço chamado echo_service que expõe um ponto de extremidade (ponto de extremidade de eco) conforme definido na especificação do serviço:

spec:

  endpoints:
  - name: echoendpoint
    port: 8080
Copy

echoendpoint é um nome de ponto de extremidade amigável que representa a porta correspondente (8080). Para se comunicar com esse ponto de extremidade de serviço, crie uma função de serviço fornecendo os parâmetros SERVICE e ENDPOINT conforme mostrado:

CREATE FUNCTION my_echo_udf (text varchar)
   RETURNS varchar
   SERVICE=echo_service
   ENDPOINT=echoendpoint
   AS '/echo';
Copy

O parâmetro AS fornece o caminho HTTP para o código de serviço. Você obtém esse valor de caminho a partir do código de serviço. Por exemplo, as seguintes linhas de código são do service.py no Tutorial 1.

@app.post("/echo")
def echo():
...
Copy

Quando você invoca a função de serviço, o Snowflake direciona a solicitação para o ponto de extremidade do serviço e caminho de serviço associado.

Nota

Uma função de serviço é usada para se comunicar com um serviço e não com um trabalho. Em outras palavras, você só pode associar um serviço (não um trabalho) a uma função de serviço.

Especificação do tamanho do lote ao enviar dados para um serviço para aumentar a simultaneidade

Ao executar várias instâncias do seu serviço, você pode criar uma função de serviço especificando o parâmetro opcional MAX_BATCH_ROWS para limitar o tamanho do lote, o máximo de linhas que o Snowflake envia em um lote para o serviço. Por exemplo, suponha que MAX_BATCH_ROWS seja 10 e você chame a função de serviço my_echo_udf com 100 linhas de entrada. O Snowflake particiona as linhas de entrada em lotes, com cada lote tendo no máximo 10 linhas, e envia uma série de solicitações ao serviço com o lote de linhas no corpo da solicitação. Configurar o tamanho do lote pode ajudar quando o processamento leva um tempo não trivial, e distribuir linhas por todos os servidores disponíveis também pode ajudar.

Você pode usar ALTER FUNCTION para alterar uma função de serviço. O comando ALTER FUNCTION a seguir altera o ponto de extremidade do serviço ao qual ele está associado e o tamanho do lote:

ALTER FUNCTION my_echo_udf(VARCHAR)
   SET SERVICE=other_service
   ENDPOINT=otherendpoint
   MAX_BATCH_ROWS=100
Copy

Formato de troca de dados

Para troca de dados entre uma função de serviço e um contêiner de aplicativo, o Snowflake segue o mesmo formato que as funções externas usam (consulte Formatos de dados). Por exemplo, suponha que você tenha linhas de dados armazenadas em uma tabela (input_table):

"Alex", "2014-01-01 16:00:00"
"Steve", "2015-01-01 16:00:00"

Para enviar esses dados ao seu serviço, você invoca a função de serviço passando estas linhas como parâmetros:

SELECT service_func(col1, col2) FROM input_table;
Copy

Snowflake envia uma série de solicitações ao contêiner, com lotes de linhas de dados no corpo da solicitação neste formato:

{
   "data":[
      [
         0,
         "Alex",
         "2014-01-01 16:00:00"
      ],
      [
         1,
         "Steve",
         "2015-01-01 16:00:00"
      ],
      …
      [
         <row_index>,
         "<column1>",
         "<column2>"
      ],
   ]
}
Copy

O contêiner então retorna a saída no seguinte formato:

{
   "data":[
      [0, "a"],
      [1, "b"],
      …
      [ row_index,  output_column1]
   ]
}
Copy

O exemplo de saída mostrado assume que o resultado é uma tabela de uma coluna com linhas («a», «b»…).

Quando diversas instâncias de serviço estão em execução, você pode criar uma função de serviço usando o parâmetro MAX_BATCH_ROWS para distribuir as linhas de entrada para processamento em todos os servidores disponíveis. Para obter mais informações, consulte Especificação do tamanho do lote ao enviar dados para um serviço para aumentar a simultaneidade.

Privilégios necessários para criar e gerenciar funções de serviço

Para criar e gerenciar funções de serviço, uma função precisa dos seguintes privilégios:

  • Para criar uma função de serviço: a função atual deve ter o privilégio USAGE no serviço que está sendo referenciado.

  • Para alterar uma função de serviço: você pode alterar uma função de serviço e associá-la a outro serviço. A função atual deve ter o privilégio USAGE no novo serviço.

  • Para usar uma função de serviço: a função atual deve ter o privilégio USAGE na função de serviço e a função de proprietário da função de serviço deve ter o privilégio USAGE no serviço associado.

O script de exemplo a seguir mostra como você pode conceder permissão para usar uma função de serviço:

USE ROLE service_owner;
GRANT USAGE ON service service_db.my_schema.my_service TO ROLE func_owner;

USE ROLE func_owner;
CREATE OR REPLACE test_udf(v VARCHAR)
  RETURNS VARCHAR
  SERVICE=service_db.my_schema.my_service
  ENDPOINT=endpointname1
  AS '/run';

SELECT test_udf(col1) FROM some_table;

ALTER FUNCTION test_udf(VARCHAR) SET
  SERVICE = service_db.other_schema.other_service
  ENDPOINT=anotherendpoint;

GRANT USAGE ON FUNCTION test_udf(varchar) TO ROLE func_user;
USE ROLE func_user;
SELECT my_test_udf('abcd');
Copy

Entrada: usando um serviço de fora do Snowflake

Um serviço pode expor um ou mais pontos de extremidade como públicos para permitir que os usuários utilizem o serviço na Web pública. Nesse caso, Snowflake gerencia o controle de acesso. Observe que a entrada é permitida somente com pontos de extremidade HTTP ou HTTPS.

Marque o ponto de extremidade como público em seu arquivo de especificação de serviço:

spec
  ...
  endpoints
  - name: <endpoint name>
    port: <port number>
    public: true
Copy

Acesso de ponto de extremidade público de fora do Snowflake e autenticação

Nem todos podem acessar os pontos de extremidade públicos expostos por um serviço. Somente usuários na mesma conta Snowflake que o serviço e com o privilégio USAGE no ponto de extremidade público podem acessar o ponto de extremidade público. É possível usar a função de serviço para conceder esse privilégio.

Esses usuários podem acessar o ponto de extremidade público usando um navegador ou programaticamente. O Snowflake usa OAuth para autenticar essas solicitações:

  • Acesso a um ponto de extremidade público usando um navegador: Quando o usuário usa um navegador para acessar um ponto de extremidade público, o Snowflake fornece um redirecionamento automático para autenticação do usuário. O usuário precisa efetuar login e, nos bastidores, o login do usuário gera um token OAuth do Snowflake. O token OAuth é então usado para enviar uma solicitação ao ponto de extremidade do serviço.

  • Acesso a um ponto de extremidade público programaticamente: Seu aplicativo pode usar autenticação de par de chaves para autenticar solicitações para o ponto de extremidade público. Em seu código, você gera um JSON Web Token (JWT) a partir do par de chaves, troca o JWT com o Snowflake por um token OAuth e, em seguida, usa o token OAuth para autenticar solicitações para o ponto de extremidade público de um serviço.

O Tutorial 1 fornece instruções passo a passo para você testar o acesso ao ponto de extremidade público.

A autenticação de par de chaves, conforme mostrado no Tutorial 1, é a maneira recomendada de autenticar solicitações ao acessar pontos de extremidade públicos. O código a seguir pode ser usado para autenticação como uma alternativa ao uso do par de chaves; no entanto, não há garantia de que o código funcionará com versões futuras do Conector Snowflake para Python. Este código Python usa o conector Python para primeiro gerar um token de sessão que representa sua identidade. O código então usa o token de sessão para fazer login no ponto de extremidade público.

import snowflake.connector
import requests

ctx = snowflake.connector.connect(
   user="<username>",# username
   password="<password>", # insert password here
   account="<orgname>-<acct-name>",
   session_parameters={
      'PYTHON_CONNECTOR_QUERY_RESULT_FORMAT': 'json'
   })

# Obtain a session token.
token_data = ctx._rest._token_request('ISSUE')
token_extract = token_data['data']['sessionToken']

# Create a request to the ingress endpoint with authz.
token = f'\"{token_extract}\"'
headers = {'Authorization': f'Snowflake Token={token}'}
# Set this to the ingress endpoint URL for your service
url = 'http://<ingress_url>'

# Validate the connection.
response = requests.get(f'{url}', headers=headers)
print(response.text)

# Insert your code to interact with the application here
Copy

No código:

  • Se você não conhecer as informações da sua conta (<nome da organização>-<nome da conta>), consulte o tutorial configuração comum.

  • Você pode obter o ingress_url do ponto de extremidade público exposto pelo serviço usando SHOW ENDPOINTS.

Cabeçalhos específicos do usuário em solicitações de entrada

Quando chega uma solicitação para um ponto de extremidade de entrada, o Snowflake passa automaticamente o seguinte cabeçalho junto com a solicitação HTTP para o contêiner.

Sf-Context-Current-User: <user_name>
Copy

Seu código de contêiner pode, opcionalmente, ler o cabeçalho, saber quem é o chamador e aplicar a personalização específica do contexto para diferentes usuários. Além disso, o Snowflake pode incluir opcionalmente o cabeçalho Sf-Context-Current-User-Email. Para incluir este cabeçalho, entre em contato com o suporte Snowflake.

Comunicações serviço a serviço

Os serviços podem se comunicar entre si usando o nome DNS que o Snowflake atribui automaticamente a cada serviço. Para obter um exemplo, consulte Tutorial 3. Observe que, se um ponto de extremidade do servidor for criado apenas para permitir comunicações entre serviços, o protocolo TCP deverá ser usado.

O formato do nome DNS é:

<service-name>.<schema-name>.<db-name>.snowflakecomputing.internal

Use SHOW SERVICES (ou DESCRIBE SERVICE) para obter o nome DNS de um serviço. O nome DNS anterior é um nome completo. Os serviços criados no mesmo esquema podem se comunicar usando apenas o <nome-do-serviço>. Os serviços que estão no mesmo banco de dados, mas em esquemas diferentes, devem fornecer o nome do esquema, como <nome-do-serviço>.<nome-do-esquema>.

O Snowflake permite comunicações de rede entre serviços criados pela mesma função e bloqueia comunicações de rede entre serviços criados por funções diferentes. Se você quiser evitar que seus serviços se comuniquem entre si (por motivos como segurança), use diferentes funções do Snowflake para criar esses serviços.

Os nomes DNS têm as seguintes limitações:

  • Seu banco de dados, esquema ou nomes de serviço devem ser etiquetas DNS válidas. (consulte também https://www.ietf.org/rfc/rfc1035.html#section-2.3.1). Caso contrário, a criação de um serviço falhará.

  • Snowflake substitui um sublinhado (_) nos nomes (banco de dados, esquema e nome do serviço) por um traço (-) no nome DNS.

  • Após criar um serviço, não altere o banco de dados ou o nome do esquema, pois o Snowflake não atualizará o nome DNS do serviço.

  • Um nome DNS é apenas para comunicações internas no Snowflake entre serviços em execução na mesma conta. Não é acessível pela internet.

Privilégios

Privilégio

Uso

Notas

USAGE

Para se comunicar com um serviço você precisa do privilégio USAGE no ponto de extremidade do servidor. Necessário para criar uma função de serviço, usar pontos de extremidade públicos e conectar-se a partir de outro serviço.

MONITOR

Para monitorar um serviço e obter o status do tempo de execução.

OPERATE

Para suspender ou retomar um serviço.

OWNERSHIP

Controle total sobre o serviço. Somente uma única função pode ter este privilégio sobre um objeto específico de cada vez.

ALL [ PRIVILEGES ]

Concede todos os privilégios, exceto OWNERSHIP, no serviço.