Snowpark Container Services:服务的其他注意事项

重要

Snowpark Container Services 作业服务功能目前为非公开预览版,并受预览版条款的约束,详情请访问: ` <https://snowflake.com/legal (https://snowflake.com/legal)> `_。有关更多信息,请联系您的 Snowflake 代表。

从容器内部连接到 Snowflake

当您启动服务(包括作业服务)时,Snowflake 会为正在运行的容器提供凭据,使容器代码能够使用驱动程序连接到 Snowflake 并执行 SQL(类似于连接到 Snowflake 的计算机上的任何其他代码)。提供的凭据以所有者角色(创建服务的角色)的身份进行身份验证。Snowflake 将提供一些信息作为容器中的环境变量。

Snowflake 中的每个对象都有一个所有者角色。服务的所有者角色决定了在与 Snowflake 交互时,服务可以执行哪些功能。这包括执行 SQL、访问暂存区和服务到服务网络。

备注

服务的所有者角色是指创建服务的角色。您还可以定义一个或多个服务角色来管理对服务公开的端点的访问。有关更多信息,请参阅 管理对服务端点的访问

当您创建服务时,Snowflake 还会创建特定于该服务的 服务用户。当服务运行查询时,它将使用服务的所有者角色作为服务用户运行查询。服务用户可以执行的操作由此所有者角色确定。

服务的所有者角色不能是任何特权角色,例如 ACCOUNTADMIN、SECURITYADMIN 和 ORGADMIN。这是为了限制行为不当的服务可以执行的操作,需要客户更加有意识地让服务能够执行管理操作。

要查看特定服务用户发出的查询,您可以使用 ACCOUNTADMIN 角色来查看 查询历史记录。服务用户的用户名格式为 SF$SERVICE$unique-id

连接到 Snowflake

Snowflake 提供以下环境变量,供您在服务代码中配置 Snowflake 客户端:

  • SNOWFLAKE_ACCOUNT: 提供服务当前运行使用的 Snowflake 账户的名称。

  • SNOWFLAKE_HOST: 提供用于连接到 Snowflake 的主机名。

Snowflake 还在名为 /snowflake/session/token 的文件内的容器中提供 OAuth 令牌。创建连接时,向连接器提供此令牌。

从容器创建到 Snowflake 的连接时,必须使用 SNOWFLAKE_HOST、SNOWFLAKE_ACCOUNT 和 OAuth 令牌。您不能使用 OAuth 令牌而不使用 SNOWFLAKE_HOST,也不能在 Snowpark Container Services 外使用 OAuth 令牌。有关更多信息,请参阅 使用 OAuth 令牌执行 SQL

有关使用各种 Snowflake 驱动程序的示例代码,请参阅 ` Snowflake 连接示例 <https://github.com/Snowflake-Labs/sf-samples/tree/main/samples/spcs/sf-connection (https://github.com/Snowflake-Labs/sf-samples/tree/main/samples/spcs/sf-connection)>`_。

例子

  • 在 :doc:` 教程 2 <tutorials/tutorial-2>` (请参阅 main.py)中,代码按如下方式读取环境变量:

    SNOWFLAKE_ACCOUNT = os.getenv('SNOWFLAKE_ACCOUNT')
    SNOWFLAKE_HOST = os.getenv('SNOWFLAKE_HOST')
    
    Copy

    代码将这些变量传递给所选 Snowflake 客户端的连接创建代码。容器使用这些凭据创建一个新会话,并将所有者角色作为主要角色,来执行查询。以下示例代码是使用 Python 创建 Snowflake 连接所需的最简代码:

    def get_login_token():
      with open('/snowflake/session/token', 'r') as f:
        return f.read()
    
    conn = snowflake.connector.connect(
      host = os.getenv('SNOWFLAKE_HOST'),
      account = os.getenv('SNOWFLAKE_ACCOUNT'),
      token = get_login_token(),
      authenticator = 'oauth'
    )
    
    Copy
  • 当使用默认主机(即,在创建连接时不纳入 host 实参)时,将支持使用其他形式的身份验证(如用户名和密码)连接到 Snowflake。例如,以下连接指定要进行身份验证的用户名和密码:

    conn = snowflake.connector.connect(
      account = os.getenv('SNOWFLAKE_ACCOUNT'),
      user = '<user-name>',
      password = <password>
    )
    
    Copy

    使用默认主机需要与网络规则进行外部访问集成,该规则允许从服务访问您账户的 Snowflake 主机名。例如,如果您的账户名称是 MyAccount,则主机名将为 myaccount.snowflakecomputing.cn。有关更多信息,请参阅 网络出口

    • 创建与您账户的 Snowflake API 主机名匹配的网络规则:

      CREATE OR REPLACE NETWORK RULE snowflake_egress_access
        MODE = EGRESS
        TYPE = HOST_PORT
        VALUE_LIST = ('myaccount.snowflakecomputing.cn');
      
      Copy
    • 使用上述网络规则创建集成:

      CREATE EXTERNAL ACCESS INTEGRATION snowflake_egress_access_integration
        ALLOWED_NETWORK_RULES = (snowflake_egress_access)
        ENABLED = true;
      
      Copy

配置用于执行 SQL 的数据库和架构上下文

本节介绍两个概念:

  • Snowflake 用于确定要在其中创建服务的数据库和架构的逻辑。

  • Snowflake 将此信息传达给容器,从而使容器代码能够在同一数据库和架构上下文中执行 SQL 的方法。

Snowflake 使用服务名称来确定要在其中创建服务的数据库和架构:

  • 示例 1:在以下 CREATE SERVICE 和 EXECUTE JOB SERVICE 命令中,服务名称不会显式指定数据库和架构名称。Snowflake 在当前数据库和架构中创建服务和作业服务。

    -- Create a service.
    CREATE SERVICE test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service ...
    
    Copy
  • 示例 2:在以下 CREATE SERVICE 和 EXECUTE JOB SERVICE 命令中,服务名称包括数据库和架构名称。Snowflake 在指定的数据库 (test_db) 和架构 (test_schema) 中创建服务和作业服务,无论当前架构如何。

    -- Create a service.
    CREATE SERVICE test_db.test_schema.test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = test_db.test_schema.example_job_service ...
    
    Copy

当 Snowflake 启动服务时,它会使用以下环境变量向正在运行的容器提供数据库和架构信息:

  • SNOWFLAKE_DATABASE

  • SNOWFLAKE_SCHEMA

容器代码可以使用连接代码中的环境变量来确定要使用的数据库和架构,如以下示例所示:

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth',
  database = os.getenv('SNOWFLAKE_DATABASE'),
  schema = os.getenv('SNOWFLAKE_SCHEMA')
)
Copy

示例

教程 2 中,您可以创建与 Snowflake 连接并执行 SQL 语句的 Snowflake 作业服务。以下步骤总结了教程代码如何使用环境变量:

  1. 在通用设置中(请参阅 通用设置 部分),您可以创建资源,包括数据库和架构。您还可以为会话设置当前数据库和架构:

    USE DATABASE tutorial_db;
    ...
    USE SCHEMA data_schema;
    
    Copy
  2. 创建作业服务(通过运行 EXECUTE JOB SERVICE)后,Snowflake 启动容器,并将容器中的以下环境变量设置为会话的当前数据库和架构:

    • 将 SNOWFLAKE_DATABASE 设置为“TUTORIAL_DB”

    • 将 SNOWFLAKE_SCHEMA 设置为“DATA_SCHEMA”

  3. 作业代码(请参阅教程 2 中的 main.py)读取以下环境变量:

    SNOWFLAKE_DATABASE = os.getenv('SNOWFLAKE_DATABASE')
    SNOWFLAKE_SCHEMA = os.getenv('SNOWFLAKE_SCHEMA')
    
    Copy
  4. 作业代码将数据库和架构设置为执行 SQL 语句(main.py 中的 run_job() 函数)的上下文:

    {
       "account": SNOWFLAKE_ACCOUNT,
       "host": SNOWFLAKE_HOST,
       "authenticator": "oauth",
       "token": get_login_token(),
       "warehouse": SNOWFLAKE_WAREHOUSE,
       "database": SNOWFLAKE_DATABASE,
       "schema": SNOWFLAKE_SCHEMA
    }
    ...
    
    Copy

    备注

    SNOWFLAKE_ACCOUNT、SNOWFLAKE_HOST、SNOWFLAKE_DATABASE、SNOWFLAKE_SCHEMA 是 Snowflake 为应用程序容器生成的环境变量,但 SNOWFLAKE_WAREHOUSE 不是(教程 2 应用程序代码创建了此变量,因为 Snowflake 不会将仓库名称传递给容器)。

为容器指定仓库

如果服务连接到 Snowflake,以在 Snowflake 仓库中执行查询,则您可以使用以下选项来指定仓库:

  • 在应用程序代码中指定仓库。 在启动 Snowflake 会话以在代码中运行查询时,在连接配置中指定仓库。有关示例,请参阅 教程 2

  • 在创建服务时指定默认仓库。CREATE SERVICE (或 EXECUTE JOB SERVICE )命令中指定可选的 QUERY_WAREHOUSE 参数,以提供默认仓库。如果应用程序代码未在连接配置中提供仓库,则 Snowflake 将使用默认仓库。使用 ALTER SERVICE 命令更改默认仓库。

如果同时使用这两种方法指定仓库,则将使用应用程序代码中指定的仓库。

使用 OAuth 令牌执行 SQL

所有 Snowflake 提供的客户端都支持使用 OAuth 作为身份验证方式。服务容器还使用 OAuth 机制来向 Snowflake 进行身份验证。例如,当容器要执行时 SQL 时,容器将创建与 Snowflake 的连接,类似于任何其他 Snowflake 客户端:

def get_login_token():
  with open('/snowflake/session/token', 'r') as f:
    return f.read()

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth'
)
Copy

当您创建服务时,Snowflake 会运行容器,并为容器提供 Oauth 令牌,以便在容器中的以下位置使用:/snowflake/session/token

请注意以下有关此 OAuth 令牌的详细信息:

  • 您应该先阅读 /snowflake/session/token 文件的内容然后再立即使用,因为内容将在 10 分钟后过期,而 Snowflake 每隔几分钟就会刷新一次此文件。容器成功连接到 Snowflake 后,过期时间将不适用于该连接(与用户直接创建的任何会话一样)。

  • 此 OAuth 令牌仅在特定的 Snowflake 服务中有效。您无法复制 OAuth 令牌并在服务外使用它。

  • 使用 OAuth 令牌,容器作为服务用户与 Snowflake 连接,并使用服务的所有者角色。

  • 使用 OAuth 令牌进行连接将创建一个新会话。OAuth 令牌不与任何现有 SQL 会话关联。

    备注

    执行存储过程和执行服务间的一个显著差异是,存储过程与运行存储过程的 SQL 在同一会话中运行。但是,每次容器建立新连接时,您都会创建一个新会话。

配置网络功能

以下部分说明如何为服务(包括作业服务)配置网络功能(网络入口和出口)。

网络入口

要允许任何内容通过互联网与服务交互,请在服务规范文件中将服务侦听的网络端口声明为端点。这些端点控制入口。

默认情况下,服务端点是专用的。只有 服务函数服务到服务通信 可以向专用端点发出请求。您可以将端点声明为公共端点,以允许通过互联网向端点发出请求。服务的所有者角色必须具有账户的 BIND SERVICE ENDPOINT 权限。

endpoints:
- name: <endpoint name>
  port: <port number>
  protocol : < TCP / HTTP / HTTPS >
  public: true
Copy

有关示例,请参阅 教程 1

备注

目前只有服务支持网络入口,作业服务不支持。

入口和 Web 应用程序安全性

您可以使用公共端点支持(网络入口)创建用于 Web 托管的 Snowpark Container Services。为了提高安全性,Snowflake 采用代理服务来监控从客户端到服务的传入请求以及从服务到客户端的传出响应。本节介绍代理的作用以及它如何影响部署到 Snowpark Container Services 的服务。

备注

在本地测试服务时,您没有使用 Snowflake 代理,因此在本地运行服务的体验与在 Snowpark Container Services 中部署的体验之间存在差异。查看本节并更新本地设置以更好地进行测试。

例如:

  • 如果请求使用了被禁止的 HTTP 方法,代理不会转发传入的 HTTP 请求。

  • 如果响应中的 Content-Type 标头指出响应包含可执行文件,则代理会向客户端发送 403 响应。

此外,代理还可以在请求和响应中注入新的标头并更改现有标头,同时兼顾容器和数据安全性。

例如,在收到请求后,服务可能会在响应中,将 HTML、JavaScript、CSS 以及其他网页内容发送到客户端浏览器。浏览器中的网页是服务的一部分,充当用户界面。出于安全原因,如果服务有限制(例如,限制与其他站点建立网络连接),您可能还希望服务网页具有同样的限制。

默认情况下,服务没有访问互联网的权限。浏览器还应限制客户端应用程序访问互联网和潜在的数据共享行为。如果设置外部访问集成 (EAI) 以允许服务访问 example.com (请参阅 网络出口 ),服务网页也应该能够通过浏览器访问 example.com

Snowflake 代理通过在响应中添加 Content-Security-Policy (CSP) 标头,对服务和网页应用同样的网络限制。默认情况下,代理会在响应中添加基线 CSP,以防范常见的安全威胁。此外,如果服务配置为使用 EAI,代理将对网页从 EAI 到 CSP 应用同样的网络规则。此 CSP 使浏览器中的网页能够访问与服务相同的站点。

以下各节介绍了 Snowflake 代理如何处理对服务的传入请求,并修改服务对客户端的传出响应。

传入服务的请求

当请求到达时,代理会先执行以下操作,然后再将请求转发到服务:

  • 采用禁止的 HTTP 方法的传入请求: 如果传入 HTTP 请求使用以下任意被禁止的 HTTP 方法,代理不会将请求转发到服务:

    • TRACE

    • OPTIONS

    • CONNECT

传出到客户端的响应

Snowflake 代理会先将这些修改应用于服务发送的响应,然后再将响应转发到客户端。

  • 标头清理: Snowflake 代理会删除这些响应标头(如果存在):

    • X-XSS-Protection

    • Server

    • X-Powered-By

    • Public-Key-Pins

  • Content-Type 响应标头: 如果服务响应包含 Content-Type 标头以及以下任何 MIME 类型值(指示可执行文件),Snowflake 代理不会将该响应转发到客户端。相反,代理会发送一个 403 Forbidden 响应。

    • application/x-msdownload:Microsoft 可执行文件。

    • application/exe:通用可执行文件。

    • application/x-exe:另一个通用可执行文件。

    • application/dos-exe:DOS 可执行文件。

    • application/x-winexe:Windows 可执行文件。

    • application/msdos-windows:MS-DOS Windows 可执行文件。

    • application/x-msdos-program:MS-DOS 可执行文件。

    • application/x-sh:Unix shell 脚本。

    • application/x-bsh:Bourne shell 脚本。

    • application/x-csh:C shell 脚本。

    • application/x-tcsh:Tcsh shell 脚本。

    • application/batch:Windows 批处理文件。

  • X-Frame-Options 响应标头: 为防止点击劫持攻击,Snowflake 代理将此响应标头设置为 DENY,以防止其他网页使用 iframe 访问服务网页。

  • Cross-Origin-Opener-Policy (COOP) 响应标头: Snowflake 将 COOP 响应标头设置为 same-origin 以防止引用跨域窗口访问服务选项卡。

  • Cross-Origin-Resource-Policy (CORP) 响应标头: Snowflake 将 CORP 标头设置为 same-origin 以防止外部站点加载入口端点公开的资源(例如,在 iframe 中)。

  • X-Content-Type-Options 响应标头: Snowflake 代理将此标头设置为 nosniff,以确保客户端不会更改服务在响应中指出的 MIME 类型。

  • Cross-Origin-Embedder-Policy (COEP) 响应标头: Snowflake 代理将 COEP 响应标头设置为 credentialless,这意味着在加载跨域对象(如图像或脚本)时,如果远程对象不支持跨域资源共享 (CORS) 协议,Snowflake 在加载时不会发送凭据。

  • Content-Security-Policy-Report-Only 响应标头: Snowflake 代理将此响应标头替换为新值,指示客户端向 Snowflake 发送 CSP 报告。

  • Content-Security-Policy (CSP) 响应标头: 默认情况下,Snowflake 代理会添加以下基线 CSP,以防止常见的 Web 攻击。

    default-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data:; object-src 'none'; connect-src 'self'; frame-ancestors 'self';
    
    Copy

    有两个内容安全策略注意事项:

    • 除了代理添加的基线内容安全策略外,服务本身还可以在响应中显式添加 CSP。服务可能会选择通过添加更严格的 CSP 来增强安全性。例如,服务可能会添加以下 CSP 以仅允许来自 self 的脚本。

      script-src 'self'
      
      Copy

      在发送给客户端的结果响应中,将有两个 CSP 标头。收到响应后,客户端浏览器将应用最严格的内容安全策略,其中包括每个策略指定的其他限制。

    • 如果配置外部访问集成 (EAI) 以允许服务访问外部站点 (网络出口),Snowflake 代理会创建一个 CSP,以允许网页访问该站点。例如,假设与 EAI 关联的网络规则允许服务出口访问 example.com。然后,Snowflake 代理将添加此 CSP 响应标头:

      default-src 'self' 'unsafe-inline' 'unsafe-eval' http://example.com https://example.com blob: data:; object-src 'none'; connect-src 'self' http://example.com https://example.com wss://example.com; frame-ancestors 'self';
      
      Copy

      浏览器遵循响应中收到的内容访问策略。在此示例中,浏览器允许应用程序访问 example.com, 但不允许访问其他站点。

网络出口

应用程序代码可能需要访问互联网。默认情况下,应用程序容器没有访问互联网的权限。您需要使用 外部访问集成 (EAIs) 启用互联网访问。

通常,您希望账户管理员创建 EAIs 来管理允许通过服务(包括作业服务)进行的外部访问。然后,账户管理员可以向开发者用于运行服务的特定角色授予 EAI 使用量。

以下示例概述了创建 EAI 的步骤,这允许出口流量流向使用网络规则制定的特定目的地。然后,您可以在创建服务时引用 EAI 以允许对特定互联网目的地的请求。

示例

假设您希望应用程序代码将请求发送到以下目的地:

  • 向 translation.googleapis.com 发出 HTTPS 请求

  • 向 google.com 发出 HTTP 和 HTTPS 请求

按照以下步骤操作,使服务能够访问互联网上的这些域:

  1. 创建外部访问集成 (EAI)。这需要适当的权限。例如,您可以使用 ACCOUNTADMIN 角色来创建 EAI。这个过程分为两步:

    1. 使用 CREATE NETWORK RULE 命令创建一个或多个出口网络规则,列出您希望允许访问的外部目的地。您可以使用一个网络规则来完成此示例,但为便于说明,我们创建了两个网络规则:

      1. 创建名为 translate_network_rule 的网络规则:

        CREATE OR REPLACE NETWORK RULE translate_network_rule
          MODE = EGRESS
          TYPE = HOST_PORT
          VALUE_LIST = ('translation.googleapis.com');
        
        Copy

        此规则允许 TCP 连接到 translation.googleapis.com 目的地。VALUE_LIST 属性中的域未指定可选端口号,因此将使用默认端口 443 (HTTPS)。这使应用程序可以连接到以 https://translation.googleapis.com/ 开头的任何 URL。

      2. 创建名为 google_network_rule 的网络规则:

        CREATE OR REPLACE NETWORK RULE google_network_rule
          MODE = EGRESS
          TYPE = HOST_PORT
          VALUE_LIST = ('google.com:80', 'google.com:443');
        
        Copy

        这使应用程序可以连接到任何以 http://google.com/https://google.com/ 开头的 URL。

      备注

      对于 VALUE_LIST 参数,您必须提供完整的主机名。不支持通配符(例如,*.googleapis.com)。

      Snowpark Container Services 仅支持允许端口 22、80、443 和 1024+ 的网络规则。如果引用的网络规则允许访问其他端口,则服务创建将失败。如果您需要使用其他端口,请联系客户代表。

      备注

      要允许服务向互联网上的任何目的地发送 HTTP 或 HTTPS 请求,请指定“0.0.0.0”作为 VALUE_LIST 属性。以下网络规则允许在互联网上的任何位置发送“HTTP”和“HTTPS”请求。“0.0.0.0”仅支持端口 80 或 443。

      CREATE NETWORK RULE allow_all_rule
        TYPE = 'HOST_PORT'
        MODE= 'EGRESS'
        VALUE_LIST = ('0.0.0.0:443','0.0.0.0:80');
      
      Copy
    2. 创建外部访问集成 (EAI),指定允许使用上述两个出口网络规则:

      CREATE EXTERNAL ACCESS INTEGRATION google_apis_access_integration
        ALLOWED_NETWORK_RULES = (translate_network_rule, google_network_rule)
        ENABLED = true;
      
      Copy

      现在,账户管理员可以向开发者授予集成使用量,以允许他们运行可以访问互联网上特定目的地的服务。

      GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE test_role;
      
      Copy
  2. 按照以下示例,通过提供 EAI 创建服务。创建服务的所有者角色需要 EAI 的 USAGE 权限和引用密钥的 READ 权限。请注意,您不能使用 ACCOUNTADMIN 角色来创建服务。

    • 创建服务:

      USE ROLE test_role;
      
      CREATE SERVICE eai_service
        IN COMPUTE POOL MYPOOL
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION)
        FROM SPECIFICATION
        $$
        spec:
          containers:
            - name: main
              image: /db/data_schema/tutorial_repository/my_echo_service_image:tutorial
              env:
                TEST_FILE_STAGE: source_stage/test_file
              args:
                - read_secret.py
          endpoints:
            - name: read
              port: 8080
        $$;
      
      Copy

      此示例 CREATE SERVICE 请求使用内联服务规范,并指定可选的 EXTERNAL_ACCESS_INTEGRATIONS 属性以纳入 EAI。EAI 指定允许从服务到特定目的地的出口流量的网络规则。

    • 执行作业服务:

      EXECUTE JOB SERVICE
        IN COMPUTE POOL tt_cp
        NAME = example_job_service
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION)
        FROM SPECIFICATION $$
        spec:
          container:
          - name: curl
            image: /tutorial_db/data_schema/tutorial_repo/alpine-curl:latest
            command:
            - "curl"
            - "http://google.com/"
        $$;
      
      Copy

      此示例 EXECUTE JOB SERVICE 命令指定内联规范和可选的 EXTERNAL_ACCESS_INTEGRATIONS 属性以纳入 EAI。这允许从作业到 EAI 允许的网络规则中指定的目的地的出口流量。

