快速入门

本页重点介绍 FeatureStore 自定义资源,它是 operator 安装完成后用于部署和配置 Feast 的主要接口。

先决条件

  • 已安装 Feast Operator。请参见 安装 Feast
  • 对于基于 PVC 的示例,集群应具有默认的 StorageClass,或者应提前 জানা目标 storageClassName
  • 对于使用外部后端而不是基于 PVC 的文件存储,请提前准备所需服务:
    • 建议使用 PostgreSQL 16。PostgreSQL 用于 SQL registry,也可选用于 PostgreSQL online store。
    • 建议使用 Redis 6.0 或更高版本。Redis 用于 Redis online store。Feast 支持单个 Redis 实例、Redis Cluster 和 Redis Sentinel。
    • FeatureStore CR 引用这些后端之前,请先准备包含后端连接参数的 Kubernetes Secret。

对于本页中的 PostgreSQL 和 Redis 示例,默认假定后端服务、数据库或 schema、凭据以及 Kubernetes Secret 已经存在。仍应在目标集群中验证连通性和驱动兼容性。

FeatureStore CR 概览

FeatureStore CR 中最常用的字段如下:

字段用途常见用法
spec.feastProjectFeast 项目名称必需。用于组织特征定义和元数据。
spec.feastProjectDir特征仓库的创建方式使用默认的 feast init、init 模板或 Git 仓库。
spec.services.offlineStore离线存储配置历史数据存储和可选的远程离线 server。
spec.services.onlineStore在线存储配置低延迟的在线特征读取。
spec.services.registryregistry 配置用于实体、feature view、feature service 和权限的元数据存储。
spec.services.uiUI 服务启用 Feast UI。
spec.authz授权配置通常是基于 Kubernetes 的角色或基于 OIDC 的访问控制。
spec.replicasPod 副本数简单部署时保持为 1。对于多个副本,请使用由持久化存储支持的 durable store。

常见服务配置

离线存储

offlineStore 控制历史特征数据的存储位置,以及是否暴露远程 offline server。

常见选项:

  • persistence.file:基于文件的存储,通常是在 PVC 上使用 DuckDB,适用于本地开发和评估
  • persistence.store:外部离线后端,例如 BigQuery 或其他受支持的 Feast offline store
  • server: {}:创建用于网络访问的远程 offline server Service

基于 PVC 的 DuckDB 示例:

services:
  offlineStore:
    persistence:
      file:
        type: duckdb
        pvc:
          create:
            storageClassName: fast
            resources:
              requests:
                storage: 10Gi
          mountPath: /data/offline
    server: {}

基于 store 的示例:

services:
  offlineStore:
    persistence:
      store:
        type: bigquery
        secretRef:
          name: feast-data-stores
    server: {}

在线存储

onlineStore 用于低延迟特征服务。

常见选项:

  • persistence.file:基于文件的本地存储,通常仅用于开发
  • persistence.store:Redis、PostgreSQL 或其他受支持的 Feast online store 后端
  • server:可选的额外 server 设置,例如 envenvFromresourcestlsvolumeMounts

本页示例推荐的后端版本:

  • Redis 6.0 或更高版本
  • PostgreSQL 16

基于 PVC 的文件示例:

services:
  onlineStore:
    persistence:
      file:
        path: online_store.db
        pvc:
          create:
            resources:
              requests:
                storage: 5Gi
          mountPath: /data/online

基于 Redis 的示例:

services:
  onlineStore:
    persistence:
      store:
        type: redis
        secretRef:
          name: feast-data-stores

基于 PostgreSQL 的示例:

services:
  onlineStore:
    persistence:
      store:
        type: postgres
        secretRef:
          name: feast-data-stores
    server:
      envFrom:
        - secretRef:
            name: postgres-secret

registry

registry 用于存储 Feast 元数据。它可以是当前 FeatureStore 的本地 registry,也可以复用远程 registry。

常见选项:

  • registry.local.persistence.file:位于 PVC 或对象存储上的基于文件的 registry
  • registry.local.persistence.store:基于 SQL 的 registry
  • registry.local.server: {}:暴露 registry server 以供远程访问
  • registry.remote:复用另一个 FeatureStore 或外部主机名中的 registry

对于本页中的 SQL-backed registry 示例,建议使用 PostgreSQL 16。

基于 PVC 的 registry 示例:

services:
  registry:
    local:
      persistence:
        file:
          path: registry.db
          pvc:
            create:
              resources:
                requests:
                  storage: 5Gi
            mountPath: /data/registry
      server: {}

基于 SQL 的 registry 示例:

services:
  registry:
    local:
      persistence:
        store:
          type: sql
          secretRef:
            name: feast-data-stores
      server: {}

远程 registry 示例:

services:
  registry:
    remote:
      feastRef:
        name: <shared-featurestore-name>
        namespace: <shared-namespace>

UI

要启用 Feast UI,请设置:

services:
  ui: {}

如果不设置 ui: {},则不会创建 UI Service。

常见持久化模式

基于 PVC 的配置

这是用于评估、本地测试和单副本部署的最简单模式:

apiVersion: feast.dev/v1
kind: FeatureStore
metadata:
  name: <featurestore-name>
  namespace: <namespace>
spec:
  feastProject: <feast-project>
  replicas: 1
  services:
    offlineStore:
      persistence:
        file:
          type: duckdb
          pvc:
            create:
              resources:
                requests:
                  storage: 10Gi
            mountPath: /data/offline
      server: {}
    onlineStore:
      persistence:
        file:
          path: online_store.db
          pvc:
            create:
              resources:
                requests:
                  storage: 5Gi
            mountPath: /data/online
    registry:
      local:
        persistence:
          file:
            path: registry.db
            pvc:
              create:
                resources:
                  requests:
                    storage: 5Gi
              mountPath: /data/registry
        server: {}
    ui: {}

Redis Online Store + SQL Registry

这是用于持久化 online store 和基于数据库的 registry 的常见模式。

先创建 Secret:

apiVersion: v1
kind: Secret
metadata:
  name: feast-data-stores
  namespace: <namespace>
type: Opaque
stringData:
  redis: |
    connection_string: redis.<namespace>.svc.cluster.local:6379,password=<redis-password>
  sql: |
    path: postgresql+psycopg://<user>:<password>@postgres.<namespace>.svc.cluster.local:5432/feast
    cache_ttl_seconds: 60
    sqlalchemy_config_kwargs:
      pool_pre_ping: true
      echo: false

然后在 FeatureStore 中引用它:

apiVersion: feast.dev/v1
kind: FeatureStore
metadata:
  name: <featurestore-name>
  namespace: <namespace>
spec:
  feastProject: <feast-project>
  services:
    offlineStore:
      persistence:
        file:
          type: duckdb
          pvc:
            create: {}
            mountPath: /data/offline
      server: {}
    onlineStore:
      persistence:
        store:
          type: redis
          secretRef:
            name: feast-data-stores
    registry:
      local:
        persistence:
          store:
            type: sql
            secretRef:
              name: feast-data-stores
        server: {}
    ui: {}

PostgreSQL Online Store + SQL Registry

如果将 PostgreSQL 作为 online store 后端,Secret 可以同时包含 postgressql 条目:

apiVersion: v1
kind: Secret
metadata:
  name: feast-data-stores
  namespace: <namespace>
type: Opaque
stringData:
  postgres: |
    host: postgres.<namespace>.svc.cluster.local
    port: 5432
    database: feast
    db_schema: public
    user: <user>
    password: <password>
  sql: |
    path: postgresql+psycopg://<user>:<password>@postgres.<namespace>.svc.cluster.local:5432/feast
    cache_ttl_seconds: 60
    sqlalchemy_config_kwargs:
      pool_pre_ping: true
      echo: false

然后使用:

services:
  onlineStore:
    persistence:
      store:
        type: postgres
        secretRef:
          name: feast-data-stores
  registry:
    local:
      persistence:
        store:
          type: sql
          secretRef:
            name: feast-data-stores
      server: {}

对象存储中的 registry

registry 文件也可以放在 S3 或 GCS 中:

services:
  registry:
    local:
      persistence:
        file:
          path: s3://bucket/registry.db
          cache_ttl_seconds: 60
          cache_mode: sync

关于 Secret 的说明

当使用 persistence.store 时,operator 会从 Kubernetes Secret 中读取后端参数。

重要说明:

  • 默认情况下,Secret 键名与配置的 type 匹配
  • 对于 type: redis,operator 读取 redis
  • 对于 type: postgres,operator 读取 postgres
  • 对于 type: sql,operator 读取 sql
  • 如有需要,可使用 secretKeyName 覆盖键名

Secret 内容应遵循 feature_store.yaml 中使用的后端配置样式,但需要省略后端自身的 type 字段。

特征仓库初始化

operator 可以通过三种常见方式初始化特征仓库。

默认初始化

如果未设置 spec.feastProjectDir,operator 会执行默认的 feast init <project>,并在以下路径下创建仓库:

<offline mount path>/<feastProject>/feature_repo

Init 模板

当 operator 需要引导特定 Feast 模板时,可以使用 init 模板:

spec:
  feastProject: <feast-project>
  feastProjectDir:
    init:
      template: spark

Git 仓库

当特征定义已经在源码管理中维护时,可以使用 Git:

spec:
  feastProject: <feast-project>
  feastProjectDir:
    git:
      url: https://github.com/feast-dev/feast-credit-score-local-tutorial
      ref: 598a270

如果特征仓库不位于默认的 feature_repo 子目录中,请设置 featureRepoPath

部署 FeatureStore

应用基于 PVC 的示例:

kubectl apply -f featurestore.yaml

主要的就绪字段是 status.phase。当部署就绪时,此字段会变为 Ready

可通过以下命令直接检查:

kubectl get featurestore <featurestore-name> -n <namespace> -o jsonpath='{.status.phase}'

服务与访问

operator 会将连接信息写入 FeatureStore 的 status:

kubectl get featurestore <featurestore-name> -n <namespace> -o jsonpath='{.status.serviceHostnames}'
kubectl get featurestore <featurestore-name> -n <namespace> -o jsonpath='{.status.clientConfigMap}'

operator 使用以下模式创建 Service 名称:feast-<featurestore-name>-<component>。常见示例如下:

  • feast-<featurestore-name>-online
  • feast-<featurestore-name>-offline
  • feast-<featurestore-name>-registry
  • feast-<featurestore-name>-ui

生成的 clientConfigMap 包含当前 FeatureStore 部署对应的客户端 feature_store.yaml。配置存储在 feature_store.yaml 键下,Feast 客户端可以直接加载,包括 Python 应用程序和集群内作业。

常见访问模式:

  • 在集群内使用生成的 Service 名称
  • 使用生成的 client ConfigMap 作为 Feast 客户端配置
  • 通过目标环境中使用的访问方式暴露这些 Service

如果需要访问 offline server 或 registry server,则应在 CR 中设置 offlineStore.server: {}registry.local.server: {}

使用 Feast SDK 和 CLI

特征定义通常维护在 FeatureStore 工作负载之外,例如本地仓库、Git 仓库、CI 作业或其他基于 SDK 的工作流中。生成的客户端 feature_store.yaml 用于将 Feast CLI 或 Python SDK 连接到已部署的服务。

当从客户端环境运行 feast apply 时,registry service 必须可被 Feast 客户端访问。对于本页使用的本地 registry 模式,请设置:

services:
  registry:
    local:
      server: {}

如果还需要远程 materialization 或远程 historical retrieval,也请暴露 offline server:

services:
  offlineStore:
    server: {}

仓库布局

在 Feast 客户端环境中准备一个特征仓库,并将生成的客户端配置作为 feature_store.yaml 放入该仓库。配置可以从 .status.clientConfigMap 中指定的 ConfigMap 读取。

示例仓库布局:

<feature-repo>/
  feature_store.yaml
  driver_repo.py
  data/

仓库根目录是包含 feature_store.yaml 的目录。

Feast CLI 和 Python SDK 都使用同一个仓库根目录。对于 Python 代码,可通过以下方式加载:

from feast import FeatureStore

store = FeatureStore(repo_path=".")

特征定义示例

下面的示例定义了一个 entity、一个基于文件的 batch source、两个 feature view、一个 push source 和一个 feature service。这些对象足以在单个仓库中演示注册、在线服务、materialization 和基于 push 的更新。

driver_stats_sourcedata/driver_stats.parquet 读取批量数据。driver_hourly_stats 暴露这些字段,用于常规的 batch-to-online materialization。driver_stats_push_sourcedriver_hourly_stats_fresh 展示同一 entity 如何通过 push 接收新鲜值。driver_activity_v1 将该 feature view 组合为可复用的服务定义。

示例特征定义文件:

from datetime import timedelta

from feast import Entity, FeatureService, FeatureView, Field, FileSource, PushSource
from feast.data_format import ParquetFormat
from feast.types import Float32, Int64
from feast.value_type import ValueType

driver = Entity(name="driver", join_keys=["driver_id"], value_type=ValueType.INT64)

driver_stats_source = FileSource(
    name="driver_stats_source",
    path="data/driver_stats.parquet",
    file_format=ParquetFormat(),
    timestamp_field="event_timestamp",
    created_timestamp_column="created",
)

