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>
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>
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
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 theDockerfile
ENTRYPOINT
. This allows you to run a different executable in the container.containers.args
overrides theDockerfile
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"]
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
To override the argument “Bob”, add the
containers.args
field in the specification file:spec: containers: - name: echo image: <image_name> args: - Alice
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>
…
…
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)
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
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():
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
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
or5Gi
. 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 alimit
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 theINSTANCE_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
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 16 GB of memory and one GPU:
CREATE COMPUTE POOL tutorial_compute_pool MIN_NODES = 2 MAX_NODES = 2 INSTANCE_FAMILY = gpu_nv_s
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>;
Both
MIN_INSTANCES
andMAX_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
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
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
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 thedirectoryPath
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 specifydirectoryPath
, do not specifysecretKeyRef
. Either this or theenvVarName
field is required.
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.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 totrue
. 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
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 byspec.containers.volumeMounts.name
.source
: This can belocal
,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
means5*1024*1024*1024
bytes.blockConfig
: For theblock
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
to16384Gi
. 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');
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>
Snowflake uses this information to mount the stage with appropriate permissions.
To obtain the UID and GID of the container:
Run the container locally using
docker run
.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…"
Run the
docker id
command inside the container to get the UID and GID:docker exec -it <container-id> id
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 applicationA
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"
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
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 >
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
meansnumber*1024
. For example, 4Ki is equivalent to 4096.numberMi
meansnumber*1024^2
.numberGi
meansnumber*1024^3
.
Decimal units:
numberk
meansnumber*10^3
. For example, 4k is equivalent to 4000.numberM
meansnumber*10^6
.numberG
meannumber*10^9
.
Fractional units:
numberm
meansnumber*0.001
. For example,cpu: 500m
is equivalent tocpu: 0.5
.