容器间的网络通信

有两个注意事项:

  • 服务实例的容器之间的通信: 如果一个服务实例运行多个容器,这些容器可以通过 localhost 相互通信(无需在服务规范中定义端点)。

  • 跨多个服务或多个服务实例的容器之间的通信: 属于不同服务(或同一服务的不同实例)的容器可以使用规范文件中定义的端点进行通信。有关更多信息,请参阅 服务到服务通信

使用 Snowflake 密钥将凭据传递到容器

如果服务与外部端点(Snowflake 外)通信,则需要在容器中提供凭据信息,以便应用程序代码使用。要提供凭据,请执行以下操作:

  1. 将凭据存储在 Snowflake 密钥 对象中。

  2. 在服务规范文件中,纳入 containers.secrets 字段,以将这些密钥传递给容器。您可以将这些凭据传递给容器中的环境变量,也可以使其在容器的本地文件中可用。根据您的选择,规范文件将提供构造,如以下各节所述。

将密钥作为环境变量传递

要将容器 Snowflake 密钥作为环境变量传递,请纳入 containers.secrets 字段:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: <snowflake-secret-name>
    secretKeyRef: <secret-key-reference>
    envVarName: <env-variable-name>
Copy

secretKeyRef:此值取决于 Snowflake 密钥的类型。可能的值如下:

  • 如果 Snowflake 密钥是 password 类型,则为 usernamepassword

  • 如果 Snowflake 密钥是 generic_string 类型,则为 secret_string

  • 如果 Snowflake 密钥是 oauth2 类型,则为 access_token

备注

创建服务后,将无法更新作为环境变量传递的密钥。

示例 1:将 password 类型的密钥作为环境变量传递

在此示例中,您将创建以下 password 类型的 Snowflake 密钥对象:

CREATE SECRET testdb.testschema.my_secret_object
  TYPE = password
  USERNAME = 'snowman'
  PASSWORD = '1234abc';
Copy

要在容器中将此 Snowflake 密钥对象提供给环境变量(例如,LOGIN_USERLOGIN_PASSWORD),请在规范文件中添加以下 containers.secrets 字段:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret_object
    secretKeyRef: username
    envVarName: LOGIN_USER
  - snowflakeSecret: testdb.testschema.my_secret_object
    secretKeyRef: password
    envVarName: LOGIN_PASSWORD
Copy

此示例中的 containers.secrets 字段是两个 snowflakeSecret 对象的列表:

  • 第一个对象将 Snowflake 密钥对象中的 username 映射到容器中的 LOGIN_USER 环境变量。

  • 第二个对象将 Snowflake 密钥对象中的 password 映射到容器中的 LOGIN_PASSWORD 环境变量。

示例 2:将 generic_string 类型的密钥作为环境变量传递

在此示例中,您将创建以下 generic_string 类型的 Snowflake 密钥对象:

CREATE SECRET testdb.testschema.my_secret
  TYPE=generic_string
  SECRET_STRING='
       some_magic: config
  ';
Copy

要在容器中将此 Snowflake 密钥对象提供给环境变量(例如,GENERIC_SECRET),请在规范文件中添加以下 containers.secrets 字段:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret
    secretKeyRef: secret_string
    envVarName: GENERIC_SECRET
Copy

关于将 oauth2 类型的密钥传递给环境变量

这不是一个有用的场景,因为如果 OAuth 令牌过期,则必须向容器中传入新令牌。但是作为环境变量传递的密钥无法更新,因此请勿将“oauth2”类型的密钥作为环境变量传递。

在本地容器文件中传递密钥

要使 Snowflake 密钥可用于本地容器文件中的应用程序容器,请纳入 containers.secrets 字段:

containers:
- name: <name>
  image: <url>
  ...
  secrets:
  - snowflakeSecret: <snowflake-secret-name>
    directoryPath: '<local directory path in the container>'
Copy

directoryPath:Snowflake 为此指定目录中的每个密钥填充一个文件;指定 secretKeyRef 不是必需的。

备注

创建完服务后,如果更新了 Snowflake 密钥对象,Snowflake 将更新正在运行的容器中对应的密钥文件。

示例 1:在本地容器文件中传递 password 类型的密钥

在此示例中,您将创建以下 password 类型的 Snowflake 密钥对象:

CREATE SECRET testdb.testschema.my_secret_object
  TYPE = password
  USERNAME = 'snowman'
  PASSWORD = '1234abc';
Copy

要使这些凭据在本地容器文件中可用,请在规范文件中添加以下 containers.secrets 字段:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret_object
    directoryPath: '/usr/local/creds'
Copy

当您启动服务时,Snowflake 会在容器中创建两个文件:/usr/local/creds/username/usr/local/creds/password。然后,应用程序代码可以读取这些文件。

示例 2:在本地容器文件中传递 oauth2 类型的密钥

在此示例中,您将创建以下 oauth2 类型的 Snowflake 密钥对象:

CREATE SECRET testdb.testschema.oauth_secret
  TYPE = OAUTH2
  OAUTH_REFRESH_TOKEN = '34n;vods4nQsdg09wee4qnfvadH'
  OAUTH_REFRESH_TOKEN_EXPIRY_TIME = '2023-12-31 20:00:00'
  API_AUTHENTICATION = my_integration;
Copy

