diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md index 2a288bb48aa..9ea8def1f18 100644 --- a/infra/charts/feast/README.md +++ b/infra/charts/feast/README.md @@ -1,8 +1,8 @@ -# Feast Java Helm Charts (alpha) +# Feast Helm Charts -This repo contains Helm charts for Feast Java components that are being installed on Kubernetes: +This repo contains Helm charts for Feast components that are being installed on Kubernetes: * Feast (root chart): The complete Helm chart containing all Feast components and dependencies. Most users will use this chart, but can selectively enable/disable subcharts using the values.yaml file. - * [Feature Server](charts/feature-server): High performant JVM-based implementation of feature server. + * [Feature Server](charts/feature-server): Python-based online feature serving service. * [Transformation Service](charts/transformation-service): Transformation server for calculating on-demand features * Redis: (Optional) One of possible options for an online store used by Feature Server @@ -21,45 +21,39 @@ helm repo add feast-charts https://feast-helm-charts.storage.googleapis.com helm repo update ``` -Install Feast +Install Feast (using an existing Secret — recommended for production): ``` -helm install feast-release feast-charts/feast +kubectl create secret generic my-feast-config \ + --from-literal=feature_store_yaml_base64=$(base64 < feature_store.yaml) + +helm install feast-release feast-charts/feast \ + --set feature-server.existingSecret=my-feast-config +``` + +Or pass the config inline (the value will be stored in Helm release metadata): +``` +helm install feast-release feast-charts/feast \ + --set feature-server.feature_store_yaml_base64=$(base64 < feature_store.yaml) ``` ## Customize your installation This Feast chart comes with a [values.yaml](values.yaml) that allows for configuration and customization of all sub-charts. -In order to modify the default configuration of Feature Server, please use the `application-override.yaml` key in the `values.yaml` file in this chart. A code snippet example -``` -feature-server: - application-override.yaml: - enabled: true - feast: - active_store: online - stores: - - name: online - type: REDIS - config: - host: localhost - port: 6379 - entityKeySerializationVersion: 3 - -global: - registry: - path: gs://[YOUR GCS BUCKET]/demo-repo/registry.db - cache_ttl_seconds: 60 - project: feast_java_demo +The feature server requires a base64-encoded `feature_store.yaml`. You can either reference a pre-existing Kubernetes Secret or provide the value inline: +```yaml +feature-server: + # Option A: reference an existing Secret (recommended) + existingSecret: my-feast-config + # Option B: provide inline (stored in Helm release metadata) + feature_store_yaml_base64: ``` -For the default configuration, please see the [Feature Server Configuration](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). +> **Upgrading from the Java chart?** See the [feature-server migration guide](charts/feature-server/README.md#migration-from-java-chart) for details on removed gRPC and Java-specific values. For more details, please see: https://docs.feast.dev/how-to-guides/running-feast-in-production -## Example -See [here](https://github.com/feast-dev/feast/tree/master/examples/java-demo) for a sample tutorial on testing this helm chart with a demo feature repository and a local Redis instance. - ## Requirements | Repository | Name | Version | @@ -79,4 +73,4 @@ See [here](https://github.com/feast-dev/feast/tree/master/examples/java-demo) fo | global.registry.path | string | `"gs://path/to/registry.db"` | Path to the registry file managed by Feast Python SDK | | redis.enabled | bool | `false` | Flag to install Redis | | redis.usePassword | bool | `false` | Disable redis password | -| transformation-service.enabled | bool | `true` | | \ No newline at end of file +| transformation-service.enabled | bool | `true` | | diff --git a/infra/charts/feast/charts/feature-server/README.md b/infra/charts/feast/charts/feature-server/README.md index 571449d9009..b7f357252f3 100644 --- a/infra/charts/feast/charts/feature-server/README.md +++ b/infra/charts/feast/charts/feature-server/README.md @@ -6,47 +6,103 @@ Feast Feature Server: Online feature serving service for Feast **Homepage:** +## Migration from Java chart + +This chart now deploys the Python-based feature server instead of the Java-based one. + +### Removed values (no equivalent) + +These Java-specific values have been removed. Delete them from your values files: + +| Removed value | Reason | +|---|---| +| `javaOpts` | Python server, no JVM | +| `logType`, `logLevel` | Java logging config, not applicable | +| `transformationService.*` | Use the separate `transformation-service` subchart | +| `application.yaml`, `application-generated.yaml` | Java Spring config, not applicable | +| `application-override.yaml` | Replaced by `feature_store_yaml_base64` or `existingSecret` | +| `application-secret.yaml` | Replaced by `feature_store_yaml_base64` or `existingSecret` | + +### Changed values + +| Old value | New value | Notes | +|---|---|---| +| `service.grpc.port` | `service.port` | Protocol changed from gRPC to HTTP | +| `service.grpc.targetPort` | (removed) | `targetPort` now uses the named port `http` | +| `service.grpc.nodePort` | `service.nodePort` | Flat key | +| `ingress.grpc.*` | (removed) | Python server is HTTP-only | +| `ingress.http.class` | (removed) | Use `ingress.http.ingressClassName` or `annotations` | +| `ingress.http.auth.*` | (removed) | Use `ingress.http.annotations` for controller-specific auth | +| `ingress.http.whitelist` | (removed) | Use `ingress.http.annotations` for controller-specific whitelist | +| `image.repository` | `image.repository` | Changed from `feature-server-java` to `feature-server` | + +### New values + +| Value | Purpose | +|---|---| +| `feature_store_yaml_base64` | Base64-encoded `feature_store.yaml`, stored in a K8s Secret | +| `existingSecret` | Reference a pre-created Secret instead of providing inline config | +| `ingress.http.ingressClassName` | Support for `networking.k8s.io/v1` IngressClass | + +### What still works + +- `ingress.http.*` — same value structure, now uses `networking.k8s.io/v1` +- `secrets` — volume mounts for additional Kubernetes secrets +- `envOverrides` — extra environment variables +- `service.type`, `service.loadBalancerIP`, `service.loadBalancerSourceRanges` +- All probe settings (`livenessProbe.*`, `readinessProbe.*`) + +## Installation + +### Option A: Using an existing Secret (recommended) + +Create the Secret outside of Helm so that credentials never pass through Helm values or release metadata: + +```bash +kubectl create secret generic my-feast-config \ + --from-literal=feature_store_yaml_base64=$(base64 < feature_store.yaml) +``` + +Then reference it during install: +```bash +helm install feast-feature-server . --set existingSecret=my-feast-config +``` + +This is the recommended approach when `feature_store.yaml` contains registry or online-store credentials. + +### Option B: Using inline config + +```bash +helm install feast-feature-server . --set feature_store_yaml_base64=$(base64 < feature_store.yaml) +``` + +> **Note:** When using `--set`, the base64-encoded config is stored in Helm release metadata and is retrievable via `helm get values`. Use Option A or an external secrets operator (e.g. SealedSecrets, ExternalSecrets) for production deployments with sensitive credentials. + ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| -| "application-generated.yaml".enabled | bool | `true` | Flag to include Helm generated configuration. Please set `application-override.yaml` to override this configuration. | -| "application-override.yaml" | object | `{"enabled":true}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a ConfigMap. `application-override.yaml` has a higher precedence than `application-secret.yaml` | -| "application-secret.yaml" | object | `{"enabled":false}` | Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a Secret. `application-override.yaml` has a higher precedence than `application-secret.yaml`. It is recommended to either set `application-override.yaml` or `application-secret.yaml` only to simplify config management. | -| "application.yaml".enabled | bool | `true` | Flag to include the default [configuration](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Please set `application-override.yaml` to override this configuration. | | envOverrides | object | `{}` | Extra environment variables to set | +| existingSecret | string | `""` | Name of an existing Secret containing key `feature_store_yaml_base64` with base64-encoded config | +| feature_store_yaml_base64 | string | `""` | [required] a base64 encoded version of feature_store.yaml (stored in a K8s Secret) | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | -| image.repository | string | `"quay.io/feastdev/feature-server-java"` | Docker image for Feature Server repository | +| image.repository | string | `"quay.io/feastdev/feature-server"` | Docker image for Feature Server repository | | image.tag | string | `"0.65.0"` | Image tag | -| ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress | -| ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth | -| ingress.grpc.class | string | `"nginx"` | Which ingress controller to use | -| ingress.grpc.enabled | bool | `false` | Flag to create an ingress resource for the service | -| ingress.grpc.hosts | list | `[]` | List of hostnames to match when routing requests | -| ingress.grpc.https.enabled | bool | `true` | Flag to enable HTTPS | -| ingress.grpc.https.secretNames | object | `{}` | Map of hostname to TLS secret name | -| ingress.grpc.whitelist | string | `""` | Allowed client IP source ranges | -| ingress.http.annotations | object | `{}` | Extra annotations for the ingress | -| ingress.http.auth.authUrl | string | `"http://auth-server.auth-ns.svc.cluster.local/auth"` | URL to an existing authentication service | -| ingress.http.auth.enabled | bool | `false` | Flag to enable auth | -| ingress.http.class | string | `"nginx"` | Which ingress controller to use | +| ingress.http.annotations | object | `{}` | Extra annotations for the ingress (use for controller-specific settings) | | ingress.http.enabled | bool | `false` | Flag to create an ingress resource for the service | | ingress.http.hosts | list | `[]` | List of hostnames to match when routing requests | | ingress.http.https.enabled | bool | `true` | Flag to enable HTTPS | | ingress.http.https.secretNames | object | `{}` | Map of hostname to TLS secret name | -| ingress.http.whitelist | string | `""` | Allowed client IP source ranges | -| javaOpts | string | `nil` | [JVM options](https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html). For better performance, it is advised to set the min and max heap:
`-Xms2048m -Xmx2048m` | +| ingress.http.ingressClassName | string | `nil` | IngressClass resource name | | livenessProbe.enabled | bool | `true` | Flag to enabled the probe | | livenessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed | | livenessProbe.initialDelaySeconds | int | `60` | Delay before the probe is initiated | | livenessProbe.periodSeconds | int | `10` | How often to perform the probe | | livenessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful | | livenessProbe.timeoutSeconds | int | `5` | When the probe times out | -| logLevel | string | `"WARN"` | Default log level, use either one of `DEBUG`, `INFO`, `WARN` or `ERROR` | -| logType | string | `"Console"` | Log format, either `JSON` or `Console` | | nodeSelector | object | `{}` | Node labels for pod assignment | -| podAnnotations | object | `{}` | Annotations to be added to Feast Serving pods | -| podLabels | object | `{}` | Labels to be added to Feast Serving pods | +| podAnnotations | object | `{}` | Annotations to be added to Feature Server pods | +| podLabels | object | `{}` | Labels to be added to Feature Server pods | | readinessProbe.enabled | bool | `true` | Flag to enabled the probe | | readinessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed | | readinessProbe.initialDelaySeconds | int | `15` | Delay before the probe is initiated | @@ -55,13 +111,12 @@ Feast Feature Server: Online feature serving service for Feast | readinessProbe.timeoutSeconds | int | `10` | When the probe times out | | replicaCount | int | `1` | Number of pods that will be created | | resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) | -| secrets | list | `[]` | List of Kubernetes secrets to be mounted. These secrets will be mounted on /etc/secrets/. | -| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to | -| service.grpc.port | int | `6566` | Service port for GRPC requests | -| service.grpc.targetPort | int | `6566` | Container port serving GRPC requests | +| secrets | list | `[]` | List of Kubernetes secrets to be mounted on /etc/secrets/\ | +| service.loadBalancerIP | string | `nil` | Specify a load balancer IP if service type is LoadBalancer | +| service.loadBalancerSourceRanges | list | `[]` | Optionally restrict load balancer traffic to specified IPs | +| service.nodePort | string | `nil` | Port number that each cluster node will listen to | +| service.port | int | `6566` | Service port | | service.type | string | `"ClusterIP"` | Kubernetes service type | -| transformationService.host | string | `""` | | -| transformationService.port | int | `6566` | | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/infra/charts/feast/charts/feature-server/templates/NOTES.txt b/infra/charts/feast/charts/feature-server/templates/NOTES.txt new file mode 100644 index 00000000000..4cf3efbf439 --- /dev/null +++ b/infra/charts/feast/charts/feature-server/templates/NOTES.txt @@ -0,0 +1,23 @@ +Feast Feature Server has been deployed. + +{{- if and (not .Values.existingSecret) (not .Values.feature_store_yaml_base64) }} + +WARNING: Neither "existingSecret" nor "feature_store_yaml_base64" is set. + The feature server will fail to start without a valid feature_store.yaml. + + Option A (recommended): create a Secret and reference it: + kubectl create secret generic my-feast-config \ + --from-literal=feature_store_yaml_base64=$(base64 < feature_store.yaml) + helm upgrade {{ .Release.Name }} . --set existingSecret=my-feast-config + + Option B: provide inline: + helm upgrade {{ .Release.Name }} . \ + --set feature_store_yaml_base64=$(base64 < feature_store.yaml) +{{- end }} + +{{- if and .Values.feature_store_yaml_base64 (not .Values.existingSecret) }} + +NOTE: "feature_store_yaml_base64" is stored in Helm release metadata. + If feature_store.yaml contains credentials, consider using "existingSecret" + to keep sensitive data out of Helm values. +{{- end }} diff --git a/infra/charts/feast/charts/feature-server/templates/_helpers.tpl b/infra/charts/feast/charts/feature-server/templates/_helpers.tpl index 23f2d810574..bf289108332 100644 --- a/infra/charts/feast/charts/feature-server/templates/_helpers.tpl +++ b/infra/charts/feast/charts/feature-server/templates/_helpers.tpl @@ -25,21 +25,21 @@ If release name contains chart name it will be used as a full name. {{- end -}} {{/* -Create chart name and version as used by the chart label. +Common labels */}} -{{- define "feature-server.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- define "feature-server.labels" -}} +app: {{ include "feature-server.name" . }} +component: serving +chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +release: {{ .Release.Name }} +heritage: {{ .Release.Service }} {{- end -}} {{/* -Common labels +Selector labels */}} -{{- define "feature-server.labels" -}} -app.kubernetes.io/name: {{ include "feature-server.name" . }} -helm.sh/chart: {{ include "feature-server.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- define "feature-server.selectorLabels" -}} +app: {{ include "feature-server.name" . }} +component: serving +release: {{ .Release.Name }} {{- end -}} diff --git a/infra/charts/feast/charts/feature-server/templates/_ingress.yaml b/infra/charts/feast/charts/feature-server/templates/_ingress.yaml deleted file mode 100644 index 5bed6df0470..00000000000 --- a/infra/charts/feast/charts/feature-server/templates/_ingress.yaml +++ /dev/null @@ -1,68 +0,0 @@ -{{- /* -This takes an array of three values: -- the top context -- the feast component -- the service protocol -- the ingress context -*/ -}} -{{- define "feast.ingress" -}} -{{- $top := (index . 0) -}} -{{- $component := (index . 1) -}} -{{- $protocol := (index . 2) -}} -{{- $ingressValues := (index . 3) -}} -apiVersion: extensions/v1beta1 -kind: Ingress -{{ include "feast.ingress.metadata" . }} -spec: - rules: - {{- range $host := $ingressValues.hosts }} - - host: {{ $host }} - http: - paths: - - path: / - backend: - serviceName: {{ include (printf "feast-%s.fullname" $component) $top }} - servicePort: {{ index $top.Values "service" $protocol "port" }} - {{- end }} -{{- if $ingressValues.https.enabled }} - tls: - {{- range $host := $ingressValues.hosts }} - - secretName: {{ index $ingressValues.https.secretNames $host | default (splitList "." $host | rest | join "-" | printf "%s-tls") }} - hosts: - - {{ $host }} - {{- end }} -{{- end -}} -{{- end -}} - -{{- define "feast.ingress.metadata" -}} -{{- $commonMetadata := fromYaml (include "common.metadata" (first .)) }} -{{- $overrides := fromYaml (include "feast.ingress.metadata-overrides" .) -}} -{{- toYaml (merge $overrides $commonMetadata) -}} -{{- end -}} - -{{- define "feast.ingress.metadata-overrides" -}} -{{- $top := (index . 0) -}} -{{- $component := (index . 1) -}} -{{- $protocol := (index . 2) -}} -{{- $ingressValues := (index . 3) -}} -{{- $commonFullname := include "common.fullname" $top }} -metadata: - name: {{ $commonFullname }}-{{ $component }}-{{ $protocol }} - annotations: - kubernetes.io/ingress.class: {{ $ingressValues.class | quote }} - {{- if (and (eq $ingressValues.class "nginx") $ingressValues.auth.enabled) }} - nginx.ingress.kubernetes.io/auth-url: {{ $ingressValues.auth.authUrl | quote }} - nginx.ingress.kubernetes.io/auth-response-headers: "x-auth-request-email, x-auth-request-user" - nginx.ingress.kubernetes.io/auth-signin: "https://{{ $ingressValues.auth.signinHost | default (splitList "." (index $ingressValues.hosts 0) | rest | join "." | printf "auth.%s")}}/oauth2/start?rd=/r/$host/$request_uri" - {{- end }} - {{- if (and (eq $ingressValues.class "nginx") $ingressValues.whitelist) }} - nginx.ingress.kubernetes.io/whitelist-source-range: {{ $ingressValues.whitelist | quote -}} - {{- end }} - {{- if (and (eq $ingressValues.class "nginx") (eq $protocol "grpc") ) }} - # TODO: Allow choice of GRPC/GRPCS - nginx.ingress.kubernetes.io/backend-protocol: "GRPC" - {{- end }} - {{- if $ingressValues.annotations -}} - {{ include "common.annote" $ingressValues.annotations | indent 4 }} - {{- end }} -{{- end -}} diff --git a/infra/charts/feast/charts/feature-server/templates/configmap.yaml b/infra/charts/feast/charts/feature-server/templates/configmap.yaml deleted file mode 100644 index c172e9e288a..00000000000 --- a/infra/charts/feast/charts/feature-server/templates/configmap.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "feature-server.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "feature-server.name" . }} - component: serving - chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - application-generated.yaml: | -{{- if index .Values "application-generated.yaml" "enabled" }} - feast: - registry: {{ .Values.global.registry.path }} - registryRefreshInterval: {{ .Values.global.registry.cache_ttl_seconds }} - {{- if .Values.transformationService.host }} - transformationServiceEndpoint: {{ .Values.transformationService.host}}:{{ .Values.transformationService.port }} - {{- else }} - transformationServiceEndpoint: {{ .Release.Name }}-transformation-service:{{ .Values.transformationService.port }} - {{- end }} - - activeStore: online - stores: - - name: online - type: REDIS - config: - host: {{ .Release.Name }}-redis-master - port: 6379 - grpc: - server: - port: {{ .Values.service.grpc.targetPort }} -{{- end }} - - application-override.yaml: | -{{- if index .Values "application-override.yaml" "enabled" }} - {{- if index .Values "application-override.yaml" "feast" }} - feast: {{- toYaml (index .Values "application-override.yaml" "feast") | nindent 6 }} - registry: {{ .Values.global.registry.path }} - registryRefreshInterval: {{ .Values.global.registry.cache_ttl_seconds }} - project: {{ .Values.global.project }} - {{- end }} - {{- if index .Values "application-override.yaml" "rest" }} - rest: {{- toYaml (index .Values "application-override.yaml" "rest") | nindent 6 }} - {{- end }} - {{- if index .Values "application-override.yaml" "grpc" }} - grpc: {{- toYaml (index .Values "application-override.yaml" "grpc") | nindent 6 }} - {{- end }} -{{- end }} diff --git a/infra/charts/feast/charts/feature-server/templates/deployment.yaml b/infra/charts/feast/charts/feature-server/templates/deployment.yaml index ad0a12b3fc7..b7cc56e5fed 100644 --- a/infra/charts/feast/charts/feature-server/templates/deployment.yaml +++ b/infra/charts/feast/charts/feature-server/templates/deployment.yaml @@ -4,32 +4,27 @@ metadata: name: {{ template "feature-server.fullname" . }} namespace: {{ .Release.Namespace }} labels: - app: {{ template "feature-server.name" . }} - component: serving - chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + {{- include "feature-server.labels" . | nindent 4 }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - app: {{ template "feature-server.name" . }} - component: serving - release: {{ .Release.Name }} + {{- include "feature-server.selectorLabels" . | nindent 6 }} template: metadata: + {{- if or (not .Values.existingSecret) .Values.podAnnotations }} annotations: - checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if not .Values.existingSecret }} checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} - {{- if .Values.podAnnotations }} - {{ toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} labels: - app: {{ template "feature-server.name" . }} - component: serving - release: {{ .Release.Name }} + {{- include "feature-server.selectorLabels" . | nindent 8 }} {{- if .Values.podLabels }} - {{ toYaml .Values.podLabels | nindent 8 }} + {{- toYaml .Values.podLabels | nindent 8 }} {{- end }} spec: {{- with .Values.nodeSelector }} @@ -37,46 +32,26 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} + {{- if .Values.secrets }} volumes: - - name: {{ template "feature-server.fullname" . }}-config - configMap: - name: {{ template "feature-server.fullname" . }} - - name: {{ template "feature-server.fullname" . }}-secret - secret: - secretName: {{ template "feature-server.fullname" . }} {{- range $secret := .Values.secrets }} - name: {{ $secret }} secret: secretName: {{ $secret }} {{- end }} + {{- end }} containers: - name: {{ .Chart.Name }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} - volumeMounts: - - name: {{ template "feature-server.fullname" . }}-config - mountPath: /etc/feast - - name: {{ template "feature-server.fullname" . }}-secret - mountPath: /etc/secrets/feast - readOnly: true - {{- range $secret := .Values.secrets }} - - name: {{ $secret }} - mountPath: "/etc/secrets/{{ $secret }}" - readOnly: true - {{- end }} - env: - - name: LOG_TYPE - value: {{ .Values.logType | quote }} - - name: LOG_LEVEL - value: {{ .Values.logLevel | quote }} - - {{- if .Values.javaOpts }} - - name: JAVA_TOOL_OPTIONS - value: {{ .Values.javaOpts }} - {{- end }} + - name: FEATURE_STORE_YAML_BASE64 + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecret | default (include "feature-server.fullname" .) }} + key: feature_store_yaml_base64 {{- range $key, $value := .Values.envOverrides }} - name: {{ printf "%s" $key | replace "." "_" | upper | quote }} @@ -89,53 +64,46 @@ spec: {{- end }} command: - - java - - -jar - - /opt/feast/feast-serving.jar - - {{ if index .Values "application.yaml" "enabled" -}} - classpath:/application.yml - {{- end }} - {{- if index .Values "application-generated.yaml" "enabled" -}} - ,file:/etc/feast/application-generated.yaml - {{- end }} - {{- if index .Values "application-secret.yaml" "enabled" -}} - ,file:/etc/secrets/feast/application-secret.yaml - {{- end }} - {{- if index .Values "application-override.yaml" "enabled" -}} - ,file:/etc/feast/application-override.yaml - {{- end }} + - "feast" + - "serve" + - "-h" + - "0.0.0.0" + - "-p" + - "{{ .Values.service.port }}" ports: - - name: grpc - containerPort: {{ .Values.service.grpc.targetPort }} + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + + {{- if .Values.secrets }} + volumeMounts: + {{- range $secret := .Values.secrets }} + - name: {{ $secret }} + mountPath: "/etc/secrets/{{ $secret }}" + readOnly: true + {{- end }} + {{- end }} {{- if .Values.livenessProbe.enabled }} livenessProbe: - exec: - command: - - "grpc-health-probe" - - "-addr=:{{ .Values.service.grpc.targetPort }}" - - "-connect-timeout={{ .Values.livenessProbe.timeoutSeconds }}s" - - "-rpc-timeout={{ .Values.livenessProbe.timeoutSeconds }}s" + tcpSocket: + port: http initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} failureThreshold: {{ .Values.livenessProbe.failureThreshold }} {{- end }} {{- if .Values.readinessProbe.enabled }} readinessProbe: - exec: - command: - - "grpc-health-probe" - - "-addr=:{{ .Values.service.grpc.targetPort }}" - - "-connect-timeout={{ .Values.readinessProbe.timeoutSeconds }}s" - - "-rpc-timeout={{ .Values.readinessProbe.timeoutSeconds }}s" + tcpSocket: + port: http initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} failureThreshold: {{ .Values.readinessProbe.failureThreshold }} {{- end }} diff --git a/infra/charts/feast/charts/feature-server/templates/ingress.yaml b/infra/charts/feast/charts/feature-server/templates/ingress.yaml index 1bcd176147a..9fe4e5272fd 100644 --- a/infra/charts/feast/charts/feature-server/templates/ingress.yaml +++ b/infra/charts/feast/charts/feature-server/templates/ingress.yaml @@ -1,7 +1,38 @@ -{{- if .Values.ingress.http.enabled -}} -{{ template "feast.ingress" (list . "serving" "http" .Values.ingress.http) }} -{{- end }} ---- -{{ if .Values.ingress.grpc.enabled -}} -{{ template "feast.ingress" (list . "serving" "grpc" .Values.ingress.grpc) }} +{{- if .Values.ingress.http.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ template "feature-server.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "feature-server.labels" . | nindent 4 }} + {{- with .Values.ingress.http.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.http.ingressClassName }} + ingressClassName: {{ .Values.ingress.http.ingressClassName }} + {{- end }} + rules: + {{- range $host := .Values.ingress.http.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "feature-server.fullname" $ }} + port: + name: http + {{- end }} + {{- if .Values.ingress.http.https.enabled }} + tls: + {{- range $host := .Values.ingress.http.hosts }} + - secretName: {{ index $.Values.ingress.http.https.secretNames $host | default (printf "%s-tls" (splitList "." $host | rest | join "-")) }} + hosts: + - {{ $host }} + {{- end }} + {{- end }} {{- end }} diff --git a/infra/charts/feast/charts/feature-server/templates/secret.yaml b/infra/charts/feast/charts/feature-server/templates/secret.yaml index b6aa88c258e..04ffc72f889 100644 --- a/infra/charts/feast/charts/feature-server/templates/secret.yaml +++ b/infra/charts/feast/charts/feature-server/templates/secret.yaml @@ -1,23 +1,12 @@ +{{- if not .Values.existingSecret }} apiVersion: v1 kind: Secret metadata: name: {{ template "feature-server.fullname" . }} namespace: {{ .Release.Namespace }} labels: - app: {{ template "feature-server.name" . }} - component: serving - chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + {{- include "feature-server.labels" . | nindent 4 }} type: Opaque stringData: - application-secret.yaml: | - {{- if index .Values "application-secret.yaml" "feast" }} - feast: {{- toYaml (index .Values "application-secret.yaml" "feast") | nindent 6 }} - {{- end }} - {{- if index .Values "application-secret.yaml" "rest" }} - rest: {{- toYaml (index .Values "application-secret.yaml" "rest") | nindent 6 }} - {{- end }} - {{- if index .Values "application-secret.yaml" "grpc" }} - grpc: {{- toYaml (index .Values "application-secret.yaml" "grpc") | nindent 6 }} - {{- end }} + feature_store_yaml_base64: {{ .Values.feature_store_yaml_base64 | quote }} +{{- end }} diff --git a/infra/charts/feast/charts/feature-server/templates/service.yaml b/infra/charts/feast/charts/feature-server/templates/service.yaml index c2455bd9f75..c7077ee1d21 100644 --- a/infra/charts/feast/charts/feature-server/templates/service.yaml +++ b/infra/charts/feast/charts/feature-server/templates/service.yaml @@ -4,13 +4,10 @@ metadata: name: {{ template "feature-server.fullname" . }} namespace: {{ .Release.Namespace }} labels: - app: {{ template "feature-server.name" . }} - chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} + {{- include "feature-server.labels" . | nindent 4 }} {{- with .Values.service.annotations }} annotations: -{{ toYaml . | indent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} spec: type: {{ .Values.service.type }} @@ -19,16 +16,14 @@ spec: {{- end }} {{- if .Values.service.loadBalancerSourceRanges }} loadBalancerSourceRanges: -{{ toYaml .Values.service.loadBalancerSourceRanges | indent 2 }} + {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 2 }} {{- end }} ports: - - name: grpc - port: {{ .Values.service.grpc.port }} - targetPort: {{ .Values.service.grpc.targetPort }} - {{- if .Values.service.grpc.nodePort }} - nodePort: {{ .Values.service.grpc.nodePort }} + - name: http + port: {{ .Values.service.port }} + targetPort: http + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} {{- end }} selector: - app: {{ template "feature-server.name" . }} - component: serving - release: {{ .Release.Name }} + {{- include "feature-server.selectorLabels" . | nindent 4 }} diff --git a/infra/charts/feast/charts/feature-server/values.yaml b/infra/charts/feast/charts/feature-server/values.yaml index 3367dd665fa..9cdbc9b2b82 100644 --- a/infra/charts/feast/charts/feature-server/values.yaml +++ b/infra/charts/feast/charts/feature-server/values.yaml @@ -3,42 +3,17 @@ replicaCount: 1 image: # image.repository -- Docker image for Feature Server repository - repository: quay.io/feastdev/feature-server-java + repository: quay.io/feastdev/feature-server # image.tag -- Image tag tag: 0.65.0 # image.pullPolicy -- Image pull policy pullPolicy: IfNotPresent +# feature_store_yaml_base64 -- [required] a base64 encoded version of feature_store.yaml. Stored in a Kubernetes Secret (not passed as a plain env value). Ignored when existingSecret is set. +feature_store_yaml_base64: "" -transformationService: - host: "" - port: 6566 - - -application.yaml: - # "application.yaml".enabled -- Flag to include the default [configuration](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Please set `application-override.yaml` to override this configuration. - enabled: true - -application-generated.yaml: - # "application-generated.yaml".enabled -- Flag to include Helm generated configuration. Please set `application-override.yaml` to override this configuration. - enabled: true - -# "application-secret.yaml" -- Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a Secret. `application-override.yaml` has a higher precedence than `application-secret.yaml`. It is recommended to either set `application-override.yaml` or `application-secret.yaml` only to simplify config management. -application-secret.yaml: - enabled: false - -# "application-override.yaml" -- Configuration to override the default [application.yaml](https://github.com/feast-dev/feast/blob/master/java/serving/src/main/resources/application.yml). Will be created as a ConfigMap. `application-override.yaml` has a higher precedence than `application-secret.yaml` -application-override.yaml: - enabled: true - -# javaOpts -- [JVM options](https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html). For better performance, it is advised to set the min and max heap:
`-Xms2048m -Xmx2048m` -javaOpts: - -# logType -- Log format, either `JSON` or `Console` -logType: Console -# logLevel -- Default log level, use either one of `DEBUG`, `INFO`, `WARN` or `ERROR` -logLevel: WARN - +# existingSecret -- Name of an existing Kubernetes Secret that contains the key `feature_store_yaml_base64` with the base64-encoded feature_store.yaml. When set, the chart will not create its own Secret. +existingSecret: "" livenessProbe: # livenessProbe.enabled -- Flag to enabled the probe @@ -71,55 +46,30 @@ readinessProbe: service: # service.type -- Kubernetes service type type: ClusterIP - grpc: - # service.grpc.port -- Service port for GRPC requests - port: 6566 - # service.grpc.targetPort -- Container port serving GRPC requests - targetPort: 6566 - # service.grpc.nodePort -- Port number that each cluster node will listen to - nodePort: + # service.port -- Service port for HTTP requests + port: 6566 + # service.nodePort -- Port number that each cluster node will listen to + nodePort: + # service.loadBalancerIP -- Specify a load balancer IP if service type is LoadBalancer + loadBalancerIP: + # service.loadBalancerSourceRanges -- Optionally restrict load balancer traffic to specified IPs + loadBalancerSourceRanges: [] ingress: - grpc: - # ingress.grpc.enabled -- Flag to create an ingress resource for the service - enabled: false - # ingress.grpc.class -- Which ingress controller to use - class: nginx - # ingress.grpc.hosts -- List of hostnames to match when routing requests - hosts: [] - # ingress.grpc.annotations -- Extra annotations for the ingress - annotations: {} - https: - # ingress.grpc.https.enabled -- Flag to enable HTTPS - enabled: true - # ingress.grpc.https.secretNames -- Map of hostname to TLS secret name - secretNames: {} - # ingress.grpc.whitelist -- Allowed client IP source ranges - whitelist: "" - auth: - # ingress.grpc.auth.enabled -- Flag to enable auth - enabled: false http: # ingress.http.enabled -- Flag to create an ingress resource for the service enabled: false - # ingress.http.class -- Which ingress controller to use - class: nginx + # ingress.http.ingressClassName -- IngressClass resource name (for networking.k8s.io/v1) + ingressClassName: # ingress.http.hosts -- List of hostnames to match when routing requests hosts: [] - # ingress.http.annotations -- Extra annotations for the ingress + # ingress.http.annotations -- Extra annotations for the ingress (use this for controller-specific settings like nginx auth, whitelist, etc.) annotations: {} https: # ingress.http.https.enabled -- Flag to enable HTTPS enabled: true # ingress.http.https.secretNames -- Map of hostname to TLS secret name secretNames: {} - # ingress.http.whitelist -- Allowed client IP source ranges - whitelist: "" - auth: - # ingress.http.auth.enabled -- Flag to enable auth - enabled: false - # ingress.http.auth.authUrl -- URL to an existing authentication service - authUrl: http://auth-server.auth-ns.svc.cluster.local/auth # resources -- CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) resources: {} @@ -133,8 +83,8 @@ envOverrides: {} # secrets -- List of Kubernetes secrets to be mounted. These secrets will be mounted on /etc/secrets/. secrets: [] -# podAnnotations -- Annotations to be added to Feast Serving pods +# podAnnotations -- Annotations to be added to Feature Server pods podAnnotations: {} -# podLabels -- Labels to be added to Feast Serving pods +# podLabels -- Labels to be added to Feature Server pods podLabels: {}