快速开始

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

前提条件

  • 已安装 Feast Operator。请参阅 Install 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 中最常用的字段如下:

Field作用常见用法
spec.feastProjectFeast 项目名称必需。用于组织 feature 定义和元数据。
spec.feastProjectDirfeature repository 的创建方式使用默认的 feast init、init template 或 Git repository。
spec.services.offlineStoreoffline store 配置历史数据存储以及可选的远程 offline server。
spec.services.onlineStoreonline store 配置低延迟的 online feature 读取。
spec.services.registryRegistry 配置用于 entity、feature view、feature service 和权限的元数据存储。
spec.services.uiUI service启用 Feast UI。
spec.authz授权配置通常基于 Kubernetes 的角色或基于 OIDC 的访问控制。
spec.replicasPod 副本数简单部署时保持为 1。对于多个副本,请使用持久化存储支持的持久化方案。

通用 Service 配置

Offline Store

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

常见选项:

  • persistence.file:基于文件的存储,通常是 PVC 上的 DuckDB,适合本地开发和评估
  • persistence.store:外部 offline backend,例如 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: {}

Online Store

onlineStore 用于低延迟 feature 服务。

常见选项:

  • persistence.file:基于文件的本地存储,通常仅用于开发
  • persistence.store:Redis、PostgreSQL 或其他受支持的 Feast online store backend
  • 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.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 backend 的场景,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 的 key 名称与配置的 type 匹配
  • 对于 type: redis,operator 读取 redis key
  • 对于 type: postgres,operator 读取 postgres key
  • 对于 type: sql,operator 读取 sql key
  • 如有需要,可以使用 secretKeyName 覆盖该 key

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

Feature Repository 初始化

operator 可以通过三种常见方式初始化 feature repository。

默认初始化

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

<offline mount path>/<feastProject>/feature_repo

Init Template

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

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

Git Repository

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

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

如果 feature repository 不位于默认的 feature_repo 子目录中,请设置 featureRepoPath

部署 FeatureStore

应用基于 PVC 的示例:

kubectl apply -f featurestore.yaml

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

可直接使用以下命令检查:

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

Services 和访问

operator 会将连接信息写入 FeatureStore 状态:

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

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

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

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

常见访问模式:

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

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

使用 Feast SDK 和 CLI

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

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

services:
  registry:
    local:
      server: {}

如果还需要远程 materialization 或远程历史数据检索,也应暴露 offline server:

services:
  offlineStore:
    server: {}

Repository 布局

在 Feast 客户端环境中准备一个 feature repository,并将生成的客户端配置作为 feature_store.yaml 放入该 repository。该配置可以从 .status.clientConfigMap 中命名的 ConfigMap 读取。

示例 repository 布局:

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

repository 根目录是包含 feature_store.yaml 的目录。

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

from feast import FeatureStore

store = FeatureStore(repo_path=".")

示例 Feature 定义

以下示例定义了一个 entity、一个基于文件的 batch source、两个 feature view、一个 push source 和一个 feature service。组合起来,这些对象足以在单个 repository 中演示注册、online serving、materialization 和基于 push 的更新。

driver_stats_sourcedata/driver_stats.parquet 读取 batch data。driver_hourly_stats 暴露这些字段,用于常规的 batch-to-online materialization。driver_stats_push_sourcedriver_hourly_stats_fresh 展示同一个 entity 也可以通过 push 接收新鲜值。driver_activity_v1 将该 feature view 组织成一个可复用的 serving 定义。

示例 feature definition 文件:

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

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

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

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

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

默认形式如下:

feast apply

配置授权

Feast 中基于 Kubernetes 的授权分为三部分:

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

仅在 FeatureStore CR 中声明 feast-readerfeast-writer 并将 subject 绑定到这些角色是不够的。Feast 的授权决策还需要在 feature repository 中存在匹配的 Permission 定义。

FeatureStore 片段示例:

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

feature repository 中的 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 文档: