Referência de especificação de serviço

A especificação do Snowpark Container Services está em YAML (https://yaml.org/spec/). Fornece ao Snowflake as informações necessárias para configurar e executar seu serviço ou trabalho.

A sintaxe geral é:

spec:
  containers:                           # container list
  - name: <name>
    image: <image-name>
    command:                            # optional list of strings
      - <cmd>
      - <arg1>
    args:                               # optional list of strings
      - <arg2>
      - <arg3>
      - ...
    env:                                # optional
        <key>: <value>
        <key>: <value>
        ...
    readinessProbe:                     # optional
        port: <TCP port-num>
        path: <http-path>
    volumeMounts:                       # optional list
      - name: <volume-name>
        mountPath: <mount-path>
      - name: <volume-name>
        ...
    resources:                          # optional
        requests:
          memory: <memory-reserved>
          nvidia.com/gpu: <count>
          cpu: <cpu-units>
        limits:
          memory: <memory-reserved>
          nvidia.com/gpu: <count>
          cpu: <cpu-units>
    secrets:                            # optional list
      - snowflakeSecret:
        secretKeyRef:
        envVarName:                      # specify this or directoryPath
        directoryPath:                   # specify this or envVarName
  endpoints:                             # optional endpoint list
    - name: <name>
      port: <TCP port-num>
      public: <true / false>
      protocol : < TCP / HTTP / HTTPS >
    - name: <name>
      ...
  volumes:                               # optional volume list
    - name: <name>
      source: local | @<stagename> | memory
      size: <amount-of-memory>           # specify if memory is the volume source
    - name: <name>
      source: local | @<stagename> | memory
      size: <amount-of-memory>           # specify if memory is the volume source
      ...
  logExporters:
    eventTableConfig:
      logLevel: <INFO | ERROR | NONE>
Copy

Diretrizes gerais

Uma especificação de serviço/trabalho tem estes campos spec de nível superior:

  • spec.containers (obrigatório): uma lista de um ou mais contêineres de aplicativos. Seu aplicativo conteinerizado deve ter pelo menos um contêiner.

  • spec.endpoints (opcional): uma lista de pontos de extremidade que o serviço expõe. Você pode escolher um ponto de extremidade público, permitindo acesso de entrada de rede ao serviço.

  • spec.volumes (opcional): uma lista de volumes de armazenamento para uso pelos contêineres.

  • spec.logExporters (opcional): este campo gerencia o nível de logs de contêiner exportados para a tabela de eventos em sua conta.

As seguintes diretrizes de formato se aplicam aos campos name (nomes de contêiner, ponto de extremidade e volume):

  • Pode ter até 63 caracteres

  • Pode conter uma sequência de caracteres alfanuméricos minúsculos ou “-“

  • Deve começar com um caractere alfabético

  • Deve terminar com um caractere alfanumérico

Atenção

Os clientes devem garantir que nenhum dado pessoal (exceto para um objeto do usuário), dados sensíveis, dados controlados por exportação ou outros dados regulamentados sejam inseridos como metadados no arquivo de especificação. Para obter mais informações, consulte Campos de metadados no Snowflake.

As seções a seguir explicam cada um dos campos spec de nível superior.

Campo spec.containers (obrigatório)

O campo containers é uma lista de contêineres OCI no seu aplicativo. Para cada contêiner, apenas name e image são campos obrigatórios. O campo image refere-se ao nome da imagem que você carregou em um repositório de imagens do Snowflake em sua conta Snowflake. Por exemplo:

spec:
  containers:
    - name: echo
      image: /tutorial_db/data_schema/tutorial_repository/echo_service:dev
Copy

Quando você cria um serviço (ou trabalho), o Snowflake executa esses contêineres em um único nó no pool de computação especificado, compartilhando a mesma interface de rede. É possível executar diversas instâncias de serviço; nesse caso, cada conjunto desses contêineres em execução é conhecido como Instância de serviço.

Nota

Atualmente, o Snowpark Container Services requer imagens da plataforma Linux/AMD64.

As seções a seguir explicam os tipos de campos containers.

Campos containers.command e containers.args

Use estes campos opcionais para substituir o ponto de entrada do contêiner (o comando que o contêiner executa junto com quaisquer parâmetros) definido em Dockerfile (parte da imagem do seu aplicativo) sem precisar recriar a imagem do seu aplicativo:

  • containers.command substitui o Dockerfile ENTRYPOINT. Isso permite que você execute um executável diferente no contêiner.

  • containers.args substitui o Dockerfile CMD. Isso permite fornecer diferentes argumentos ao comando (o executável).

Exemplo

Seu Dockerfile inclui o seguinte código:

ENTRYPOINT ["python3", "main.py"]
CMD ["Bob"]
Copy

Essas entradas Dockerfile executam o comando python3 e passam dois argumentos: main.py e Bob. Você pode substituir esses valores no arquivo de especificação da seguinte forma:

  • Para substituir ENTRYPOINT, adicione o campo containers.command no arquivo de especificação:

    spec:
      containers:
      - name: echo
        image: <image_name>
        command:
        - python3.9
        - main.py
    
    Copy
  • Para substituir o argumento “Bob”, adicione o campo containers.args no arquivo de especificação:

    spec:
      containers:
      - name: echo
        image: <image_name>
        args:
          - Alice
    
    Copy

Campo containers.env

Use o campo containers.env para especificar variáveis de ambiente que são passadas para todos os processos no seu contêiner:

spec:
  containers:
  - name: <name>
    image: <image_name>
    env:
      ENV_VARIABLE_1: <value1>
      ENV_VARIABLE_2: <value2>
      
      
Copy

Exemplo

No Tutorial 1, o código do aplicativo (echo_service.py) lê as variáveis de ambiente com valores padrão, se o valor não for definido explicitamente.

CHARACTER_NAME = os.getenv('CHARACTER_NAME', 'I')
SERVER_PORT = os.getenv('SERVER_PORT', 8080)
Copy
  • CHARACTER_NAME: quando o serviço Echo recebe uma solicitação HTTP POST com uma cadeia de caracteres (por exemplo, «Olá»), o serviço retorna «Eu disse Olá». Você pode substituir esse valor padrão no arquivo de especificação. Por exemplo, defina o valor como «Bob»; o serviço Echo retorna uma resposta «Bob disse Olá».

  • SERVER_PORT: nesta configuração padrão, o serviço Echo escuta na porta 8080. Você pode substituir o valor padrão e especificar outra porta.

O arquivo de especificação a seguir substitui esses dois valores de variáveis de ambiente:

spec:
  containers:
  - name: echo
    image: <image_name>
    env:
      CHARACTER_NAME: Bob
      SERVER_PORT: 8085
  endpoints:
  - name: echo-endpoint
    port: 8085
Copy

Observe que, como você alterou o número da porta em que seu serviço escuta, a especificação também atualizou o ponto de extremidade (valor do campo endpoints.port).

Campo containers.readinessProbe

Use o objeto containers.readinessProbe para fornecer ao Snowflake uma análise de prontidão em seu aplicativo. Snowflake chama essa investigação para determinar quando seu aplicativo está pronto para atender solicitações.

Snowflake faz uma solicitação HTTP GET para a análise de prontidão especificada, na porta e no caminho especificados, e procura que seu serviço retorne um status HTTP 200 OK para garantir que apenas contêineres íntegros tenham tráfego.

Use os seguintes campos para fornecer as informações necessárias:

  • port: a porta de rede na qual o serviço está atendendo às solicitações de análise de prontidão. Você não precisa declarar esta porta como um ponto de extremidade.

  • path: Snowflake faz solicitações HTTP GET ao serviço com este caminho.

Exemplo

No Tutorial 1, o código do aplicativo (echo_python.py) implementa a seguinte análise de prontidão:

@app.get("/healthcheck")
def readiness_probe():
Copy

Assim, o arquivo de especificação inclui o campo containers.readinessProbe:

spec:
  containers:
  - name: echo
    image: <image_name>
    env:
      SERVER_PORT: 8088
      CHARACTER_NAME: Bob
    readinessProbe:
      port: 8088
      path: /healthcheck
  endpoints:
  - name: echo-endpoint
    port: 8088
Copy

A porta especificada pela análise de prontidão não precisa ser um ponto de extremidade configurado. Seu serviço pode escutar em uma porta diferente apenas para fins de análise de prontidão.

Campo containers.volumeMounts

Como os campos spec.volumes e spec.containers.volumeMounts funcionam juntos, eles são explicados juntos em uma seção. Para obter mais informações, consulte Campo spec.volumes (opcional).

Campo containers.resources

Snowflake determina como usar os recursos do pool de computação disponíveis para executar seu aplicativo. É recomendável indicar explicitamente os requisitos de recursos para suas instâncias de serviço e definir limites apropriados na especificação. Observe que os recursos especificados são limitados pela família de instâncias dos nós no seu pool de computação. Para obter mais informações, consulte CREATE COMPUTE POOL.

Snowflake garante que os recursos especificados por containers.resources.requests sejam fornecidos e também evita que o serviço utilize mais do que o containers.resources.limits indicado. Você pode especificar solicitações e limites para os seguintes recursos:

  • memory: esta é a memória necessária para o contêiner do seu aplicativo. Você pode usar unidades decimais ou binárias para expressar os valores. Por exemplo, 2G representa uma solicitação de 2.000.000.000 bytes. Para obter mais informações, consulte Sobre as unidades.

  • cpu: refere-se a unidades de núcleo virtual (vCPU). Por exemplo, a unidade 1 CPU é equivalente a 1 vCPU. São permitidas solicitações fracionárias, como 0,5, que também pode ser expressa como 500m. Para obter mais informações, consulte Sobre as unidades.

  • nvidia.com/gpu: se GPUs forem necessários, eles deverão ser solicitados e também deverá haver um limit especificado para a mesma quantidade. Se o seu contêiner não especificar solicitações e limites para a capacidade de GPU, ele não poderá acessar GPUs. O número de GPUs que você pode solicitar é limitado pelo máximo de GPUs suportado pelo INSTANCE_TYPE que você escolhe ao criar um pool de computação. Para obter mais informações, consulte CREATE COMPUTE POOL.

Se o Snowflake não puder alocar os recursos incluídos explicitamente no arquivo de especificação, você poderá criar os serviços (usando CREATE SERVICE), mas o status do serviço indicará que o serviço não pode ser agendado devido a recursos insuficientes.

Exemplo 1

Na especificação a seguir, o campo containers.resources descreve os requisitos de recursos do contêiner:

spec:
  containers:
  - name: resource-test-gpu
    image: ...
    resources:
      requests:
        memory: 2G
        cpu: 0.5
        nvidia.com/gpu: 1
      limits:
        memory: 4G
        nvidia.com/gpu: 1
Copy

Neste exemplo, o Snowflake é solicitado a alocar pelo menos 2 GB de memória, um GPU e meio núcleo CPU para o contêiner. Ao mesmo tempo, o contêiner não pode usar mais de 4 GB de memória e um GPU.

Exemplo 2

  • Você cria um pool de computação de dois nós; cada nó tem 16 GB de memória e um GPU:

    CREATE COMPUTE POOL tutorial_compute_pool
      MIN_NODES = 2
      MAX_NODES = 2
      INSTANCE_FAMILY = gpu_nv_s
    
    Copy
  • Você cria um serviço que pede ao Snowflake para executar duas instâncias do serviço:

    CREATE SERVICE echo_service
      MIN_INSTANCES=2
      MAX_INSTANCES=2
      IN COMPUTE POOL tutorial_compute_pool
      FROM @<stage_path>
      SPEC=<spec-file-stage-path>;
    
    Copy

    Tanto MIN_INSTANCES quanto MAX_INSTANCES estão definidos como 2. Portanto, o Snowflake executará duas instâncias do serviço.

Se você não incluir explicitamente os requisitos de recursos na especificação do aplicativo, o Snowflake decidirá se executará essas instâncias no mesmo nó ou em nós diferentes no pool de computação.

  • Você inclui requisitos de recursos e solicita 10 GB de memória para o contêiner:

    - name: resource-test
      image: ...
      resources:
        requests:
          memory: 10G
    
    Copy

    Seu nó do pool de computação tem 16 GB de memória e o Snowflake não pode executar dois contêineres no mesmo nó. O Snowflake executará as duas instâncias de serviço em nós separados no pool de computação.

  • Solicite 1 GB de memória e um GPU para o contêiner:

    spec:
      containers:
      - name: resource-test-gpu
        image: ...
        resources:
          requests:
            memory: 2G
            nvidia.com/gpu: 1
          limits:
            nvidia.com/gpu: 1
    
    Copy

    Você está solicitando um GPU por contêiner e cada nó possui apenas um GPU. Nesse caso, embora a memória não seja um problema, o Snowflake não pode agendar ambos os serviços em um nó. Este requisito força o Snowflake a executar as duas instâncias de serviço em dois nós de pool de computação separados.

Campo containers.secrets

secrets:                            # optional list
  - snowflakeSecret:
    secretKeyRef:
    envVarName:                      # specify this or directoryPath
    directoryPath:                   # specify this or envVarName
Copy

Use containers.secrets para fornecer objetos de segredo ao Snowflake que o contêiner pode usar para autenticar quando um serviço ou trabalho se comunica com pontos de extremidade externos (fora do Snowflake). Para obter mais informações, consulte Como usar segredos do Snowflake para passar credenciais para um contêiner.

  • snowflakeSecret (obrigatório): um nome de objeto do segredo do Snowflake.

  • secretKeyRef: o nome da chave no segredo. Quando este campo é fornecido, o Snowflake passa o valor associado a esta referência de chave para o contêiner. Necessário para segredos de autenticação básicos montados como variáveis de ambiente. Você especifica esse campo somente ao passar segredos para variáveis de ambiente em contêineres.

  • envVarName: o nome da variável de ambiente que contém o segredo. Este ou o campo directoryPath são obrigatórios.

  • directoryPath: o caminho do diretório no contêiner onde você deseja copiar os segredos. Snowflake preenche um arquivo para cada chave secreta neste diretório especificado. Ao especificar directoryPath, não especifique secretKeyRef. Este ou o campo envVarName são obrigatórios.

Para obter mais informações, consulte Como passar segredos do Snowflake para um contêiner.

Campo spec.endpoints (opcional)

Use o campo spec.endpoints para especificar uma lista de nomes para as portas de rede TCP que seu aplicativo expõe. O Snowpark Container Services pode expor zero a muitos pontos de extremidade. Use os seguintes campos para descrever um ponto de extremidade:

  • name: nome exclusivo do ponto de extremidade. Ao se referir ao ponto de extremidade em uma função de serviço, você especifica esse nome.

  • port: a porta de rede na qual seu aplicativo está escutando.

  • protocol: o protocolo suportado pelo ponto de extremidade. Os valores aceitos são TCP, HTTP e HTTPS. Por padrão, o protocolo é HTTP. O protocolo deve ser HTTP ou HTTPS quando esse ponto de extremidade for público ou o destino de uma função de serviço (consulte Como usar um serviço).

  • public: se você quiser que esse ponto de extremidade seja acessível pela internet, defina esse campo como true.

Nota

O Snowflake realiza verificações de autenticação e autorização para acesso público que permite que apenas usuários do Snowflake tenham permissão para usar o serviço.

Exemplo

A seguir está a especificação do aplicativo usada no Tutorial 1:

spec:
  container:
  - name: echo
    image: <image-name>
    env:
      SERVER_PORT: 8000
      CHARACTER_NAME: Bob
    readinessProbe:
      port: 8000
      path: /healthcheck
  endpoint:
  - name: echoendpoint
    port: 8000
    public: true
Copy

Este contêiner de aplicativo expõe um ponto de extremidade. Também inclui o campo opcional public para permitir o acesso ao ponto de extremidade de fora do Snowflake (acesso à internet). Por padrão, public é false.

Campo spec.volumes (opcional)

Esta seção explica os campos spec.volumes e spec.containers.volumeMounts. volumes define um sistema de arquivos compartilhado. Um volumeMount define onde um volume aparece em contêineres. Vários contêineres podem compartilhar o mesmo volume. Portanto, volumes é um campo de nível spec e volumeMount faz parte de uma especificação de contêiner.

Use esses campos para descrever os volumes e montagens de volume

  • Use spec.volumes para especificar os volumes disponíveis para seus contêineres. volumes é uma lista. Ou seja, pode haver vários volumes. Use os seguintes campos para descrever um volume:

    • name: nome exclusivo do volume. É referido por spec.containers.volumeMounts.name.

    • source: pode ser local, memory ou "@<nome do estágio>".

    • uid: para um volume de estágio Snowflake, esse é o uid do arquivo montado.

    • gid: para um volume de estágio Snowflake, este é o gid do arquivo montado.

    • size: para um volume de memória, esse é o tamanho do volume.

  • Use spec.containers.volumeMounts para indicar onde os volumes especificados estão montados no sistema de arquivos do contêiner. containers.volumeMounts também é uma lista. Ou seja, cada contêiner pode ter múltiplas montagens de volume. Use os campos a seguir para descrever uma montagem de volume:

    • name: o nome do volume a ser montado. Um único contêiner pode fazer referência ao mesmo volume várias vezes.

    • mountPath: o caminho do arquivo onde o volume do contêiner deve ser montado.

Snowflake oferece suporte a estes tipos de volume para uso de contêineres de aplicativos: volumes locais, memória e estágio Snowflake.

  • Volume local: os contêineres em uma instância de serviço podem usar um disco local para compartilhar arquivos. Por exemplo, se seu aplicativo tiver dois contêineres—um contêiner de aplicativo e um analisador de logs—, o aplicativo poderá gravar logs no volume local e o analisador de logs poderá ler os logs.

    Observe que, se você estiver executando diversas instâncias de um serviço, somente contêineres pertencentes a uma instância de serviço poderão compartilhar volumes. Os contêineres que pertencem a diferentes instâncias de serviço não compartilham volumes.

  • Memória: você pode usar um sistema de arquivos com suporte de RAM para uso em contêiner.

  • Estágio Snowflake: você pode criar um estágio Snowflake e fornecer aos contêineres acesso conveniente aos arquivos preparados. As seguintes condições se aplicam quando você monta um estágio Snowflake:

    • Estágios externos não são suportados. Somente estágios internos do Snowflake com criptografia SSE são suportados. Use CREATE STAGE para criar esse estágio:

      CREATE STAGE my_stage ENCRYPTION = (type = 'SNOWFLAKE_SSE');
      
      Copy
    • Você pode montar um estágio ou subdiretório, por exemplo, @my_stage, @my_stage/folder, em um estágio. Não é possível montar um arquivo, por exemplo, @my_stage/folder/file, em um estágio.

    • A função de serviço determina as permissões concedidas aos contêineres para acessar um estágio montado. A função de serviço é a função usada para criar o serviço/trabalho. É também a função que o serviço/trabalho usa para todas as interações do Snowflake.

      Por exemplo, se a função de serviço não tiver o privilégio WRITE em um estágio, a montagem desse estágio será somente leitura. Ou seja, os containers só podem ler os arquivos do estágio. Se a função de serviço tiver o privilégio WRITE em um estágio, a montagem desse estágio oferecerá suporte para leitura e gravação. Snowflake carrega atualizações de arquivos de forma assíncrona.

    • Um contêiner que monta um estágio Snowflake normalmente é executado como um usuário root. No entanto, às vezes o seu contêiner pode ser executado como um usuário não root. Por exemplo:

      • Se o seu aplicativo usar uma biblioteca de terceiros, a biblioteca usará um usuário não root para executar o código do aplicativo dentro do contêiner.

      • Por outros motivos, como segurança, você pode executar seu aplicativo como um usuário não root dentro do contêiner.

        Para evitar possíveis erros relacionados às permissões do usuário do arquivo, é importante definir o UID (ID do usuário) e o GID (ID do grupo) do contêiner como parte da especificação. Isto é especialmente relevante para contêineres que usam um usuário e grupo específico para iniciar ou executar o aplicativo dentro do contêiner. Ao definir UID e GID apropriados, você pode usar um contêiner em execução como usuário não root. Por exemplo:

        spec:
          ...
        
          volumes:
          - name: stagemount
            source: "@test"
            uid: <UID-value>
            gid: <GID-value>
        
        Copy

        Snowflake usa essas informações para montar o estágio com as permissões apropriadas.

        Para obter UID e GID do contêiner:

        1. Execute o contêiner localmente usando docker run.

        2. Procure o ID do contêiner usando o comando docker container list. Amostra de saída parcial:

          CONTAINER ID   IMAGE                       COMMAND
          —----------------------------------------------------------
          a6a1f1fe204d  tutorial-image         "/usr/local/bin/entr…"
          
        3. Execute o comando docker id dentro do contêiner para obter UID e GID:

          docker exec -it <container-id> id
          
          Copy

          Exemplo de saída:

          uid=0(root) gid=0(root) groups=0(root)
          

Exemplo

Seu aplicativo de machine learning inclui os dois contêineres a seguir:

  • Um contêiner app para o aplicativo principal

  • Um contêiner logger-agent que coleta logs e os carrega no Amazon S3

Esses contêineres usam os dois volumes a seguir:

  • Volume local: este aplicativo grava os logs que o agente de log lê.

  • Estágio do Snowflake, @model_stage: o aplicativo principal lê arquivos deste estágio.

Na especificação de exemplo a seguir, o contêiner app monta os volumes logs e models, e o contêiner logging-agent monta apenas o volume logs:

spec:
  containers:
  - name: app
    image: <image1-name>
    volumeMounts:
    - name: logs
      mountPath: /opt/app/logs
    - name: models
      mountPath: /opt/models
  - name: logging-agent
    image: <image2-name>
    volumeMounts:
    - name: logs
      mountPath: /opt/logs
  volumes:
  - name: logs
    source: local
  - name: models
    source: "@model_stage"
Copy

Se diversas instâncias do serviço estiverem em execução, os contêineres logging-agent e app em uma instância de serviço compartilharão o volume logs. O volume logs não é compartilhado entre instâncias de serviço.

Se, além desses volumes, seu contêiner app também usar um volume de memória de 2 GB, revise a especificação para incluir o volume na lista volumes e também adicione outra montagem de volume nos contêineres app lista volumeMounts:

spec:
  containers:
  - name: app
    image: <image1-name>
    volumeMounts:
    - name: logs
      mountPath: /opt/app/logs
    - name: models
      mountPath: /opt/models
    - name: my-mem-volume
      mountPath: /dev/shm
  - name: logging-agent
    image: <image2-name>
    volumeMounts:
    - name: logs
      mountPath: /opt/logs
  volumes:
  - name: logs
    source: local
  - name: models
    source: "@model_stage"
  - name: "my-mem-volume"
    source: memory
    size: 2G
Copy

Observe que, ao especificar memory como o volume source, você também deve especificar o campo volumes.size para indicar o tamanho da memória. Para obter informações sobre as unidades de tamanho de memória que você pode especificar, consulte Sobre as unidades.

Campo spec.logExporters (opcional)

Use spec.logExporters para configurar como o Snowflake coleta os logs do seu aplicativo. Snowflake coleta a saída do seu código no contêiner do aplicativo para saída padrão ou erro padrão.

O Snowflake exporta esses registros para uma tabela de eventos na sua conta. Para obter mais informações, consulte Acesso a logs de contêiner locais. Use spec.logExporters.eventTableConfig para indicar quais logs você deseja salvar na tabela de eventos:

logExporters:
  eventTableConfig:
    logLevel: < INFO | ERROR | NONE >
Copy

Os valores logLevel aceitos são:

  • INFO: exporte todos os logs do usuário.

  • ERROR: exporte apenas os logs de erros. Snowflake exporta apenas os logs do fluxo stderr.

  • NONE (padrão): não exporte logs para a tabela de eventos.

Sobre as unidades

Uma especificação de serviço assume valores numéricos em vários lugares. O Snowpark Container Services oferece suporte a diversas unidades para expressar esses valores. Para valores grandes e pequenos, você pode usar unidades binárias e decimais conforme mostrado. Na lista a seguir, “#” representa um valor inteiro.

  • Unidades binárias:

    • numberKi significa number*1024. Por exemplo, memory: 4Ki é equivalente a memory: 4096.

    • numberMi significa number*1024^2.

    • numberGi significa number*1024^3.

  • Unidades decimais:

    • numberk significa number*10^3. Por exemplo, memory: 4k é equivalente a memory: 4000.

    • numberM significa number*10^6.

    • numberG significa number*10^9.

  • Unidades fracionárias:

    • numberm significa number*0.001. Por exemplo, cpu: 500m é equivalente a cpu: 0.5.