要使这些凭据在本地容器文件中可用,请在规范文件中添加以下 containers.secrets 字段:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.oauth_secret
    directoryPath: '/usr/local/creds'
Copy

Snowflake 从 OAuth 密钥对象中提取访问令牌,并在容器中创建 /usr/local/creds/access_token

当服务使用 oauth2 类型的密钥时,该服务将使用该密钥访问互联网目的地。oauth 密钥必须得到 外部访问集成 (EAI) 的允许;否则,CREATE SERVICE 或 EXECUTE JOB SERVICE 将失败。这个额外的 EAI 要求仅适用于 oauth2 类型的密钥,而不适用于其他类型的密钥。

总之,创建此类服务的一般步骤是:

  1. 创建 oauth2 类型的密钥(如前所示)。

  2. 创建 EAI 以允许服务使用密钥。例如:

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION example_eai
      ALLOWED_NETWORK_RULES = (<name>)
      ALLOWED_AUTHENTICATION_SECRETS = (testdb.testschema.oauth_secret)
      ENABLED = true;
    
    Copy
  3. 创建规范中包含 containers.secrets 字段的服务。这也会指定可选的 EXTERNAL_ACCESS_INTEGRATIONS 属性以纳入 EAI,从而允许使用 oauth2 密钥。

    一个示例 CREATE SERVICE(带内联规范)命令:

    CREATE SERVICE eai_service
      IN COMPUTE POOL MYPOOL
      EXTERNAL_ACCESS_INTEGRATIONS = (example_eai)
      FROM SPECIFICATION
      $$
      spec:
        containers:
          - name: main
            image: <url>
            secrets:
            - snowflakeSecret: testdb.testschema.oauth_secret
              directoryPath: '/usr/local/creds'
        endpoints:
          - name: api
            port: 8080
      $$;
    
    Copy

有关出口的更多信息,请参阅 网络出口

准则和限制

  • 镜像平台要求: 目前,Snowpark Container Services 需要 linux/amd64 平台镜像。

  • 服务容器没有特权: 服务容器不以特权身份运行,因此无法更改主机上的硬件配置,只能更改有限的 OS 配置。服务容器只能执行普通用户(即不需要 root 的用户)可以执行的操作系统配置。

  • 重命名数据库和架构:

    • 请勿重命名已创建服务的数据库和架构。重命名实际上是将服务移动到另一个数据库和架构,系统不支持此操作。例如:

      • 服务 DNS 名称将继续反映旧的数据库和架构名称。

      • Snowflake 提供给正在运行的服务容器的数据库和架构信息将继续引用旧名称。

      • 服务在事件表中引入的新日志将继续引用旧的数据库和架构名称。

      • 服务函数将继续引用旧数据库和架构中的服务,当您调用服务函数时,它将失败。

    • 服务规范可以引用 Snowflake 暂存区和镜像仓库等对象。如果重命名这些对象所在的数据库或架构名称,则需要手动更新服务规范中引用的对象的数据库和架构的名称。

  • 删除和取消删除数据库和架构:

    • 删除父数据库或架构时,将异步删除服务。这意味着在内部进程移除服务之前,服务可能会继续运行一段时间。

    • 如果尝试取消删除以前删除的数据库或架构,则无法保证会还原服务。

  • 所有权转让: 不支持转让服务(包括工作服务)的所有权。

  • 复制: 在 Snowflake 中处理复制时,请注意以下事项:

    • Snowpark Container Services 对象(例如服务、计算池和镜像仓库)无法复制。

    • 如果在数据库中创建镜像仓库,则整个数据库都无法复制。如果数据库包含其他资源(如服务或计算池),则数据库复制过程将成功,但不会复制数据库中的这些单个对象。

  • 作业服务超时: Snowpark Container Services 作业服务同步运行。如果语句超时,则取消作业服务。默认语句超时为两天。客户可以通过使用 ALTER SESSION 设置参数 STATEMENT_TIMEOUT_IN_SECONDS 来更改超时。

    ALTER SESSION SET statement_timeout_in_seconds=<time>
    
    Copy

    请在运行 EXECUTE JOB SERVICE 命令前进行该设置。

语言: 中文