driver_hourly_stats = FeatureView(
    name="driver_hourly_stats",
    entities=[driver],
    ttl=timedelta(days=365),
    schema=[
        Field(name="conv_rate", dtype=Float32),
        Field(name="acc_rate", dtype=Float32),
        Field(name="avg_daily_trips", dtype=Int64),
    ],
    online=True,
    source=driver_stats_source,
)

driver_stats_push_source = PushSource(
    name="driver_stats_push_source",
    batch_source=driver_stats_source,
)

driver_hourly_stats_fresh = FeatureView(
    name="driver_hourly_stats_fresh",
    entities=[driver],
    ttl=timedelta(days=365),
    schema=[
        Field(name="conv_rate", dtype=Float32),
        Field(name="acc_rate", dtype=Float32),
        Field(name="avg_daily_trips", dtype=Int64),
    ],
    online=True,
    source=driver_stats_push_source,
)

driver_activity_v1 = FeatureService(
    name="driver_activity_v1",
    features=[driver_hourly_stats],
)

CLI

从特征仓库的根目录运行 feast apply。在上面的示例中,该命令是在 <feature-repo> 中运行的,而不是在 data/ 子目录中运行。

feast apply 会从仓库根目录读取 feature_store.yaml,并递归扫描该仓库中的 Python 文件。如果特征定义存储在子目录中,只要这些文件位于仓库内且未被 .feastignore 排除,命令仍然应从仓库根目录运行。

如果从其他工作目录运行该命令,请显式指定仓库:

feast --chdir /path/to/<feature-repo> apply

默认形式为:

feast apply

配置授权

Feast 中基于 Kubernetes 的授权由三部分组成:

  1. FeatureStore CR 中声明角色名称。
  2. 使用相同的角色名称在特征仓库中定义 Feast Permission 对象。
  3. 通过 RoleBinding 将 Kubernetes 用户或 ServiceAccount 绑定到这些角色。

仅在 FeatureStore CR 中声明 feast-readerfeast-writer 并将主体绑定到这些角色,还不足以完成授权。Feast 的授权决策还需要特征仓库中匹配的 Permission 定义。

FeatureStore 片段示例:

spec:
  authz:
    kubernetes:
      roles:
        - feast-reader
        - feast-writer

特征仓库中的 Permission 定义示例:

from feast import Entity, FeatureService, FeatureView
from feast.permissions.action import ALL_ACTIONS, READ
from feast.permissions.permission import Permission
from feast.permissions.policy import RoleBasedPolicy

reader_perm = Permission(
    name="reader_perm",
    types=[Entity, FeatureView, FeatureService],
    policy=RoleBasedPolicy(roles=["feast-reader"]),
    actions=READ,
)

writer_perm = Permission(
    name="writer_perm",
    types=[Entity, FeatureView, FeatureService],
    policy=RoleBasedPolicy(roles=["feast-writer"]),
    actions=ALL_ACTIONS,
)

添加或更新 Permission 对象后,请运行 feast apply,以便将授权元数据注册到 Feast 中。

RoleBinding 配置示例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: feast-reader-sa
  namespace: <namespace>
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: feast-writer-sa
  namespace: <namespace>
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: feast-reader-binding
  namespace: <namespace>
subjects:
  - kind: ServiceAccount
    name: feast-reader-sa
    namespace: <namespace>
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: feast-reader
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: feast-writer-binding
  namespace: <namespace>
subjects:
  - kind: ServiceAccount
    name: feast-writer-sa
    namespace: <namespace>
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: feast-writer

创建示例 ServiceAccount token:

READER_TOKEN=$(kubectl create token feast-reader-sa -n <namespace>)
WRITER_TOKEN=$(kubectl create token feast-writer-sa -n <namespace>)

如果需要自定义 token 生命周期,请在命令中添加 --duration

SDK token 配置

启用 authz.kubernetes 后,Feast Python 客户端会自动将 token 作为 bearer token 发送。对于运行在同一集群内且挂载了 ServiceAccount token 的客户端,通常不需要额外的 SDK 设置。

对于外部客户端,可通过以下方式之一提供 token:

  • feature_store.yaml 中设置 authz_config.user_token
  • 设置 LOCAL_K8S_TOKEN 环境变量

feature_store.yaml 片段示例:

authz_config:
  type: kubernetes
  user_token: <kubernetes-token>

环境变量示例:

export LOCAL_K8S_TOKEN=<kubernetes-token>

延伸阅读

有关端到端 Feast 工作流和更广泛的产品用法,请继续阅读 Feast 官方文档: