Service specification reference

The Snowpark Container Services specification is in YAML (https://yaml.org/spec/). It gives Snowflake the necessary information to configure and run your service.

The general syntax is:

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: <amount-of-memory>
          nvidia.com/gpu: <count>
          cpu: <cpu-units>
        limits:
          memory: <amount-of-memory>
          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>                     # specify this or portRange
      portRange: <TCP port-num>-<TCP port-num> # specify this or port
      public: <true / false>
      protocol : < TCP / HTTP / HTTPS >
    - name: <name>
      ...
  volumes:                               # optional volume list
    - name: <name>
      source: local | @<stagename> | memory | block
      size: <bytes-of-storage>           # specify if memory or block is the volume source
      blockConfig:                       # optional
        initialContents:
          fromSnapshot: <snapshot-name>
      uid: <UID-value>                   # optional, only for stage volumes
      gid: <GID-value>                   # optional, only for stage volumes
    - name: <name>
      source: local | @<stagename> | memory | block
      size: <bytes-of-storage>           # specify if memory or block is the volume source
      ...
  logExporters:
    eventTableConfig:
      logLevel: <INFO | ERROR | NONE>
serviceRoles:                   # Optional list of service roles
- name: <service-role-name>
  endpoints:
  - <endpoint_name1>
  - <endpoint_name2>
  - ...
- ...
Copy

General guidelines

A service specification has these top-level spec fields:

  • spec.containers (required): A list of one or more application containers. Your containerized application must have at least one container.

  • spec.endpoints (optional): A list of endpoints that the service exposes. You might choose to make an endpoint public, allowing network ingress access to the service.

  • spec.volumes (optional): A list of storage volumes for use by the containers.

  • spec.logExporters (optional): This field manages the level of container logs exported to the event table in your account.

The following format guidelines apply for the name fields (container, endpoint, and volume names):

  • Can be up to 63 characters long

  • Can contain a sequence of lowercase alphanumeric or - characters

  • Must start with an alphabetic character

  • Must end with an alphanumeric character

Attention

Customers should ensure that no personal data, sensitive data, export-controlled data, or other regulated data is entered as metadata in the specification file. For more information, see Metadata Fields in Snowflake.

The following sections explain each of the top-level spec fields.

spec.containers field (required)

The containers field is a list of OCI containers in your application. For each container, only name and image are required fields. The image field refers to the name of the image you uploaded to a Snowflake image repository in your Snowflake account. For example:

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

When you create a service (including job services), Snowflake runs these containers on a single node in the specified compute pool, sharing the same network interface. You can run multiple service instances; in which case, each set of these containers running is known as a Service Instance.

Note

Currently, Snowpark Container Services requires linux/amd64 platform images.

The following sections explain the types of containers fields.

containers.command and containers.args fields

Use these optional fields to override the container’s entry point (the command the container runs along with any parameters) defined in the Dockerfile (part of your application image) without having to recreate your application image:

  • containers.command overrides the Dockerfile ENTRYPOINT. This allows you to run a different executable in the container.

  • containers.args overrides the Dockerfile CMD. This allows you to provide different arguments to the command (the executable).

Example

Your Dockerfile includes the following code:

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

These Dockerfile entries execute the python3 command and pass two arguments: main.py and Bob. You can override these values in the specification file as follows:

  • To override the ENTRYPOINT, add the containers.command field in the specification file:

    spec:
      containers:
      - name: echo
        image: <image_name>
        command:
        - python3.9
        - main.py
    
    Copy
  • To override the argument “Bob”, add the containers.args field in the specification file:

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

containers.env field

Use the containers.env field to specify environment variables that are passed to all processes in your container:

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

Example

In Tutorial 1, the application code (echo_service.py) reads the environment variables with default values, if the value is not explicitly set.

CHARACTER_NAME = os.getenv('CHARACTER_NAME', 'I')
SERVER_PORT = os.getenv('SERVER_PORT', 8080)
Copy
  • CHARACTER_NAME: When the Echo service receives an HTTP POST request with a string (for example, “Hello”), the service returns “I said Hello”. You can overwrite this default value in the specification file. For example, set the value to “Bob”; the Echo service returns a “Bob said Hello” response.

  • SERVER_PORT: In this default configuration, the Echo service listens on port 8080. You can override the default value and specify another port.

The following specification file overrides both these environment variable values:

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

Note that, because you changed the port number your service listens on, the specification also updated the endpoint (endpoints.port field value).

containers.readinessProbe field

Use the containers.readinessProbe object to give Snowflake a readiness probe in your application. Snowflake calls this probe to determine when your application is ready to serve requests.

Snowflake makes an HTTP GET request to the specified readiness probe, at the specified port and path, and looks for your service to return an HTTP 200 OK status to ensure that only healthy containers serve traffic.

Use the following fields to provide the required information:

  • port: The network port on which the service is listening for the readiness probe requests. You need not declare this port as an endpoint.

  • path: Snowflake makes HTTP GET requests to the service with this path.

Example

In Tutorial 1, the application code (echo_python.py) implements the following readiness probe:

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

Accordingly, the specification file includes the containers.readinessProbe field:

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

The port specified by the readiness probe does not have to be a configured endpoint. Your service could listen on a different port solely for the purpose of the readiness probe.

containers.volumeMounts field

Because the spec.volumes and spec.containers.volumeMounts fields work together, they are explained together in one section. For more information, see spec.volumes field (optional).

containers.resources field

Snowflake determines how to use the available compute pool resources to run your application. It is recommended that you explicitly indicate resource requirements for your service instances and set appropriate limits in the specification. Note that the resources you specify are constrained by the instance family of the nodes in your compute pool. For more information, see CREATE COMPUTE POOL.

Snowflake ensures that the resources specified by the containers.resources.requests are provided and also prevents the service from using more than the indicated containers.resources.limits. You can specify requests and limits for the following resources:

  • memory: This is the memory required for your application container. You can use either decimal or binary units to express the values. For example, 2G represents a request for 2,000,000,000 bytes. When specifying memory, unit is required. For example, 100M or 5Gi. The supported units are: M, Mi, G, Gi. For more information, see About units.

  • cpu: This refers to virtual core (vCPU) units. For example, 1 CPU unit is equivalent to 1 vCPU. Fractional requests are allowed, such as 0.5, which can also be expressed as 500m. For more information, see About units.

  • nvidia.com/gpu: If GPUs are required, they must be requested, and there must also be a limit specified for the same quantity. If your container does not specify requests and limits for GPU capacity, it cannot access any GPUs. The number of GPUs you can request is limited by the maximum GPUs supported by the INSTANCE_TYPE you choose when creating a compute pool. For more information, see CREATE COMPUTE POOL.

If Snowflake cannot allocate the resources included explicitly in the specification file, you can create the services (using CREATE SERVICE), but the service status will indicate that the service cannot be scheduled due to insufficient resources.

Example 1

In the following specification, the containers.resources field describes the resource requirements for the container:

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

In this example, Snowflake is asked to allocate at least 2 GB of memory, one GPU, and a half CPU core for the container. At the same time, the container is not allowed to use more than 4 GB of memory and one GPU.

Example 2

  • You create a compute pool of two nodes; each node has 30 GB of memory and one GPU:

    CREATE COMPUTE POOL tutorial_compute_pool
      MIN_NODES = 2
      MAX_NODES = 2
      INSTANCE_FAMILY = gpu_nv_s
    
    Copy
  • You create a service that asks Snowflake to run two instances of the service:

    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

    Both MIN_INSTANCES and MAX_INSTANCES are set to 2. Therefore, Snowflake will run two instances of the service.

If you don’t explicitly include resource requirements in your application specification, Snowflake decides whether to run these instances on the same node or different nodes in the compute pool.

  • You do include resource requirements and request 10 GB of memory for the container:

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

    Your compute pool node has 16 GB of memory, and Snowflake cannot run two containers on the same node. Snowflake will run the two service instances on separate nodes in the compute pool.

  • Request 1 GB of memory and one GPU for the container:

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

    You are requesting one GPU per container, and each node has only one GPU. In this case, although memory is not an issue, Snowflake cannot schedule both services on one node. This requirement forces Snowflake to run the two service instances on two separate compute pool nodes.

containers.secrets field

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

Use containers.secrets to give secrets objects to Snowflake that the container can use to authenticate when a service communicates with external endpoints (outside Snowflake). For more information, see Using Snowflake secrets to pass credentials to a container.

  • snowflakeSecret (required): A Snowflake secret object name.

  • secretKeyRef: The name of the key in the secret. When this field is provided, Snowflake passes the value associated with this key ref to the container. Required for basic auth secrets mounted as environment variables. You specify this field only when passing secrets to environment variables in containers.

  • envVarName: The name of the environment variable that holds the secret. Either this or the directoryPath field is required.

  • directoryPath: The directory path in the container where you want to copy the secrets. Snowflake populates one file for each secret key in this specified directory. When you specify directoryPath, do not specify secretKeyRef. Either this or the envVarName field is required.

Note that, the role that is creating the service (owner role) will need the READ privilege on the secrets referenced.

For more information, see Passing Snowflake Secrets to a Container.

spec.endpoints field (optional)

Use the spec.endpoints field to specify a list of names for the TCP network ports that your application exposes. Snowpark Container Services may expose zero to many endpoints. Use the following fields to describe an endpoint:

  • name: Unique name of the endpoint. When referring to the endpoint in a service function, you specify this name.

  • port: The network port on which your application is listening. You must specify this field or the portRange field.

  • portRange: The network port range on which your application is listening. You must specify this field or the port field.

    Note that you can only specify the portRange field if the protocol field is set to TCP and the public field is false.

  • protocol: The protocol that the endpoint supports. The supported values are TCP, HTTP, and HTTPS. By default, the protocol is HTTP. The protocol must be HTTP or HTTPS when this endpoint is public or the target of a service function (see Using a service). The job services require all specified endpoints to use the TCP protocol; HTTP/HTTPS protocols are not supported.

  • public: If you want this endpoint to be accessible from the internet, set this field to true. Public endpoints are not supported with the TCP protocol.

Note

Snowflake performs authentication and authorization checks for public access that allow only Snowflake users that have permission to use the service.

Example

The following is the application specification used in 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

This application container exposes one endpoint. It also includes the optional public field to enable access to the endpoint from outside of Snowflake (internet access). By default, public is false.

spec.volumes field (optional)

This section explains both spec.volumes and spec.containers.volumeMounts specification fields because they are closely related.

  • spec.volumes defines a shared file system, volumes available to your containers.

  • spec.containers.volumeMount defines where a volume appears in specific containers.

In the specification, the volumes field is specified at the spec level, but since multiple containers can share the same volume, volumeMounts becomes a spec.containers-level field.

Use these fields to describe both the volumes and volume mounts.

  • Use spec.volumes to specify the volumes available to your containers. volumes is a list. That is, there can be multiple volumes. Use the following fields to describe a volume:

    • name: Unique name of the volume. It is referred to by spec.containers.volumeMounts.name.

    • source: This can be local, memory, block, or "@<stagename>". The next section explains these volume types.

    • size: For a memory and block volumes, this is the size of the volume in bytes. For block storage, the value must always be an integer, specified using the Gi unit suffix. For example, 5Gi means 5*1024*1024*1024 bytes.

    • blockConfig: For the block type volume, specify this optional field if you want to initialize the block volume using a previously taken snapshot of another volume. For more information, see Specifying block storage in service specification.

  • Use spec.containers.volumeMounts to indicate where the specified volumes are mounted in the container’s file system. containers.volumeMounts is also a list. That is, each container can have multiple volume mounts. Use the following fields to describe a volume mount:

    • name: The name of the volume to mount. A single container can reference the same volume multiple times.

    • mountPath: The file path to where the volume for the container should be mounted.

About the supported volume types

Snowflake supports these volume types for application containers to use: local, memory, block, and Snowflake stage.

  • Local volume: Containers in a service instance can use a local disk to share files. For example, if your application has two containers—an application container and a log analyzer— the application can write logs to the local volume, and the log analyzer can read the logs.

    Note that, if you are running multiple instances of a service, only containers belonging to a service instance can share volumes. Containers that belong to different service instances do not share volumes.

  • Memory: You can use a RAM-backed file system for container use.

  • Block: Containers can also use block storage volumes. The size value can range from 1Gi to 16384Gi. For more information, see Using block storage volumes with services.

  • Snowflake stage: You can create a Snowflake stage and give containers convenient access to staged files. The following conditions apply when you mount a Snowflake stage:

    • External stages are not supported. Only Snowflake internal stages with SSE encryption (see Internal Stage Parameters) are supported. Use CREATE STAGE to create such a stage:

      CREATE STAGE my_stage ENCRYPTION = (type = 'SNOWFLAKE_SSE');
      
      Copy
    • You can mount a stage or a subdirectory, for example, @my_stage, @my_stage/folder, in a stage. You cannot mount a file, for example, @my_stage/folder/file, in a stage.

    • The service role determines the permissions granted to containers for accessing a mounted stage. The service role is the role that is used to create the service. It is also the role which the service uses for all Snowflake interactions.

      For example, if the service role does not have the WRITE privilege on a stage, the mount for that stage will be read-only. That is, the containers can only read the files from the stage. If the service role does have the WRITE privilege on a stage, the mount for that stage will support both read and write. Snowflake uploads file updates asynchronously.

    • A container that mounts a Snowflake stage typically runs as a root user. However, sometimes your container might run as a non-root user. For example:

      • If your application uses a third-party library, the library uses a non-root user to run application code inside the container.

      • For other reasons, such as security, you might run your application as a non-root user inside the container.

        In order to avoid potential errors related to file user permissions, it is important to set the UID (User ID) and GID (Group ID) of the container as part of the specification. This is particularly relevant for containers that use a specific user and group for launching or running the application within the container. By setting the appropriate UID and GID, you can use a container running as a non-root user. For example:

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

        Snowflake uses this information to mount the stage with appropriate permissions.

        To obtain the UID and GID of the container:

        1. Run the container locally using docker run.

        2. Look up the container ID using the docker container list command. Partial sample output:

          CONTAINER ID   IMAGE                       COMMAND
          —----------------------------------------------------------
          a6a1f1fe204d  tutorial-image         "/usr/local/bin/entr…"
          
        3. Run the docker id command inside the container to get the UID and GID:

          docker exec -it <container-id> id
          
          Copy

          Sample output:

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

Example

Your machine learning application includes the following two containers:

  • An app container for the main application

  • A logger-agent container that collects logs and uploads them to Amazon S3

These containers use the following two volumes:

  • local volume: This application writes logs that the log agent reads.

  • Snowflake stage, @model_stage: The main application reads files from this stage.

In the following example specification, the app container mounts both the logs and models volumes, and the logging-agent container mounts only the logs volume:

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

If multiple instances of the service are running, the logging-agent and the app containers within a service instance share the logs volume. The logs volume is not shared across service instances.

If, in addition to these volumes, your app container also uses a 2-GB memory volume, revise the specification to include the volume in the volumes list and also add another volume mount in the app containers volumeMounts list:

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

Note that, when you specify memory as the volume source, you must also specify the volumes.size field to indicate the memory size. For information about the memory size units you can specify, see About units.

spec.logExporters field (optional)

Use spec.logExporters to configure how Snowflake collects your application logs. Snowflake collects the output from your code in your application container to standard output or standard error.

Snowflake exports these logs to an event table in your account. For more information, see Accessing local container logs. Use the spec.logExporters.eventTableConfig to indicate which logs you want saved to the event table:

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

The supported logLevel values are:

  • INFO (default): Export all the user logs.

  • ERROR: Export only the error logs. Snowflake exports only the logs from stderr stream.

  • NONE: Do not export logs to the event table.

About units

A service specification takes numeric values in several places. Snowpark Container Services supports a variety of units to express these values. For large and small values, you can use binary and decimal units as shown. In the following list, “#” represents an integer value.

  • Binary units:

    • numberKi means number*1024. For example, 4Ki is equivalent to 4096.

    • numberMi means number*1024^2.

    • numberGi means number*1024^3.

  • Decimal units:

    • numberk means number*10^3. For example, 4k is equivalent to 4000.

    • numberM means number*10^6.

    • numberG mean number*10^9.

  • Fractional units:

    • numberm means number*0.001. For example, cpu: 500m is equivalent to cpu: 0.5.

serviceRoles field (optional)

Use the serviceRoles top-level field in the specification to define one or more service roles. For each service role, provide a name and a list of one or more endpoints (defined in the spec.endpoints) you want the service role to grant USAGE privilege on.

serviceRoles:                   # Optional list of service roles
- name: <name>
  endpoints:
  - <endpoint-name>
  - <endpoint-name>
  - ...
- ...
Copy

Note the following:

  • Both the name and endpoints are required.

  • The service role name must adhere to the following format:

    • Must contain alphanumeric or _ characters.

    • Must start with an alphabetic character.

    • Must end with an alphanumeric character.

For more information, see Managing access to service endpoints.