From dd6eea336f611cac07e7e9a3a19b0ab2a0b4a2f1 Mon Sep 17 00:00:00 2001 From: ntkathole Date: Fri, 27 Feb 2026 16:55:05 +0530 Subject: [PATCH 1/2] feat: Feature Server High-Availability on Kubernetes Signed-off-by: ntkathole --- .secrets.baseline | 10 +- docs/how-to-guides/feast-on-kubernetes.md | 6 +- docs/how-to-guides/scaling-feast.md | 70 +- .../api/v1/featurestore_types.go | 30 + .../api/v1/zz_generated.deepcopy.go | 43 + .../crd/bases/feast.dev_featurestores.yaml | 5118 +++++++++----- infra/feast-operator/config/rbac/role.yaml | 12 + .../samples/v1_featurestore_scaling_hpa.yaml | 4 +- .../v1_featurestore_scaling_static.yaml | 18 +- infra/feast-operator/dist/install.yaml | 5992 +++++++++++------ infra/feast-operator/docs/api/markdown/ref.md | 27 + .../controller/featurestore_controller.go | 3 + .../internal/controller/services/scaling.go | 65 + .../controller/services/scaling_test.go | 287 + .../internal/controller/services/services.go | 53 + .../docs/blog/scaling-feast-feature-server.md | 77 +- 16 files changed, 7976 insertions(+), 3839 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 4b60a70c46f..f660c578f0d 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -934,7 +934,7 @@ "filename": "infra/feast-operator/api/v1/featurestore_types.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 695 + "line_number": 726 } ], "infra/feast-operator/api/v1/zz_generated.deepcopy.go": [ @@ -943,21 +943,21 @@ "filename": "infra/feast-operator/api/v1/zz_generated.deepcopy.go", "hashed_secret": "f914fc9324de1bec1ad13dec94a8ea2ddb41fc87", "is_verified": false, - "line_number": 663 + "line_number": 681 }, { "type": "Secret Keyword", "filename": "infra/feast-operator/api/v1/zz_generated.deepcopy.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 1206 + "line_number": 1249 }, { "type": "Secret Keyword", "filename": "infra/feast-operator/api/v1/zz_generated.deepcopy.go", "hashed_secret": "c2028031c154bbe86fd69bef740855c74b927dcf", "is_verified": false, - "line_number": 1211 + "line_number": 1254 } ], "infra/feast-operator/api/v1alpha1/featurestore_types.go": [ @@ -1156,7 +1156,7 @@ "filename": "infra/feast-operator/internal/controller/services/services.go", "hashed_secret": "36dc326eb15c7bdd8d91a6b87905bcea20b637d1", "is_verified": false, - "line_number": 173 + "line_number": 176 } ], "infra/feast-operator/internal/controller/services/tls_test.go": [ diff --git a/docs/how-to-guides/feast-on-kubernetes.md b/docs/how-to-guides/feast-on-kubernetes.md index e87e3efa8b2..1a4cb3b280f 100644 --- a/docs/how-to-guides/feast-on-kubernetes.md +++ b/docs/how-to-guides/feast-on-kubernetes.md @@ -65,9 +65,11 @@ spec: > _More advanced FeatureStore CR examples can be found in the feast-operator [samples directory](../../infra/feast-operator/config/samples)._ {% hint style="success" %} -**Scaling:** The Feast Operator supports horizontal scaling via static replicas, HPA autoscaling, or external autoscalers like [KEDA](https://keda.sh). Scaling requires DB-backed persistence for all enabled services. +**Scaling & High Availability:** The Feast Operator supports horizontal scaling via static replicas, HPA autoscaling, or external autoscalers like [KEDA](https://keda.sh). Scaling requires DB-backed persistence for all enabled services. -See the [Horizontal Scaling with the Feast Operator](./scaling-feast.md#horizontal-scaling-with-the-feast-operator) guide for configuration details, or check the general recommendations on [how to scale Feast](./scaling-feast.md). +When scaling is enabled, the operator auto-injects soft pod anti-affinity and zone topology spread constraints for resilience. You can also configure a PodDisruptionBudget to protect against voluntary disruptions. + +See the [Horizontal Scaling with the Feast Operator](./scaling-feast.md#horizontal-scaling-with-the-feast-operator) guide for configuration details, including [HA options](./scaling-feast.md#high-availability), or check the general recommendations on [how to scale Feast](./scaling-feast.md). {% endhint %} > _Sample scaling CRs are available at [`v1_featurestore_scaling_static.yaml`](../../infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml) and [`v1_featurestore_scaling_hpa.yaml`](../../infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml)._ diff --git a/docs/how-to-guides/scaling-feast.md b/docs/how-to-guides/scaling-feast.md index 23c13bfe5ad..8f6485785d3 100644 --- a/docs/how-to-guides/scaling-feast.md +++ b/docs/how-to-guides/scaling-feast.md @@ -86,6 +86,8 @@ spec: target: type: Utilization averageUtilization: 70 + pdb: + maxUnavailable: 1 onlineStore: persistence: store: @@ -107,7 +109,7 @@ spec: ``` {% hint style="info" %} -When autoscaling is configured, the operator automatically sets the deployment strategy to `RollingUpdate` (instead of the default `Recreate`) to ensure zero-downtime scaling. You can override this by explicitly setting `deploymentStrategy` in the CR. +When autoscaling is configured, the operator automatically sets the deployment strategy to `RollingUpdate` (instead of the default `Recreate`) to ensure zero-downtime scaling, and auto-injects soft pod anti-affinity and zone topology spread constraints. You can override any of these by explicitly setting `deploymentStrategy`, `affinity`, or `topologySpreadConstraints` in the CR. {% endhint %} #### Validation Rules @@ -117,6 +119,72 @@ The operator enforces the following rules: - Scaling with `replicas > 1` or any `autoscaling` config is **rejected** if any enabled service uses file-based persistence. - S3 (`s3://`) and GCS (`gs://`) backed registry file persistence is allowed with scaling, since these object stores support concurrent readers. +#### High Availability + +When scaling is enabled (`replicas > 1` or `autoscaling`), the operator provides HA features to improve resilience: + +**Pod Anti-Affinity** — The operator automatically injects a soft (`preferredDuringSchedulingIgnoredDuringExecution`) pod anti-affinity rule that prefers spreading pods across different nodes. This prevents multiple replicas from being co-located on the same node, improving resilience to node failures. You can override this by providing your own `affinity` configuration: + +```yaml +spec: + replicas: 3 + services: + # Override with custom affinity (e.g. strict anti-affinity) + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + feast.dev/name: my-feast + # ... +``` + +**Topology Spread Constraints** — The operator automatically injects a soft zone-spread constraint (`whenUnsatisfiable: ScheduleAnyway`) that distributes pods across availability zones. This is a best-effort spread — if zones are unavailable, pods will still be scheduled. You can override this with explicit constraints or disable it with an empty array: + +```yaml +spec: + replicas: 3 + services: + # Override with custom topology spread (e.g. strict zone spreading) + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + feast.dev/name: my-feast + # ... +``` + +To disable the auto-injected topology spread: + +```yaml +spec: + replicas: 3 + services: + topologySpreadConstraints: [] + # ... +``` + +**PodDisruptionBudget** — You can configure a PDB to limit voluntary disruptions (e.g. during node drains or cluster upgrades). The PDB is only created when scaling is enabled. Exactly one of `minAvailable` or `maxUnavailable` must be set: + +```yaml +spec: + replicas: 3 + services: + pdb: + maxUnavailable: 1 # at most 1 pod unavailable during disruptions + # -- OR -- + # pdb: + # minAvailable: "50%" # at least 50% of pods must remain available + # ... +``` + +{% hint style="info" %} +The PDB is not auto-injected — you must explicitly configure it. This is intentional because a misconfigured PDB (e.g. `minAvailable` equal to the replica count) can block node drains and cluster upgrades. +{% endhint %} + #### Using KEDA (Kubernetes Event-Driven Autoscaling) [KEDA](https://keda.sh) is also supported as an external autoscaler. KEDA should target the FeatureStore's scale sub-resource directly (since it implements the Kubernetes scale API). This is the recommended approach because the operator manages the Deployment's replica count from `spec.replicas` — targeting the Deployment directly would conflict with the operator's reconciliation. diff --git a/infra/feast-operator/api/v1/featurestore_types.go b/infra/feast-operator/api/v1/featurestore_types.go index d0b67427ccb..38e980cd10d 100644 --- a/infra/feast-operator/api/v1/featurestore_types.go +++ b/infra/feast-operator/api/v1/featurestore_types.go @@ -22,6 +22,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) const ( @@ -314,6 +315,21 @@ type FeatureStoreServices struct { // Scaling configures horizontal scaling for the FeatureStore deployment (e.g. HPA autoscaling). // For static replicas, use spec.replicas instead. Scaling *ScalingConfig `json:"scaling,omitempty"` + // PDB configures a PodDisruptionBudget for the FeatureStore deployment. + // Only created when scaling is enabled (replicas > 1 or autoscaling). + // +optional + PDB *PDBConfig `json:"pdb,omitempty"` + // TopologySpreadConstraints defines how pods are spread across topology domains. + // When scaling is enabled and this is not set, the operator auto-injects a soft + // zone-spread constraint (whenUnsatisfiable: ScheduleAnyway). + // Set to an empty array to disable auto-injection. + // +optional + TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` + // Affinity defines the pod scheduling constraints for the FeatureStore deployment. + // When scaling is enabled and this is not set, the operator auto-injects a soft + // pod anti-affinity rule to prefer spreading pods across nodes. + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty"` } // ScalingConfig configures horizontal scaling for the FeatureStore deployment. @@ -342,6 +358,20 @@ type AutoscalingConfig struct { Behavior *autoscalingv2.HorizontalPodAutoscalerBehavior `json:"behavior,omitempty"` } +// PDBConfig configures a PodDisruptionBudget for the FeatureStore deployment. +// Exactly one of minAvailable or maxUnavailable must be set. +// +kubebuilder:validation:XValidation:rule="[has(self.minAvailable), has(self.maxUnavailable)].exists_one(c, c)",message="Exactly one of minAvailable or maxUnavailable must be set." +type PDBConfig struct { + // MinAvailable specifies the minimum number/percentage of pods that must remain available. + // Mutually exclusive with maxUnavailable. + // +optional + MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty"` + // MaxUnavailable specifies the maximum number/percentage of pods that can be unavailable. + // Mutually exclusive with minAvailable. + // +optional + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` +} + // OfflineStore configures the offline store service type OfflineStore struct { // Creates a remote offline server container diff --git a/infra/feast-operator/api/v1/zz_generated.deepcopy.go b/infra/feast-operator/api/v1/zz_generated.deepcopy.go index 6b12020435b..6d0a4d02e70 100644 --- a/infra/feast-operator/api/v1/zz_generated.deepcopy.go +++ b/infra/feast-operator/api/v1/zz_generated.deepcopy.go @@ -27,6 +27,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -380,6 +381,23 @@ func (in *FeatureStoreServices) DeepCopyInto(out *FeatureStoreServices) { *out = new(ScalingConfig) (*in).DeepCopyInto(*out) } + if in.PDB != nil { + in, out := &in.PDB, &out.PDB + *out = new(PDBConfig) + (*in).DeepCopyInto(*out) + } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(corev1.Affinity) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureStoreServices. @@ -878,6 +896,31 @@ func (in *OptionalCtrConfigs) DeepCopy() *OptionalCtrConfigs { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PDBConfig) DeepCopyInto(out *PDBConfig) { + *out = *in + if in.MinAvailable != nil { + in, out := &in.MinAvailable, &out.MinAvailable + *out = new(intstr.IntOrString) + **out = **in + } + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PDBConfig. +func (in *PDBConfig) DeepCopy() *PDBConfig { + if in == nil { + return nil + } + out := new(PDBConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PvcConfig) DeepCopyInto(out *PvcConfig) { *out = *in diff --git a/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml b/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml index ae91726b42b..dc8496ee99d 100644 --- a/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml +++ b/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml @@ -723,549 +723,794 @@ spec: description: FeatureStoreServices defines the desired feast services. An ephemeral onlineStore feature server is deployed by default. properties: - deploymentStrategy: - description: DeploymentStrategy describes how to replace existing - pods with new ones. + affinity: + description: Affinity defines the pod scheduling constraints for + the FeatureStore deployment. properties: - rollingUpdate: - description: |- - Rolling update config params. Present only if DeploymentStrategyType = - RollingUpdate. + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. properties: - maxSurge: - anyOf: - - type: integer - - type: string + preferredDuringSchedulingIgnoredDuringExecution: description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: The maximum number of pods that can be unavailable - during the update. - x-kubernetes-int-or-string: true - type: object - type: - description: Type of deployment. Can be "Recreate" or "RollingUpdate". - Default is RollingUpdate. - type: string - type: object - disableInitContainers: - description: Disable the 'feast repo initialization' initContainer - type: boolean - offlineStore: - description: OfflineStore configures the offline store service - properties: - persistence: - description: OfflineStorePersistence configures the persistence - settings for the offline store service - properties: - file: - description: OfflineStoreFilePersistence configures the - file-based persistence for the offline store service - properties: - pvc: - description: PvcConfig defines the settings for a - persistent file store based on PVCs. - properties: - create: - description: Settings for creating a new PVC - properties: - accessModes: - description: AccessModes k8s persistent volume - access modes. Defaults to ["ReadWriteOnce"]. - items: - type: string - type: array - resources: - description: Resources describes the storage - resource requirements for a volume. + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). + properties: + preference: + description: A node selector term, associated with + the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true + key: + description: The label key that the selector + applies to. + type: string + operator: description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum - amount of compute resources required. - type: object + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator type: object - storageClassName: - description: StorageClassName is the name - of an existing StorageClass to which this - persistent volume belongs. - type: string - type: object - x-kubernetes-validations: - - message: PvcCreate is immutable - rule: self == oldSelf - mountPath: - description: |- - MountPath within the container at which the volume should be mounted. - Must start by "/" and cannot contain ':'. - type: string - ref: - description: Reference to an existing field - properties: - name: - default: "" + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - required: - - mountPath - type: object - x-kubernetes-validations: - - message: One selection is required between ref and - create. - rule: '[has(self.ref), has(self.create)].exists_one(c, - c)' - - message: Mount path must start with '/' and must - not contain ':' - rule: self.mountPath.matches('^/[^:]*$') - type: - enum: - - file - - dask - - duckdb - type: string - type: object - store: - description: OfflineStoreDBStorePersistence configures - the DB store persistence for the offline store service + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified by + this field are not met at\nscheduling time, the pod + will not be scheduled onto " properties: - secretKeyName: - description: By default, the selected store "type" - is used as the SecretKeyName - type: string - secretRef: - description: Data store parameters should be placed - as-is from the "feature_store.yaml" under the secret - key. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: - description: Type of the persistence type you want - to use. - enum: - - snowflake.offline - - bigquery - - redshift - - spark - - postgres - - trino - - athena - - mssql - - couchbase.offline - - clickhouse - - ray - type: string + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic required: - - secretRef - - type + - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object - x-kubernetes-validations: - - message: One selection required between file or store. - rule: '[has(self.file), has(self.store)].exists_one(c, c)' - server: - description: Creates a remote offline server container + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). properties: - env: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i items: - description: EnvVar represents an environment variable - present in a Container. + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: + labelSelector: description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - name + - podAffinityTerm + - weight type: object type: array - envFrom: + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified by + this field are not met at\nscheduling time, the pod + will not be scheduled onto " items: - description: EnvFromSource represents the source of - a set of ConfigMaps + description: "Defines a set of pods (namely those matching + the labelSelector\nrelative to the given namespace(s)) + that this pod should " properties: - configMapRef: - description: The ConfigMap to select from + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey type: object type: array - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - logLevel: - description: |- - LogLevel sets the logging level for the server - Allowed values: "debug", "info", "warning", "error", "critical". - enum: - - debug - - info - - warning - - error - - critical - type: string - metrics: - description: Metrics exposes Prometheus-compatible metrics - for the Feast server when enabled. - type: boolean - nodeSelector: - additionalProperties: - type: string - type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: "The scheduler will prefer to schedule pods + to nodes that satisfy\nthe anti-affinity expressions + specified by this field, " + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. properties: - name: + labelSelector: description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string required: - - name + - topologyKey type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object - type: object - tls: - description: TlsConfigs configures server TLS for a feast - service. - properties: - disable: - description: will disable TLS for the feast service. - useful in an openshift cluster, for example, where - TLS is configured by default - type: boolean - secretKeyNames: - description: SecretKeyNames defines the secret key - names for the TLS key and cert. - properties: - tlsCrt: - description: defaults to "tls.crt" - type: string - tlsKey: - description: defaults to "tls.key" - type: string - type: object - secretRef: - description: references the local k8s secret where - the TLS key and cert reside - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: object - x-kubernetes-validations: - - message: '`secretRef` required if `disable` is false.' - rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) - : true' - volumeMounts: - description: VolumeMounts defines the list of volumes - that should be mounted into the feast container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - type: string - subPath: + weight: description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - type: string + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - mountPath - - name + - podAffinityTerm + - weight type: object type: array - workerConfigs: - description: WorkerConfigs defines the worker configuration - for the Feast server. - properties: - keepAliveTimeout: - description: |- - KeepAliveTimeout is the timeout for keep-alive connections in seconds. - Defaults to 30. - format: int32 - minimum: 1 - type: integer - maxRequests: - description: |- - MaxRequests is the maximum number of requests a worker will process before restarting. - This helps prevent memory leaks. - format: int32 - minimum: 0 - type: integer - maxRequestsJitter: - description: |- - MaxRequestsJitter is the maximum jitter to add to max-requests to prevent - thundering herd effect on worker restart. - format: int32 - minimum: 0 - type: integer - registryTTLSeconds: - description: RegistryTTLSeconds is the number of seconds - after which the registry is refreshed. - format: int32 - minimum: 0 - type: integer - workerConnections: - description: |- - WorkerConnections is the maximum number of simultaneous clients per worker process. - Defaults to 1000. - format: int32 - minimum: 1 - type: integer - workers: - description: Workers is the number of worker processes. - Use -1 to auto-calculate based on CPU cores (2 * - CPU + 1). - format: int32 - minimum: -1 - type: integer - type: object + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the anti-affinity requirements specified + by this field are not met at\nscheduling time, the pod + will not be scheduled " + items: + description: "Defines a set of pods (namely those matching + the labelSelector\nrelative to the given namespace(s)) + that this pod should " + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic type: object type: object - onlineStore: - description: OnlineStore configures the online store service + deploymentStrategy: + description: DeploymentStrategy describes how to replace existing + pods with new ones. + properties: + rollingUpdate: + description: |- + Rolling update config params. Present only if DeploymentStrategyType = + RollingUpdate. + properties: + maxSurge: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be scheduled above the desired number of + pods. + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + description: The maximum number of pods that can be unavailable + during the update. + x-kubernetes-int-or-string: true + type: object + type: + description: Type of deployment. Can be "Recreate" or "RollingUpdate". + Default is RollingUpdate. + type: string + type: object + disableInitContainers: + description: Disable the 'feast repo initialization' initContainer + type: boolean + offlineStore: + description: OfflineStore configures the offline store service properties: persistence: - description: OnlineStorePersistence configures the persistence - settings for the online store service + description: OfflineStorePersistence configures the persistence + settings for the offline store service properties: file: - description: OnlineStoreFilePersistence configures the - file-based persistence for the online store service + description: OfflineStoreFilePersistence configures the + file-based persistence for the offline store service properties: - path: - type: string pvc: description: PvcConfig defines the settings for a persistent file store based on PVCs. @@ -1342,21 +1587,16 @@ spec: - message: Mount path must start with '/' and must not contain ':' rule: self.mountPath.matches('^/[^:]*$') + type: + enum: + - file + - dask + - duckdb + type: string type: object - x-kubernetes-validations: - - message: Ephemeral stores must have absolute paths. - rule: '(!has(self.pvc) && has(self.path)) ? self.path.startsWith(''/'') - : true' - - message: PVC path must be a file name only, with no - slashes. - rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') - : true' - - message: Online store does not support S3 or GS buckets. - rule: 'has(self.path) ? !(self.path.startsWith(''s3://'') - || self.path.startsWith(''gs://'')) : true' store: - description: OnlineStoreDBStorePersistence configures - the DB store persistence for the online store service + description: OfflineStoreDBStorePersistence configures + the DB store persistence for the offline store service properties: secretKeyName: description: By default, the selected store "type" @@ -1380,22 +1620,17 @@ spec: description: Type of the persistence type you want to use. enum: - - snowflake.online - - redis - - datastore - - dynamodb - - bigtable + - snowflake.offline + - bigquery + - redshift + - spark - postgres - - cassandra - - mysql - - hazelcast - - singlestore - - hbase - - elasticsearch - - qdrant - - couchbase.online - - milvus - - hybrid + - trino + - athena + - mssql + - couchbase.offline + - clickhouse + - ray type: string required: - secretRef @@ -1406,7 +1641,7 @@ spec: - message: One selection required between file or store. rule: '[has(self.file), has(self.store)].exists_one(c, c)' server: - description: Creates a feature server container + description: Creates a remote offline server container properties: env: items: @@ -1762,151 +1997,74 @@ spec: type: object type: object type: object - registry: - description: Registry configures the registry service. One selection - is required. Local is the default setting. + onlineStore: + description: OnlineStore configures the online store service properties: - local: - description: LocalRegistryConfig configures the registry service + persistence: + description: OnlineStorePersistence configures the persistence + settings for the online store service properties: - persistence: - description: RegistryPersistence configures the persistence - settings for the registry service + file: + description: OnlineStoreFilePersistence configures the + file-based persistence for the online store service properties: - file: - description: RegistryFilePersistence configures the - file-based persistence for the registry service + path: + type: string + pvc: + description: PvcConfig defines the settings for a + persistent file store based on PVCs. properties: - cache_mode: - description: |- - CacheMode defines the registry cache update strategy. - Allowed values are "sync" and "thread". - enum: - - none - - sync - - thread - type: string - cache_ttl_seconds: - description: CacheTTLSeconds defines the TTL (in - seconds) for the registry cache. - format: int32 - minimum: 0 - type: integer - path: - type: string - pvc: - description: PvcConfig defines the settings for - a persistent file store based on PVCs. + create: + description: Settings for creating a new PVC properties: - create: - description: Settings for creating a new PVC - properties: - accessModes: - description: AccessModes k8s persistent - volume access modes. Defaults to ["ReadWriteOnce"]. - items: - type: string - type: array - resources: - description: Resources describes the storage - resource requirements for a volume. - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the - minimum amount of compute resources - required. - type: object - type: object - storageClassName: - description: StorageClassName is the name - of an existing StorageClass to which - this persistent volume belongs. - type: string - type: object - x-kubernetes-validations: - - message: PvcCreate is immutable - rule: self == oldSelf - mountPath: - description: |- - MountPath within the container at which the volume should be mounted. - Must start by "/" and cannot contain ':'. - type: string - ref: - description: Reference to an existing field + accessModes: + description: AccessModes k8s persistent volume + access modes. Defaults to ["ReadWriteOnce"]. + items: + type: string + type: array + resources: + description: Resources describes the storage + resource requirements for a volume. properties: - name: - default: "" + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum + amount of compute resources required. + type: object type: object - x-kubernetes-map-type: atomic - required: - - mountPath + storageClassName: + description: StorageClassName is the name + of an existing StorageClass to which this + persistent volume belongs. + type: string type: object x-kubernetes-validations: - - message: One selection is required between ref - and create. - rule: '[has(self.ref), has(self.create)].exists_one(c, - c)' - - message: Mount path must start with '/' and - must not contain ':' - rule: self.mountPath.matches('^/[^:]*$') - s3_additional_kwargs: - additionalProperties: - type: string - type: object - type: object - x-kubernetes-validations: - - message: Registry files must use absolute paths - or be S3 ('s3://') or GS ('gs://') object store - URIs. - rule: '(!has(self.pvc) && has(self.path)) ? (self.path.startsWith(''/'') - || self.path.startsWith(''s3://'') || self.path.startsWith(''gs://'')) - : true' - - message: PVC path must be a file name only, with - no slashes. - rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') - : true' - - message: PVC persistence does not support S3 or - GS object store URIs. - rule: '(has(self.pvc) && has(self.path)) ? !(self.path.startsWith(''s3://'') - || self.path.startsWith(''gs://'')) : true' - - message: Additional S3 settings are available only - for S3 object store URIs. - rule: '(has(self.s3_additional_kwargs) && has(self.path)) - ? self.path.startsWith(''s3://'') : true' - store: - description: RegistryDBStorePersistence configures - the DB store persistence for the registry service - properties: - secretKeyName: - description: By default, the selected store "type" - is used as the SecretKeyName + - message: PvcCreate is immutable + rule: self == oldSelf + mountPath: + description: |- + MountPath within the container at which the volume should be mounted. + Must start by "/" and cannot contain ':'. type: string - secretRef: - description: Data store parameters should be placed - as-is from the "feature_store.yaml" under the - secret key. + ref: + description: Reference to an existing field properties: name: default: "" @@ -1917,146 +2075,108 @@ spec: type: string type: object x-kubernetes-map-type: atomic - type: - description: Type of the persistence type you - want to use. - enum: - - sql - - snowflake.registry - type: string required: - - secretRef - - type + - mountPath type: object + x-kubernetes-validations: + - message: One selection is required between ref and + create. + rule: '[has(self.ref), has(self.create)].exists_one(c, + c)' + - message: Mount path must start with '/' and must + not contain ':' + rule: self.mountPath.matches('^/[^:]*$') type: object x-kubernetes-validations: - - message: One selection required between file or store. - rule: '[has(self.file), has(self.store)].exists_one(c, - c)' - server: - description: Creates a registry server container + - message: Ephemeral stores must have absolute paths. + rule: '(!has(self.pvc) && has(self.path)) ? self.path.startsWith(''/'') + : true' + - message: PVC path must be a file name only, with no + slashes. + rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') + : true' + - message: Online store does not support S3 or GS buckets. + rule: 'has(self.path) ? !(self.path.startsWith(''s3://'') + || self.path.startsWith(''gs://'')) : true' + store: + description: OnlineStoreDBStorePersistence configures + the DB store persistence for the online store service properties: - env: - items: - description: EnvVar represents an environment variable - present in a Container. + secretKeyName: + description: By default, the selected store "type" + is used as the SecretKeyName + type: string + secretRef: + description: Data store parameters should be placed + as-is from the "feature_store.yaml" under the secret + key. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: + description: Type of the persistence type you want + to use. + enum: + - snowflake.online + - redis + - datastore + - dynamodb + - bigtable + - postgres + - cassandra + - mysql + - hazelcast + - singlestore + - hbase + - elasticsearch + - qdrant + - couchbase.online + - milvus + - hybrid + type: string + required: + - secretRef + - type + type: object + type: object + x-kubernetes-validations: + - message: One selection required between file or store. + rule: '[has(self.file), has(self.store)].exists_one(c, c)' + server: + description: Creates a feature server container + properties: + env: + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: - supports metadata.name, metadata.namespace, - `metadata.labels['''']`, `metadata.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults - to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source - of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from + configMapKeyRef: + description: Selects a key of a ConfigMap. properties: + key: + description: The key to select. + type: string name: default: "" description: |- @@ -2066,17 +2186,62 @@ spec: type: string optional: description: Specify whether the ConfigMap - must be defined + or its key must be defined type: boolean + required: + - key type: object x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend - to each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string name: default: "" description: |- @@ -2086,380 +2251,983 @@ spec: type: string optional: description: Specify whether the Secret - must be defined + or its key must be defined type: boolean + required: + - key type: object x-kubernetes-map-type: atomic type: object - type: array - grpc: - description: Enable gRPC registry server. Defaults - to true if unset. - type: boolean - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - logLevel: - description: |- - LogLevel sets the logging level for the server - Allowed values: "debug", "info", "warning", "error", "critical". - enum: - - debug - - info - - warning - - error - - critical - type: string - metrics: - description: Metrics exposes Prometheus-compatible - metrics for the Feast server when enabled. - type: boolean - nodeSelector: - additionalProperties: + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. type: string - type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object - type: object - restAPI: - description: Enable REST API registry server. - type: boolean - tls: - description: TlsConfigs configures server TLS for - a feast service. - properties: - disable: - description: will disable TLS for the feast service. - useful in an openshift cluster, for example, - where TLS is configured by default - type: boolean - secretKeyNames: - description: SecretKeyNames defines the secret - key names for the TLS key and cert. - properties: - tlsCrt: - description: defaults to "tls.crt" - type: string - tlsKey: - description: defaults to "tls.key" - type: string - type: object - secretRef: - description: references the local k8s secret where - the TLS key and cert reside - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: object - x-kubernetes-validations: - - message: '`secretRef` required if `disable` is false.' - rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) - : true' - volumeMounts: - description: VolumeMounts defines the list of volumes - that should be mounted into the feast container. - items: - description: VolumeMount describes a mounting of - a Volume within a container. + secretRef: + description: The Secret to select from properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - type: string name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: + default: "" description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. type: string - subPath: + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + logLevel: + description: |- + LogLevel sets the logging level for the server + Allowed values: "debug", "info", "warning", "error", "critical". + enum: + - debug + - info + - warning + - error + - critical + type: string + metrics: + description: Metrics exposes Prometheus-compatible metrics + for the Feast server when enabled. + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume - from which the container's volume should be - mounted. + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. type: string required: - - mountPath - name type: object type: array - workerConfigs: - description: WorkerConfigs defines the worker configuration - for the Feast server. + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object + type: object + tls: + description: TlsConfigs configures server TLS for a feast + service. + properties: + disable: + description: will disable TLS for the feast service. + useful in an openshift cluster, for example, where + TLS is configured by default + type: boolean + secretKeyNames: + description: SecretKeyNames defines the secret key + names for the TLS key and cert. properties: - keepAliveTimeout: - description: |- - KeepAliveTimeout is the timeout for keep-alive connections in seconds. - Defaults to 30. - format: int32 - minimum: 1 - type: integer - maxRequests: - description: |- - MaxRequests is the maximum number of requests a worker will process before restarting. - This helps prevent memory leaks. - format: int32 - minimum: 0 - type: integer - maxRequestsJitter: - description: |- - MaxRequestsJitter is the maximum jitter to add to max-requests to prevent - thundering herd effect on worker restart. - format: int32 - minimum: 0 - type: integer - registryTTLSeconds: - description: RegistryTTLSeconds is the number - of seconds after which the registry is refreshed. - format: int32 - minimum: 0 - type: integer - workerConnections: + tlsCrt: + description: defaults to "tls.crt" + type: string + tlsKey: + description: defaults to "tls.key" + type: string + type: object + secretRef: + description: references the local k8s secret where + the TLS key and cert reside + properties: + name: + default: "" description: |- - WorkerConnections is the maximum number of simultaneous clients per worker process. - Defaults to 1000. - format: int32 - minimum: 1 - type: integer - workers: - description: Workers is the number of worker processes. - Use -1 to auto-calculate based on CPU cores - (2 * CPU + 1). - format: int32 - minimum: -1 - type: integer + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string type: object + x-kubernetes-map-type: atomic type: object x-kubernetes-validations: - - message: At least one of restAPI or grpc must be true - rule: self.restAPI == true || self.grpc == true || !has(self.grpc) - type: object - remote: - description: RemoteRegistryConfig points to a remote feast - registry server. - properties: - feastRef: - description: Reference to an existing `FeatureStore` CR - in the same k8s cluster. - properties: - name: - description: Name of the FeatureStore - type: string - namespace: - description: Namespace of the FeatureStore - type: string - required: - - name - type: object - hostname: - description: Host address of the remote registry service - - :, e.g. `registry..svc.cluster.local:80` - type: string - tls: - description: TlsRemoteRegistryConfigs configures client - TLS for a remote feast registry. + - message: '`secretRef` required if `disable` is false.' + rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) + : true' + volumeMounts: + description: VolumeMounts defines the list of volumes + that should be mounted into the feast container. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + type: string + required: + - mountPath + - name + type: object + type: array + workerConfigs: + description: WorkerConfigs defines the worker configuration + for the Feast server. properties: - certName: - description: defines the configmap key name for the - client TLS cert. - type: string - configMapRef: - description: references the local k8s configmap where - the TLS cert resides - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - required: - - certName - - configMapRef + keepAliveTimeout: + description: |- + KeepAliveTimeout is the timeout for keep-alive connections in seconds. + Defaults to 30. + format: int32 + minimum: 1 + type: integer + maxRequests: + description: |- + MaxRequests is the maximum number of requests a worker will process before restarting. + This helps prevent memory leaks. + format: int32 + minimum: 0 + type: integer + maxRequestsJitter: + description: |- + MaxRequestsJitter is the maximum jitter to add to max-requests to prevent + thundering herd effect on worker restart. + format: int32 + minimum: 0 + type: integer + registryTTLSeconds: + description: RegistryTTLSeconds is the number of seconds + after which the registry is refreshed. + format: int32 + minimum: 0 + type: integer + workerConnections: + description: |- + WorkerConnections is the maximum number of simultaneous clients per worker process. + Defaults to 1000. + format: int32 + minimum: 1 + type: integer + workers: + description: Workers is the number of worker processes. + Use -1 to auto-calculate based on CPU cores (2 * + CPU + 1). + format: int32 + minimum: -1 + type: integer type: object type: object - x-kubernetes-validations: - - message: One selection required. - rule: '[has(self.hostname), has(self.feastRef)].exists_one(c, - c)' + type: object + pdb: + description: PDB configures a PodDisruptionBudget for the FeatureStore + deployment. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable specifies the maximum number/percentage + of pods that can be unavailable. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable specifies the minimum number/percentage + of pods that must remain available. + x-kubernetes-int-or-string: true type: object x-kubernetes-validations: - - message: One selection required. - rule: '[has(self.local), has(self.remote)].exists_one(c, c)' - scaling: - description: Scaling configures horizontal scaling for the FeatureStore - deployment (e.g. HPA autoscaling). + - message: Exactly one of minAvailable or maxUnavailable must + be set. + rule: '[has(self.minAvailable), has(self.maxUnavailable)].exists_one(c, + c)' + registry: + description: Registry configures the registry service. One selection + is required. Local is the default setting. properties: - autoscaling: - description: |- - Autoscaling configures a HorizontalPodAutoscaler for the FeatureStore deployment. - Mutually exclusive with spec.replicas. + local: + description: LocalRegistryConfig configures the registry service properties: - behavior: - description: Behavior configures the scaling behavior - of the target. + persistence: + description: RegistryPersistence configures the persistence + settings for the registry service properties: - scaleDown: - description: scaleDown is scaling policy for scaling - Down. + file: + description: RegistryFilePersistence configures the + file-based persistence for the registry service properties: - policies: - description: policies is a list of potential scaling - polices which can be used during scaling. - items: - description: HPAScalingPolicy is a single policy - which must hold true for a specified past - interval. - properties: - periodSeconds: - description: periodSeconds specifies the - window of time for which the policy should - hold true. - format: int32 - type: integer - type: - description: type is used to specify the - scaling policy. - type: string - value: - description: |- - value contains the amount of change which is permitted by the policy. - It must be greater than zero - format: int32 - type: integer - required: - - periodSeconds - - type - - value - type: object - type: array - x-kubernetes-list-type: atomic - selectPolicy: + cache_mode: description: |- - selectPolicy is used to specify which policy should be used. - If not set, the default value Max is used. + CacheMode defines the registry cache update strategy. + Allowed values are "sync" and "thread". + enum: + - none + - sync + - thread type: string - stabilizationWindowSeconds: - description: |- - stabilizationWindowSeconds is the number of seconds for which past recommendations should be - considered while scaling up + cache_ttl_seconds: + description: CacheTTLSeconds defines the TTL (in + seconds) for the registry cache. format: int32 + minimum: 0 type: integer - type: object - scaleUp: - description: scaleUp is scaling policy for scaling - Up. - properties: - policies: - description: policies is a list of potential scaling - polices which can be used during scaling. - items: - description: HPAScalingPolicy is a single policy - which must hold true for a specified past - interval. - properties: - periodSeconds: - description: periodSeconds specifies the - window of time for which the policy should - hold true. - format: int32 - type: integer - type: - description: type is used to specify the - scaling policy. - type: string - value: - description: |- - value contains the amount of change which is permitted by the policy. - It must be greater than zero - format: int32 - type: integer - required: - - periodSeconds - - type - - value - type: object - type: array - x-kubernetes-list-type: atomic - selectPolicy: - description: |- - selectPolicy is used to specify which policy should be used. - If not set, the default value Max is used. + path: type: string - stabilizationWindowSeconds: + pvc: + description: PvcConfig defines the settings for + a persistent file store based on PVCs. + properties: + create: + description: Settings for creating a new PVC + properties: + accessModes: + description: AccessModes k8s persistent + volume access modes. Defaults to ["ReadWriteOnce"]. + items: + type: string + type: array + resources: + description: Resources describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the + minimum amount of compute resources + required. + type: object + type: object + storageClassName: + description: StorageClassName is the name + of an existing StorageClass to which + this persistent volume belongs. + type: string + type: object + x-kubernetes-validations: + - message: PvcCreate is immutable + rule: self == oldSelf + mountPath: + description: |- + MountPath within the container at which the volume should be mounted. + Must start by "/" and cannot contain ':'. + type: string + ref: + description: Reference to an existing field + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - mountPath + type: object + x-kubernetes-validations: + - message: One selection is required between ref + and create. + rule: '[has(self.ref), has(self.create)].exists_one(c, + c)' + - message: Mount path must start with '/' and + must not contain ':' + rule: self.mountPath.matches('^/[^:]*$') + s3_additional_kwargs: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-validations: + - message: Registry files must use absolute paths + or be S3 ('s3://') or GS ('gs://') object store + URIs. + rule: '(!has(self.pvc) && has(self.path)) ? (self.path.startsWith(''/'') + || self.path.startsWith(''s3://'') || self.path.startsWith(''gs://'')) + : true' + - message: PVC path must be a file name only, with + no slashes. + rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') + : true' + - message: PVC persistence does not support S3 or + GS object store URIs. + rule: '(has(self.pvc) && has(self.path)) ? !(self.path.startsWith(''s3://'') + || self.path.startsWith(''gs://'')) : true' + - message: Additional S3 settings are available only + for S3 object store URIs. + rule: '(has(self.s3_additional_kwargs) && has(self.path)) + ? self.path.startsWith(''s3://'') : true' + store: + description: RegistryDBStorePersistence configures + the DB store persistence for the registry service + properties: + secretKeyName: + description: By default, the selected store "type" + is used as the SecretKeyName + type: string + secretRef: + description: Data store parameters should be placed + as-is from the "feature_store.yaml" under the + secret key. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: + description: Type of the persistence type you + want to use. + enum: + - sql + - snowflake.registry + type: string + required: + - secretRef + - type + type: object + type: object + x-kubernetes-validations: + - message: One selection required between file or store. + rule: '[has(self.file), has(self.store)].exists_one(c, + c)' + server: + description: Creates a registry server container + properties: + env: + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + grpc: + description: Enable gRPC registry server. Defaults + to true if unset. + type: boolean + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + logLevel: + description: |- + LogLevel sets the logging level for the server + Allowed values: "debug", "info", "warning", "error", "critical". + enum: + - debug + - info + - warning + - error + - critical + type: string + metrics: + description: Metrics exposes Prometheus-compatible + metrics for the Feast server when enabled. + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object + type: object + restAPI: + description: Enable REST API registry server. + type: boolean + tls: + description: TlsConfigs configures server TLS for + a feast service. + properties: + disable: + description: will disable TLS for the feast service. + useful in an openshift cluster, for example, + where TLS is configured by default + type: boolean + secretKeyNames: + description: SecretKeyNames defines the secret + key names for the TLS key and cert. + properties: + tlsCrt: + description: defaults to "tls.crt" + type: string + tlsKey: + description: defaults to "tls.key" + type: string + type: object + secretRef: + description: references the local k8s secret where + the TLS key and cert reside + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: object + x-kubernetes-validations: + - message: '`secretRef` required if `disable` is false.' + rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) + : true' + volumeMounts: + description: VolumeMounts defines the list of volumes + that should be mounted into the feast container. + items: + description: VolumeMount describes a mounting of + a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should be + mounted. + type: string + required: + - mountPath + - name + type: object + type: array + workerConfigs: + description: WorkerConfigs defines the worker configuration + for the Feast server. + properties: + keepAliveTimeout: + description: |- + KeepAliveTimeout is the timeout for keep-alive connections in seconds. + Defaults to 30. + format: int32 + minimum: 1 + type: integer + maxRequests: + description: |- + MaxRequests is the maximum number of requests a worker will process before restarting. + This helps prevent memory leaks. + format: int32 + minimum: 0 + type: integer + maxRequestsJitter: + description: |- + MaxRequestsJitter is the maximum jitter to add to max-requests to prevent + thundering herd effect on worker restart. + format: int32 + minimum: 0 + type: integer + registryTTLSeconds: + description: RegistryTTLSeconds is the number + of seconds after which the registry is refreshed. + format: int32 + minimum: 0 + type: integer + workerConnections: + description: |- + WorkerConnections is the maximum number of simultaneous clients per worker process. + Defaults to 1000. + format: int32 + minimum: 1 + type: integer + workers: + description: Workers is the number of worker processes. + Use -1 to auto-calculate based on CPU cores + (2 * CPU + 1). + format: int32 + minimum: -1 + type: integer + type: object + type: object + x-kubernetes-validations: + - message: At least one of restAPI or grpc must be true + rule: self.restAPI == true || self.grpc == true || !has(self.grpc) + type: object + remote: + description: RemoteRegistryConfig points to a remote feast + registry server. + properties: + feastRef: + description: Reference to an existing `FeatureStore` CR + in the same k8s cluster. + properties: + name: + description: Name of the FeatureStore + type: string + namespace: + description: Namespace of the FeatureStore + type: string + required: + - name + type: object + hostname: + description: Host address of the remote registry service + - :, e.g. `registry..svc.cluster.local:80` + type: string + tls: + description: TlsRemoteRegistryConfigs configures client + TLS for a remote feast registry. + properties: + certName: + description: defines the configmap key name for the + client TLS cert. + type: string + configMapRef: + description: references the local k8s configmap where + the TLS cert resides + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - certName + - configMapRef + type: object + type: object + x-kubernetes-validations: + - message: One selection required. + rule: '[has(self.hostname), has(self.feastRef)].exists_one(c, + c)' + type: object + x-kubernetes-validations: + - message: One selection required. + rule: '[has(self.local), has(self.remote)].exists_one(c, c)' + scaling: + description: Scaling configures horizontal scaling for the FeatureStore + deployment (e.g. HPA autoscaling). + properties: + autoscaling: + description: |- + Autoscaling configures a HorizontalPodAutoscaler for the FeatureStore deployment. + Mutually exclusive with spec.replicas. + properties: + behavior: + description: Behavior configures the scaling behavior + of the target. + properties: + scaleDown: + description: scaleDown is scaling policy for scaling + Down. + properties: + policies: + description: policies is a list of potential scaling + polices which can be used during scaling. + items: + description: HPAScalingPolicy is a single policy + which must hold true for a specified past + interval. + properties: + periodSeconds: + description: periodSeconds specifies the + window of time for which the policy should + hold true. + format: int32 + type: integer + type: + description: type is used to specify the + scaling policy. + type: string + value: + description: |- + value contains the amount of change which is permitted by the policy. + It must be greater than zero + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + description: |- + selectPolicy is used to specify which policy should be used. + If not set, the default value Max is used. + type: string + stabilizationWindowSeconds: + description: |- + stabilizationWindowSeconds is the number of seconds for which past recommendations should be + considered while scaling up + format: int32 + type: integer + type: object + scaleUp: + description: scaleUp is scaling policy for scaling + Up. + properties: + policies: + description: policies is a list of potential scaling + polices which can be used during scaling. + items: + description: HPAScalingPolicy is a single policy + which must hold true for a specified past + interval. + properties: + periodSeconds: + description: periodSeconds specifies the + window of time for which the policy should + hold true. + format: int32 + type: integer + type: + description: type is used to specify the + scaling policy. + type: string + value: + description: |- + value contains the amount of change which is permitted by the policy. + It must be greater than zero + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + description: |- + selectPolicy is used to specify which policy should be used. + If not set, the default value Max is used. + type: string + stabilizationWindowSeconds: description: |- stabilizationWindowSeconds is the number of seconds for which past recommendations should be considered while scaling up @@ -3062,6 +3830,96 @@ spec: type: string type: object type: object + topologySpreadConstraints: + description: TopologySpreadConstraints defines how pods are spread + across topology domains. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: MaxSkew describes the degree to which pods + may be unevenly distributed. + format: int32 + type: integer + minDomains: + description: MinDomains indicates a minimum number of eligible + domains. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. + type: string + topologyKey: + description: TopologyKey is the key of node labels. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array ui: description: Creates a UI server container properties: @@ -4888,79 +5746,474 @@ spec: items: type: string type: array - type: object - oidc: - description: |- - OidcAuthz defines the authorization settings for deployments using an Open ID Connect identity provider. - https://auth0. - properties: - secretRef: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. + type: object + oidc: + description: |- + OidcAuthz defines the authorization settings for deployments using an Open ID Connect identity provider. + https://auth0. + properties: + secretRef: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - secretRef + type: object + type: object + x-kubernetes-validations: + - message: One selection required between kubernetes or oidc. + rule: '[has(self.kubernetes), has(self.oidc)].exists_one(c, + c)' + batchEngine: + description: BatchEngineConfig defines the batch compute engine + configuration. + properties: + configMapKey: + description: Key name in the ConfigMap. Defaults to "config" + if not specified. + type: string + configMapRef: + description: Reference to a ConfigMap containing the batch + engine configuration. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: object + cronJob: + description: FeastCronJob defines a CronJob to execute against + a Feature Store deployment. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the CronJob metadata. + type: object + concurrencyPolicy: + description: Specifies how to treat concurrent executions + of a Job. + type: string + containerConfigs: + description: CronJobContainerConfigs k8s container settings + for the CronJob + properties: + commands: + description: Array of commands to be executed (in order) + against a Feature Store deployment. + items: + type: string + type: array + env: + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. properties: - name: - default: "" + claims: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object type: object - x-kubernetes-map-type: atomic - required: - - secretRef type: object - type: object - x-kubernetes-validations: - - message: One selection required between kubernetes or oidc. - rule: '[has(self.kubernetes), has(self.oidc)].exists_one(c, - c)' - batchEngine: - description: BatchEngineConfig defines the batch compute engine - configuration. - properties: - configMapKey: - description: Key name in the ConfigMap. Defaults to "config" - if not specified. - type: string - configMapRef: - description: Reference to a ConfigMap containing the batch - engine configuration. + failedJobsHistoryLimit: + description: The number of failed finished jobs to retain. + Value must be non-negative integer. + format: int32 + type: integer + jobSpec: + description: Specification of the desired behavior of a job. properties: - name: - default: "" + activeDeadlineSeconds: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. + Specifies the duration in seconds relative to the startTime that the job + may be continuously active before the system tr + format: int64 + type: integer + backoffLimit: + description: Specifies the number of retries before marking + this job failed. + format: int32 + type: integer + backoffLimitPerIndex: + description: |- + Specifies the limit for the number of retries within an + index before marking this index as failed. + format: int32 + type: integer + completionMode: + description: |- + completionMode specifies how Pod completions are tracked. It can be + `NonIndexed` (default) or `Indexed`. + type: string + completions: + description: |- + Specifies the desired number of successfully finished pods the + job should be run with. + format: int32 + type: integer + maxFailedIndexes: + description: |- + Specifies the maximal number of failed indexes before marking the Job as + failed, when backoffLimitPerIndex is set. + format: int32 + type: integer + parallelism: + description: |- + Specifies the maximum desired number of pods the job should + run at any given time. + format: int32 + type: integer + podFailurePolicy: + description: Specifies the policy of handling failed pods. + properties: + rules: + description: A list of pod failure policy rules. The + rules are evaluated in order. + items: + description: PodFailurePolicyRule describes how + a pod failure is handled when the requirements + are met. + properties: + action: + description: Specifies the action taken on a + pod failure when the requirements are satisfied. + type: string + onExitCodes: + description: Represents the requirement on the + container exit codes. + properties: + containerName: + description: |- + Restricts the check for exit codes to the container with the + specified name. + type: string + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. + type: string + values: + description: Specifies the set of values. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + description: |- + Represents the requirement on the pod conditions. The requirement is represented + as a list of pod condition patterns. + items: + description: |- + PodFailurePolicyOnPodConditionsPattern describes a pattern for matching + an actual pod condition type. + properties: + status: + description: Specifies the required Pod + condition status. + type: string + type: + description: Specifies the required Pod + condition type. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object + podReplacementPolicy: + description: podReplacementPolicy specifies when to create + replacement Pods. type: string + podTemplateAnnotations: + additionalProperties: + type: string + description: |- + PodTemplateAnnotations are annotations to be applied to the CronJob's PodTemplate + metadata. + type: object + suspend: + description: suspend specifies whether the Job controller + should create Pods or not. + type: boolean + ttlSecondsAfterFinished: + description: |- + ttlSecondsAfterFinished limits the lifetime of a Job that has finished + execution (either Complete or Failed). + format: int32 + type: integer type: object - x-kubernetes-map-type: atomic + schedule: + description: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + type: string + startingDeadlineSeconds: + description: |- + Optional deadline in seconds for starting the job if it misses scheduled + time for any reason. + format: int64 + type: integer + successfulJobsHistoryLimit: + description: The number of successful finished jobs to retain. + Value must be non-negative integer. + format: int32 + type: integer + suspend: + description: |- + This flag tells the controller to suspend subsequent executions, it does + not apply to already started executions. + type: boolean + timeZone: + description: The time zone name for the given schedule, see + https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. + type: string type: object - cronJob: - description: FeastCronJob defines a CronJob to execute against - a Feature Store deployment. + feastProject: + description: FeastProject is the Feast project id. + pattern: ^[A-Za-z0-9][A-Za-z0-9_-]*$ + type: string + feastProjectDir: + description: FeastProjectDir defines how to create the feast project + directory. properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to the CronJob metadata. - type: object - concurrencyPolicy: - description: Specifies how to treat concurrent executions - of a Job. - type: string - containerConfigs: - description: CronJobContainerConfigs k8s container settings - for the CronJob + git: + description: GitCloneOptions describes how a clone should + be performed. properties: - commands: - description: Array of commands to be executed (in order) - against a Feature Store deployment. - items: + configs: + additionalProperties: type: string - type: array + description: |- + Configs passed to git via `-c` + e.g. http.sslVerify: 'false' + OR 'url."https://api:\${TOKEN}@github.com/". + type: object env: items: description: EnvVar represents an environment variable @@ -5018,552 +6271,909 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic - resourceFieldRef: + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + featureRepoPath: + description: FeatureRepoPath is the relative path to the + feature repo subdirectory. Default is 'feature_repo'. + type: string + ref: + description: Reference to a branch / tag / commit + type: string + url: + description: The repository URL to clone from. + type: string + required: + - url + type: object + x-kubernetes-validations: + - message: RepoPath must be a file name only, with no slashes. + rule: 'has(self.featureRepoPath) ? !self.featureRepoPath.startsWith(''/'') + : true' + init: + description: FeastInitOptions defines how to run a `feast + init`. + properties: + minimal: + type: boolean + template: + description: Template for the created project + enum: + - local + - gcp + - aws + - snowflake + - spark + - postgres + - hbase + - cassandra + - hazelcast + - couchbase + - clickhouse + type: string + type: object + type: object + x-kubernetes-validations: + - message: One selection required between init or git. + rule: '[has(self.git), has(self.init)].exists_one(c, c)' + replicas: + default: 1 + description: |- + Replicas is the desired number of pod replicas. Used by the scale sub-resource. + Mutually exclusive with services. + format: int32 + minimum: 1 + type: integer + services: + description: FeatureStoreServices defines the desired feast services. + An ephemeral onlineStore feature server is deployed by default. + properties: + affinity: + description: Affinity defines the pod scheduling constraints + for the FeatureStore deployment. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled onto " + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. + A null or empty node selector term matches no objects. The requirements of + them are ANDed. properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic type: object x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" + labelSelector: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean required: - - key + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled onto " + items: + description: "Defines a set of pods (namely those + matching the labelSelector\nrelative to the given + namespace(s)) that this pod should " + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" + matchLabelKeys: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - nodeSelector: - additionalProperties: - type: string - type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string required: - - name + - topologyKey type: object type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object + x-kubernetes-list-type: atomic type: object - type: object - failedJobsHistoryLimit: - description: The number of failed finished jobs to retain. - Value must be non-negative integer. - format: int32 - type: integer - jobSpec: - description: Specification of the desired behavior of a job. - properties: - activeDeadlineSeconds: - description: |- - Specifies the duration in seconds relative to the startTime that the job - may be continuously active before the system tr - format: int64 - type: integer - backoffLimit: - description: Specifies the number of retries before marking - this job failed. - format: int32 - type: integer - backoffLimitPerIndex: - description: |- - Specifies the limit for the number of retries within an - index before marking this index as failed. - format: int32 - type: integer - completionMode: - description: |- - completionMode specifies how Pod completions are tracked. It can be - `NonIndexed` (default) or `Indexed`. - type: string - completions: - description: |- - Specifies the desired number of successfully finished pods the - job should be run with. - format: int32 - type: integer - maxFailedIndexes: - description: |- - Specifies the maximal number of failed indexes before marking the Job as - failed, when backoffLimitPerIndex is set. - format: int32 - type: integer - parallelism: - description: |- - Specifies the maximum desired number of pods the job should - run at any given time. - format: int32 - type: integer - podFailurePolicy: - description: Specifies the policy of handling failed pods. + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. properties: - rules: - description: A list of pod failure policy rules. The - rules are evaluated in order. + preferredDuringSchedulingIgnoredDuringExecution: + description: "The scheduler will prefer to schedule + pods to nodes that satisfy\nthe anti-affinity expressions + specified by this field, " items: - description: PodFailurePolicyRule describes how - a pod failure is handled when the requirements - are met. + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) properties: - action: - description: Specifies the action taken on a - pod failure when the requirements are satisfied. - type: string - onExitCodes: - description: Represents the requirement on the - container exit codes. + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. properties: - containerName: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: description: |- - Restricts the check for exit codes to the container with the - specified name. - type: string - operator: + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: description: |- - Represents the relationship between the container exit code(s) and the - specified values. - type: string - values: - description: Specifies the set of values. + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. items: - format: int32 - type: integer + type: string type: array - x-kubernetes-list-type: set + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string required: - - operator - - values + - topologyKey type: object - onPodConditions: + weight: description: |- - Represents the requirement on the pod conditions. The requirement is represented - as a list of pod condition patterns. - items: - description: |- - PodFailurePolicyOnPodConditionsPattern describes a pattern for matching - an actual pod condition type. - properties: - status: - description: Specifies the required Pod - condition status. - type: string - type: - description: Specifies the required Pod - condition type. - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - action + - podAffinityTerm + - weight type: object type: array x-kubernetes-list-type: atomic - required: - - rules - type: object - podReplacementPolicy: - description: podReplacementPolicy specifies when to create - replacement Pods. - type: string - podTemplateAnnotations: - additionalProperties: - type: string - description: |- - PodTemplateAnnotations are annotations to be applied to the CronJob's PodTemplate - metadata. - type: object - suspend: - description: suspend specifies whether the Job controller - should create Pods or not. - type: boolean - ttlSecondsAfterFinished: - description: |- - ttlSecondsAfterFinished limits the lifetime of a Job that has finished - execution (either Complete or Failed). - format: int32 - type: integer - type: object - schedule: - description: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. - type: string - startingDeadlineSeconds: - description: |- - Optional deadline in seconds for starting the job if it misses scheduled - time for any reason. - format: int64 - type: integer - successfulJobsHistoryLimit: - description: The number of successful finished jobs to retain. - Value must be non-negative integer. - format: int32 - type: integer - suspend: - description: |- - This flag tells the controller to suspend subsequent executions, it does - not apply to already started executions. - type: boolean - timeZone: - description: The time zone name for the given schedule, see - https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. - type: string - type: object - feastProject: - description: FeastProject is the Feast project id. - pattern: ^[A-Za-z0-9][A-Za-z0-9_-]*$ - type: string - feastProjectDir: - description: FeastProjectDir defines how to create the feast project - directory. - properties: - git: - description: GitCloneOptions describes how a clone should - be performed. - properties: - configs: - additionalProperties: - type: string - description: |- - Configs passed to git via `-c` - e.g. http.sslVerify: 'false' - OR 'url."https://api:\${TOKEN}@github.com/". - type: object - env: - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the anti-affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled " + items: + description: "Defines a set of pods (namely those + matching the labelSelector\nrelative to the given + namespace(s)) that this pod should " properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.' + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - resourceFieldRef: + matchLabelKeys: description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. - properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean + required: + - topologyKey type: object - x-kubernetes-map-type: atomic - type: object - type: array - featureRepoPath: - description: FeatureRepoPath is the relative path to the - feature repo subdirectory. Default is 'feature_repo'. - type: string - ref: - description: Reference to a branch / tag / commit - type: string - url: - description: The repository URL to clone from. - type: string - required: - - url - type: object - x-kubernetes-validations: - - message: RepoPath must be a file name only, with no slashes. - rule: 'has(self.featureRepoPath) ? !self.featureRepoPath.startsWith(''/'') - : true' - init: - description: FeastInitOptions defines how to run a `feast - init`. - properties: - minimal: - type: boolean - template: - description: Template for the created project - enum: - - local - - gcp - - aws - - snowflake - - spark - - postgres - - hbase - - cassandra - - hazelcast - - couchbase - - clickhouse - type: string + type: array + x-kubernetes-list-type: atomic + type: object type: object - type: object - x-kubernetes-validations: - - message: One selection required between init or git. - rule: '[has(self.git), has(self.init)].exists_one(c, c)' - replicas: - default: 1 - description: |- - Replicas is the desired number of pod replicas. Used by the scale sub-resource. - Mutually exclusive with services. - format: int32 - minimum: 1 - type: integer - services: - description: FeatureStoreServices defines the desired feast services. - An ephemeral onlineStore feature server is deployed by default. - properties: deploymentStrategy: description: DeploymentStrategy describes how to replace existing pods with new ones. @@ -6618,6 +8228,30 @@ spec: type: object type: object type: object + pdb: + description: PDB configures a PodDisruptionBudget for the + FeatureStore deployment. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable specifies the maximum number/percentage + of pods that can be unavailable. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable specifies the minimum number/percentage + of pods that must remain available. + x-kubernetes-int-or-string: true + type: object + x-kubernetes-validations: + - message: Exactly one of minAvailable or maxUnavailable must + be set. + rule: '[has(self.minAvailable), has(self.maxUnavailable)].exists_one(c, + c)' registry: description: Registry configures the registry service. One selection is required. Local is the default setting. @@ -7941,6 +9575,98 @@ spec: type: string type: object type: object + topologySpreadConstraints: + description: TopologySpreadConstraints defines how pods are + spread across topology domains. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: MaxSkew describes the degree to which pods + may be unevenly distributed. + format: int32 + type: integer + minDomains: + description: MinDomains indicates a minimum number of + eligible domains. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. + type: string + topologyKey: + description: TopologyKey is the key of node labels. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array ui: description: Creates a UI server container properties: diff --git a/infra/feast-operator/config/rbac/role.yaml b/infra/feast-operator/config/rbac/role.yaml index 3fa228afc6b..dca06c870e4 100644 --- a/infra/feast-operator/config/rbac/role.yaml +++ b/infra/feast-operator/config/rbac/role.yaml @@ -101,6 +101,18 @@ rules: - get - patch - update +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - rbac.authorization.k8s.io resources: diff --git a/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml b/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml index 4380b28d018..ccb8fd9036b 100644 --- a/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml +++ b/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml @@ -30,7 +30,7 @@ stringData: user: ${POSTGRES_USER} password: ${POSTGRES_PASSWORD} --- -# HPA autoscaling: 2-10 replicas with DB-backed persistence +# HPA autoscaling: 2-10 replicas with DB-backed persistence and HA apiVersion: feast.dev/v1 kind: FeatureStore metadata: @@ -50,6 +50,8 @@ spec: target: type: Utilization averageUtilization: 70 + pdb: + maxUnavailable: 1 onlineStore: persistence: store: diff --git a/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml b/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml index c0f0f21cd6a..601eb854001 100644 --- a/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml +++ b/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml @@ -30,7 +30,13 @@ stringData: user: ${POSTGRES_USER} password: ${POSTGRES_PASSWORD} --- -# Static scaling: 3 replicas with DB-backed persistence +# Static scaling: 3 replicas with DB-backed persistence, PDB, and HA +# +# By default the operator auto-injects: +# - Soft pod anti-affinity (prefer different nodes) +# - Soft zone topology spread (prefer different zones, e.g. us-east-1a, us-east-1b, us-east-1c) +# +# To enforce strict zone spreading on AWS (DoNotSchedule), uncomment topologySpreadConstraints below. apiVersion: feast.dev/v1 kind: FeatureStore metadata: @@ -40,6 +46,16 @@ spec: feastProject: my_project replicas: 3 services: + pdb: + maxUnavailable: 1 + # Uncomment to enforce strict spreading across AWS availability zones: + # topologySpreadConstraints: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # feast.dev/name: sample-scaling-static onlineStore: persistence: store: diff --git a/infra/feast-operator/dist/install.yaml b/infra/feast-operator/dist/install.yaml index 43f6ef8c84c..27ea615e85a 100644 --- a/infra/feast-operator/dist/install.yaml +++ b/infra/feast-operator/dist/install.yaml @@ -731,549 +731,794 @@ spec: description: FeatureStoreServices defines the desired feast services. An ephemeral onlineStore feature server is deployed by default. properties: - deploymentStrategy: - description: DeploymentStrategy describes how to replace existing - pods with new ones. + affinity: + description: Affinity defines the pod scheduling constraints for + the FeatureStore deployment. properties: - rollingUpdate: - description: |- - Rolling update config params. Present only if DeploymentStrategyType = - RollingUpdate. + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. properties: - maxSurge: - anyOf: - - type: integer - - type: string + preferredDuringSchedulingIgnoredDuringExecution: description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: The maximum number of pods that can be unavailable - during the update. - x-kubernetes-int-or-string: true - type: object - type: - description: Type of deployment. Can be "Recreate" or "RollingUpdate". - Default is RollingUpdate. - type: string - type: object - disableInitContainers: - description: Disable the 'feast repo initialization' initContainer - type: boolean - offlineStore: - description: OfflineStore configures the offline store service - properties: - persistence: - description: OfflineStorePersistence configures the persistence - settings for the offline store service - properties: - file: - description: OfflineStoreFilePersistence configures the - file-based persistence for the offline store service - properties: - pvc: - description: PvcConfig defines the settings for a - persistent file store based on PVCs. - properties: - create: - description: Settings for creating a new PVC - properties: - accessModes: - description: AccessModes k8s persistent volume - access modes. Defaults to ["ReadWriteOnce"]. - items: - type: string - type: array - resources: - description: Resources describes the storage - resource requirements for a volume. + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). + properties: + preference: + description: A node selector term, associated with + the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true + key: + description: The label key that the selector + applies to. + type: string + operator: description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum - amount of compute resources required. - type: object + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator type: object - storageClassName: - description: StorageClassName is the name - of an existing StorageClass to which this - persistent volume belongs. - type: string - type: object - x-kubernetes-validations: - - message: PvcCreate is immutable - rule: self == oldSelf - mountPath: - description: |- - MountPath within the container at which the volume should be mounted. - Must start by "/" and cannot contain ':'. - type: string - ref: - description: Reference to an existing field - properties: - name: - default: "" + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - required: - - mountPath - type: object - x-kubernetes-validations: - - message: One selection is required between ref and - create. - rule: '[has(self.ref), has(self.create)].exists_one(c, - c)' - - message: Mount path must start with '/' and must - not contain ':' - rule: self.mountPath.matches('^/[^:]*$') - type: - enum: - - file - - dask - - duckdb - type: string - type: object - store: - description: OfflineStoreDBStorePersistence configures - the DB store persistence for the offline store service + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified by + this field are not met at\nscheduling time, the pod + will not be scheduled onto " properties: - secretKeyName: - description: By default, the selected store "type" - is used as the SecretKeyName - type: string - secretRef: - description: Data store parameters should be placed - as-is from the "feature_store.yaml" under the secret - key. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: - description: Type of the persistence type you want - to use. - enum: - - snowflake.offline - - bigquery - - redshift - - spark - - postgres - - trino - - athena - - mssql - - couchbase.offline - - clickhouse - - ray - type: string + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic required: - - secretRef - - type + - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object - x-kubernetes-validations: - - message: One selection required between file or store. - rule: '[has(self.file), has(self.store)].exists_one(c, c)' - server: - description: Creates a remote offline server container + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). properties: - env: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i items: - description: EnvVar represents an environment variable - present in a Container. + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: + labelSelector: description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - name + - podAffinityTerm + - weight type: object type: array - envFrom: + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified by + this field are not met at\nscheduling time, the pod + will not be scheduled onto " items: - description: EnvFromSource represents the source of - a set of ConfigMaps + description: "Defines a set of pods (namely those matching + the labelSelector\nrelative to the given namespace(s)) + that this pod should " properties: - configMapRef: - description: The ConfigMap to select from + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey type: object type: array - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - logLevel: - description: |- - LogLevel sets the logging level for the server - Allowed values: "debug", "info", "warning", "error", "critical". - enum: - - debug - - info - - warning - - error - - critical - type: string - metrics: - description: Metrics exposes Prometheus-compatible metrics - for the Feast server when enabled. - type: boolean - nodeSelector: - additionalProperties: - type: string - type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: "The scheduler will prefer to schedule pods + to nodes that satisfy\nthe anti-affinity expressions + specified by this field, " + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. properties: - name: + labelSelector: description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string required: - - name + - topologyKey type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object - type: object - tls: - description: TlsConfigs configures server TLS for a feast - service. - properties: - disable: - description: will disable TLS for the feast service. - useful in an openshift cluster, for example, where - TLS is configured by default - type: boolean - secretKeyNames: - description: SecretKeyNames defines the secret key - names for the TLS key and cert. - properties: - tlsCrt: - description: defaults to "tls.crt" - type: string - tlsKey: - description: defaults to "tls.key" - type: string - type: object - secretRef: - description: references the local k8s secret where - the TLS key and cert reside - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: object - x-kubernetes-validations: - - message: '`secretRef` required if `disable` is false.' - rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) - : true' - volumeMounts: - description: VolumeMounts defines the list of volumes - that should be mounted into the feast container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - type: string - subPath: + weight: description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - type: string + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - mountPath - - name + - podAffinityTerm + - weight type: object type: array - workerConfigs: - description: WorkerConfigs defines the worker configuration - for the Feast server. - properties: - keepAliveTimeout: - description: |- - KeepAliveTimeout is the timeout for keep-alive connections in seconds. - Defaults to 30. - format: int32 - minimum: 1 - type: integer - maxRequests: - description: |- - MaxRequests is the maximum number of requests a worker will process before restarting. - This helps prevent memory leaks. - format: int32 - minimum: 0 - type: integer - maxRequestsJitter: - description: |- - MaxRequestsJitter is the maximum jitter to add to max-requests to prevent - thundering herd effect on worker restart. - format: int32 - minimum: 0 - type: integer - registryTTLSeconds: - description: RegistryTTLSeconds is the number of seconds - after which the registry is refreshed. - format: int32 - minimum: 0 - type: integer - workerConnections: - description: |- - WorkerConnections is the maximum number of simultaneous clients per worker process. - Defaults to 1000. - format: int32 - minimum: 1 - type: integer - workers: - description: Workers is the number of worker processes. - Use -1 to auto-calculate based on CPU cores (2 * - CPU + 1). - format: int32 - minimum: -1 - type: integer - type: object + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the anti-affinity requirements specified + by this field are not met at\nscheduling time, the pod + will not be scheduled " + items: + description: "Defines a set of pods (namely those matching + the labelSelector\nrelative to the given namespace(s)) + that this pod should " + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic type: object type: object - onlineStore: - description: OnlineStore configures the online store service + deploymentStrategy: + description: DeploymentStrategy describes how to replace existing + pods with new ones. + properties: + rollingUpdate: + description: |- + Rolling update config params. Present only if DeploymentStrategyType = + RollingUpdate. + properties: + maxSurge: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be scheduled above the desired number of + pods. + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + description: The maximum number of pods that can be unavailable + during the update. + x-kubernetes-int-or-string: true + type: object + type: + description: Type of deployment. Can be "Recreate" or "RollingUpdate". + Default is RollingUpdate. + type: string + type: object + disableInitContainers: + description: Disable the 'feast repo initialization' initContainer + type: boolean + offlineStore: + description: OfflineStore configures the offline store service properties: persistence: - description: OnlineStorePersistence configures the persistence - settings for the online store service + description: OfflineStorePersistence configures the persistence + settings for the offline store service properties: file: - description: OnlineStoreFilePersistence configures the - file-based persistence for the online store service + description: OfflineStoreFilePersistence configures the + file-based persistence for the offline store service properties: - path: - type: string pvc: description: PvcConfig defines the settings for a persistent file store based on PVCs. @@ -1350,21 +1595,16 @@ spec: - message: Mount path must start with '/' and must not contain ':' rule: self.mountPath.matches('^/[^:]*$') + type: + enum: + - file + - dask + - duckdb + type: string type: object - x-kubernetes-validations: - - message: Ephemeral stores must have absolute paths. - rule: '(!has(self.pvc) && has(self.path)) ? self.path.startsWith(''/'') - : true' - - message: PVC path must be a file name only, with no - slashes. - rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') - : true' - - message: Online store does not support S3 or GS buckets. - rule: 'has(self.path) ? !(self.path.startsWith(''s3://'') - || self.path.startsWith(''gs://'')) : true' store: - description: OnlineStoreDBStorePersistence configures - the DB store persistence for the online store service + description: OfflineStoreDBStorePersistence configures + the DB store persistence for the offline store service properties: secretKeyName: description: By default, the selected store "type" @@ -1388,22 +1628,17 @@ spec: description: Type of the persistence type you want to use. enum: - - snowflake.online - - redis - - datastore - - dynamodb - - bigtable + - snowflake.offline + - bigquery + - redshift + - spark - postgres - - cassandra - - mysql - - hazelcast - - singlestore - - hbase - - elasticsearch - - qdrant - - couchbase.online - - milvus - - hybrid + - trino + - athena + - mssql + - couchbase.offline + - clickhouse + - ray type: string required: - secretRef @@ -1414,7 +1649,7 @@ spec: - message: One selection required between file or store. rule: '[has(self.file), has(self.store)].exists_one(c, c)' server: - description: Creates a feature server container + description: Creates a remote offline server container properties: env: items: @@ -1770,151 +2005,74 @@ spec: type: object type: object type: object - registry: - description: Registry configures the registry service. One selection - is required. Local is the default setting. + onlineStore: + description: OnlineStore configures the online store service properties: - local: - description: LocalRegistryConfig configures the registry service + persistence: + description: OnlineStorePersistence configures the persistence + settings for the online store service properties: - persistence: - description: RegistryPersistence configures the persistence - settings for the registry service + file: + description: OnlineStoreFilePersistence configures the + file-based persistence for the online store service properties: - file: - description: RegistryFilePersistence configures the - file-based persistence for the registry service + path: + type: string + pvc: + description: PvcConfig defines the settings for a + persistent file store based on PVCs. properties: - cache_mode: - description: |- - CacheMode defines the registry cache update strategy. - Allowed values are "sync" and "thread". - enum: - - none - - sync - - thread - type: string - cache_ttl_seconds: - description: CacheTTLSeconds defines the TTL (in - seconds) for the registry cache. - format: int32 - minimum: 0 - type: integer - path: - type: string - pvc: - description: PvcConfig defines the settings for - a persistent file store based on PVCs. + create: + description: Settings for creating a new PVC properties: - create: - description: Settings for creating a new PVC - properties: - accessModes: - description: AccessModes k8s persistent - volume access modes. Defaults to ["ReadWriteOnce"]. - items: - type: string - type: array - resources: - description: Resources describes the storage - resource requirements for a volume. - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the - minimum amount of compute resources - required. - type: object - type: object - storageClassName: - description: StorageClassName is the name - of an existing StorageClass to which - this persistent volume belongs. - type: string - type: object - x-kubernetes-validations: - - message: PvcCreate is immutable - rule: self == oldSelf - mountPath: - description: |- - MountPath within the container at which the volume should be mounted. - Must start by "/" and cannot contain ':'. - type: string - ref: - description: Reference to an existing field + accessModes: + description: AccessModes k8s persistent volume + access modes. Defaults to ["ReadWriteOnce"]. + items: + type: string + type: array + resources: + description: Resources describes the storage + resource requirements for a volume. properties: - name: - default: "" + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum + amount of compute resources required. + type: object type: object - x-kubernetes-map-type: atomic - required: - - mountPath + storageClassName: + description: StorageClassName is the name + of an existing StorageClass to which this + persistent volume belongs. + type: string type: object x-kubernetes-validations: - - message: One selection is required between ref - and create. - rule: '[has(self.ref), has(self.create)].exists_one(c, - c)' - - message: Mount path must start with '/' and - must not contain ':' - rule: self.mountPath.matches('^/[^:]*$') - s3_additional_kwargs: - additionalProperties: - type: string - type: object - type: object - x-kubernetes-validations: - - message: Registry files must use absolute paths - or be S3 ('s3://') or GS ('gs://') object store - URIs. - rule: '(!has(self.pvc) && has(self.path)) ? (self.path.startsWith(''/'') - || self.path.startsWith(''s3://'') || self.path.startsWith(''gs://'')) - : true' - - message: PVC path must be a file name only, with - no slashes. - rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') - : true' - - message: PVC persistence does not support S3 or - GS object store URIs. - rule: '(has(self.pvc) && has(self.path)) ? !(self.path.startsWith(''s3://'') - || self.path.startsWith(''gs://'')) : true' - - message: Additional S3 settings are available only - for S3 object store URIs. - rule: '(has(self.s3_additional_kwargs) && has(self.path)) - ? self.path.startsWith(''s3://'') : true' - store: - description: RegistryDBStorePersistence configures - the DB store persistence for the registry service - properties: - secretKeyName: - description: By default, the selected store "type" - is used as the SecretKeyName + - message: PvcCreate is immutable + rule: self == oldSelf + mountPath: + description: |- + MountPath within the container at which the volume should be mounted. + Must start by "/" and cannot contain ':'. type: string - secretRef: - description: Data store parameters should be placed - as-is from the "feature_store.yaml" under the - secret key. + ref: + description: Reference to an existing field properties: name: default: "" @@ -1925,146 +2083,108 @@ spec: type: string type: object x-kubernetes-map-type: atomic - type: - description: Type of the persistence type you - want to use. - enum: - - sql - - snowflake.registry - type: string required: - - secretRef - - type + - mountPath type: object + x-kubernetes-validations: + - message: One selection is required between ref and + create. + rule: '[has(self.ref), has(self.create)].exists_one(c, + c)' + - message: Mount path must start with '/' and must + not contain ':' + rule: self.mountPath.matches('^/[^:]*$') type: object x-kubernetes-validations: - - message: One selection required between file or store. - rule: '[has(self.file), has(self.store)].exists_one(c, - c)' - server: - description: Creates a registry server container + - message: Ephemeral stores must have absolute paths. + rule: '(!has(self.pvc) && has(self.path)) ? self.path.startsWith(''/'') + : true' + - message: PVC path must be a file name only, with no + slashes. + rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') + : true' + - message: Online store does not support S3 or GS buckets. + rule: 'has(self.path) ? !(self.path.startsWith(''s3://'') + || self.path.startsWith(''gs://'')) : true' + store: + description: OnlineStoreDBStorePersistence configures + the DB store persistence for the online store service properties: - env: - items: - description: EnvVar represents an environment variable - present in a Container. + secretKeyName: + description: By default, the selected store "type" + is used as the SecretKeyName + type: string + secretRef: + description: Data store parameters should be placed + as-is from the "feature_store.yaml" under the secret + key. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: + description: Type of the persistence type you want + to use. + enum: + - snowflake.online + - redis + - datastore + - dynamodb + - bigtable + - postgres + - cassandra + - mysql + - hazelcast + - singlestore + - hbase + - elasticsearch + - qdrant + - couchbase.online + - milvus + - hybrid + type: string + required: + - secretRef + - type + type: object + type: object + x-kubernetes-validations: + - message: One selection required between file or store. + rule: '[has(self.file), has(self.store)].exists_one(c, c)' + server: + description: Creates a feature server container + properties: + env: + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: - supports metadata.name, metadata.namespace, - `metadata.labels['''']`, `metadata.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults - to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source - of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from + configMapKeyRef: + description: Selects a key of a ConfigMap. properties: + key: + description: The key to select. + type: string name: default: "" description: |- @@ -2074,17 +2194,62 @@ spec: type: string optional: description: Specify whether the ConfigMap - must be defined + or its key must be defined type: boolean + required: + - key type: object x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend - to each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string name: default: "" description: |- @@ -2094,859 +2259,1462 @@ spec: type: string optional: description: Specify whether the Secret - must be defined + or its key must be defined type: boolean + required: + - key type: object x-kubernetes-map-type: atomic type: object - type: array - grpc: - description: Enable gRPC registry server. Defaults - to true if unset. - type: boolean - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - logLevel: - description: |- - LogLevel sets the logging level for the server - Allowed values: "debug", "info", "warning", "error", "critical". - enum: - - debug - - info - - warning - - error - - critical - type: string - metrics: - description: Metrics exposes Prometheus-compatible - metrics for the Feast server when enabled. - type: boolean - nodeSelector: - additionalProperties: + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. type: string - type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object - type: object - restAPI: - description: Enable REST API registry server. - type: boolean - tls: - description: TlsConfigs configures server TLS for - a feast service. - properties: - disable: - description: will disable TLS for the feast service. - useful in an openshift cluster, for example, - where TLS is configured by default - type: boolean - secretKeyNames: - description: SecretKeyNames defines the secret - key names for the TLS key and cert. - properties: - tlsCrt: - description: defaults to "tls.crt" - type: string - tlsKey: - description: defaults to "tls.key" - type: string - type: object - secretRef: - description: references the local k8s secret where - the TLS key and cert reside - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - type: object - x-kubernetes-validations: - - message: '`secretRef` required if `disable` is false.' - rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) - : true' - volumeMounts: - description: VolumeMounts defines the list of volumes - that should be mounted into the feast container. - items: - description: VolumeMount describes a mounting of - a Volume within a container. + secretRef: + description: The Secret to select from properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - type: string name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: + default: "" description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. type: string - subPath: + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + logLevel: + description: |- + LogLevel sets the logging level for the server + Allowed values: "debug", "info", "warning", "error", "critical". + enum: + - debug + - info + - warning + - error + - critical + type: string + metrics: + description: Metrics exposes Prometheus-compatible metrics + for the Feast server when enabled. + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume - from which the container's volume should be - mounted. + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. type: string required: - - mountPath - name type: object type: array - workerConfigs: - description: WorkerConfigs defines the worker configuration - for the Feast server. + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object + type: object + tls: + description: TlsConfigs configures server TLS for a feast + service. + properties: + disable: + description: will disable TLS for the feast service. + useful in an openshift cluster, for example, where + TLS is configured by default + type: boolean + secretKeyNames: + description: SecretKeyNames defines the secret key + names for the TLS key and cert. properties: - keepAliveTimeout: - description: |- - KeepAliveTimeout is the timeout for keep-alive connections in seconds. - Defaults to 30. - format: int32 - minimum: 1 - type: integer - maxRequests: - description: |- - MaxRequests is the maximum number of requests a worker will process before restarting. - This helps prevent memory leaks. - format: int32 - minimum: 0 - type: integer - maxRequestsJitter: - description: |- - MaxRequestsJitter is the maximum jitter to add to max-requests to prevent - thundering herd effect on worker restart. - format: int32 - minimum: 0 - type: integer - registryTTLSeconds: - description: RegistryTTLSeconds is the number - of seconds after which the registry is refreshed. - format: int32 - minimum: 0 - type: integer - workerConnections: + tlsCrt: + description: defaults to "tls.crt" + type: string + tlsKey: + description: defaults to "tls.key" + type: string + type: object + secretRef: + description: references the local k8s secret where + the TLS key and cert reside + properties: + name: + default: "" description: |- - WorkerConnections is the maximum number of simultaneous clients per worker process. - Defaults to 1000. - format: int32 - minimum: 1 - type: integer - workers: - description: Workers is the number of worker processes. - Use -1 to auto-calculate based on CPU cores - (2 * CPU + 1). - format: int32 - minimum: -1 - type: integer + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string type: object + x-kubernetes-map-type: atomic type: object x-kubernetes-validations: - - message: At least one of restAPI or grpc must be true - rule: self.restAPI == true || self.grpc == true || !has(self.grpc) - type: object - remote: - description: RemoteRegistryConfig points to a remote feast - registry server. - properties: - feastRef: - description: Reference to an existing `FeatureStore` CR - in the same k8s cluster. - properties: - name: - description: Name of the FeatureStore - type: string - namespace: - description: Namespace of the FeatureStore - type: string - required: - - name - type: object - hostname: - description: Host address of the remote registry service - - :, e.g. `registry..svc.cluster.local:80` - type: string - tls: - description: TlsRemoteRegistryConfigs configures client - TLS for a remote feast registry. + - message: '`secretRef` required if `disable` is false.' + rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) + : true' + volumeMounts: + description: VolumeMounts defines the list of volumes + that should be mounted into the feast container. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + type: string + required: + - mountPath + - name + type: object + type: array + workerConfigs: + description: WorkerConfigs defines the worker configuration + for the Feast server. properties: - certName: - description: defines the configmap key name for the - client TLS cert. - type: string - configMapRef: - description: references the local k8s configmap where - the TLS cert resides - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - type: object - x-kubernetes-map-type: atomic - required: - - certName - - configMapRef + keepAliveTimeout: + description: |- + KeepAliveTimeout is the timeout for keep-alive connections in seconds. + Defaults to 30. + format: int32 + minimum: 1 + type: integer + maxRequests: + description: |- + MaxRequests is the maximum number of requests a worker will process before restarting. + This helps prevent memory leaks. + format: int32 + minimum: 0 + type: integer + maxRequestsJitter: + description: |- + MaxRequestsJitter is the maximum jitter to add to max-requests to prevent + thundering herd effect on worker restart. + format: int32 + minimum: 0 + type: integer + registryTTLSeconds: + description: RegistryTTLSeconds is the number of seconds + after which the registry is refreshed. + format: int32 + minimum: 0 + type: integer + workerConnections: + description: |- + WorkerConnections is the maximum number of simultaneous clients per worker process. + Defaults to 1000. + format: int32 + minimum: 1 + type: integer + workers: + description: Workers is the number of worker processes. + Use -1 to auto-calculate based on CPU cores (2 * + CPU + 1). + format: int32 + minimum: -1 + type: integer type: object type: object - x-kubernetes-validations: - - message: One selection required. - rule: '[has(self.hostname), has(self.feastRef)].exists_one(c, - c)' + type: object + pdb: + description: PDB configures a PodDisruptionBudget for the FeatureStore + deployment. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable specifies the maximum number/percentage + of pods that can be unavailable. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable specifies the minimum number/percentage + of pods that must remain available. + x-kubernetes-int-or-string: true type: object x-kubernetes-validations: - - message: One selection required. - rule: '[has(self.local), has(self.remote)].exists_one(c, c)' - scaling: - description: Scaling configures horizontal scaling for the FeatureStore - deployment (e.g. HPA autoscaling). + - message: Exactly one of minAvailable or maxUnavailable must + be set. + rule: '[has(self.minAvailable), has(self.maxUnavailable)].exists_one(c, + c)' + registry: + description: Registry configures the registry service. One selection + is required. Local is the default setting. properties: - autoscaling: - description: |- - Autoscaling configures a HorizontalPodAutoscaler for the FeatureStore deployment. - Mutually exclusive with spec.replicas. + local: + description: LocalRegistryConfig configures the registry service properties: - behavior: - description: Behavior configures the scaling behavior - of the target. + persistence: + description: RegistryPersistence configures the persistence + settings for the registry service properties: - scaleDown: - description: scaleDown is scaling policy for scaling - Down. + file: + description: RegistryFilePersistence configures the + file-based persistence for the registry service properties: - policies: - description: policies is a list of potential scaling - polices which can be used during scaling. - items: - description: HPAScalingPolicy is a single policy - which must hold true for a specified past - interval. - properties: - periodSeconds: - description: periodSeconds specifies the - window of time for which the policy should - hold true. - format: int32 - type: integer - type: - description: type is used to specify the - scaling policy. - type: string - value: - description: |- - value contains the amount of change which is permitted by the policy. - It must be greater than zero - format: int32 - type: integer - required: - - periodSeconds - - type - - value - type: object - type: array - x-kubernetes-list-type: atomic - selectPolicy: + cache_mode: description: |- - selectPolicy is used to specify which policy should be used. - If not set, the default value Max is used. + CacheMode defines the registry cache update strategy. + Allowed values are "sync" and "thread". + enum: + - none + - sync + - thread type: string - stabilizationWindowSeconds: - description: |- - stabilizationWindowSeconds is the number of seconds for which past recommendations should be - considered while scaling up + cache_ttl_seconds: + description: CacheTTLSeconds defines the TTL (in + seconds) for the registry cache. format: int32 + minimum: 0 type: integer - type: object - scaleUp: - description: scaleUp is scaling policy for scaling - Up. - properties: - policies: - description: policies is a list of potential scaling - polices which can be used during scaling. - items: - description: HPAScalingPolicy is a single policy - which must hold true for a specified past - interval. - properties: - periodSeconds: - description: periodSeconds specifies the - window of time for which the policy should - hold true. - format: int32 - type: integer - type: - description: type is used to specify the - scaling policy. - type: string - value: - description: |- - value contains the amount of change which is permitted by the policy. - It must be greater than zero - format: int32 - type: integer - required: - - periodSeconds - - type - - value - type: object - type: array - x-kubernetes-list-type: atomic - selectPolicy: - description: |- - selectPolicy is used to specify which policy should be used. - If not set, the default value Max is used. + path: type: string - stabilizationWindowSeconds: - description: |- - stabilizationWindowSeconds is the number of seconds for which past recommendations should be - considered while scaling up - format: int32 - type: integer + pvc: + description: PvcConfig defines the settings for + a persistent file store based on PVCs. + properties: + create: + description: Settings for creating a new PVC + properties: + accessModes: + description: AccessModes k8s persistent + volume access modes. Defaults to ["ReadWriteOnce"]. + items: + type: string + type: array + resources: + description: Resources describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the + minimum amount of compute resources + required. + type: object + type: object + storageClassName: + description: StorageClassName is the name + of an existing StorageClass to which + this persistent volume belongs. + type: string + type: object + x-kubernetes-validations: + - message: PvcCreate is immutable + rule: self == oldSelf + mountPath: + description: |- + MountPath within the container at which the volume should be mounted. + Must start by "/" and cannot contain ':'. + type: string + ref: + description: Reference to an existing field + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - mountPath + type: object + x-kubernetes-validations: + - message: One selection is required between ref + and create. + rule: '[has(self.ref), has(self.create)].exists_one(c, + c)' + - message: Mount path must start with '/' and + must not contain ':' + rule: self.mountPath.matches('^/[^:]*$') + s3_additional_kwargs: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-validations: + - message: Registry files must use absolute paths + or be S3 ('s3://') or GS ('gs://') object store + URIs. + rule: '(!has(self.pvc) && has(self.path)) ? (self.path.startsWith(''/'') + || self.path.startsWith(''s3://'') || self.path.startsWith(''gs://'')) + : true' + - message: PVC path must be a file name only, with + no slashes. + rule: '(has(self.pvc) && has(self.path)) ? !self.path.startsWith(''/'') + : true' + - message: PVC persistence does not support S3 or + GS object store URIs. + rule: '(has(self.pvc) && has(self.path)) ? !(self.path.startsWith(''s3://'') + || self.path.startsWith(''gs://'')) : true' + - message: Additional S3 settings are available only + for S3 object store URIs. + rule: '(has(self.s3_additional_kwargs) && has(self.path)) + ? self.path.startsWith(''s3://'') : true' + store: + description: RegistryDBStorePersistence configures + the DB store persistence for the registry service + properties: + secretKeyName: + description: By default, the selected store "type" + is used as the SecretKeyName + type: string + secretRef: + description: Data store parameters should be placed + as-is from the "feature_store.yaml" under the + secret key. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: + description: Type of the persistence type you + want to use. + enum: + - sql + - snowflake.registry + type: string + required: + - secretRef + - type type: object type: object - maxReplicas: - description: MaxReplicas is the upper limit for the number - of replicas. Required. - format: int32 - minimum: 1 - type: integer - metrics: - description: Metrics contains the specifications for which - to use to calculate the desired replica count. - items: - description: |- - MetricSpec specifies how to scale based on a single metric - (only `type` and one other matching field should be set at on - properties: - containerResource: - description: |- - containerResource refers to a resource metric (such as those specified in - requests and limits) known to Kubernetes descr + x-kubernetes-validations: + - message: One selection required between file or store. + rule: '[has(self.file), has(self.store)].exists_one(c, + c)' + server: + description: Creates a registry server container + properties: + env: + items: + description: EnvVar represents an environment variable + present in a Container. properties: - container: - description: container is the name of the container - in the pods of the scaling target - type: string name: - description: name is the name of the resource - in question. + description: Name of the environment variable. + Must be a C_IDENTIFIER. type: string - target: - description: target specifies the target value - for the given metric - properties: - averageUtilization: - description: "averageUtilization is the - target value of the average of the\nresource - metric across all relevant pods, represented - as a " - format: int32 - type: integer - averageValue: - anyOf: - - type: integer - - type: string - description: |- - averageValue is the target value of the average of the - metric across all relevant pods (as a quantity) - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: - description: type represents whether the - metric type is Utilization, Value, or - AverageValue - type: string - value: - anyOf: - - type: integer - - type: string - description: value is the target value of - the metric (as a quantity). - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - required: - - type - type: object - required: - - container - - name - - target - type: object - external: - description: |- - external refers to a global metric that is not associated - with any Kubernetes object. - properties: - metric: - description: metric identifies the target metric - by name and selector + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. properties: - name: - description: name is the name of the given - metric - type: string - selector: - description: "selector is the string-encoded - form of a standard kubernetes label selector - for the given metric\nWhen set, it is - passed " + configMapKeyRef: + description: Selects a key of a ConfigMap. properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. - type: object + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key type: object x-kubernetes-map-type: atomic - required: - - name - type: object - target: - description: target specifies the target value - for the given metric - properties: - averageUtilization: - description: "averageUtilization is the - target value of the average of the\nresource - metric across all relevant pods, represented - as a " - format: int32 - type: integer - averageValue: - anyOf: - - type: integer - - type: string + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: description: |- - averageValue is the target value of the average of the - metric across all relevant pods (as a quantity) - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: - description: type represents whether the - metric type is Utilization, Value, or - AverageValue - type: string - value: - anyOf: - - type: integer - - type: string - description: value is the target value of - the metric (as a quantity). - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - required: - - type + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic type: object required: - - metric - - target + - name type: object - object: - description: |- - object refers to a metric describing a single kubernetes object - (for example, hits-per-second on an Ingress object). + type: array + envFrom: + items: + description: EnvFromSource represents the source + of a set of ConfigMaps properties: - describedObject: - description: describedObject specifies the descriptions - of a object,such as kind,name apiVersion + configMapRef: + description: The ConfigMap to select from properties: - apiVersion: - description: apiVersion is the API version - of the referent - type: string - kind: - description: 'kind is the kind of the referent; - More info: https://git.k8s.' - type: string name: - description: 'name is the name of the referent; - More info: https://kubernetes.' + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. type: string - required: - - kind - - name + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean type: object - metric: - description: metric identifies the target metric - by name and selector + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from properties: name: - description: name is the name of the given - metric + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. type: string - selector: - description: "selector is the string-encoded - form of a standard kubernetes label selector - for the given metric\nWhen set, it is - passed " - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - name + optional: + description: Specify whether the Secret + must be defined + type: boolean type: object - target: - description: target specifies the target value - for the given metric - properties: - averageUtilization: - description: "averageUtilization is the - target value of the average of the\nresource - metric across all relevant pods, represented - as a " - format: int32 - type: integer - averageValue: - anyOf: - - type: integer - - type: string - description: |- - averageValue is the target value of the average of the - metric across all relevant pods (as a quantity) - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: - description: type represents whether the - metric type is Utilization, Value, or - AverageValue - type: string - value: - anyOf: - - type: integer - - type: string - description: value is the target value of - the metric (as a quantity). - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - required: - - type - type: object - required: - - describedObject - - metric - - target + x-kubernetes-map-type: atomic type: object - pods: - description: |- - pods refers to a metric describing each pod in the current scale target - (for example, transactions-processed-per-second) - properties: - metric: - description: metric identifies the target metric - by name and selector + type: array + grpc: + description: Enable gRPC registry server. Defaults + to true if unset. + type: boolean + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + logLevel: + description: |- + LogLevel sets the logging level for the server + Allowed values: "debug", "info", "warning", "error", "critical". + enum: + - debug + - info + - warning + - error + - critical + type: string + metrics: + description: Metrics exposes Prometheus-compatible + metrics for the Feast server when enabled. + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. properties: name: - description: name is the name of the given - metric - type: string - selector: - description: "selector is the string-encoded - form of a standard kubernetes label selector - for the given metric\nWhen set, it is - passed " - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - name - type: object - target: - description: target specifies the target value - for the given metric - properties: - averageUtilization: - description: "averageUtilization is the - target value of the average of the\nresource - metric across all relevant pods, represented - as a " - format: int32 - type: integer - averageValue: - anyOf: - - type: integer - - type: string - description: |- - averageValue is the target value of the average of the - metric across all relevant pods (as a quantity) - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: - description: type represents whether the - metric type is Utilization, Value, or - AverageValue - type: string - value: - anyOf: - - type: integer - - type: string - description: value is the target value of - the metric (as a quantity). - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - required: - - type - type: object - required: - - metric - - target - type: object - resource: - description: |- - resource refers to a resource metric (such as those specified in - requests and limits) known to Kubernetes describing eac - properties: - name: - description: name is the name of the resource - in question. - type: string - target: - description: target specifies the target value - for the given metric - properties: - averageUtilization: - description: "averageUtilization is the - target value of the average of the\nresource - metric across all relevant pods, represented - as a " - format: int32 - type: integer - averageValue: - anyOf: - - type: integer - - type: string description: |- - averageValue is the target value of the average of the - metric across all relevant pods (as a quantity) - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: - description: type represents whether the - metric type is Utilization, Value, or - AverageValue + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. type: string - value: - anyOf: - - type: integer - - type: string - description: value is the target value of - the metric (as a quantity). - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true required: - - type + - name type: object - required: - - name - - target - type: object - type: - description: type is the type of metric source. - type: string - required: - - type - type: object - type: array - minReplicas: - description: MinReplicas is the lower limit for the number - of replicas. Defaults to 1. - format: int32 - minimum: 1 - type: integer - required: - - maxReplicas - type: object - type: object - securityContext: - description: PodSecurityContext holds pod-level security attributes - and common container settings. - properties: - appArmorProfile: - description: appArmorProfile is the AppArmor options to use - by the containers in this pod. - properties: + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object + type: object + restAPI: + description: Enable REST API registry server. + type: boolean + tls: + description: TlsConfigs configures server TLS for + a feast service. + properties: + disable: + description: will disable TLS for the feast service. + useful in an openshift cluster, for example, + where TLS is configured by default + type: boolean + secretKeyNames: + description: SecretKeyNames defines the secret + key names for the TLS key and cert. + properties: + tlsCrt: + description: defaults to "tls.crt" + type: string + tlsKey: + description: defaults to "tls.key" + type: string + type: object + secretRef: + description: references the local k8s secret where + the TLS key and cert reside + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: object + x-kubernetes-validations: + - message: '`secretRef` required if `disable` is false.' + rule: '(!has(self.disable) || !self.disable) ? has(self.secretRef) + : true' + volumeMounts: + description: VolumeMounts defines the list of volumes + that should be mounted into the feast container. + items: + description: VolumeMount describes a mounting of + a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should be + mounted. + type: string + required: + - mountPath + - name + type: object + type: array + workerConfigs: + description: WorkerConfigs defines the worker configuration + for the Feast server. + properties: + keepAliveTimeout: + description: |- + KeepAliveTimeout is the timeout for keep-alive connections in seconds. + Defaults to 30. + format: int32 + minimum: 1 + type: integer + maxRequests: + description: |- + MaxRequests is the maximum number of requests a worker will process before restarting. + This helps prevent memory leaks. + format: int32 + minimum: 0 + type: integer + maxRequestsJitter: + description: |- + MaxRequestsJitter is the maximum jitter to add to max-requests to prevent + thundering herd effect on worker restart. + format: int32 + minimum: 0 + type: integer + registryTTLSeconds: + description: RegistryTTLSeconds is the number + of seconds after which the registry is refreshed. + format: int32 + minimum: 0 + type: integer + workerConnections: + description: |- + WorkerConnections is the maximum number of simultaneous clients per worker process. + Defaults to 1000. + format: int32 + minimum: 1 + type: integer + workers: + description: Workers is the number of worker processes. + Use -1 to auto-calculate based on CPU cores + (2 * CPU + 1). + format: int32 + minimum: -1 + type: integer + type: object + type: object + x-kubernetes-validations: + - message: At least one of restAPI or grpc must be true + rule: self.restAPI == true || self.grpc == true || !has(self.grpc) + type: object + remote: + description: RemoteRegistryConfig points to a remote feast + registry server. + properties: + feastRef: + description: Reference to an existing `FeatureStore` CR + in the same k8s cluster. + properties: + name: + description: Name of the FeatureStore + type: string + namespace: + description: Namespace of the FeatureStore + type: string + required: + - name + type: object + hostname: + description: Host address of the remote registry service + - :, e.g. `registry..svc.cluster.local:80` + type: string + tls: + description: TlsRemoteRegistryConfigs configures client + TLS for a remote feast registry. + properties: + certName: + description: defines the configmap key name for the + client TLS cert. + type: string + configMapRef: + description: references the local k8s configmap where + the TLS cert resides + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - certName + - configMapRef + type: object + type: object + x-kubernetes-validations: + - message: One selection required. + rule: '[has(self.hostname), has(self.feastRef)].exists_one(c, + c)' + type: object + x-kubernetes-validations: + - message: One selection required. + rule: '[has(self.local), has(self.remote)].exists_one(c, c)' + scaling: + description: Scaling configures horizontal scaling for the FeatureStore + deployment (e.g. HPA autoscaling). + properties: + autoscaling: + description: |- + Autoscaling configures a HorizontalPodAutoscaler for the FeatureStore deployment. + Mutually exclusive with spec.replicas. + properties: + behavior: + description: Behavior configures the scaling behavior + of the target. + properties: + scaleDown: + description: scaleDown is scaling policy for scaling + Down. + properties: + policies: + description: policies is a list of potential scaling + polices which can be used during scaling. + items: + description: HPAScalingPolicy is a single policy + which must hold true for a specified past + interval. + properties: + periodSeconds: + description: periodSeconds specifies the + window of time for which the policy should + hold true. + format: int32 + type: integer + type: + description: type is used to specify the + scaling policy. + type: string + value: + description: |- + value contains the amount of change which is permitted by the policy. + It must be greater than zero + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + description: |- + selectPolicy is used to specify which policy should be used. + If not set, the default value Max is used. + type: string + stabilizationWindowSeconds: + description: |- + stabilizationWindowSeconds is the number of seconds for which past recommendations should be + considered while scaling up + format: int32 + type: integer + type: object + scaleUp: + description: scaleUp is scaling policy for scaling + Up. + properties: + policies: + description: policies is a list of potential scaling + polices which can be used during scaling. + items: + description: HPAScalingPolicy is a single policy + which must hold true for a specified past + interval. + properties: + periodSeconds: + description: periodSeconds specifies the + window of time for which the policy should + hold true. + format: int32 + type: integer + type: + description: type is used to specify the + scaling policy. + type: string + value: + description: |- + value contains the amount of change which is permitted by the policy. + It must be greater than zero + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + description: |- + selectPolicy is used to specify which policy should be used. + If not set, the default value Max is used. + type: string + stabilizationWindowSeconds: + description: |- + stabilizationWindowSeconds is the number of seconds for which past recommendations should be + considered while scaling up + format: int32 + type: integer + type: object + type: object + maxReplicas: + description: MaxReplicas is the upper limit for the number + of replicas. Required. + format: int32 + minimum: 1 + type: integer + metrics: + description: Metrics contains the specifications for which + to use to calculate the desired replica count. + items: + description: |- + MetricSpec specifies how to scale based on a single metric + (only `type` and one other matching field should be set at on + properties: + containerResource: + description: |- + containerResource refers to a resource metric (such as those specified in + requests and limits) known to Kubernetes descr + properties: + container: + description: container is the name of the container + in the pods of the scaling target + type: string + name: + description: name is the name of the resource + in question. + type: string + target: + description: target specifies the target value + for the given metric + properties: + averageUtilization: + description: "averageUtilization is the + target value of the average of the\nresource + metric across all relevant pods, represented + as a " + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + description: |- + averageValue is the target value of the average of the + metric across all relevant pods (as a quantity) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + description: type represents whether the + metric type is Utilization, Value, or + AverageValue + type: string + value: + anyOf: + - type: integer + - type: string + description: value is the target value of + the metric (as a quantity). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + description: |- + external refers to a global metric that is not associated + with any Kubernetes object. + properties: + metric: + description: metric identifies the target metric + by name and selector + properties: + name: + description: name is the name of the given + metric + type: string + selector: + description: "selector is the string-encoded + form of a standard kubernetes label selector + for the given metric\nWhen set, it is + passed " + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + description: target specifies the target value + for the given metric + properties: + averageUtilization: + description: "averageUtilization is the + target value of the average of the\nresource + metric across all relevant pods, represented + as a " + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + description: |- + averageValue is the target value of the average of the + metric across all relevant pods (as a quantity) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + description: type represents whether the + metric type is Utilization, Value, or + AverageValue + type: string + value: + anyOf: + - type: integer + - type: string + description: value is the target value of + the metric (as a quantity). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + description: |- + object refers to a metric describing a single kubernetes object + (for example, hits-per-second on an Ingress object). + properties: + describedObject: + description: describedObject specifies the descriptions + of a object,such as kind,name apiVersion + properties: + apiVersion: + description: apiVersion is the API version + of the referent + type: string + kind: + description: 'kind is the kind of the referent; + More info: https://git.k8s.' + type: string + name: + description: 'name is the name of the referent; + More info: https://kubernetes.' + type: string + required: + - kind + - name + type: object + metric: + description: metric identifies the target metric + by name and selector + properties: + name: + description: name is the name of the given + metric + type: string + selector: + description: "selector is the string-encoded + form of a standard kubernetes label selector + for the given metric\nWhen set, it is + passed " + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + description: target specifies the target value + for the given metric + properties: + averageUtilization: + description: "averageUtilization is the + target value of the average of the\nresource + metric across all relevant pods, represented + as a " + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + description: |- + averageValue is the target value of the average of the + metric across all relevant pods (as a quantity) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + description: type represents whether the + metric type is Utilization, Value, or + AverageValue + type: string + value: + anyOf: + - type: integer + - type: string + description: value is the target value of + the metric (as a quantity). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + description: |- + pods refers to a metric describing each pod in the current scale target + (for example, transactions-processed-per-second) + properties: + metric: + description: metric identifies the target metric + by name and selector + properties: + name: + description: name is the name of the given + metric + type: string + selector: + description: "selector is the string-encoded + form of a standard kubernetes label selector + for the given metric\nWhen set, it is + passed " + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + description: target specifies the target value + for the given metric + properties: + averageUtilization: + description: "averageUtilization is the + target value of the average of the\nresource + metric across all relevant pods, represented + as a " + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + description: |- + averageValue is the target value of the average of the + metric across all relevant pods (as a quantity) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + description: type represents whether the + metric type is Utilization, Value, or + AverageValue + type: string + value: + anyOf: + - type: integer + - type: string + description: value is the target value of + the metric (as a quantity). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + description: |- + resource refers to a resource metric (such as those specified in + requests and limits) known to Kubernetes describing eac + properties: + name: + description: name is the name of the resource + in question. + type: string + target: + description: target specifies the target value + for the given metric + properties: + averageUtilization: + description: "averageUtilization is the + target value of the average of the\nresource + metric across all relevant pods, represented + as a " + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + description: |- + averageValue is the target value of the average of the + metric across all relevant pods (as a quantity) + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + description: type represents whether the + metric type is Utilization, Value, or + AverageValue + type: string + value: + anyOf: + - type: integer + - type: string + description: value is the target value of + the metric (as a quantity). + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + description: type is the type of metric source. + type: string + required: + - type + type: object + type: array + minReplicas: + description: MinReplicas is the lower limit for the number + of replicas. Defaults to 1. + format: int32 + minimum: 1 + type: integer + required: + - maxReplicas + type: object + type: object + securityContext: + description: PodSecurityContext holds pod-level security attributes + and common container settings. + properties: + appArmorProfile: + description: appArmorProfile is the AppArmor options to use + by the containers in this pod. + properties: localhostProfile: description: localhostProfile indicates a profile loaded on the node that should be used. @@ -3070,6 +3838,96 @@ spec: type: string type: object type: object + topologySpreadConstraints: + description: TopologySpreadConstraints defines how pods are spread + across topology domains. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: MaxSkew describes the degree to which pods + may be unevenly distributed. + format: int32 + type: integer + minDomains: + description: MinDomains indicates a minimum number of eligible + domains. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. + type: string + topologyKey: + description: TopologyKey is the key of node labels. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array ui: description: Creates a UI server container properties: @@ -4894,81 +5752,476 @@ spec: description: The Kubernetes RBAC roles to be deployed in the same namespace of the FeatureStore. items: - type: string + type: string + type: array + type: object + oidc: + description: |- + OidcAuthz defines the authorization settings for deployments using an Open ID Connect identity provider. + https://auth0. + properties: + secretRef: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - secretRef + type: object + type: object + x-kubernetes-validations: + - message: One selection required between kubernetes or oidc. + rule: '[has(self.kubernetes), has(self.oidc)].exists_one(c, + c)' + batchEngine: + description: BatchEngineConfig defines the batch compute engine + configuration. + properties: + configMapKey: + description: Key name in the ConfigMap. Defaults to "config" + if not specified. + type: string + configMapRef: + description: Reference to a ConfigMap containing the batch + engine configuration. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + type: object + x-kubernetes-map-type: atomic + type: object + cronJob: + description: FeastCronJob defines a CronJob to execute against + a Feature Store deployment. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the CronJob metadata. + type: object + concurrencyPolicy: + description: Specifies how to treat concurrent executions + of a Job. + type: string + containerConfigs: + description: CronJobContainerConfigs k8s container settings + for the CronJob + properties: + commands: + description: Array of commands to be executed (in order) + against a Feature Store deployment. + items: + type: string + type: array + env: + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object type: array + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when + to pull a container image + type: string + nodeSelector: + additionalProperties: + type: string + type: object + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Requests describes the minimum amount + of compute resources required. + type: object + type: object type: object - oidc: - description: |- - OidcAuthz defines the authorization settings for deployments using an Open ID Connect identity provider. - https://auth0. + failedJobsHistoryLimit: + description: The number of failed finished jobs to retain. + Value must be non-negative integer. + format: int32 + type: integer + jobSpec: + description: Specification of the desired behavior of a job. properties: - secretRef: + activeDeadlineSeconds: description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. + Specifies the duration in seconds relative to the startTime that the job + may be continuously active before the system tr + format: int64 + type: integer + backoffLimit: + description: Specifies the number of retries before marking + this job failed. + format: int32 + type: integer + backoffLimitPerIndex: + description: |- + Specifies the limit for the number of retries within an + index before marking this index as failed. + format: int32 + type: integer + completionMode: + description: |- + completionMode specifies how Pod completions are tracked. It can be + `NonIndexed` (default) or `Indexed`. + type: string + completions: + description: |- + Specifies the desired number of successfully finished pods the + job should be run with. + format: int32 + type: integer + maxFailedIndexes: + description: |- + Specifies the maximal number of failed indexes before marking the Job as + failed, when backoffLimitPerIndex is set. + format: int32 + type: integer + parallelism: + description: |- + Specifies the maximum desired number of pods the job should + run at any given time. + format: int32 + type: integer + podFailurePolicy: + description: Specifies the policy of handling failed pods. properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string + rules: + description: A list of pod failure policy rules. The + rules are evaluated in order. + items: + description: PodFailurePolicyRule describes how + a pod failure is handled when the requirements + are met. + properties: + action: + description: Specifies the action taken on a + pod failure when the requirements are satisfied. + type: string + onExitCodes: + description: Represents the requirement on the + container exit codes. + properties: + containerName: + description: |- + Restricts the check for exit codes to the container with the + specified name. + type: string + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. + type: string + values: + description: Specifies the set of values. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + - values + type: object + onPodConditions: + description: |- + Represents the requirement on the pod conditions. The requirement is represented + as a list of pod condition patterns. + items: + description: |- + PodFailurePolicyOnPodConditionsPattern describes a pattern for matching + an actual pod condition type. + properties: + status: + description: Specifies the required Pod + condition status. + type: string + type: + description: Specifies the required Pod + condition type. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + required: + - rules + type: object + podReplacementPolicy: + description: podReplacementPolicy specifies when to create + replacement Pods. + type: string + podTemplateAnnotations: + additionalProperties: + type: string + description: |- + PodTemplateAnnotations are annotations to be applied to the CronJob's PodTemplate + metadata. type: object - x-kubernetes-map-type: atomic - required: - - secretRef - type: object - type: object - x-kubernetes-validations: - - message: One selection required between kubernetes or oidc. - rule: '[has(self.kubernetes), has(self.oidc)].exists_one(c, - c)' - batchEngine: - description: BatchEngineConfig defines the batch compute engine - configuration. - properties: - configMapKey: - description: Key name in the ConfigMap. Defaults to "config" - if not specified. - type: string - configMapRef: - description: Reference to a ConfigMap containing the batch - engine configuration. - properties: - name: - default: "" + suspend: + description: suspend specifies whether the Job controller + should create Pods or not. + type: boolean + ttlSecondsAfterFinished: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string + ttlSecondsAfterFinished limits the lifetime of a Job that has finished + execution (either Complete or Failed). + format: int32 + type: integer type: object - x-kubernetes-map-type: atomic + schedule: + description: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + type: string + startingDeadlineSeconds: + description: |- + Optional deadline in seconds for starting the job if it misses scheduled + time for any reason. + format: int64 + type: integer + successfulJobsHistoryLimit: + description: The number of successful finished jobs to retain. + Value must be non-negative integer. + format: int32 + type: integer + suspend: + description: |- + This flag tells the controller to suspend subsequent executions, it does + not apply to already started executions. + type: boolean + timeZone: + description: The time zone name for the given schedule, see + https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. + type: string type: object - cronJob: - description: FeastCronJob defines a CronJob to execute against - a Feature Store deployment. + feastProject: + description: FeastProject is the Feast project id. + pattern: ^[A-Za-z0-9][A-Za-z0-9_-]*$ + type: string + feastProjectDir: + description: FeastProjectDir defines how to create the feast project + directory. properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to the CronJob metadata. - type: object - concurrencyPolicy: - description: Specifies how to treat concurrent executions - of a Job. - type: string - containerConfigs: - description: CronJobContainerConfigs k8s container settings - for the CronJob + git: + description: GitCloneOptions describes how a clone should + be performed. properties: - commands: - description: Array of commands to be executed (in order) - against a Feature Store deployment. - items: + configs: + additionalProperties: type: string - type: array + description: |- + Configs passed to git via `-c` + e.g. http.sslVerify: 'false' + OR 'url."https://api:\${TOKEN}@github.com/". + type: object env: items: description: EnvVar represents an environment variable @@ -5051,527 +6304,884 @@ spec: - resource type: object x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + featureRepoPath: + description: FeatureRepoPath is the relative path to the + feature repo subdirectory. Default is 'feature_repo'. + type: string + ref: + description: Reference to a branch / tag / commit + type: string + url: + description: The repository URL to clone from. + type: string + required: + - url + type: object + x-kubernetes-validations: + - message: RepoPath must be a file name only, with no slashes. + rule: 'has(self.featureRepoPath) ? !self.featureRepoPath.startsWith(''/'') + : true' + init: + description: FeastInitOptions defines how to run a `feast + init`. + properties: + minimal: + type: boolean + template: + description: Template for the created project + enum: + - local + - gcp + - aws + - snowflake + - spark + - postgres + - hbase + - cassandra + - hazelcast + - couchbase + - clickhouse + type: string + type: object + type: object + x-kubernetes-validations: + - message: One selection required between init or git. + rule: '[has(self.git), has(self.init)].exists_one(c, c)' + replicas: + default: 1 + description: |- + Replicas is the desired number of pod replicas. Used by the scale sub-resource. + Mutually exclusive with services. + format: int32 + minimum: 1 + type: integer + services: + description: FeatureStoreServices defines the desired feast services. + An ephemeral onlineStore feature server is deployed by default. + properties: + affinity: + description: Affinity defines the pod scheduling constraints + for the FeatureStore deployment. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled onto " + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic type: object x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - type: string - imagePullPolicy: - description: PullPolicy describes a policy for if/when - to pull a container image - type: string - nodeSelector: - additionalProperties: - type: string + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic type: object - resources: - description: ResourceRequirements describes the compute - resource requirements. + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). properties: - claims: + preferredDuringSchedulingIgnoredDuringExecution: description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but i + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled onto " items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. + description: "Defines a set of pods (namely those + matching the labelSelector\nrelative to the given + namespace(s)) that this pod should " properties: - name: + labelSelector: description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string required: - - name + - topologyKey type: object type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes. - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Requests describes the minimum amount - of compute resources required. - type: object + x-kubernetes-list-type: atomic type: object - type: object - failedJobsHistoryLimit: - description: The number of failed finished jobs to retain. - Value must be non-negative integer. - format: int32 - type: integer - jobSpec: - description: Specification of the desired behavior of a job. - properties: - activeDeadlineSeconds: - description: |- - Specifies the duration in seconds relative to the startTime that the job - may be continuously active before the system tr - format: int64 - type: integer - backoffLimit: - description: Specifies the number of retries before marking - this job failed. - format: int32 - type: integer - backoffLimitPerIndex: - description: |- - Specifies the limit for the number of retries within an - index before marking this index as failed. - format: int32 - type: integer - completionMode: - description: |- - completionMode specifies how Pod completions are tracked. It can be - `NonIndexed` (default) or `Indexed`. - type: string - completions: - description: |- - Specifies the desired number of successfully finished pods the - job should be run with. - format: int32 - type: integer - maxFailedIndexes: - description: |- - Specifies the maximal number of failed indexes before marking the Job as - failed, when backoffLimitPerIndex is set. - format: int32 - type: integer - parallelism: - description: |- - Specifies the maximum desired number of pods the job should - run at any given time. - format: int32 - type: integer - podFailurePolicy: - description: Specifies the policy of handling failed pods. + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. properties: - rules: - description: A list of pod failure policy rules. The - rules are evaluated in order. + preferredDuringSchedulingIgnoredDuringExecution: + description: "The scheduler will prefer to schedule + pods to nodes that satisfy\nthe anti-affinity expressions + specified by this field, " items: - description: PodFailurePolicyRule describes how - a pod failure is handled when the requirements - are met. + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) properties: - action: - description: Specifies the action taken on a - pod failure when the requirements are satisfied. - type: string - onExitCodes: - description: Represents the requirement on the - container exit codes. + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. properties: - containerName: + labelSelector: description: |- - Restricts the check for exit codes to the container with the - specified name. - type: string - operator: + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: description: |- - Represents the relationship between the container exit code(s) and the - specified values. - type: string - values: - description: Specifies the set of values. + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. items: - format: int32 - type: integer + type: string type: array - x-kubernetes-list-type: set + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t + type: string required: - - operator - - values + - topologyKey type: object - onPodConditions: + weight: description: |- - Represents the requirement on the pod conditions. The requirement is represented - as a list of pod condition patterns. - items: - description: |- - PodFailurePolicyOnPodConditionsPattern describes a pattern for matching - an actual pod condition type. - properties: - status: - description: Specifies the required Pod - condition status. - type: string - type: - description: Specifies the required Pod - condition type. - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer required: - - action + - podAffinityTerm + - weight type: object type: array x-kubernetes-list-type: atomic - required: - - rules - type: object - podReplacementPolicy: - description: podReplacementPolicy specifies when to create - replacement Pods. - type: string - podTemplateAnnotations: - additionalProperties: - type: string - description: |- - PodTemplateAnnotations are annotations to be applied to the CronJob's PodTemplate - metadata. - type: object - suspend: - description: suspend specifies whether the Job controller - should create Pods or not. - type: boolean - ttlSecondsAfterFinished: - description: |- - ttlSecondsAfterFinished limits the lifetime of a Job that has finished - execution (either Complete or Failed). - format: int32 - type: integer - type: object - schedule: - description: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. - type: string - startingDeadlineSeconds: - description: |- - Optional deadline in seconds for starting the job if it misses scheduled - time for any reason. - format: int64 - type: integer - successfulJobsHistoryLimit: - description: The number of successful finished jobs to retain. - Value must be non-negative integer. - format: int32 - type: integer - suspend: - description: |- - This flag tells the controller to suspend subsequent executions, it does - not apply to already started executions. - type: boolean - timeZone: - description: The time zone name for the given schedule, see - https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. - type: string - type: object - feastProject: - description: FeastProject is the Feast project id. - pattern: ^[A-Za-z0-9][A-Za-z0-9_-]*$ - type: string - feastProjectDir: - description: FeastProjectDir defines how to create the feast project - directory. - properties: - git: - description: GitCloneOptions describes how a clone should - be performed. - properties: - configs: - additionalProperties: - type: string - description: |- - Configs passed to git via `-c` - e.g. http.sslVerify: 'false' - OR 'url."https://api:\${TOKEN}@github.com/". - type: object - env: - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. + requiredDuringSchedulingIgnoredDuringExecution: + description: "If the anti-affinity requirements specified + by this field are not met at\nscheduling time, the + pod will not be scheduled " + items: + description: "Defines a set of pods (namely those + matching the labelSelector\nrelative to the given + namespace(s)) that this pod should " properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: + labelSelector: description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits. + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object type: object x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in t type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean + required: + - topologyKey type: object - x-kubernetes-map-type: atomic - type: object - type: array - featureRepoPath: - description: FeatureRepoPath is the relative path to the - feature repo subdirectory. Default is 'feature_repo'. - type: string - ref: - description: Reference to a branch / tag / commit - type: string - url: - description: The repository URL to clone from. - type: string - required: - - url - type: object - x-kubernetes-validations: - - message: RepoPath must be a file name only, with no slashes. - rule: 'has(self.featureRepoPath) ? !self.featureRepoPath.startsWith(''/'') - : true' - init: - description: FeastInitOptions defines how to run a `feast - init`. - properties: - minimal: - type: boolean - template: - description: Template for the created project - enum: - - local - - gcp - - aws - - snowflake - - spark - - postgres - - hbase - - cassandra - - hazelcast - - couchbase - - clickhouse - type: string + type: array + x-kubernetes-list-type: atomic + type: object type: object - type: object - x-kubernetes-validations: - - message: One selection required between init or git. - rule: '[has(self.git), has(self.init)].exists_one(c, c)' - replicas: - default: 1 - description: |- - Replicas is the desired number of pod replicas. Used by the scale sub-resource. - Mutually exclusive with services. - format: int32 - minimum: 1 - type: integer - services: - description: FeatureStoreServices defines the desired feast services. - An ephemeral onlineStore feature server is deployed by default. - properties: deploymentStrategy: description: DeploymentStrategy describes how to replace existing pods with new ones. @@ -6626,6 +8236,30 @@ spec: type: object type: object type: object + pdb: + description: PDB configures a PodDisruptionBudget for the + FeatureStore deployment. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable specifies the maximum number/percentage + of pods that can be unavailable. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable specifies the minimum number/percentage + of pods that must remain available. + x-kubernetes-int-or-string: true + type: object + x-kubernetes-validations: + - message: Exactly one of minAvailable or maxUnavailable must + be set. + rule: '[has(self.minAvailable), has(self.maxUnavailable)].exists_one(c, + c)' registry: description: Registry configures the registry service. One selection is required. Local is the default setting. @@ -7949,6 +9583,98 @@ spec: type: string type: object type: object + topologySpreadConstraints: + description: TopologySpreadConstraints defines how pods are + spread across topology domains. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: MaxSkew describes the degree to which pods + may be unevenly distributed. + format: int32 + type: integer + minDomains: + description: MinDomains indicates a minimum number of + eligible domains. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. + type: string + topologyKey: + description: TopologyKey is the key of node labels. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array ui: description: Creates a UI server container properties: @@ -18648,6 +20374,18 @@ rules: - get - patch - update +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - rbac.authorization.k8s.io resources: diff --git a/infra/feast-operator/docs/api/markdown/ref.md b/infra/feast-operator/docs/api/markdown/ref.md index 1e2367a583f..a0647bee8ac 100644 --- a/infra/feast-operator/docs/api/markdown/ref.md +++ b/infra/feast-operator/docs/api/markdown/ref.md @@ -243,6 +243,15 @@ _Appears in:_ | `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volume-v1-core) array_ | Volumes specifies the volumes to mount in the FeatureStore deployment. A corresponding `VolumeMount` should be added to whichever feast service(s) require access to said volume(s). | | `scaling` _[ScalingConfig](#scalingconfig)_ | Scaling configures horizontal scaling for the FeatureStore deployment (e.g. HPA autoscaling). For static replicas, use spec.replicas instead. | +| `pdb` _[PDBConfig](#pdbconfig)_ | PDB configures a PodDisruptionBudget for the FeatureStore deployment. +Only created when scaling is enabled (replicas > 1 or autoscaling). | +| `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#topologyspreadconstraint-v1-core) array_ | TopologySpreadConstraints defines how pods are spread across topology domains. +When scaling is enabled and this is not set, the operator auto-injects a soft +zone-spread constraint (whenUnsatisfiable: ScheduleAnyway). +Set to an empty array to disable auto-injection. | +| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | Affinity defines the pod scheduling constraints for the FeatureStore deployment. +When scaling is enabled and this is not set, the operator auto-injects a soft +pod anti-affinity rule to prefer spreading pods across nodes. | #### FeatureStoreSpec @@ -617,6 +626,24 @@ _Appears in:_ | `nodeSelector` _map[string]string_ | | +#### PDBConfig + + + +PDBConfig configures a PodDisruptionBudget for the FeatureStore deployment. +Exactly one of minAvailable or maxUnavailable must be set. + +_Appears in:_ +- [FeatureStoreServices](#featurestoreservices) + +| Field | Description | +| --- | --- | +| `minAvailable` _[IntOrString](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#intorstring-intstr-util)_ | MinAvailable specifies the minimum number/percentage of pods that must remain available. +Mutually exclusive with maxUnavailable. | +| `maxUnavailable` _[IntOrString](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#intorstring-intstr-util)_ | MaxUnavailable specifies the maximum number/percentage of pods that can be unavailable. +Mutually exclusive with minAvailable. | + + #### PvcConfig diff --git a/infra/feast-operator/internal/controller/featurestore_controller.go b/infra/feast-operator/internal/controller/featurestore_controller.go index d73b30c0175..6f67852a601 100644 --- a/infra/feast-operator/internal/controller/featurestore_controller.go +++ b/infra/feast-operator/internal/controller/featurestore_controller.go @@ -25,6 +25,7 @@ import ( autoscalingv2 "k8s.io/api/autoscaling/v2" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" apimeta "k8s.io/apimachinery/pkg/api/meta" @@ -67,6 +68,7 @@ type FeatureStoreReconciler struct { // +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=get;list;create;update;watch;delete // +kubebuilder:rbac:groups=batch,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=autoscaling,resources=horizontalpodautoscalers,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=get;list;watch;create;update;patch;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -232,6 +234,7 @@ func (r *FeatureStoreReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&rbacv1.Role{}). Owns(&batchv1.CronJob{}). Owns(&autoscalingv2.HorizontalPodAutoscaler{}). + Owns(&policyv1.PodDisruptionBudget{}). Watches(&feastdevv1.FeatureStore{}, handler.EnqueueRequestsFromMapFunc(r.mapFeastRefsToFeastRequests)) if services.IsOpenShift() { diff --git a/infra/feast-operator/internal/controller/services/scaling.go b/infra/feast-operator/internal/controller/services/scaling.go index b8555555498..34584de58e9 100644 --- a/infra/feast-operator/internal/controller/services/scaling.go +++ b/infra/feast-operator/internal/controller/services/scaling.go @@ -23,10 +23,12 @@ import ( appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" hpaac "k8s.io/client-go/applyconfigurations/autoscaling/v2" metaac "k8s.io/client-go/applyconfigurations/meta/v1" + pdbac "k8s.io/client-go/applyconfigurations/policy/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" ) @@ -179,6 +181,69 @@ func convertBehavior(behavior *autoscalingv2.HorizontalPodAutoscalerBehavior) *h return result } +// createOrDeletePDB reconciles the PodDisruptionBudget for the FeatureStore +// deployment using Server-Side Apply. If PDB is not configured or scaling is +// not enabled, any existing PDB is deleted. +func (feast *FeastServices) createOrDeletePDB() error { + cr := feast.Handler.FeatureStore + services := cr.Status.Applied.Services + + if services == nil || services.PDB == nil || !isScalingEnabled(cr) { + pdb := &policyv1.PodDisruptionBudget{ObjectMeta: feast.GetObjectMeta()} + pdb.SetGroupVersionKind(policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget")) + return feast.Handler.DeleteOwnedFeastObj(pdb) + } + + pdbAC := feast.buildPDBApplyConfig() + data, err := json.Marshal(pdbAC) + if err != nil { + return err + } + + pdb := &policyv1.PodDisruptionBudget{ObjectMeta: feast.GetObjectMeta()} + logger := log.FromContext(feast.Handler.Context) + if err := feast.Handler.Client.Patch(feast.Handler.Context, pdb, + client.RawPatch(types.ApplyPatchType, data), + client.FieldOwner(fieldManager), client.ForceOwnership); err != nil { + return err + } + logger.Info("Successfully applied", "PodDisruptionBudget", pdb.Name) + + return nil +} + +// buildPDBApplyConfig constructs the fully desired PDB state as a typed apply +// configuration for Server-Side Apply. +func (feast *FeastServices) buildPDBApplyConfig() *pdbac.PodDisruptionBudgetApplyConfiguration { + cr := feast.Handler.FeatureStore + pdbConfig := cr.Status.Applied.Services.PDB + objMeta := feast.GetObjectMeta() + + pdb := pdbac.PodDisruptionBudget(objMeta.Name, objMeta.Namespace). + WithLabels(feast.getLabels()). + WithOwnerReferences( + metaac.OwnerReference(). + WithAPIVersion(feastdevv1.GroupVersion.String()). + WithKind("FeatureStore"). + WithName(cr.Name). + WithUID(cr.UID). + WithController(true). + WithBlockOwnerDeletion(true), + ). + WithSpec(pdbac.PodDisruptionBudgetSpec(). + WithSelector(metaac.LabelSelector().WithMatchLabels(feast.getLabels())), + ) + + if pdbConfig.MinAvailable != nil { + pdb.Spec.WithMinAvailable(*pdbConfig.MinAvailable) + } + if pdbConfig.MaxUnavailable != nil { + pdb.Spec.WithMaxUnavailable(*pdbConfig.MaxUnavailable) + } + + return pdb +} + // updateScalingStatus updates the scaling status fields using the deployment func (feast *FeastServices) updateScalingStatus(deploy *appsv1.Deployment) { cr := feast.Handler.FeatureStore diff --git a/infra/feast-operator/internal/controller/services/scaling_test.go b/infra/feast-operator/internal/controller/services/scaling_test.go index db803757112..9c1318d43ea 100644 --- a/infra/feast-operator/internal/controller/services/scaling_test.go +++ b/infra/feast-operator/internal/controller/services/scaling_test.go @@ -29,9 +29,14 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" ) +func ptrIntStr(v intstr.IntOrString) *intstr.IntOrString { + return &v +} + var _ = Describe("Horizontal Scaling", func() { var ( featureStore *feastdevv1.FeatureStore @@ -633,6 +638,288 @@ var _ = Describe("Horizontal Scaling", func() { }) }) + Describe("PDB Configuration", func() { + It("should build a PDB apply config with maxUnavailable", func() { + maxUnavail := intstr.FromInt(1) + featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + MaxUnavailable: &maxUnavail, + } + featureStore.Status.Applied.Replicas = ptr(int32(3)) + + pdb := feast.buildPDBApplyConfig() + Expect(*pdb.Kind).To(Equal("PodDisruptionBudget")) + Expect(*pdb.APIVersion).To(Equal("policy/v1")) + Expect(pdb.Spec.MaxUnavailable).NotTo(BeNil()) + Expect(pdb.Spec.MaxUnavailable.IntValue()).To(Equal(1)) + Expect(pdb.Spec.MinAvailable).To(BeNil()) + Expect(pdb.Spec.Selector.MatchLabels).To(HaveKeyWithValue(NameLabelKey, featureStore.Name)) + }) + + It("should build a PDB apply config with minAvailable", func() { + minAvail := intstr.FromString("50%") + featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + MinAvailable: &minAvail, + } + featureStore.Status.Applied.Replicas = ptr(int32(3)) + + pdb := feast.buildPDBApplyConfig() + Expect(pdb.Spec.MinAvailable).NotTo(BeNil()) + Expect(pdb.Spec.MinAvailable.String()).To(Equal("50%")) + Expect(pdb.Spec.MaxUnavailable).To(BeNil()) + }) + + It("should set owner reference on PDB for SSA", func() { + maxUnavail := intstr.FromInt(1) + featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + MaxUnavailable: &maxUnavail, + } + featureStore.Status.Applied.Replicas = ptr(int32(3)) + + pdb := feast.buildPDBApplyConfig() + Expect(pdb.OwnerReferences).To(HaveLen(1)) + Expect(*pdb.OwnerReferences[0].Name).To(Equal(featureStore.Name)) + Expect(*pdb.OwnerReferences[0].Controller).To(BeTrue()) + }) + }) + + Describe("CEL admission validation rejects invalid PDB configurations", func() { + dbOnlineStore := &feastdevv1.OnlineStore{ + Persistence: &feastdevv1.OnlineStorePersistence{ + DBPersistence: &feastdevv1.OnlineStoreDBStorePersistence{ + Type: "redis", + SecretRef: corev1.LocalObjectReference{Name: "redis-secret"}, + }, + }, + } + dbRegistry := &feastdevv1.Registry{ + Local: &feastdevv1.LocalRegistryConfig{ + Persistence: &feastdevv1.RegistryPersistence{ + DBPersistence: &feastdevv1.RegistryDBStorePersistence{ + Type: "sql", + SecretRef: corev1.LocalObjectReference{Name: "registry-secret"}, + }, + }, + }, + } + + It("should reject PDB with both minAvailable and maxUnavailable set", func() { + fs := &feastdevv1.FeatureStore{ + ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-both", Namespace: "default"}, + Spec: feastdevv1.FeatureStoreSpec{ + FeastProject: "celtest", + Replicas: ptr(int32(3)), + Services: &feastdevv1.FeatureStoreServices{ + OnlineStore: dbOnlineStore, + Registry: dbRegistry, + PDB: &feastdevv1.PDBConfig{ + MinAvailable: ptrIntStr(intstr.FromInt(1)), + MaxUnavailable: ptrIntStr(intstr.FromInt(1)), + }, + }, + }, + } + err := k8sClient.Create(ctx, fs) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Exactly one of minAvailable or maxUnavailable")) + }) + + It("should reject PDB with neither minAvailable nor maxUnavailable set", func() { + fs := &feastdevv1.FeatureStore{ + ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-none", Namespace: "default"}, + Spec: feastdevv1.FeatureStoreSpec{ + FeastProject: "celtest", + Replicas: ptr(int32(3)), + Services: &feastdevv1.FeatureStoreServices{ + OnlineStore: dbOnlineStore, + Registry: dbRegistry, + PDB: &feastdevv1.PDBConfig{}, + }, + }, + } + err := k8sClient.Create(ctx, fs) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Exactly one of minAvailable or maxUnavailable")) + }) + + It("should accept PDB with only maxUnavailable", func() { + fs := &feastdevv1.FeatureStore{ + ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-maxu", Namespace: "default"}, + Spec: feastdevv1.FeatureStoreSpec{ + FeastProject: "celtest", + Replicas: ptr(int32(3)), + Services: &feastdevv1.FeatureStoreServices{ + OnlineStore: dbOnlineStore, + Registry: dbRegistry, + PDB: &feastdevv1.PDBConfig{ + MaxUnavailable: ptrIntStr(intstr.FromInt(1)), + }, + }, + }, + } + Expect(k8sClient.Create(ctx, fs)).To(Succeed()) + Expect(k8sClient.Delete(ctx, fs)).To(Succeed()) + }) + + It("should accept PDB with only minAvailable", func() { + fs := &feastdevv1.FeatureStore{ + ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-mina", Namespace: "default"}, + Spec: feastdevv1.FeatureStoreSpec{ + FeastProject: "celtest", + Replicas: ptr(int32(3)), + Services: &feastdevv1.FeatureStoreServices{ + OnlineStore: dbOnlineStore, + Registry: dbRegistry, + PDB: &feastdevv1.PDBConfig{ + MinAvailable: ptrIntStr(intstr.FromString("50%")), + }, + }, + }, + } + Expect(k8sClient.Create(ctx, fs)).To(Succeed()) + Expect(k8sClient.Delete(ctx, fs)).To(Succeed()) + }) + }) + + Describe("Topology Spread", func() { + It("should auto-inject soft zone constraint when replicas > 1 and no explicit constraints", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + + podSpec := &corev1.PodSpec{} + feast.applyTopologySpread(podSpec) + + Expect(podSpec.TopologySpreadConstraints).To(HaveLen(1)) + Expect(podSpec.TopologySpreadConstraints[0].TopologyKey).To(Equal("topology.kubernetes.io/zone")) + Expect(podSpec.TopologySpreadConstraints[0].WhenUnsatisfiable).To(Equal(corev1.ScheduleAnyway)) + Expect(podSpec.TopologySpreadConstraints[0].MaxSkew).To(Equal(int32(1))) + Expect(podSpec.TopologySpreadConstraints[0].LabelSelector.MatchLabels).To(HaveKeyWithValue(NameLabelKey, featureStore.Name)) + }) + + It("should auto-inject when autoscaling is configured", func() { + featureStore.Status.Applied.Services.Scaling = &feastdevv1.ScalingConfig{ + Autoscaling: &feastdevv1.AutoscalingConfig{MaxReplicas: 5}, + } + + podSpec := &corev1.PodSpec{} + feast.applyTopologySpread(podSpec) + + Expect(podSpec.TopologySpreadConstraints).To(HaveLen(1)) + Expect(podSpec.TopologySpreadConstraints[0].WhenUnsatisfiable).To(Equal(corev1.ScheduleAnyway)) + }) + + It("should not inject when replicas is 1 and no autoscaling", func() { + podSpec := &corev1.PodSpec{} + feast.applyTopologySpread(podSpec) + + Expect(podSpec.TopologySpreadConstraints).To(BeEmpty()) + }) + + It("should use user-provided constraints instead of defaults", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Services.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{{ + MaxSkew: 2, + TopologyKey: "kubernetes.io/hostname", + WhenUnsatisfiable: corev1.DoNotSchedule, + LabelSelector: metav1.SetAsLabelSelector(map[string]string{"custom": "label"}), + }} + + podSpec := &corev1.PodSpec{} + feast.applyTopologySpread(podSpec) + + Expect(podSpec.TopologySpreadConstraints).To(HaveLen(1)) + Expect(podSpec.TopologySpreadConstraints[0].TopologyKey).To(Equal("kubernetes.io/hostname")) + Expect(podSpec.TopologySpreadConstraints[0].WhenUnsatisfiable).To(Equal(corev1.DoNotSchedule)) + Expect(podSpec.TopologySpreadConstraints[0].MaxSkew).To(Equal(int32(2))) + }) + + It("should disable auto-injection when empty array is set", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Services.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{} + + podSpec := &corev1.PodSpec{} + feast.applyTopologySpread(podSpec) + + Expect(podSpec.TopologySpreadConstraints).To(BeEmpty()) + }) + }) + + Describe("Pod Anti-Affinity", func() { + It("should auto-inject soft node anti-affinity when replicas > 1", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + + podSpec := &corev1.PodSpec{} + feast.applyAffinity(podSpec) + + Expect(podSpec.Affinity).NotTo(BeNil()) + Expect(podSpec.Affinity.PodAntiAffinity).NotTo(BeNil()) + terms := podSpec.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution + Expect(terms).To(HaveLen(1)) + Expect(terms[0].Weight).To(Equal(int32(100))) + Expect(terms[0].PodAffinityTerm.TopologyKey).To(Equal("kubernetes.io/hostname")) + Expect(terms[0].PodAffinityTerm.LabelSelector.MatchLabels).To(HaveKeyWithValue(NameLabelKey, featureStore.Name)) + }) + + It("should auto-inject when autoscaling is configured", func() { + featureStore.Status.Applied.Services.Scaling = &feastdevv1.ScalingConfig{ + Autoscaling: &feastdevv1.AutoscalingConfig{MaxReplicas: 5}, + } + + podSpec := &corev1.PodSpec{} + feast.applyAffinity(podSpec) + + Expect(podSpec.Affinity).NotTo(BeNil()) + Expect(podSpec.Affinity.PodAntiAffinity).NotTo(BeNil()) + }) + + It("should not inject when replicas is 1 and no autoscaling", func() { + podSpec := &corev1.PodSpec{} + feast.applyAffinity(podSpec) + + Expect(podSpec.Affinity).To(BeNil()) + }) + + It("should use user-provided affinity instead of defaults", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Services.Affinity = &corev1.Affinity{ + PodAntiAffinity: &corev1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{ + TopologyKey: "kubernetes.io/hostname", + LabelSelector: metav1.SetAsLabelSelector(map[string]string{"custom": "label"}), + }}, + }, + } + + podSpec := &corev1.PodSpec{} + feast.applyAffinity(podSpec) + + Expect(podSpec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution).To(HaveLen(1)) + Expect(podSpec.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution).To(BeEmpty()) + Expect(podSpec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].TopologyKey).To(Equal("kubernetes.io/hostname")) + }) + + It("should allow user to set node affinity alongside anti-affinity", func() { + featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Services.Affinity = &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchExpressions: []corev1.NodeSelectorRequirement{{ + Key: "gpu", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"true"}, + }}, + }}, + }, + }, + } + + podSpec := &corev1.PodSpec{} + feast.applyAffinity(podSpec) + + Expect(podSpec.Affinity.NodeAffinity).NotTo(BeNil()) + Expect(podSpec.Affinity.PodAntiAffinity).To(BeNil()) + }) + }) + Describe("Scale sub-resource", func() { newDBFeatureStore := func(name string) *feastdevv1.FeatureStore { return &feastdevv1.FeatureStore{ diff --git a/infra/feast-operator/internal/controller/services/services.go b/infra/feast-operator/internal/controller/services/services.go index a76f21d18c8..06542399151 100644 --- a/infra/feast-operator/internal/controller/services/services.go +++ b/infra/feast-operator/internal/controller/services/services.go @@ -84,6 +84,9 @@ func (feast *FeastServices) Deploy() error { if err := feast.createOrDeleteHPA(); err != nil { return err } + if err := feast.createOrDeletePDB(); err != nil { + return err + } if err := feast.deployClient(); err != nil { return err } @@ -431,6 +434,8 @@ func (feast *FeastServices) setPod(podSpec *corev1.PodSpec) error { feast.mountEmptyDirVolumes(podSpec) feast.mountUserDefinedVolumes(podSpec) feast.applyNodeSelector(podSpec) + feast.applyTopologySpread(podSpec) + feast.applyAffinity(podSpec) return nil } @@ -920,6 +925,54 @@ func (feast *FeastServices) applyNodeSelector(podSpec *corev1.PodSpec) { podSpec.NodeSelector = finalNodeSelector } +func (feast *FeastServices) applyTopologySpread(podSpec *corev1.PodSpec) { + cr := feast.Handler.FeatureStore + services := cr.Status.Applied.Services + + // User-provided explicit constraints take precedence (including empty array to disable) + if services != nil && services.TopologySpreadConstraints != nil { + podSpec.TopologySpreadConstraints = services.TopologySpreadConstraints + return + } + + if !isScalingEnabled(cr) { + return + } + + podSpec.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{{ + MaxSkew: 1, + TopologyKey: "topology.kubernetes.io/zone", + WhenUnsatisfiable: corev1.ScheduleAnyway, + LabelSelector: metav1.SetAsLabelSelector(feast.getLabels()), + }} +} + +func (feast *FeastServices) applyAffinity(podSpec *corev1.PodSpec) { + cr := feast.Handler.FeatureStore + services := cr.Status.Applied.Services + + if services != nil && services.Affinity != nil { + podSpec.Affinity = services.Affinity + return + } + + if !isScalingEnabled(cr) { + return + } + + podSpec.Affinity = &corev1.Affinity{ + PodAntiAffinity: &corev1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{{ + Weight: 100, + PodAffinityTerm: corev1.PodAffinityTerm{ + TopologyKey: "kubernetes.io/hostname", + LabelSelector: metav1.SetAsLabelSelector(feast.getLabels()), + }, + }}, + }, + } +} + // mergeNodeSelectors merges existing and operator node selectors // Existing selectors are preserved, operator selectors can override existing keys func (feast *FeastServices) mergeNodeSelectors(existing, operator map[string]string) map[string]string { diff --git a/infra/website/docs/blog/scaling-feast-feature-server.md b/infra/website/docs/blog/scaling-feast-feature-server.md index 4406d280c81..0e55ab0fa2d 100644 --- a/infra/website/docs/blog/scaling-feast-feature-server.md +++ b/infra/website/docs/blog/scaling-feast-feature-server.md @@ -1,11 +1,11 @@ --- -title: Scaling the Feast Feature Server on Kubernetes -description: The Feast Operator now supports horizontal scaling with static replicas, HPA autoscaling, and external autoscalers like KEDA — enabling production-grade, high-availability feature serving. -date: 2026-02-21 +title: Feature Server High-Availability and Auto-Scaling on Kubernetes +description: The Feast Operator now supports horizontal scaling with static replicas, HPA autoscaling, KEDA, and high-availability features including PodDisruptionBudgets and topology spread constraints. +date: 2026-02-27 authors: ["Nikhil Kathole"] --- -# Scaling the Feast Feature Server on Kubernetes +# Feature Server High-Availability and Auto-Scaling on Kubernetes As ML systems move from experimentation to production, the feature server often becomes a critical bottleneck. A single-replica deployment might handle development traffic, but production workloads — real-time inference, batch scoring, multiple consuming services — demand the ability to scale horizontally. @@ -79,6 +79,8 @@ spec: target: type: Utilization averageUtilization: 70 + pdb: + maxUnavailable: 1 onlineStore: persistence: store: @@ -102,7 +104,7 @@ spec: name: feast-data-stores ``` -The operator creates the HPA as an owned resource — it's automatically cleaned up if you remove the autoscaling configuration or delete the FeatureStore CR. If no custom metrics are specified, the operator defaults to **80% CPU utilization**. +The operator creates the HPA as an owned resource — it's automatically cleaned up if you remove the autoscaling configuration or delete the FeatureStore CR. If no custom metrics are specified, the operator defaults to **80% CPU utilization**. The operator also auto-injects soft pod anti-affinity (node-level) and topology spread constraints (zone-level) to improve resilience — see the [High Availability](#high-availability) section for details. ## 3. External Autoscalers (KEDA, Custom HPAs) @@ -154,6 +156,62 @@ spec: When KEDA scales up `spec.replicas` via the scale sub-resource, the CRD's CEL validation rules automatically ensure DB-backed persistence is configured. The operator also automatically switches the deployment strategy to `RollingUpdate` when `replicas > 1`. This gives you the full power of KEDA's 50+ event-driven triggers with built-in safety checks. +# High Availability + +Scaling to multiple replicas is only half the story — you also need to ensure pods are spread across failure domains and protected during disruptions. The operator includes two HA features that activate when scaling is enabled: + +## Pod Anti-Affinity + +When scaling is enabled, the operator **automatically injects** a soft pod anti-affinity rule that prefers spreading pods across different nodes: + +```yaml +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + feast.dev/name: my-feast +``` + +This means the scheduler will *try* to place each replica on a separate node, but won't prevent scheduling if nodes are constrained. You can override this with your own `affinity` configuration in the CR, or set it to an explicit value to customize the behavior (e.g. `requiredDuringSchedulingIgnoredDuringExecution` for strict anti-affinity). + +## Topology Spread Constraints + +When `replicas > 1` or autoscaling is configured, the operator **automatically injects** a soft zone-spread constraint: + +```yaml +topologySpreadConstraints: +- maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + feast.dev/name: my-feast +``` + +This distributes pods across availability zones on a best-effort basis. If your cluster has 3 zones and 3 replicas, each zone gets one pod. If zones are unavailable, pods still get scheduled rather than staying pending. + +You can override this with explicit constraints (e.g. strict `DoNotSchedule`) or disable it entirely by setting `topologySpreadConstraints: []`. + +## PodDisruptionBudgets + +For protection during voluntary disruptions (node drains, cluster upgrades), you can configure a PDB: + +```yaml +spec: + replicas: 3 + services: + pdb: + maxUnavailable: 1 + onlineStore: + # ... +``` + +The PDB requires explicit configuration — it's not auto-injected because a misconfigured PDB can block node drains. The operator enforces that exactly one of `minAvailable` or `maxUnavailable` is set via CEL validation. The PDB is only created when scaling is enabled and is automatically cleaned up when scaling is disabled. + # Safety First: Persistence Validation Not all persistence backends are safe for multi-replica deployments. File-based stores like SQLite, DuckDB, and local `registry.db` use single-writer file locks that don't work across pods. @@ -188,6 +246,8 @@ The implementation adds three key behaviors to the operator's reconciliation loo **3. HPA lifecycle** — The operator creates, updates, and deletes the HPA as an owned resource tied to the FeatureStore CR. Removing the `autoscaling` configuration automatically cleans up the HPA. +**4. HA features** — The operator auto-injects soft topology spread constraints across zones when scaling is enabled, and manages PodDisruptionBudgets as owned resources when explicitly configured. + The scaling status is reported back on the FeatureStore status: ```yaml @@ -209,17 +269,22 @@ Scaling is designed to work seamlessly with existing operator features: **1. Ensure DB-backed persistence** for all enabled services (online store, offline store, registry). -**2. Configure scaling** in your FeatureStore CR — use either static replicas or HPA (mutually exclusive): +**2. Configure scaling** in your FeatureStore CR — use either static replicas or HPA (mutually exclusive). Optionally add a PDB for disruption protection: ```yaml spec: replicas: 3 # static replicas (top-level) + services: + pdb: # optional: protect against disruptions + maxUnavailable: 1 # -- OR -- # services: # scaling: # autoscaling: # HPA # minReplicas: 2 # maxReplicas: 10 + # pdb: + # maxUnavailable: 1 ``` **3. Apply** the updated CR: From fd641fb28ac1ae4d1407542e401374edf02756bf Mon Sep 17 00:00:00 2001 From: ntkathole Date: Sat, 28 Feb 2026 21:01:37 +0530 Subject: [PATCH 2/2] fix: Address comments Signed-off-by: ntkathole --- .secrets.baseline | 2 +- docs/how-to-guides/scaling-feast.md | 6 +- .../api/v1/featurestore_types.go | 4 +- .../api/v1/zz_generated.deepcopy.go | 4 +- .../crd/bases/feast.dev_featurestores.yaml | 12 +- .../samples/v1_featurestore_scaling_hpa.yaml | 2 +- .../v1_featurestore_scaling_static.yaml | 2 +- infra/feast-operator/dist/install.yaml | 12 +- infra/feast-operator/docs/api/markdown/ref.md | 2 +- .../internal/controller/services/scaling.go | 12 +- .../controller/services/scaling_test.go | 113 +++++++++--------- .../internal/controller/services/services.go | 2 +- .../controller/services/services_test.go | 31 +++-- .../docs/blog/scaling-feast-feature-server.md | 12 +- 14 files changed, 105 insertions(+), 111 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index f660c578f0d..70829ab7dee 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -934,7 +934,7 @@ "filename": "infra/feast-operator/api/v1/featurestore_types.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 726 + "line_number": 725 } ], "infra/feast-operator/api/v1/zz_generated.deepcopy.go": [ diff --git a/docs/how-to-guides/scaling-feast.md b/docs/how-to-guides/scaling-feast.md index 8f6485785d3..5982f917674 100644 --- a/docs/how-to-guides/scaling-feast.md +++ b/docs/how-to-guides/scaling-feast.md @@ -86,7 +86,7 @@ spec: target: type: Utilization averageUtilization: 70 - pdb: + podDisruptionBudgets: maxUnavailable: 1 onlineStore: persistence: @@ -173,10 +173,10 @@ spec: spec: replicas: 3 services: - pdb: + podDisruptionBudgets: maxUnavailable: 1 # at most 1 pod unavailable during disruptions # -- OR -- - # pdb: + # podDisruptionBudgets: # minAvailable: "50%" # at least 50% of pods must remain available # ... ``` diff --git a/infra/feast-operator/api/v1/featurestore_types.go b/infra/feast-operator/api/v1/featurestore_types.go index 38e980cd10d..c97c9c7dd00 100644 --- a/infra/feast-operator/api/v1/featurestore_types.go +++ b/infra/feast-operator/api/v1/featurestore_types.go @@ -315,10 +315,10 @@ type FeatureStoreServices struct { // Scaling configures horizontal scaling for the FeatureStore deployment (e.g. HPA autoscaling). // For static replicas, use spec.replicas instead. Scaling *ScalingConfig `json:"scaling,omitempty"` - // PDB configures a PodDisruptionBudget for the FeatureStore deployment. + // PodDisruptionBudgets configures a PodDisruptionBudget for the FeatureStore deployment. // Only created when scaling is enabled (replicas > 1 or autoscaling). // +optional - PDB *PDBConfig `json:"pdb,omitempty"` + PodDisruptionBudgets *PDBConfig `json:"podDisruptionBudgets,omitempty"` // TopologySpreadConstraints defines how pods are spread across topology domains. // When scaling is enabled and this is not set, the operator auto-injects a soft // zone-spread constraint (whenUnsatisfiable: ScheduleAnyway). diff --git a/infra/feast-operator/api/v1/zz_generated.deepcopy.go b/infra/feast-operator/api/v1/zz_generated.deepcopy.go index 6d0a4d02e70..63500266f02 100644 --- a/infra/feast-operator/api/v1/zz_generated.deepcopy.go +++ b/infra/feast-operator/api/v1/zz_generated.deepcopy.go @@ -381,8 +381,8 @@ func (in *FeatureStoreServices) DeepCopyInto(out *FeatureStoreServices) { *out = new(ScalingConfig) (*in).DeepCopyInto(*out) } - if in.PDB != nil { - in, out := &in.PDB, &out.PDB + if in.PodDisruptionBudgets != nil { + in, out := &in.PodDisruptionBudgets, &out.PodDisruptionBudgets *out = new(PDBConfig) (*in).DeepCopyInto(*out) } diff --git a/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml b/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml index dc8496ee99d..76f134dbbed 100644 --- a/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml +++ b/infra/feast-operator/config/crd/bases/feast.dev_featurestores.yaml @@ -2506,9 +2506,9 @@ spec: type: object type: object type: object - pdb: - description: PDB configures a PodDisruptionBudget for the FeatureStore - deployment. + podDisruptionBudgets: + description: PodDisruptionBudgets configures a PodDisruptionBudget + for the FeatureStore deployment. properties: maxUnavailable: anyOf: @@ -8228,9 +8228,9 @@ spec: type: object type: object type: object - pdb: - description: PDB configures a PodDisruptionBudget for the - FeatureStore deployment. + podDisruptionBudgets: + description: PodDisruptionBudgets configures a PodDisruptionBudget + for the FeatureStore deployment. properties: maxUnavailable: anyOf: diff --git a/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml b/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml index ccb8fd9036b..af4a9fd1d02 100644 --- a/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml +++ b/infra/feast-operator/config/samples/v1_featurestore_scaling_hpa.yaml @@ -50,7 +50,7 @@ spec: target: type: Utilization averageUtilization: 70 - pdb: + podDisruptionBudgets: maxUnavailable: 1 onlineStore: persistence: diff --git a/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml b/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml index 601eb854001..e4df5a6245a 100644 --- a/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml +++ b/infra/feast-operator/config/samples/v1_featurestore_scaling_static.yaml @@ -46,7 +46,7 @@ spec: feastProject: my_project replicas: 3 services: - pdb: + podDisruptionBudgets: maxUnavailable: 1 # Uncomment to enforce strict spreading across AWS availability zones: # topologySpreadConstraints: diff --git a/infra/feast-operator/dist/install.yaml b/infra/feast-operator/dist/install.yaml index 27ea615e85a..f2484e8b7f3 100644 --- a/infra/feast-operator/dist/install.yaml +++ b/infra/feast-operator/dist/install.yaml @@ -2514,9 +2514,9 @@ spec: type: object type: object type: object - pdb: - description: PDB configures a PodDisruptionBudget for the FeatureStore - deployment. + podDisruptionBudgets: + description: PodDisruptionBudgets configures a PodDisruptionBudget + for the FeatureStore deployment. properties: maxUnavailable: anyOf: @@ -8236,9 +8236,9 @@ spec: type: object type: object type: object - pdb: - description: PDB configures a PodDisruptionBudget for the - FeatureStore deployment. + podDisruptionBudgets: + description: PodDisruptionBudgets configures a PodDisruptionBudget + for the FeatureStore deployment. properties: maxUnavailable: anyOf: diff --git a/infra/feast-operator/docs/api/markdown/ref.md b/infra/feast-operator/docs/api/markdown/ref.md index a0647bee8ac..698c3f6bbe3 100644 --- a/infra/feast-operator/docs/api/markdown/ref.md +++ b/infra/feast-operator/docs/api/markdown/ref.md @@ -243,7 +243,7 @@ _Appears in:_ | `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volume-v1-core) array_ | Volumes specifies the volumes to mount in the FeatureStore deployment. A corresponding `VolumeMount` should be added to whichever feast service(s) require access to said volume(s). | | `scaling` _[ScalingConfig](#scalingconfig)_ | Scaling configures horizontal scaling for the FeatureStore deployment (e.g. HPA autoscaling). For static replicas, use spec.replicas instead. | -| `pdb` _[PDBConfig](#pdbconfig)_ | PDB configures a PodDisruptionBudget for the FeatureStore deployment. +| `podDisruptionBudgets` _[PDBConfig](#pdbconfig)_ | PodDisruptionBudgets configures a PodDisruptionBudget for the FeatureStore deployment. Only created when scaling is enabled (replicas > 1 or autoscaling). | | `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#topologyspreadconstraint-v1-core) array_ | TopologySpreadConstraints defines how pods are spread across topology domains. When scaling is enabled and this is not set, the operator auto-injects a soft diff --git a/infra/feast-operator/internal/controller/services/scaling.go b/infra/feast-operator/internal/controller/services/scaling.go index 34584de58e9..ef1dd1f91d8 100644 --- a/infra/feast-operator/internal/controller/services/scaling.go +++ b/infra/feast-operator/internal/controller/services/scaling.go @@ -181,14 +181,14 @@ func convertBehavior(behavior *autoscalingv2.HorizontalPodAutoscalerBehavior) *h return result } -// createOrDeletePDB reconciles the PodDisruptionBudget for the FeatureStore -// deployment using Server-Side Apply. If PDB is not configured or scaling is -// not enabled, any existing PDB is deleted. -func (feast *FeastServices) createOrDeletePDB() error { +// applyOrDeletePDB reconciles the PodDisruptionBudget for the FeatureStore +// deployment using Server-Side Apply. If PodDisruptionBudgets is not configured +// or scaling is not enabled, any existing PDB is deleted. +func (feast *FeastServices) applyOrDeletePDB() error { cr := feast.Handler.FeatureStore services := cr.Status.Applied.Services - if services == nil || services.PDB == nil || !isScalingEnabled(cr) { + if services == nil || services.PodDisruptionBudgets == nil || !isScalingEnabled(cr) { pdb := &policyv1.PodDisruptionBudget{ObjectMeta: feast.GetObjectMeta()} pdb.SetGroupVersionKind(policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget")) return feast.Handler.DeleteOwnedFeastObj(pdb) @@ -216,7 +216,7 @@ func (feast *FeastServices) createOrDeletePDB() error { // configuration for Server-Side Apply. func (feast *FeastServices) buildPDBApplyConfig() *pdbac.PodDisruptionBudgetApplyConfiguration { cr := feast.Handler.FeatureStore - pdbConfig := cr.Status.Applied.Services.PDB + pdbConfig := cr.Status.Applied.Services.PodDisruptionBudgets objMeta := feast.GetObjectMeta() pdb := pdbac.PodDisruptionBudget(objMeta.Name, objMeta.Namespace). diff --git a/infra/feast-operator/internal/controller/services/scaling_test.go b/infra/feast-operator/internal/controller/services/scaling_test.go index 9c1318d43ea..58e808ac2dc 100644 --- a/infra/feast-operator/internal/controller/services/scaling_test.go +++ b/infra/feast-operator/internal/controller/services/scaling_test.go @@ -30,13 +30,10 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" ) -func ptrIntStr(v intstr.IntOrString) *intstr.IntOrString { - return &v -} - var _ = Describe("Horizontal Scaling", func() { var ( featureStore *feastdevv1.FeatureStore @@ -64,7 +61,7 @@ var _ = Describe("Horizontal Scaling", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, }, @@ -83,11 +80,11 @@ var _ = Describe("Horizontal Scaling", func() { ServerConfigs: feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, }, - GRPC: ptr(true), + GRPC: ptr.To(true), }, Persistence: &feastdevv1.RegistryPersistence{ DBPersistence: &feastdevv1.RegistryDBStorePersistence{ @@ -126,12 +123,12 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should return false when replicas=1", func() { - featureStore.Status.Applied.Replicas = ptr(int32(1)) + featureStore.Status.Applied.Replicas = ptr.To(int32(1)) Expect(isScalingEnabled(featureStore)).To(BeFalse()) }) It("should return true when replicas > 1", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) Expect(isScalingEnabled(featureStore)).To(BeTrue()) }) @@ -171,7 +168,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-valid-db", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: dbRegistry, @@ -187,7 +184,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-no-online", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ Registry: dbRegistry, }, @@ -203,7 +200,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-file-online", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: &feastdevv1.OnlineStore{ Persistence: &feastdevv1.OnlineStorePersistence{ @@ -226,7 +223,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-file-offline", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: dbRegistry, @@ -250,7 +247,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-no-registry", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, }, @@ -266,7 +263,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-file-registry", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: &feastdevv1.Registry{ @@ -291,7 +288,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-s3-registry", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: &feastdevv1.Registry{ @@ -315,7 +312,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-gs-registry", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: &feastdevv1.Registry{ @@ -339,12 +336,12 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-remote-reg", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: &feastdevv1.Registry{ Remote: &feastdevv1.RemoteRegistryConfig{ - Hostname: ptr("registry.example.com:80"), + Hostname: ptr.To("registry.example.com:80"), }, }, }, @@ -359,7 +356,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-rep1-file", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(1)), + Replicas: ptr.To(int32(1)), }, } Expect(k8sClient.Create(ctx, fs)).To(Succeed()) @@ -400,7 +397,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-online-nop", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: &feastdevv1.OnlineStore{}, Registry: dbRegistry, @@ -417,7 +414,7 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-mutual-excl", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ Scaling: &feastdevv1.ScalingConfig{ Autoscaling: &feastdevv1.AutoscalingConfig{MaxReplicas: 5}, @@ -441,7 +438,7 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should return static replicas when configured", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) replicas := feast.getDesiredReplicas() Expect(replicas).NotTo(BeNil()) Expect(*replicas).To(Equal(int32(3))) @@ -465,13 +462,13 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should default to RollingUpdate when scaling is enabled via replicas", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) strategy := feast.getDeploymentStrategy() Expect(strategy.Type).To(Equal(appsv1.RollingUpdateDeploymentStrategyType)) }) It("should respect user-defined strategy even with scaling", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) featureStore.Status.Applied.Services.DeploymentStrategy = &appsv1.DeploymentStrategy{ Type: appsv1.RecreateDeploymentStrategyType, } @@ -486,7 +483,7 @@ var _ = Describe("Horizontal Scaling", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, }, @@ -502,11 +499,11 @@ var _ = Describe("Horizontal Scaling", func() { ServerConfigs: feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, }, - GRPC: ptr(true), + GRPC: ptr.To(true), }, Persistence: &feastdevv1.RegistryPersistence{ FilePersistence: &feastdevv1.RegistryFilePersistence{ @@ -519,7 +516,7 @@ var _ = Describe("Horizontal Scaling", func() { It("should set static replicas on the deployment", func() { setFilePersistence() - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) deployment := feast.initFeastDeploy() Expect(feast.setDeployment(deployment)).To(Succeed()) @@ -573,7 +570,7 @@ var _ = Describe("Horizontal Scaling", func() { It("should build an HPA apply config with custom min replicas", func() { featureStore.Status.Applied.Services.Scaling = &feastdevv1.ScalingConfig{ Autoscaling: &feastdevv1.AutoscalingConfig{ - MinReplicas: ptr(int32(2)), + MinReplicas: ptr.To(int32(2)), MaxReplicas: 10, }, } @@ -619,7 +616,7 @@ var _ = Describe("Horizontal Scaling", func() { Name: corev1.ResourceMemory, Target: autoscalingv2.MetricTarget{ Type: autoscalingv2.UtilizationMetricType, - AverageUtilization: ptr(int32(75)), + AverageUtilization: ptr.To(int32(75)), }, }, }, @@ -641,10 +638,10 @@ var _ = Describe("Horizontal Scaling", func() { Describe("PDB Configuration", func() { It("should build a PDB apply config with maxUnavailable", func() { maxUnavail := intstr.FromInt(1) - featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + featureStore.Status.Applied.Services.PodDisruptionBudgets = &feastdevv1.PDBConfig{ MaxUnavailable: &maxUnavail, } - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) pdb := feast.buildPDBApplyConfig() Expect(*pdb.Kind).To(Equal("PodDisruptionBudget")) @@ -657,10 +654,10 @@ var _ = Describe("Horizontal Scaling", func() { It("should build a PDB apply config with minAvailable", func() { minAvail := intstr.FromString("50%") - featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + featureStore.Status.Applied.Services.PodDisruptionBudgets = &feastdevv1.PDBConfig{ MinAvailable: &minAvail, } - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) pdb := feast.buildPDBApplyConfig() Expect(pdb.Spec.MinAvailable).NotTo(BeNil()) @@ -670,10 +667,10 @@ var _ = Describe("Horizontal Scaling", func() { It("should set owner reference on PDB for SSA", func() { maxUnavail := intstr.FromInt(1) - featureStore.Status.Applied.Services.PDB = &feastdevv1.PDBConfig{ + featureStore.Status.Applied.Services.PodDisruptionBudgets = &feastdevv1.PDBConfig{ MaxUnavailable: &maxUnavail, } - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) pdb := feast.buildPDBApplyConfig() Expect(pdb.OwnerReferences).To(HaveLen(1)) @@ -707,13 +704,13 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-both", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: dbRegistry, - PDB: &feastdevv1.PDBConfig{ - MinAvailable: ptrIntStr(intstr.FromInt(1)), - MaxUnavailable: ptrIntStr(intstr.FromInt(1)), + PodDisruptionBudgets: &feastdevv1.PDBConfig{ + MinAvailable: ptr.To(intstr.FromInt(1)), + MaxUnavailable: ptr.To(intstr.FromInt(1)), }, }, }, @@ -728,11 +725,11 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-none", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ - OnlineStore: dbOnlineStore, - Registry: dbRegistry, - PDB: &feastdevv1.PDBConfig{}, + OnlineStore: dbOnlineStore, + Registry: dbRegistry, + PodDisruptionBudgets: &feastdevv1.PDBConfig{}, }, }, } @@ -746,12 +743,12 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-maxu", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: dbRegistry, - PDB: &feastdevv1.PDBConfig{ - MaxUnavailable: ptrIntStr(intstr.FromInt(1)), + PodDisruptionBudgets: &feastdevv1.PDBConfig{ + MaxUnavailable: ptr.To(intstr.FromInt(1)), }, }, }, @@ -765,12 +762,12 @@ var _ = Describe("Horizontal Scaling", func() { ObjectMeta: metav1.ObjectMeta{Name: "cel-pdb-mina", Namespace: "default"}, Spec: feastdevv1.FeatureStoreSpec{ FeastProject: "celtest", - Replicas: ptr(int32(3)), + Replicas: ptr.To(int32(3)), Services: &feastdevv1.FeatureStoreServices{ OnlineStore: dbOnlineStore, Registry: dbRegistry, - PDB: &feastdevv1.PDBConfig{ - MinAvailable: ptrIntStr(intstr.FromString("50%")), + PodDisruptionBudgets: &feastdevv1.PDBConfig{ + MinAvailable: ptr.To(intstr.FromString("50%")), }, }, }, @@ -782,7 +779,7 @@ var _ = Describe("Horizontal Scaling", func() { Describe("Topology Spread", func() { It("should auto-inject soft zone constraint when replicas > 1 and no explicit constraints", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) podSpec := &corev1.PodSpec{} feast.applyTopologySpread(podSpec) @@ -814,7 +811,7 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should use user-provided constraints instead of defaults", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) featureStore.Status.Applied.Services.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{{ MaxSkew: 2, TopologyKey: "kubernetes.io/hostname", @@ -832,7 +829,7 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should disable auto-injection when empty array is set", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) featureStore.Status.Applied.Services.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{} podSpec := &corev1.PodSpec{} @@ -844,7 +841,7 @@ var _ = Describe("Horizontal Scaling", func() { Describe("Pod Anti-Affinity", func() { It("should auto-inject soft node anti-affinity when replicas > 1", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) podSpec := &corev1.PodSpec{} feast.applyAffinity(podSpec) @@ -878,7 +875,7 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should use user-provided affinity instead of defaults", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) featureStore.Status.Applied.Services.Affinity = &corev1.Affinity{ PodAntiAffinity: &corev1.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{ @@ -897,7 +894,7 @@ var _ = Describe("Horizontal Scaling", func() { }) It("should allow user to set node affinity alongside anti-affinity", func() { - featureStore.Status.Applied.Replicas = ptr(int32(3)) + featureStore.Status.Applied.Replicas = ptr.To(int32(3)) featureStore.Status.Applied.Services.Affinity = &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ @@ -995,7 +992,7 @@ var _ = Describe("Horizontal Scaling", func() { It("should read the status replicas from the scale sub-resource", func() { fs := newDBFeatureStore("scale-sub-status") - fs.Spec.Replicas = ptr(int32(2)) + fs.Spec.Replicas = ptr.To(int32(2)) Expect(k8sClient.Create(ctx, fs)).To(Succeed()) defer func() { Expect(k8sClient.Delete(ctx, fs)).To(Succeed()) }() diff --git a/infra/feast-operator/internal/controller/services/services.go b/infra/feast-operator/internal/controller/services/services.go index 06542399151..fe8f3ecbc15 100644 --- a/infra/feast-operator/internal/controller/services/services.go +++ b/infra/feast-operator/internal/controller/services/services.go @@ -84,7 +84,7 @@ func (feast *FeastServices) Deploy() error { if err := feast.createOrDeleteHPA(); err != nil { return err } - if err := feast.createOrDeletePDB(); err != nil { + if err := feast.applyOrDeletePDB(); err != nil { return err } if err := feast.deployClient(); err != nil { diff --git a/infra/feast-operator/internal/controller/services/services_test.go b/infra/feast-operator/internal/controller/services/services_test.go index b8863e10a74..d53caa3e25f 100644 --- a/infra/feast-operator/internal/controller/services/services_test.go +++ b/infra/feast-operator/internal/controller/services/services_test.go @@ -27,12 +27,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" ) -func ptr[T any](v T) *T { - return &v -} - func (feast *FeastServices) refreshFeatureStore(ctx context.Context, key types.NamespacedName) { fs := &feastdevv1.FeatureStore{} Expect(k8sClient.Get(ctx, key, fs)).To(Succeed()) @@ -54,8 +51,8 @@ var _ = Describe("Registry Service", func() { ) var setFeatureStoreServerConfig = func(grpcEnabled, restEnabled bool) { - featureStore.Spec.Services.Registry.Local.Server.GRPC = ptr(grpcEnabled) - featureStore.Spec.Services.Registry.Local.Server.RestAPI = ptr(restEnabled) + featureStore.Spec.Services.Registry.Local.Server.GRPC = ptr.To(grpcEnabled) + featureStore.Spec.Services.Registry.Local.Server.RestAPI = ptr.To(restEnabled) Expect(k8sClient.Update(ctx, featureStore)).To(Succeed()) Expect(feast.ApplyDefaults()).To(Succeed()) applySpecToStatus(featureStore) @@ -83,12 +80,12 @@ var _ = Describe("Registry Service", func() { ServerConfigs: feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, }, - GRPC: ptr(true), - RestAPI: ptr(false), + GRPC: ptr.To(true), + RestAPI: ptr.To(false), }, }, }, @@ -248,7 +245,7 @@ var _ = Describe("Registry Service", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, OptionalCtrConfigs: feastdevv1.OptionalCtrConfigs{ NodeSelector: &onlineNodeSelector, @@ -284,7 +281,7 @@ var _ = Describe("Registry Service", func() { featureStore.Spec.Services.UI = &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, OptionalCtrConfigs: feastdevv1.OptionalCtrConfigs{ NodeSelector: &uiNodeSelector, @@ -332,7 +329,7 @@ var _ = Describe("Registry Service", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, OptionalCtrConfigs: feastdevv1.OptionalCtrConfigs{ NodeSelector: &onlineNodeSelector, @@ -349,7 +346,7 @@ var _ = Describe("Registry Service", func() { featureStore.Spec.Services.UI = &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, OptionalCtrConfigs: feastdevv1.OptionalCtrConfigs{ NodeSelector: &uiNodeSelector, @@ -377,7 +374,7 @@ var _ = Describe("Registry Service", func() { It("should enable metrics on the online service when configured", func() { featureStore.Spec.Services.OnlineStore = &feastdevv1.OnlineStore{ - Server: &feastdevv1.ServerConfigs{Metrics: ptr(true)}, + Server: &feastdevv1.ServerConfigs{Metrics: ptr.To(true)}, } Expect(k8sClient.Update(ctx, featureStore)).To(Succeed()) @@ -451,7 +448,7 @@ var _ = Describe("Registry Service", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, WorkerConfigs: &feastdevv1.WorkerConfigs{ @@ -503,7 +500,7 @@ var _ = Describe("Registry Service", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, WorkerConfigs: &feastdevv1.WorkerConfigs{ @@ -545,7 +542,7 @@ var _ = Describe("Registry Service", func() { Server: &feastdevv1.ServerConfigs{ ContainerConfigs: feastdevv1.ContainerConfigs{ DefaultCtrConfigs: feastdevv1.DefaultCtrConfigs{ - Image: ptr("test-image"), + Image: ptr.To("test-image"), }, }, // WorkerConfigs is not set (nil) diff --git a/infra/website/docs/blog/scaling-feast-feature-server.md b/infra/website/docs/blog/scaling-feast-feature-server.md index 0e55ab0fa2d..994811ea0ac 100644 --- a/infra/website/docs/blog/scaling-feast-feature-server.md +++ b/infra/website/docs/blog/scaling-feast-feature-server.md @@ -1,8 +1,8 @@ --- title: Feature Server High-Availability and Auto-Scaling on Kubernetes description: The Feast Operator now supports horizontal scaling with static replicas, HPA autoscaling, KEDA, and high-availability features including PodDisruptionBudgets and topology spread constraints. -date: 2026-02-27 -authors: ["Nikhil Kathole"] +date: 2026-03-02 +authors: ["Nikhil Kathole", "Antonin Stefanutti"] --- # Feature Server High-Availability and Auto-Scaling on Kubernetes @@ -79,7 +79,7 @@ spec: target: type: Utilization averageUtilization: 70 - pdb: + podDisruptionBudgets: maxUnavailable: 1 onlineStore: persistence: @@ -204,7 +204,7 @@ For protection during voluntary disruptions (node drains, cluster upgrades), you spec: replicas: 3 services: - pdb: + podDisruptionBudgets: maxUnavailable: 1 onlineStore: # ... @@ -275,7 +275,7 @@ Scaling is designed to work seamlessly with existing operator features: spec: replicas: 3 # static replicas (top-level) services: - pdb: # optional: protect against disruptions + podDisruptionBudgets: # optional: protect against disruptions maxUnavailable: 1 # -- OR -- # services: @@ -283,7 +283,7 @@ spec: # autoscaling: # HPA # minReplicas: 2 # maxReplicas: 10 - # pdb: + # podDisruptionBudgets: # maxUnavailable: 1 ```