Cortex Skills
  • Skills Directory
  • Categories
  • Docs
Add SkillBrowse Skills
  1. Home
  2. Skills Directory
  3. Document AI
  4. deploy-to-spcs
IntermediateDocument AIfeatured

deploy-to-spcs

Deploy containerized apps to Snowpark Container Services.
Jump to Installation

Compatible with

Cortex

About this skill

Deploy to Snowpark Container Services (SPCS)

Overview

Deploy any containerized application to Snowflake using Snowpark Container Services. Works with any Docker-based app (Next.js, Python, Go, etc.).

When to Use

  • User has a containerized app (Docker) ready to deploy
  • User wants to host an app on Snowflake infrastructure
  • User mentions SPCS, Snowpark Container Services, or deploying to Snowflake

Tools Used

  • bash - Run docker commands, snow CLI
  • snowflake_sql_execute - Create compute pools, repos, services
  • cortex browser - Verify deployed apps

Stopping Points

  • ⚠️ Step 1: Confirm app is ready for deployment
  • ⚠️ Step 2: Confirm SPCS prerequisites exist
  • ⚠️ Step 5: Confirm deployment success
  • ⚠️ Step 6: Confirm consumer role access

Workflow

Step 1: Verify App Readiness

Before deploying, confirm:

  • App has a working Dockerfile
  • App builds successfully locally (docker build)
  • App exposes a port (default: 8080)
docker build --platform linux/amd64 -t <image-name>:latest .

⚠️ STOP: Confirm app builds successfully before proceeding.


Step 2: SPCS Prerequisites

Check Current Role

SELECT CURRENT_ROLE(), CURRENT_USER();

Check/Create Compute Pool

SHOW COMPUTE POOLS;

-- If no accessible pool exists:
CREATE COMPUTE POOL <pool_name>
  MIN_NODES = 1
  MAX_NODES = 1
  INSTANCE_FAMILY = CPU_X64_XS;

Check/Create Image Repository

SHOW IMAGE REPOSITORIES;

-- If needed:
CREATE IMAGE REPOSITORY <db>.<schema>.<repo_name>;

Login to Registry

snow spcs image-registry login --connection <conn>

⚠️ STOP: Confirm compute pool and image repository exist before proceeding.


Step 3: Create Service Specification

Create service-spec.yaml:

spec:
  containers:
  - name: <app-name>
    image: /<db>/<schema>/<repo>/<image>:latest
    env:
      HOSTNAME: "0.0.0.0"
      PORT: "8080"
      NODE_ENV: production
    resources:
      requests:
        memory: 1Gi
        cpu: 500m
      limits:
        memory: 2Gi
        cpu: 1000m
    readinessProbe:
      port: 8080
      path: /
  endpoints:
  - name: <endpoint-name>
    port: 8080
    public: true

Adjust resources, port, and env based on app requirements.


Step 4: Build and Push Image

docker build --platform linux/amd64 -t <image-name>:latest .
docker tag <image-name>:latest <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
docker push <registry-url>/<db>/<schema>/<repo>/<image-name>:latest

Registry URL format: <account>.registry.snowflakecomputing.com


Step 5: Deploy Service

CREATE SERVICE <service_name>
  IN COMPUTE POOL <pool_name>
  FROM SPECIFICATION $$
  <contents of service-spec.yaml>
  $$
  MIN_INSTANCES = 1
  MAX_INSTANCES = 1;

Monitor and Get URL

SELECT SYSTEM$GET_SERVICE_STATUS('<service_name>');
SHOW ENDPOINTS IN SERVICE <service_name>;

IMPORTANT: Extract the ingress_url from SHOW ENDPOINTS and display it to the user.

Verify Deployment

cortex browser open "https://<ingress_url>"
cortex browser snapshot -i  # Verify app loads correctly

⚠️ STOP: Confirm deployment success with user.


Step 6: Grant Consumer Access

Ask the user: "What role will consume this service?"

