Tutorial 3: Create and manage Snowpark Container Services (original) (raw)

Introduction

Snowpark Container Services is a fully managed container offering designed to facilitate the deployment, management, and scaling of containerized applications within the Snowflake ecosystem. With this feature, you can run containerized workloads directly within Snowflake.

In this tutorial, you learn how to use Snowflake Python APIs to manage components in Snowpark Container Services.

Prerequisites

Before you start this tutorial, you must complete these steps:

  1. Install Docker Desktop.
    This tutorial provides instructions that require Docker Desktop. For installation instructions, see https://docs.docker.com/get-docker/.
  2. Follow the common setup instructions, which include the following steps:
    • Set up your development environment.
    • Install the Snowflake Python APIs package.
    • Configure your Snowflake connection.
    • Import all the modules required for the Python API tutorials.
    • Create an API Root object.
      Note
      If you have already completed the common setup, you can skip this step and begin the tutorial.

After completing these prerequisites, you are ready to start using the API for managing Snowpark Container Services.

Set up your development environment

If you were using a notebook for the previous Snowflake Python APIs tutorials, you switch to a new notebook in this tutorial. The notebook will contain sample code that runs an NGINX web server using Snowpark Container Services, all of which runs in Snowflake.

  1. Open a new notebook using your preferred code editor or by running the command jupyter notebook.
  2. In the first cell of your notebook, run the following code:
    from snowflake.core.database import Database
    from snowflake.core.schema import Schema
    database = root.databases.create(Database(name="spcs_python_api_db"), mode="orreplace")
    schema = database.schemas.create(Schema(name="public"), mode="orreplace")
    Using the Snowflake connection and root object that you created previously in the common setup, you create a database named spcs_python_api_db and a schema named public in that database. You also save references that represent these newly created objects. Your Snowpark Container Services components will live in this database and schema.

Overview of Snowpark Container Services

Before you continue with the tutorial, briefly review the main components of Snowpark Container Services. To run containerized applications in Snowpark Container Services, you typically work with the following objects:

Continue to the next steps to create and set up these objects.

Create an image repository

In this section, first you create an image repository using the Snowflake Python APIs. Then you fetch an NGINX application image from Docker Hub and upload the image to the image repository using the Docker CLI.

Create a repository and get information about the repository

  1. In the next cell of your notebook, run the following code:
    from snowflake.core.image_repository import ImageRepository
    my_repo = ImageRepository("MyImageRepository")
    schema.image_repositories.create(my_repo)
    In this code example, you create an image repository in the database and schema you created previously in this tutorial.
  2. To confirm the repository was created successfully by fetching its details and printing its name, run the following code:
    my_repo_res = schema.image_repositories["MyImageRepository"]
    my_repo = my_repo_res.fetch()
    print(my_repo.name)
  3. You will need information about the repository (the repository URL and the registry hostname) before you can upload the image.
    To get the repository URL, in your next cell, run the following code:
    repositories = schema.image_repositories
    for repo_obj in repositories.iter():
    print(repo_obj.repository_url)
    • The repository_url attribute in the output provides the URL. For example:
      -.registry.snowflakecomputing.com/spcs_python_api_db/public/myimagerepository
    • The hostname in the repository URL is the registry hostname. For example:
      -.registry.snowflakecomputing.com

Fetch the NGINX image and upload it to the repository

  1. For Docker to upload an image to your repository on your behalf, you must first authenticate Docker with Snowflake.
    To authenticate Docker with the Snowflake registry, open a command line terminal and run the following docker login command using the Docker CLI:
    docker login -u
    • _registryhostname_: Specify the hostname in repository_url from the result of the previous step.
    • _username_: Specify your Snowflake username. Docker will prompt you for your password.
      Example
      docker login myorg-myacct.registry.snowflakecomputing.com -u admin
  2. Fetch the AMD64 build of the NGINX image from Docker Hub:
    docker pull --platform linux/amd64 amd64/nginx
  3. Tag the amd64/nginx image with the Snowflake image repository URL:
    docker tag docker.io/amd64/nginx:latest /
    Example
    docker tag docker.io/amd64/nginx:latest myorg-myacct.registry.snowflakecomputing.com/spcs_python_api_db/public/myimagerepository/amd64/nginx:latest
    A tag is a custom, human-readable identifier that you can optionally use to identify a specific version or variant of an image.
  4. Upload the image to the repository in your Snowflake account:
    docker push /
    Example
    docker push myorg-myacct.registry.snowflakecomputing.com/spcs_python_api_db/public/myimagerepository/amd64/nginx:latest

Create a compute pool

To define and create a compute pool, in the next cell of your notebook, run the following code:

new_compute_pool_def = ComputePool( name="MyComputePool", instance_family="CPU_X64_XS", min_nodes=1, max_nodes=2, )

new_compute_pool = root.compute_pools.create(new_compute_pool_def)

In this cell, you define a compute pool using the ComputePool constructor by providing values for the following attributes:

Then you create the compute pool by passing the compute pool definition to compute_pools.create().

Create a service

Using the image repository and compute pool you set up, you can now define and create your service. A service refers to a collection of containers running in a compute pool, which are all orchestrated in Snowflake.

  1. To retrieve the repository containing your container image, in the next cell of your notebook, run the following code:
    image_repository = schema.image_repositories["MyImageRepository"]
    This repository is in your Snowflake account, listed as a stage in the PUBLIC schema. You need this reference to fetch the container image information in the next step.
  2. To define and create your service, in your next cell, run the following code:
    from textwrap import dedent
    from io import BytesIO
    from snowflake.core.service import Service, ServiceSpecInlineText
    specification = dedent(f"""\
    spec:
    containers:
    • name: web-server
      image: {image_repository.fetch().repository_url}/amd64/nginx:latest
      endpoints:
    • name: ui
      port: 80
      public: true
      """)
      service_def = Service(
      name="MyService",
      compute_pool="MyComputePool",
      spec=ServiceSpecInlineText(spec_text=specification),
      min_instances=1,
      max_instances=1,
      )
      nginx_service = schema.services.create(service_def)
      This cell defines the service specification and the service, and then creates the service for your NGINX web server. The definitions for the specification and the service have the following properties:
    • specification – You define the specification using a Python formatted string literal (f-string). The string is formatted as YAML.
      The specification contains the name of the container, a path to the container image, and the endpoints that the service will expose for public access. In this example, you define the specification inline, but you can also define a specification as a reference to a.yml file in a stage.
    • service_def – You define a service with the Service constructor, passing in a name for the service, the compute pool it will run in, a path to the specification, and the total number of instances for the service.
      In this cell, you use ServiceSpecInlineText to set the value of spec because you define the specification inline as an f-string. You can specify the service to run multiple instances, but in this example you specify only one instance of the service to run by setting min_instances and max_instances to 1.
  3. To check the status of the service, in your next cell, run the following code:
    from pprint import pprint
    pprint(nginx_service.get_service_status(timeout=5))
    The output should be similar to this:
    {'auto_resume': True,
    'auto_suspend_secs': 3600,
    'instance_family': 'CPU_X64_XS',
    'max_nodes': 1,
    'min_nodes': 1,
    'name': 'MyService'}

Use your service

After you create the service, Snowpark Container Services will take a few minutes to provision the endpoints that are needed to access the service.

  1. To check the status of the endpoints, in the next cell of your notebook, run the following code:
    import json, time
    while True:
    public_endpoints = nginx_service.fetch().public_endpoints
    try:
    endpoints = json.loads(public_endpoints)
    except json.JSONDecodeError:
    print(public_endpoints)
    time.sleep(15)
    else:
    break

The code example isn’t specific to Snowpark Container Services or the Snowflake Python APIs – it simply provides a handy way to check whether the endpoints are ready. Note that you fetch the endpoints by calling .fetch().public_endpoints on your service object.
The output should be similar to this:
Endpoints provisioning in progress... check back in a few minutes
Endpoints provisioning in progress... check back in a few minutes
Endpoints provisioning in progress... check back in a few minutes 2. After the endpoints are provisioned, you can open the public endpoints in your browser.
In your next cell, run the following code:
import webbrowser
print(f"Visiting {endpoints['ui']} in your browser. You might need to log in there.")
webbrowser.open(f"https://{endpoints['ui']}")
The output should be similar to this:
Visiting myorg-myacct.snowflakecomputing.app in your browser. You might need to log in there.
If successful, you’ll see the following NGINX success page in your browser when visiting the endpoint:
Screenshot of the NGINX web server success page in a browser 3. You can use the Python API to manage your new service.
For example, to suspend the service and then check its status, run the following code:
from time import sleep
nginx_service.suspend()
sleep(3)
print(nginx_service.get_service_status(timeout=5)) 4. To resume the service, run the following code:
nginx_service.resume()
sleep(3)
print(nginx_service.get_service_status(timeout=5))

With just a few lines of Python, you were able to run an NGINX web server in Snowflake using Snowpark Container Services.

Clean up

Snowflake charges for active compute pool nodes in your account. To prevent unwanted charges, first suspend the service and the compute pool, and then drop both objects.

  1. To suspend the compute pool and the service, in the next cell of your notebook, run the following code:
    new_compute_pool_def.suspend()
    nginx_service.suspend()
  2. To drop the compute pool and the service, run the following code:
    new_compute_pool_def.drop()
    nginx_service.drop()

What’s next?

Congratulations! In this tutorial, you learned the fundamentals for managing components in Snowpark Container Services using the Snowflake Python APIs.

Summary

Along the way, you completed these steps:

Additional resources

For more examples of using the API to manage other types of objects in Snowflake, see the following developer guides:

Guide Description
Managing Snowflake databases, schemas, tables, and views with Python Use the API to create and manage databases, schemas, and tables.
Managing Snowflake users, roles, and grants with Python Use the API to create and manage users, roles, and grants.
Managing data loading and unloading resources with Python Use the API to create and manage data loading and unloading resources, including external volumes, pipes, and stages.
Managing Snowflake tasks and task graphs with Python Use the API to create, execute, and manage tasks and task graphs.