1. Check Data Access

SHOW GRANTS TO ROLE <consumer_role>;

If required privileges on tables are missing, grant what the service needs:

GRANT USAGE ON DATABASE <db> TO ROLE <consumer_role>;
GRANT USAGE ON SCHEMA <db>.<schema> TO ROLE <consumer_role>;
-- Grant privileges the service requires (SELECT, INSERT, UPDATE, DELETE, etc.)
GRANT <privileges> ON TABLE <db>.<schema>.<table> TO ROLE <consumer_role>;

2. Check Service Endpoint Access

SHOW GRANTS TO ROLE <consumer_role>;

If service role grant is missing:

GRANT SERVICE ROLE <service_name>!ALL_ENDPOINTS_USAGE TO ROLE <consumer_role>;

⚠️ STOP: Confirm consumer role can access the service.


Updating a Service

⚠️ CAUTION: Always use ALTER SERVICE to update an existing service. Never drop and recreate—this changes the service URL and breaks existing integrations.

docker build --platform linux/amd64 -t <image-name>:latest .
docker tag <image-name>:latest <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
docker push <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
ALTER SERVICE <service_name> FROM SPECIFICATION $$
<full yaml spec>
$$;

Troubleshooting

Service not starting

SELECT SYSTEM$GET_SERVICE_LOGS('<service_name>', 0, '<container_name>');

Service Won't Start

  • Image not found: The image path in your spec must exactly match the repository structure. Format: /<db>/<schema>/<repo>/<image>:latest. Case-sensitive and must include leading slash.
  • Port mismatch: Three ports must align: readinessProbe.port (health check), PORT env var (app listens on), and endpoints.port (external access). If any differ, the service fails readiness checks.
  • Auth errors: Registry login expires. Re-run snow spcs image-registry login --connection <conn> before pushing images.

Permission Errors

  • Missing privileges: The role that owns the service needs access to any tables/views the app queries. Common issue when app works locally but fails in SPCS.
    GRANT SELECT ON TABLE <db>.<schema>.<table> TO ROLE <role>;
    GRANT DELETE ON TABLE <db>.<schema>.<table> TO ROLE <role>;  -- if app deletes data
    

Output

  • Deployed SPCS service URL
  • Service status confirmation
  • Consumer role access configured

Installation

Install using the Cortex CLI:

bash
$cortex skill install deploy-to-spcs

Requires Cortex CLI v2.0+. Install guide →

Repository Sources

Loading repository files...

SKILL.md Preview

SKILL.md
---
name: deploy-to-spcs
description: "Deploy containerized apps to Snowpark Container Services. Use when: deploying Docker apps, creating SPCS services, pushing images to Snowflake registry."
---

# Deploy to Snowpark Container Services (SPCS)

## Overview
Deploy any containerized application to Snowflake using Snowpark Container Services. Works with any Docker-based app (Next.js, Python, Go, etc.).

## When to Use
- User has a containerized app (Docker) ready to deploy
- User wants to host an app on Snowflake infrastructure
- User mentions SPCS, Snowpark Container Services, or deploying to Snowflake

## Tools Used
- `bash` - Run docker commands, snow CLI
- `snowflake_sql_execute` - Create compute pools, repos, services
- `cortex browser` - Verify deployed apps

## Stopping Points
- ⚠️ Step 1: Confirm app is ready for deployment
- ⚠️ Step 2: Confirm SPCS prerequisites exist
- ⚠️ Step 5: Confirm deployment success
- ⚠️ Step 6: Confirm consumer role access

---

## Workflow

### Step 1: Verify App Readiness

Before deploying, confirm:
- App has a working `Dockerfile`
- App builds successfully locally (`docker build`)
- App exposes a port (default: 8080)

```bash
docker build --platform linux/amd64 -t <image-name>:latest .
```

**⚠️ STOP:** Confirm app builds successfully before proceeding.

---

### Step 2: SPCS Prerequisites

#### Check Current Role
```sql
SELECT CURRENT_ROLE(), CURRENT_USER();
```

#### Check/Create Compute Pool
```sql
SHOW COMPUTE POOLS;

-- If no accessible pool exists:
CREATE COMPUTE POOL <pool_name>
  MIN_NODES = 1
  MAX_NODES = 1
  INSTANCE_FAMILY = CPU_X64_XS;
```

#### Check/Create Image Repository
```sql
SHOW IMAGE REPOSITORIES;

-- If needed:
CREATE IMAGE REPOSITORY <db>.<schema>.<repo_name>;
```

#### Login to Registry
```bash
snow spcs image-registry login --connection <conn>
```

**⚠️ STOP:** Confirm compute pool and image repository exist before proceeding.

---

### Step 3: Create Service Specification

Create `service-spec.yaml`:

```yaml
spec:
  containers:
  - name: <app-name>
    image: /<db>/<schema>/<repo>/<image>:latest
    env:
      HOSTNAME: "0.0.0.0"
      PORT: "8080"
      NODE_ENV: production
    resources:
      requests:
        memory: 1Gi
        cpu: 500m
      limits:
        memory: 2Gi
        cpu: 1000m
    readinessProbe:
      port: 8080
      path: /
  endpoints:
  - name: <endpoint-name>
    port: 8080
    public: true
```

Adjust `resources`, `port`, and `env` based on app requirements.

---

### Step 4: Build and Push Image

```bash
docker build --platform linux/amd64 -t <image-name>:latest .
docker tag <image-name>:latest <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
docker push <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
```

Registry URL format: `<account>.registry.snowflakecomputing.com`

---

### Step 5: Deploy Service

```sql
CREATE SERVICE <service_name>
  IN COMPUTE POOL <pool_name>
  FROM SPECIFICATION $$
  <contents of service-spec.yaml>
  $$
  MIN_INSTANCES = 1
  MAX_INSTANCES = 1;
```

#### Monitor and Get URL
```sql
SELECT SYSTEM$GET_SERVICE_STATUS('<service_name>');
SHOW ENDPOINTS IN SERVICE <service_name>;
```

**IMPORTANT:** Extract the `ingress_url` from SHOW ENDPOINTS and display it to the user.

#### Verify Deployment
```bash
cortex browser open "https://<ingress_url>"
cortex browser snapshot -i  # Verify app loads correctly
```

**⚠️ STOP:** Confirm deployment success with user.

---

### Step 6: Grant Consumer Access

Ask the user: **"What role will consume this service?"**

#### 1. Check Data Access
```sql
SHOW GRANTS TO ROLE <consumer_role>;
```
If required privileges on tables are missing, grant what the service needs:
```sql
GRANT USAGE ON DATABASE <db> TO ROLE <consumer_role>;
GRANT USAGE ON SCHEMA <db>.<schema> TO ROLE <consumer_role>;
-- Grant privileges the service requires (SELECT, INSERT, UPDATE, DELETE, etc.)
GRANT <privileges> ON TABLE <db>.<schema>.<table> TO ROLE <consumer_role>;
```

#### 2. Check Service Endpoint Access
```sql
SHOW GRANTS TO ROLE <consumer_role>;
```
If service role grant is missing:
```sql
GRANT SERVICE ROLE <service_name>!ALL_ENDPOINTS_USAGE TO ROLE <consumer_role>;
```

**⚠️ STOP:** Confirm consumer role can access the service.

---

## Updating a Service

**⚠️ CAUTION:** Always use `ALTER SERVICE` to update an existing service. Never drop and recreate—this changes the service URL and breaks existing integrations.

```bash
docker build --platform linux/amd64 -t <image-name>:latest .
docker tag <image-name>:latest <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
docker push <registry-url>/<db>/<schema>/<repo>/<image-name>:latest
```

```sql
ALTER SERVICE <service_name> FROM SPECIFICATION $$
<full yaml spec>
$$;
```

---

## Troubleshooting

#### Service not starting
```sql
SELECT SYSTEM$GET_SERVICE_LOGS('<service_name>', 0, '<container_name>');
```

#### Service Won't Start
- **Image not found**: The image path in your spec must exactly match the repository structure. Format: `/<db>/<schema>/<repo>/<image>:latest`. Case-sensitive and must include leading slash.
- **Port mismatch**: Three ports must align: `readinessProbe.port` (health check), `PORT` env var (app listens on), and `endpoints.port` (external access). If any differ, the service fails readiness checks.
- **Auth errors**: Registry login expires. Re-run `snow spcs image-registry login --connection <conn>` before pushing images.

#### Permission Errors
- **Missing privileges**: The role that owns the service needs access to any tables/views the app queries. Common issue when app works locally but fails in SPCS.
  ```sql
  GRANT SELECT ON TABLE <db>.<schema>.<table> TO ROLE <role>;
  GRANT DELETE ON TABLE <db>.<schema>.<table> TO ROLE <role>;  -- if app deletes data
  ```

## Output
- Deployed SPCS service URL
- Service status confirmation
- Consumer role access configured

Tags

#deploy-to-spcs

Related Skills

Browse all
v1.0.0

snowflake-notebooks

cortex-community
Create and edit Workspace notebooks (.ipynb files) for Snowflake. Use when: creating workspace notebooks, editing notebooks, debugging notebook issues, converting code to notebooks, working with Snowpark, SQL cells, or data analysis in Snowflake. Triggers: notebook, .ipynb, snowflake notebook, workspace notebook, create notebook, edit notebook, jupyter, ipynb file, notebook cell, SQL cell, snowpark session.
#snowflake-notebooks
Cortex
4822.0k
2 hours ago
v1.0.0

dynamic-tables

cortex-community
[REQUIRED] Use for ALL Snowflake Dynamic Table operations: creating, optimizing, monitoring, and troubleshooting. This is the required entry point for any dynamic table related tasks (DT is an acronym for dynamic table). Triggers: dynamic table, data pipeline, incremental pipeline, DT pipeline, incremental refresh, target lag, UPSTREAM_FAILED, refresh failing, full refresh instead of incremental, DT health, create DT, debug DT.
#dynamic-tables
Cortex
3791.2k
2 hours ago
v0.1.0

snowconvert-assessment

cortex-community
Analyzes workloads to be migrated to Snowflake using SnowConvert assessment reports. Routes to specialized sub-skills for high-quality assessments. Use this skill when user wants to do an assessment of their code or ETL workload, waves generation, object exclusion, sql dynamic and/or ETL analysis (SSIS)
#snowconvert-assessment
Cortex
2615.1k
2 hours ago
v1.0.0

iceberg

cortex-community
Use for ALL Iceberg table requests in Snowflake. This is the REQUIRED entry point for catalog integrations, catalog-linked databases, external volumes, auto-refresh issues, and Snowflake Intelligence. DO NOT work with Iceberg manually - invoke this skill first. Triggers: iceberg, iceberg table, apache iceberg, catalog integration, REST catalog, ICEBERG_REST, glue, AWS glue, glue IRC, lake formation, unity catalog, databricks, polaris, opencatalog, open catalog, CLD, catalog-linked database, linked catalog, auto-discover tables, sync tables, LINKED_CATALOG, external volume, storage access, S3, Azure blob, GCS, IAM role, trust policy, Access Denied, 403 error, ALLOW_WRITES, storage permissions, auto-refresh, autorefresh, stale data, refresh stuck, delta direct, snowflake intelligence, text-to-SQL iceberg, query iceberg natural language.
#iceberg
Cortex
2091.7k
2 hours ago

Details

Stars85
Installs4.9k
Authorcortex-community
Versionv1.0.0
Updated2 hours ago
LicenseMIT
View Repository
quick install
$ cortex skill install deploy-to-spcs