From e0f2d61dbd588a86da2cf4e7da15fbee0b44a31d Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Mon, 4 Nov 2019 14:18:36 +0800 Subject: [PATCH 01/11] Update Dockerfiles for core and serving for Feast 0.3 --- infra/docker/core/Dockerfile | 32 +++++++++++++++---------------- infra/docker/serving/Dockerfile | 34 ++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/infra/docker/core/Dockerfile b/infra/docker/core/Dockerfile index c9c609c7bf..2c717afb90 100644 --- a/infra/docker/core/Dockerfile +++ b/infra/docker/core/Dockerfile @@ -1,19 +1,19 @@ -#FROM maven:3.6-jdk-8-slim as builder -#ARG REVISION=dev -# -#WORKDIR /build -#COPY pom.xml . -#COPY core/pom.xml core/pom.xml -#COPY ingestion/pom.xml ingestion/pom.xml -#COPY serving/pom.xml serving/pom.xml -# -#RUN mvn dependency:go-offline -B -# -#COPY . /build -#WORKDIR /build -#RUN mvn --projects core,ingestion -Drevision=$REVISION -DskipTests=true --batch-mode package +FROM maven:3.6-jdk-8-slim as builder +ARG REVISION=dev +COPY . /build +WORKDIR /build +# Setting Maven repository .m2 directory relative to /build folder gives the +# user to optionally use cached repository when building the image by copying +# the existing .m2 directory to $FEAST_REPO_ROOT/.m2 +ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" +RUN mvn --also-make --projects core,ingestion -Drevision=$REVISION \ + -DskipTests=true --batch-mode package FROM openjdk:8-jre as production ARG REVISION=dev -COPY ./core/target/feast-core-$REVISION.jar /usr/share/feast/feast-core.jar -CMD ["java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-jar", "/usr/share/feast/feast-core.jar"] \ No newline at end of file +COPY --from=builder /build/core/target/feast-core-$REVISION.jar /opt/feast/feast-core.jar +CMD ["java",\ + "-Xms1024m",\ + "-Xmx1024m",\ + "-jar",\ + "/opt/feast/feast-core.jar"] diff --git a/infra/docker/serving/Dockerfile b/infra/docker/serving/Dockerfile index e3d3e3fb15..fd021940ac 100644 --- a/infra/docker/serving/Dockerfile +++ b/infra/docker/serving/Dockerfile @@ -1,16 +1,24 @@ -#FROM maven:3.6-jdk-8-slim as builder -#ARG REVISION=dev -#COPY . /build -#WORKDIR /build -#ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" -#RUN mvn --projects serving -Drevision=$REVISION -DskipTests=true --batch-mode package +FROM maven:3.6-jdk-8-slim as builder +ARG REVISION=dev +COPY . /build +WORKDIR /build +# Setting Maven repository .m2 directory relative to /build folder gives the +# user to optionally use cached repository when building the image by copying +# the existing .m2 directory to $FEAST_REPO_ROOT/.m2 +ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" +RUN mvn --also-make --projects serving -Drevision=$REVISION \ + -DskipTests=true --batch-mode package FROM openjdk:8-jre-alpine as production ARG REVISION=dev - -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ - wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ - chmod +x /bin/grpc_health_probe - -COPY ./serving/target/feast-serving-$REVISION.jar /usr/share/feast/feast-serving.jar -CMD ["java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-jar", "/usr/share/feast/feast-serving.jar"] +# Download grpc_health_probe to run health check for Feast Serving +# https://kubernetes.io/blog/2018/10/01/health-checking-grpc-servers-on-kubernetes/ +RUN wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.3.1/grpc_health_probe-linux-amd64 \ + -O /usr/local/bin/grpc-health-probe && \ + chmod +x /usr/local/bin/grpc-health-probe +COPY --from=builder /build/serving/target/feast-serving-$REVISION.jar /opt/feast/feast-serving.jar +CMD ["java",\ + "-Xms1024m",\ + "-Xmx1024m",\ + "-jar",\ + "/opt/feast/feast-serving.jar"] From 6f92dbd8f6d6f9403545e137f209924855101ae7 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Mon, 4 Nov 2019 21:18:23 +0800 Subject: [PATCH 02/11] Add example job store options for Redis in application.yaml --- serving/src/main/resources/application.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/serving/src/main/resources/application.yml b/serving/src/main/resources/application.yml index 46b40f688b..6ef68d710c 100644 --- a/serving/src/main/resources/application.yml +++ b/serving/src/main/resources/application.yml @@ -36,7 +36,12 @@ feast: # Type of store to store job metadata. This only needs to be set if the # serving store type is Bigquery. store-type: ${FEAST_JOB_STORE_TYPE:} - # Job store connection options. If the job store is redis, the redis instance host and port are required. + # + # Job store connection options. If the job store is redis, the following items are required: + # + # store-options: + # host: localhost + # port: 6379 store-options: {} grpc: From e458014bb03277f8414466ca6bdbe3d1ed9213b9 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Tue, 5 Nov 2019 14:29:48 +0800 Subject: [PATCH 03/11] Add script to publish feast helm chart --- .prow/scripts/sync-helm-charts.sh | 57 +++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100755 .prow/scripts/sync-helm-charts.sh diff --git a/.prow/scripts/sync-helm-charts.sh b/.prow/scripts/sync-helm-charts.sh new file mode 100755 index 0000000000..918979dd3f --- /dev/null +++ b/.prow/scripts/sync-helm-charts.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Script to sync local charts to remote helm repository in Google Cloud Storage +# Copied from: https://github.com/helm/charts/blob/master/test/repo-sync.sh + +set -o errexit +set -o nounset +set -o pipefail + +log_error() { + printf '\e[31mERROR: %s\n\e[39m' "$1" >&2 +} + +# Assume working directory is Feast repository root folder +repo_dir=infra/charts +bucket=gs://feast-charts +repo_url=https://feast-charts.storage.googleapis.com/ +sync_dir=/tmp/syncdir +index_dir=/tmp/indexdir + +rm -rf $sync_dir $index_dir + +echo "Syncing repo '$repo_dir'..." + +mkdir -p "$sync_dir" +if ! gsutil cp "$bucket/index.yaml" "$index_dir/index.yaml"; then + log_error "Exiting because unable to copy index locally. Not safe to proceed." + exit 1 +fi + +exit_code=0 + +for dir in "$repo_dir"/*; do + if helm dependency build "$dir"; then + helm package --destination "$sync_dir" "$dir" + else + log_error "Problem building dependencies. Skipping packaging of '$dir'." + exit_code=1 + fi +done + +if helm repo index --url "$repo_url" --merge "$index_dir/index.yaml" "$sync_dir"; then + # Move updated index.yaml to sync folder so we don't push the old one again + mv -f "$sync_dir/index.yaml" "$index_dir/index.yaml" + + gsutil -m rsync "$sync_dir" "$bucket" + + # Make sure index.yaml is synced last + gsutil cp "$index_dir/index.yaml" "$bucket" +else + log_error "Exiting because unable to update index. Not safe to push update." + exit 1 +fi + +ls -l "$sync_dir" + +exit "$exit_code" \ No newline at end of file From f7630bb375116e47c09490a4278ffdf405183dce Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Tue, 5 Nov 2019 14:31:30 +0800 Subject: [PATCH 04/11] Update default jvm options in CMD instruction in Feast Core Dockerfile --- infra/docker/core/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/docker/core/Dockerfile b/infra/docker/core/Dockerfile index 2c717afb90..45fbaab1c4 100644 --- a/infra/docker/core/Dockerfile +++ b/infra/docker/core/Dockerfile @@ -13,7 +13,7 @@ FROM openjdk:8-jre as production ARG REVISION=dev COPY --from=builder /build/core/target/feast-core-$REVISION.jar /opt/feast/feast-core.jar CMD ["java",\ - "-Xms1024m",\ - "-Xmx1024m",\ + "-Xms2048m",\ + "-Xmx2048m",\ "-jar",\ "/opt/feast/feast-core.jar"] From cb8432addb10d79f4445f7492cb6e9c5c5024161 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Tue, 5 Nov 2019 14:32:08 +0800 Subject: [PATCH 05/11] Update installation path of grpc-health-probe in Feast serving Dockerfile --- infra/docker/serving/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/docker/serving/Dockerfile b/infra/docker/serving/Dockerfile index fd021940ac..7019cf970a 100644 --- a/infra/docker/serving/Dockerfile +++ b/infra/docker/serving/Dockerfile @@ -14,8 +14,8 @@ ARG REVISION=dev # Download grpc_health_probe to run health check for Feast Serving # https://kubernetes.io/blog/2018/10/01/health-checking-grpc-servers-on-kubernetes/ RUN wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.3.1/grpc_health_probe-linux-amd64 \ - -O /usr/local/bin/grpc-health-probe && \ - chmod +x /usr/local/bin/grpc-health-probe + -O /usr/bin/grpc-health-probe && \ + chmod +x /usr/bin/grpc-health-probe COPY --from=builder /build/serving/target/feast-serving-$REVISION.jar /opt/feast/feast-serving.jar CMD ["java",\ "-Xms1024m",\ From d80f70d537b2c2cb93bb0f5ea3f11c1fec340377 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Tue, 5 Nov 2019 14:43:33 +0800 Subject: [PATCH 06/11] Update feast charts for installing Feast with Helm - Refer to README.md for more details how feast chart is structured and how to use it - Feast Core and Feast Serving are subcharts that the parent Feast chart uses to install Feast. These subcharts optionally contains other dependencies such as Kafka, Postgresql or Redis. All these components can be enabled/disabled using the enabled flag in the Helm values. --- Dockerfile | 9 - infra/charts/README.md | 119 ------ infra/charts/feast-core/Chart.yaml | 5 - .../feast-core/charts/postgresql-3.17.0.tgz | Bin 19124 -> 0 bytes infra/charts/feast-core/requirements.lock | 6 - infra/charts/feast-core/requirements.yaml | 5 - .../feast-core/templates/core-configmap.yaml | 48 --- .../feast-core/templates/core-deploy.yaml | 110 ----- infra/charts/feast-core/values.yaml | 101 ----- infra/charts/feast-serving/Chart.yaml | 5 - .../templates/serving-configmap.yaml | 69 ---- .../templates/serving-deploy.yaml | 107 ----- .../templates/store-configmap.yaml | 14 - infra/charts/feast-serving/values.yaml | 98 ----- infra/charts/feast/.helmignore | 1 + infra/charts/feast/Chart.yaml | 3 +- infra/charts/feast/README.md | 179 ++++++++ .../{ => feast/charts}/feast-core/.helmignore | 0 .../charts/feast/charts/feast-core/Chart.yaml | 4 + .../charts/feast-core/charts/kafka-0.20.1.tgz | Bin 0 -> 30761 bytes .../feast-core/charts/postgresql-6.5.5.tgz | Bin 0 -> 23599 bytes .../feast/charts/feast-core/requirements.yaml | 9 + .../charts}/feast-core/templates/_helpers.tpl | 36 +- .../feast-core/templates/configmap.yaml | 29 ++ .../feast-core/templates/deployment.yaml | 108 +++++ .../charts/feast-core/templates/ingress.yaml} | 8 +- .../charts/feast-core/templates/service.yaml} | 13 +- .../feast/charts/feast-core/values.yaml | 179 ++++++++ .../charts}/feast-serving/.helmignore | 0 .../feast/charts/feast-serving/Chart.yaml | 4 + .../feast-serving/charts/redis-9.5.0.tgz | Bin 0 -> 27574 bytes .../charts/feast-serving/requirements.yaml | 5 + .../feast-serving/templates/_helpers.tpl | 15 +- .../feast-serving/templates/configmap.yaml | 38 ++ .../feast-serving/templates/deployment.yaml | 99 +++++ .../feast-serving/templates/ingress.yaml} | 2 +- .../feast-serving/templates/service.yaml} | 0 .../feast/charts/feast-serving/values.yaml | 188 +++++++++ infra/charts/feast/charts/kafka-0.17.0.tgz | Bin 30429 -> 0 bytes .../feast/charts/nginx-ingress-1.24.2.tgz | Bin 20227 -> 0 bytes .../charts/prometheus-pushgateway-1.0.1.tgz | Bin 5433 -> 0 bytes infra/charts/feast/charts/redis-6.4.4.tgz | Bin 20203 -> 0 bytes infra/charts/feast/requirements.lock | 28 +- infra/charts/feast/requirements.yaml | 36 +- infra/charts/feast/values-demo.yaml | 28 ++ infra/charts/feast/values-external-store.yaml | 5 + infra/charts/feast/values-production.yaml | 4 + infra/charts/feast/values.yaml | 391 +++++------------- 48 files changed, 1028 insertions(+), 1080 deletions(-) delete mode 100644 Dockerfile delete mode 100644 infra/charts/README.md delete mode 100644 infra/charts/feast-core/Chart.yaml delete mode 100644 infra/charts/feast-core/charts/postgresql-3.17.0.tgz delete mode 100644 infra/charts/feast-core/requirements.lock delete mode 100644 infra/charts/feast-core/requirements.yaml delete mode 100644 infra/charts/feast-core/templates/core-configmap.yaml delete mode 100644 infra/charts/feast-core/templates/core-deploy.yaml delete mode 100644 infra/charts/feast-core/values.yaml delete mode 100644 infra/charts/feast-serving/Chart.yaml delete mode 100644 infra/charts/feast-serving/templates/serving-configmap.yaml delete mode 100644 infra/charts/feast-serving/templates/serving-deploy.yaml delete mode 100644 infra/charts/feast-serving/templates/store-configmap.yaml delete mode 100644 infra/charts/feast-serving/values.yaml create mode 100644 infra/charts/feast/README.md rename infra/charts/{ => feast/charts}/feast-core/.helmignore (100%) create mode 100644 infra/charts/feast/charts/feast-core/Chart.yaml create mode 100644 infra/charts/feast/charts/feast-core/charts/kafka-0.20.1.tgz create mode 100644 infra/charts/feast/charts/feast-core/charts/postgresql-6.5.5.tgz create mode 100644 infra/charts/feast/charts/feast-core/requirements.yaml rename infra/charts/{ => feast/charts}/feast-core/templates/_helpers.tpl (57%) create mode 100644 infra/charts/feast/charts/feast-core/templates/configmap.yaml create mode 100644 infra/charts/feast/charts/feast-core/templates/deployment.yaml rename infra/charts/{feast-core/templates/core-ingress.yaml => feast/charts/feast-core/templates/ingress.yaml} (81%) rename infra/charts/{feast-core/templates/core-service.yaml => feast/charts/feast-core/templates/service.yaml} (79%) create mode 100644 infra/charts/feast/charts/feast-core/values.yaml rename infra/charts/{ => feast/charts}/feast-serving/.helmignore (100%) create mode 100644 infra/charts/feast/charts/feast-serving/Chart.yaml create mode 100644 infra/charts/feast/charts/feast-serving/charts/redis-9.5.0.tgz create mode 100644 infra/charts/feast/charts/feast-serving/requirements.yaml rename infra/charts/{ => feast/charts}/feast-serving/templates/_helpers.tpl (73%) create mode 100644 infra/charts/feast/charts/feast-serving/templates/configmap.yaml create mode 100644 infra/charts/feast/charts/feast-serving/templates/deployment.yaml rename infra/charts/{feast-serving/templates/serving-ingress.yaml => feast/charts/feast-serving/templates/ingress.yaml} (98%) rename infra/charts/{feast-serving/templates/serving-service.yaml => feast/charts/feast-serving/templates/service.yaml} (100%) create mode 100644 infra/charts/feast/charts/feast-serving/values.yaml delete mode 100644 infra/charts/feast/charts/kafka-0.17.0.tgz delete mode 100644 infra/charts/feast/charts/nginx-ingress-1.24.2.tgz delete mode 100644 infra/charts/feast/charts/prometheus-pushgateway-1.0.1.tgz delete mode 100644 infra/charts/feast/charts/redis-6.4.4.tgz create mode 100644 infra/charts/feast/values-demo.yaml create mode 100644 infra/charts/feast/values-external-store.yaml create mode 100644 infra/charts/feast/values-production.yaml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 15881b50e6..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM openjdk:8-jre-alpine -ARG REVISION=0.3.0-dev -COPY ./serving/target/feast-serving-$REVISION.jar /usr/share/feast/feast-serving.jar -ENTRYPOINT ["java", \ - "-XX:+UseG1GC", \ - "-XX:+UseStringDeduplication", \ - "-XX:+UnlockExperimentalVMOptions", \ - "-XX:+UseCGroupMemoryLimitForHeap", \ - "-jar", "/usr/share/feast/feast-serving.jar"] \ No newline at end of file diff --git a/infra/charts/README.md b/infra/charts/README.md deleted file mode 100644 index 88edc6f4ae..0000000000 --- a/infra/charts/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# Helm charts -This chart adds all the components required to run feast, sans the stores to which you might want to ingest your features. Those will have to be deployed seperately. - -## Installing the chart - -``` -helm dep update -helm install --name feast . -``` - -## Requirements - -### External Permissions - -The feast deployment requires access to the following components: - -- `gcs`: read/write - -As well as the following, depending on your use case: - -- `bigquery`: read/write -- `bigtable`: read/write/tableAdmin - -The recommended way to give your deployment these permissions is to deploy Feast on a cluster with the required permissions. - -## Components - -The components included in this chart are: - -- `feast-core`: the main API controller of feast -- `feast-metadata`: postgres db that persists feast's metadata - - The stable postgres chart is being used for this deployment - any of the parameters described [here](https://github.com/helm/charts/tree/master/stable/postgresql) can be overridden to customise your postgres deployment. -- `feast-serving`: service that serves up features from the various serving stores - -Components that Feast supports, but this installation will not include are: - -- Serving Storage - - `Redis` or `Bigtable` dbs for feature serving storage -- [TICK stack](https://www.influxdata.com/time-series-platform/) for metrics monitoring - - Set `statsd.host` and `statsd.port` to direct job metrics to your metrics store. - - Note that if you do not provision a metrics store, feast will only retain the latest metrics from your jobs. -- [Jaeger tracing](www.jaegertracing.io) for serving performance. - - Set `serving.jaeger.enabled` to `true`, and configure the following parameters: - - `serving.jaeger.host` - - `serving.jaeger.port` - - `serving.jaeger.options.samplerType` - - `serving.jaeger.options.samplerParam` - -## Uninstalling Feast - -To uninstall the `feast` deployment: -``` -helm del feast -kubectl delete persistentvolumeclaim feast-postgresql -``` - -## Configuration -The following table lists the configurable parameters of the Feast chart and their default values. - -| var | desc | default | -| --- | --- | --- | -| `core.image.registry` | core docker image registry | feast | -| `core.image.repository` | core docker image repository | feast-core | -| `core.image.tag` | core docker image version | 0.1.0 | -| `core.jobs.monitoring.initialDelay` | delay before a job starts to be monitored in ms | 60000 | -| `core.jobs.monitoring.period` | polling interval for jobs monitoring in ms | 5000 | -| `core.jobs.options` | additional options to be provided to the beam job. Should be a char escaped json k-v object | {} | -| `core.jobs.runner` | beam job runner - one of `DirectRunner`, `FlinkRunner` or `DataflowRunner` | DirectRunner | -| `core.jobs.workspace` | workspace path for ingestion jobs, used for separate job workspaces to share importJobSpecs.yaml with ingestion and for writing errors to if no default errors store is configured | nil | -| `core.replicaCount` | core deployment replica count | 3 | -| `core.resources.limits.cpu` | core cpu limits | 1 | -| `core.resources.limits.memory` | core memory limits | 2G | -| `core.resources.requests.cpu` | core cpu requested | 1 | -| `core.resources.requests.memory` | core memory requested | 2G | -| `core.service.extIPAdr` | Internal load balancer IP Address for core, required so jobs on external runners can connect to core | nil | -| `core.service.loadBalancerSourceRanges` | IP source ranges that will have access to core. If not set, will default to 0.0.0.0/0 | nil | -| `core.service.grpc.port` | core service exposed grpc port | 8433 | -| `core.service.grpc.targetPort` | core service target grpc port | 8433 | -| `core.service.http.port` | core service exposed http port | 80 | -| `core.service.http.targetPort` | core service target http port | 8080 | -| `core.projectId` | GCP project ID core service resides at | gcp-project-id | -| `core.trainingDatasetPrefix` | prefix for training datasets created in bq | fs | -| `dataflow.location` | desired dataflow's region | nil | -| `dataflow.projectID` | desired dataflow's project id | nil | -| `serving.config.maxEntityPerBatch` | max entities that can be requested at a time | 2000 | -| `serving.config.maxNumberOfThread` | max number of threads per instance of serving | 256 | -| `serving.config.redisPool.maxIdle` | max idle connections to redis | 16 | -| `serving.config.redisPool.maxSize` | max number of connections to redis | 256 | -| `serving.config.timeout` | request timeout in seconds | 5 | -| `serving.image.registry` | serving docker image registry | feast | -| `serving.image.repository` | serving docker image repository | feast-serving | -| `serving.image.tag` | serving docker image version | 0.1.0 | -| `serving.replicaCount` | serving replica count | 4 | -| `serving.resources.limits.cpu` | serving cpu limits | 1 | -| `serving.resources.limits.memory` | serving memory limits | 2G | -| `serving.resources.requests.cpu` | serving cpu requested | 1 | -| `serving.resources.requests.memory` | serving memory requested | 2G | -| `serving.service.grpc.port` | serving service exposed grpc port | 8433 | -| `serving.service.grpc.targetPort` | serving service target grpc port | 8433 | -| `serving.service.http.port` | serving service exposed http port | 80 | -| `serving.service.http.targetPort` | serving service target http port | 8080 | -| `serving.service.extIPAdr` | Internal load balancer IP Address for serving, required so jobs on external runners can connect to the service | nil | -| `serving.service.loadBalancerSourceRanges` | IP source ranges that will have access to serving. If not set, will default to 0.0.0.0/0 | nil | -| `serviceAccount.name` | service account secret name to mount to deployments | nil | -| `serviceAccount.key` | service account secret key to mount to deployments | nil | -| `statsd.host` | host of statsd daemon for job metrics to be sent to | nil | -| `statsd.port` | port of statsd daemon for job metrics to be sent to | nil | -| `store.errors.type` | type of default errors store to write errors to. One of `stdout`, `stderr`, `file.json` | nil | -| `store.errors.options` | additional options for the default error store in json string format | `{}` | -| `store.serving.type` | type of default serving store to write errors to. One of `redis`, `bigtable` | nil | -| `store.serving.options` | additional options for the default serving store in json string format | `{}` | -| `store.warehouse.type` | type of default warehouse store to write errors to. One of `bigquery`, `file.json` | nil | -| `store.warehouse.options` | additional options for the default warehouse store in json string format | `{}` | -| `postgresql.provision` | Provision PostgreSQL | true | -| `postgresql.postgresPassword` | specify password if you want the postgres password secret to be generated | nil | -| `postgresql.resources.requests.cpu` | postgres requested cpu | 100m | -| `postgresql.resources.requests.memory` | postgres requested memory | 256Mi | -| `redis.provision` | Provision Redis instance | true | -| `redis.name` | Helm release name for the Redis instance | feast-redis | \ No newline at end of file diff --git a/infra/charts/feast-core/Chart.yaml b/infra/charts/feast-core/Chart.yaml deleted file mode 100644 index d1b4a798bc..0000000000 --- a/infra/charts/feast-core/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "0.3.0" -description: A Helm chart for feast core -name: feast-core -version: 0.3.0 diff --git a/infra/charts/feast-core/charts/postgresql-3.17.0.tgz b/infra/charts/feast-core/charts/postgresql-3.17.0.tgz deleted file mode 100644 index 3fe96f84b2ba27a2af8fc8c7be52c3957318105b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19124 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 ov8d1hvAhJYspY--7_0" - - ## For redis serving. Configuration for the redis connection pool. - # redisPool: - # maxSize: 128 - # maxIdle: 8 - - ## Job configuration is necessary if this serving store is used to - ## facilitate batch retrieval of features, which involve async jobs. - jobs: {} - # stagingLocation: gs://feast-bucket/bq/staging - # storeType: REDIS - # storeOptions: - # host: redis.svc.local - # port: 6379 - -tracing: - enabled: false - # tracer-name: jaeger - # service-name: feast-serving - -rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - -service: - # annotations: [] - http: - port: 80 - targetPort: 8080 - grpc: - port: 6566 - targetPort: 6566 - type: ClusterIP - # loadBalancerIP: - # loadBalancerSourceRanges: - # - 10.0.0.0/8 - port: 80 - -rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - -livenessProbe: - # initialDelaySeconds: 30 - # failureThreshold: 3 -readinessProbe: - initialDelaySeconds: 30 - failureThreshold: 3 - -## A service account if using the dataflow runner or BigQuery. -# serviceAccount: - # name: my-service-account - -ingress: - enabled: false - annotations: {} - # kubernetes.io/ingress.class: nginx - hosts: - # - host: chart-example.local - # port: http - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -nodeSelector: {} diff --git a/infra/charts/feast/.helmignore b/infra/charts/feast/.helmignore index f0c1319444..50af031725 100644 --- a/infra/charts/feast/.helmignore +++ b/infra/charts/feast/.helmignore @@ -19,3 +19,4 @@ .project .idea/ *.tmproj +.vscode/ diff --git a/infra/charts/feast/Chart.yaml b/infra/charts/feast/Chart.yaml index 9eb45964a6..30ccf81091 100644 --- a/infra/charts/feast/Chart.yaml +++ b/infra/charts/feast/Chart.yaml @@ -1,5 +1,4 @@ apiVersion: v1 -appVersion: "0.1.0" description: A Helm chart to install Feast on kubernetes name: feast -version: 0.1.0 +version: 0.3.0-alpha.1 diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md new file mode 100644 index 0000000000..03ba53a574 --- /dev/null +++ b/infra/charts/feast/README.md @@ -0,0 +1,179 @@ +# Feast Chart + +This directory provides the Helm chart for Feast installation. + +This chart installs Feast Core and Feast Serving components of Feast, along with +the required and optional dependencies. Components and dependencies can be +enabled or disabled by changing the corresponding `enabled` flag. Feast Core and +Feast Serving are subcharts of this parent Feast chart. The structure of the charts +are as follows: + +``` +feast // top level feast chart +│ +├── feast-core // feast-core subchart +│ ├── postgresql // Postgresql dependency for feast-core (Feast database) +│ └── kafka // Kafka dependency for feast-core (default stream source) +│ +├── feast-serving-online // feast-serving subchart +│ └── redis // Redis dependency for installation of store together with feast-serving +│ +└── feast-serving-batch // feast-serving subchart +``` + +## Prerequisites +- Kubernetes 1.13 or newer cluster +- Helm 2.15.2 or newer + +## Resources Required +The chart deploys pods that consume minimum resources as specified in the resources configuration parameter. + +## Installing the Chart + +Add repository for Feast chart: +```bash +helm repo add feast-charts https://feast-charts.storage.googleapis.com +helm repo update +``` + +Install Feast release with minimal features, without batch serving and persistency: +```bash +RELEASE_NAME=demo +helm install feast-charts/feast --name $RELEASE_NAME --version 0.3.0-alpha.1 -f values-demo.yaml +``` + +Install Feast release for typical use cases, with batch and online serving: +```bash +# To install Feast Batch serving, BigQuery and Google Cloud service account +# is required. The service account needs to have these roles: +# - bigquery.dataEditor +# - bigquery.jobUser +# +# Assuming a service account JSON file has been downloaded to /home/user/key.json, +# run the following command to create a secret in Kubernetes +# (make sure the file name is called key.json): +kubectl create secret generic feast-gcp-service-account --from-file=/home/user/key.json + +# Set these required configuration in Feast Batch Serving +STAGING_LOCATION=gs://bucket/path +PROJECT_ID=google-cloud-project-id +DATASET_ID=bigquery-dataset-id + +# Install the Helm release using default values.yaml +helm install feast-charts/feast --name feast --version 0.3.0-alpha.1 \ + --set feast-serving-batch."application\.yaml".feast.jobs.staging-location=$STAGING_LOCATION \ + --set feast-serving-batch."store\.yaml".bigquery_config.project_id=$PROJECT_ID \ + --set feast-serving-batch."store\.yaml".bigquery_config.dataset_id=$DATASET_ID +``` + +## Parameters + +The following table lists the configurable parameters of the Feast chart and their default values. + +| Parameter | Description | Default +| --------- | ----------- | ------- +| `feast-core.enabled` | Flag to install Feast Core | `true` +| `feast-core.postgresql.enabled` | Flag to install Postgresql as Feast database | `true` +| `feast-core.postgresql.postgresqlDatabase` | Name of the database used by Feast Core | `feast` +| `feast-core.postgresql.postgresqlUsername` | Username to authenticate to Feast database | `postgres` +| `feast-core.postgresql.postgresqlPassword` | Passsword to authenticate to Feast database | `password` +| `feast-core.kafka.enabled` | Flag to install Kafka as the default source for Feast | `true` +| `feast-core.kafka.topics[0].name` | Default topic name in Kafka| `feast` +| `feast-core.kafka.topics[0].replicationFactor` | No of replication factor for the topic| `1` +| `feast-core.kafka.topics[0].partitions` | No of partitions for the topic | `1` +| `feast-core.replicaCount` | No of pods to create | `1` +| `feast-core.image.repository` | Repository for Feast Core Docker image | `gcr.io/kf-feast/feast-core` +| `feast-core.image.tag` | Tag for Feast Core Docker image | `0.3.0` +| `feast-core.image.pullPolicy` | Image pull policy for Feast Core Docker image | `IfNotPresent` +| `feast-core.application.yaml` | Configuration for Feast Core application | Refer to this [link](charts/feast-core/values.yaml) +| `feast-core.springConfigMountPath` | Directory to mount application.yaml | `/etc/feast/feast-core` +| `feast-core.gcpServiceAccount.useExistingSecret` | Flag to use existing secret for GCP service account | `false` +| `feast-core.gcpServiceAccount.existingSecret.name` | Secret name for the service account | `feast-gcp-service-account` +| `feast-core.gcpServiceAccount.existingSecret.key` | Secret key for the service account | `key.json` +| `feast-core.gcpServiceAccount.mountPath` | Directory to mount the JSON key file | `/etc/gcloud/service-accounts` +| `feast-core.jvmOptions` | Options for the JVM | `[]` +| `feast-core.livenessProbe.enabled` | Flag to enable liveness probe | `true` +| `feast-core.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `60` +| `feast-core.livenessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-core.livenessProbe.timeoutSeconds` | Timeout duration for the probe | `5` +| `feast-core.livenessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-core.livenessProbe.failureThreshold` | Minimum no of consecutive failures for the probe to be considered failed | `5` +| `feast-core.readinessProbe.enabled` | Flag to enable readiness probe | `true` +| `feast-core.readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `30` +| `feast-core.readinessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-core.readinessProbe.timeoutSeconds` | Timeout duration for the probe | `10` +| `feast-core.readinessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-core.service.type` | Kubernetes Service Type | `ClusterIP` +| `feast-core.http.port` | Kubernetes Service port for HTTP request| `80` +| `feast-core.http.targetPort` | Container port for HTTP request | `8080` +| `feast-core.grpc.port` | Kubernetes Service port for GRPC request| `6565` +| `feast-core.grpc.targetPort` | Container port for GRPC request| `6565` +| `feast-core.resources` | CPU and memory allocation for the pod | `{}` +| `feast-serving-online.enabled` | Flag to install Feast Online Serving | `true` +| `feast-serving-online.redis.enabled` | Flag to install Redis in Feast Serving | `false` +| `feast-serving-online.redis.usePassword` | Flag to use password to access Redis | `false` +| `feast-serving-online.redis.cluster.enabled` | Flag to enable Redis cluster | `false` +| `feast-serving-online.core.enabled` | Flag for Feast Serving to use Feast Core in the same Helm release | `true` +| `feast-serving-online.replicaCount` | No of pods to create | `1` +| `feast-serving-online.image.repository` | Repository for Feast Serving Docker image | `gcr.io/kf-feast/feast-serving` +| `feast-serving-online.image.tag` | Tag for Feast Serving Docker image | `0.3.0` +| `feast-serving-online.image.pullPolicy` | Image pull policy for Feast Serving Docker image | `IfNotPresent` +| `feast-serving-online.application.yaml` | Application configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) +| `feast-serving-online.store.yaml` | Store configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) +| `feast-serving-online.springConfigMountPath` | Directory to mount application.yaml and store.yaml | `/etc/feast/feast-serving` +| `feast-serving-online.gcpServiceAccount.useExistingSecret` | Flag to use existing secret for GCP service account | `false` +| `feast-serving-online.gcpServiceAccount.existingSecret.name` | Secret name for the service account | `feast-gcp-service-account` +| `feast-serving-online.gcpServiceAccount.existingSecret.key` | Secret key for the service account | `key.json` +| `feast-serving-online.gcpServiceAccount.mountPath` | Directory to mount the JSON key file | `/etc/gcloud/service-accounts` +| `feast-serving-online.jvmOptions` | Options for the JVM | `[]` +| `feast-serving-online.livenessProbe.enabled` | Flag to enable liveness probe | `true` +| `feast-serving-online.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `60` +| `feast-serving-online.livenessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-serving-online.livenessProbe.timeoutSeconds` | Timeout duration for the probe | `5` +| `feast-serving-online.livenessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-serving-online.livenessProbe.failureThreshold` | Minimum no of consecutive failures for the probe to be considered failed | `5` +| `feast-serving-online.readinessProbe.enabled` | Flag to enable readiness probe | `true` +| `feast-serving-online.readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `30` +| `feast-serving-online.readinessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-serving-online.readinessProbe.timeoutSeconds` | Timeout duration for the probe | `10` +| `feast-serving-online.readinessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-serving-online.service.type` | Kubernetes Service Type | `ClusterIP` +| `feast-serving-online.http.port` | Kubernetes Service port for HTTP request| `80` +| `feast-serving-online.http.targetPort` | Container port for HTTP request | `8080` +| `feast-serving-online.grpc.port` | Kubernetes Service port for GRPC request| `6566` +| `feast-serving-online.grpc.targetPort` | Container port for GRPC request| `6566` +| `feast-serving-online.resources` | CPU and memory allocation for the pod | `{}` +| `feast-serving-batch.enabled` | Flag to install Feast Batch Serving | `true` +| `feast-serving-batch.redis.enabled` | Flag to install Redis in Feast Serving | `false` +| `feast-serving-batch.redis.usePassword` | Flag to use password to access Redis | `false` +| `feast-serving-batch.redis.cluster.enabled` | Flag to enable Redis cluster | `false` +| `feast-serving-batch.core.enabled` | Flag for Feast Serving to use Feast Core in the same Helm release | `true` +| `feast-serving-batch.replicaCount` | No of pods to create | `1` +| `feast-serving-batch.image.repository` | Repository for Feast Serving Docker image | `gcr.io/kf-feast/feast-serving` +| `feast-serving-batch.image.tag` | Tag for Feast Serving Docker image | `0.3.0` +| `feast-serving-batch.image.pullPolicy` | Image pull policy for Feast Serving Docker image | `IfNotPresent` +| `feast-serving-batch.application.yaml` | Application configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) +| `feast-serving-batch.store.yaml` | Store configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) +| `feast-serving-batch.springConfigMountPath` | Directory to mount application.yaml and store.yaml | `/etc/feast/feast-serving` +| `feast-serving-batch.gcpServiceAccount.useExistingSecret` | Flag to use existing secret for GCP service account | `false` +| `feast-serving-batch.gcpServiceAccount.existingSecret.name` | Secret name for the service account | `feast-gcp-service-account` +| `feast-serving-batch.gcpServiceAccount.existingSecret.key` | Secret key for the service account | `key.json` +| `feast-serving-batch.gcpServiceAccount.mountPath` | Directory to mount the JSON key file | `/etc/gcloud/service-accounts` +| `feast-serving-batch.jvmOptions` | Options for the JVM | `[]` +| `feast-serving-batch.livenessProbe.enabled` | Flag to enable liveness probe | `true` +| `feast-serving-batch.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `60` +| `feast-serving-batch.livenessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-serving-batch.livenessProbe.timeoutSeconds` | Timeout duration for the probe | `5` +| `feast-serving-batch.livenessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-serving-batch.livenessProbe.failureThreshold` | Minimum no of consecutive failures for the probe to be considered failed | `5` +| `feast-serving-batch.readinessProbe.enabled` | Flag to enable readiness probe | `true` +| `feast-serving-batch.readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `30` +| `feast-serving-batch.readinessProbe.periodSeconds` | How often to perform the probe | `10` +| `feast-serving-batch.readinessProbe.timeoutSeconds` | Timeout duration for the probe | `10` +| `feast-serving-batch.readinessProbe.successThreshold` | Minimum no of consecutive successes for the probe to be considered successful | `1` +| `feast-serving-batch.service.type` | Kubernetes Service Type | `ClusterIP` +| `feast-serving-batch.http.port` | Kubernetes Service port for HTTP request| `80` +| `feast-serving-batch.http.targetPort` | Container port for HTTP request | `8080` +| `feast-serving-batch.grpc.port` | Kubernetes Service port for GRPC request| `6566` +| `feast-serving-batch.grpc.targetPort` | Container port for GRPC request| `6566` +| `feast-serving-batch.resources` | CPU and memory allocation for the pod | `{}` \ No newline at end of file diff --git a/infra/charts/feast-core/.helmignore b/infra/charts/feast/charts/feast-core/.helmignore similarity index 100% rename from infra/charts/feast-core/.helmignore rename to infra/charts/feast/charts/feast-core/.helmignore diff --git a/infra/charts/feast/charts/feast-core/Chart.yaml b/infra/charts/feast/charts/feast-core/Chart.yaml new file mode 100644 index 0000000000..c741a53044 --- /dev/null +++ b/infra/charts/feast/charts/feast-core/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for core component of Feast +name: feast-core +version: 0.3.0-alpha.1 diff --git a/infra/charts/feast/charts/feast-core/charts/kafka-0.20.1.tgz b/infra/charts/feast/charts/feast-core/charts/kafka-0.20.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..76a2247577d43a5c7b7da189eab9ca2bb90e30ab GIT binary patch literal 30761 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

Aw_*qVAg6yrgW?!PQ^G`vMO~SRR z==g$;SxSXX?4>4N?e`>=%y-_6c@7zm1Q4N?8%t>fEFInfcSHy_NqxNEi$}D#W+C=T z8u@O&Gsto}rnzE_;sJLwCllHV?OnqwCZwVw1+JTAtu#F<#N369ln^0t*j1~&`-~3G ze*Nu1P}FwU#^Q!66uDP(SnSxg${Ryg!jv_|`YDx{JU?gY#J=mT*(UwcVEZScsJgym zNxRo@g2gbiiDJPc3WadY*YjAi2R} z9|=WUgZ{Jr1ENUZ4t}G(=!L#SoTUaw3KKSv+pzAr0gF$e+0TP|W{xL=n1_ov$4!mY zP$XyBDw@8zT?I~N*+&&??)_ZDnWfab^P>h8nQO6cP-9=1V#tzdDs!umQ4&tgd3OYR zkkgRopTsb<5Yz|X(NVdN?(9K}L}UZ6k`%gNB80a8w2c%`ytF zIElcv5WoxcUl72xbuG*J1&e5oNknXJ{<%T@`r8>=XlmK*ZyM*dD|~3dUvD9jTaO(c zeI7>Rhnu%DXa0)EGA6V&eYNtrF$B~?Cd0;DKsWz(aDw?P36EB2qH>db_kvC z)o##%n}%ynbldXTEvk79XL?%C;MZDB5IT4KZ@+4#Sbr410WZ^v-ExTceGo;R(!nG! z?x}&vieb>z83OK|OOa&{EpsYYJ(anJBO(NlbOttoh2j0@B?}2)Ur7=s?M`{lM1&I2 z(H9e_Lo64DSmylIOamcFfy4qC79MD6mPJgqG8XD!BsMOsT0xB%%l6ST4|ASPlw^!z z4iQ5*`%9G&oqxkMf6*|NUQ>dXsDNn7@ zrE$!nFsr?Itck|VGpxt#oI1(*yFg_aY=E5RyqHXZ;6)5%qENt6At{N_rV4^ZG$hNM z_a2U?+?>Vwtk&-vt>W>qntaR=GNNOi<2XlDDTTTT`Dsop7eCiCqXk0niEouw8{Xe!8Pt~iesvqpci0(1>$gO7rudh+qP9@?mgj3v#j)@;#(`OXFK z;+_V9yFb@(w(~F!OgH3JKWp~;nx!l$5(s%JXjouOr>R7pqbQ9gWWB1S65MHI3o0h1 z5j!OpES+G!_J>}Wii$o8ikb=I=TNkVL#xoBDhQBMCLmG!A5u>j?NfG-OGtiBBluC@ zQ~#-`>fzkrmZocJS!h2KCZWi*2w?GI*PJ4v(sf625Ys|J#4l5rsJ6#N9M8J7mC2;y z@aHUUQ3~%lIyl>X7+zGrTkmF-)QvLHbwSvR`6P!zd@g1xlq;12KZMR<`hvz(t{`hS z8!A^qfk2O(NE9KKCdcchO@g5=HomMcf``n zqIT0+<}v#Ny>k#NI$7MkfcR*S+R=Vs58}Yo?&`O&UrfHLwWZG+QP*(R8tQv5zU;SB+}D?dV`#Pzq;yt?K~YThD;; zT5i8yb43)D0XZfHM=@+gWY#KJMx#8$sBbsAhdcCX&5pg;_W$#gVh8}wam7@mqR7H7 zG|8RCb5AJm`aIl;c-!5<%TB~=3nXj=n0`*rHJk|^3&GP~^J-oHU2^49Gl;*6DcRiF zU9f5vp=fa|?hPpVoMLdV;f!o<^>;V7p6!Ow4jB(f7>%Fo?hH0}w>HDgJ|(*&`egU% z)17D>ZuZ0I*?7F&ACES-o^J2%>^z}Q&)QLxN}69RboaT215*Ixlt_0u=}k)1795^` z=-dQO$wPBp|3^pBpnuOurB)Q_fu3j!cAMyEKK=V*=mrU?vCfVv*{FFy#!?q6=1dlI z2q{!5qCqiAU??!RT|?Hr1h0lYUu$j0LSTZY~`DB^~RE)gEDF^~(`xXKCF#)i9qo|yLX zvp?neD3W7|BIDTqnx{LpP*xlun7b| za_DWM2f)%5Q;4-RvLcFX9;7pHvgj=yH>^MBIXyfEH}hi`Muh}1Hn3Ug@3d$SJ1V3*eYia7^?ogNp2WeLu)txneanLH177F(fcm5gN94njWjTx1U?7r9h)u|m+K<1J6((qCTKSS@t7 zuh3Zi`s9y7(LZ0F{%wEn==AvDpZi1T41Va`#YfGFG0`3$H!QSj&_~vzL|W$=yyNk6 zd9LAX^I^P;Dioo;Cs>|j(?!u|o?Y|dGHcduds|_l{rL8k+Rz+KnIz8ZMVeBomKqyd zUakay1~>m?ImsT*>7hc=Dy|PEYfCGRKC?$Hw87JR`ldHfv`V_Ie?Lv%^Nx*tS0y4h z3hJ5fD<$Ea&b~ph?bmMk^S3h~`J})QFv;P}P1}Cvd3!O&J4<#!;~5b6$KLB###3ub zq>U}30(D^Hp;ej*Dlkko^>U}gpe#9MLMNvm5iz|nW&F4%a<=A+Ut7Zq4O1FQqY7!G zA?5{Ps4zHb={)Zryg<-GU8kxrnw1(V0fAS4m<$^_w)LqfFFh!SVlL-^dSGN@qG@qtSnuh7?_irsTq03|fMZ=)(&lEM~h{RG}ZQx>R$nAvTJPy}O{i zW57>M^dth|OXfE3`w;X-%(^q^HUcqquORi3nQwgEtCvH?p1{ZZHqSioXG{QkR+T&h zCTf0nGhXEOE(Ps3kC%SzUrCw@eFumpqA6ZXkfVh<Cn1hQ54VahsYaTws=1l^sd1p~@7byWvWC52t2qZhA7&1)Dj^sQdvOq;SqN zVN%~_IlCZ|cGW86F`vv7IT|gytNGlR5?QFC#VBTCO7-M z97}0+dqzqUmQFmJ9jb$wn<%h-A>mio=n#Qx-y#m-=PB&{d~7-z$0SW@3{@h-z&jXg zKSw5}&ZIPZENP-LQDXaDO_XKs=}FFu%;X1FOg^4rvR9DY!;}&43SmRA)p#N0sqdsj zRT6@Lbs9_p7!je!2BT9g6w`&NinOC^PST0uJc{wQ+y@;vcRV-pC&7mg2Odc+hy)j_@9)twl$!27YJSL?mMG*y=wyb%GMy999k zD)K$sI_uWy-)o1p!ZpumYSMKzhC75aOs;j-)jtOI$L3i8dv>Fsf`YxJRB;GJn8+EB z@R8?{bOuu{Q1qz)aJ{8RG$e&^xuRO)>L0{niD7I`QOgWz+ml>v`Mqk4ntl~lO^zF( zNCAmiF9S1@jllC1D_D>{j!4~clK^biJWLHI3e2pa-;{ac81BcIDNgcBl1H8bgP>Jf z1F5?(vuNhjUf+uM2dOPqZ5|iYNlc|#7p_Q!_zI7DDWSdIGfWy2i-xkmJwl^I@nqcH zo%Av-Bnf*up~Qq;(6oxD)olPb7sq-ybi^u=KrsBaTZPYSBXkSDbMM zf{bZhn#BziWgWeV+07}5>qKfXkBN>fI&e}S<7Kv*!b%RJ13n|$9Ip7Xv7zS!l*vu- zFw1-Fypef<_qDI--i)R}8G3e=)X8&9xMcG!sR}xXvxE+tsNK^4*S~^4c+&3pgmZbok=*;7H%? z-tBaOrg*`Z+Ph3>EV3nJkfy_f@dD&Cfg@D(fQVdM0Mihzef=F^|Cf{fw{P}dDdiW> zi)%^hhL6_Qk@vu3c=Z0|-uEx}PD@_?VPiv0&XPVJ!~J`>dCcxyBXhOe8w&GzLG^qs z0~Fek;XhhmZv(0^1k4V3UqF%A?*ggw^U?cPhkGwhzuSAY_vX0*_UOY9k!yhaG1Ui) zxC3bW2a=a<0$!D3hq=ekkdXx^#n!dazNB%u}C^t?w} zX$*-3e*|shrfJQ8<-IlvhmOgQV|%2wj(eMtYWl;)jr95(Ll3rWk{UI2rq-rnxQps- zR^VZ zKLDkZGXX47m@<)LDVN4BxU|WLQ=MR4n~5-RQON=ZZBFjrYAUqQVl9h?u(~kimr9CJ z!dh9>4pgaKp)qtUl3LX0bjoE}WJ_e28o||c^>RXtB=R{4IsTlG^Vq&=3PTOiM{g-M zZztaRTepKN)kH`Vp8Hnu_tj$a?P423N5R}tEk&g;we_?+=)+_4?_dAwj30X}uRmR3 z7HWBmqg0@fTWz0;#Pfo}h{pUf(9P@XMA7<%HVd1)wS9#u?L~9j0RB-~S&FX@pZ9*)_jJ##k2$}!O%3|N z*0W%9dk}06o&dmKQl8Rpo$_k(dMD41S{vI;ww?*yo8R|K0-+@iNZ@T_lp+ujbgw}Zj%COEzAJZ%}G+uP!xju ztfHINu~KdjbGm6A<;`-HZrTRNO}c420#G-doYNC3WTiK5YK;IjMDy_$Z9ZSQP3v6n z@pT9-=6z8j?yN*KQF(j$7#7LLZGv!pg?DQ_r(0ttUqt55R%HHnw~>Akj_)TNBdvTg z;n?=}X@ujlw=cr+ClHS7vP+%NZhubER{sVuur~iC6LbZ@8a*~k^qn?p-7b;(+DCb3 zfv>%}Tg!UzGUb;kV0fAqXgu$0I85Uin5!fNn3#z2o^>>RqfvWA!gFe~J7;sD5MfMM zB4FM4FeO|_JiUj#pN}`ZuR-r}ieZ-4Y%q8<@;XysuVz|Ryed43KA9lEsl)rdloR=xy8T0qY5wFCEA;CYR^ zKpdB99jKj=a7qK7PkIp#(F0lgQLokN;bb@wjmMHmmcL)mmjT8@R#`j{HOVGKa^M->47$-N9QxAn|O<{N)UKuX2AYK_VbkPDq zwRrPu8GC9jC~x-;4S7zv=s5|*Z18K%O>|1*WCKx~a7B=*&dZ?i&2ulOBr5OZa62Ex zd;%F45?CtnSa8V*D)=-|2%l=9C#P<_Y6)R5l}WszsmV>4q>m31@(wQ+$J@+NI1!3O zg|rzZOMiBoDG>t<9Oo(Z9!KK<>-N)%&(Lj=Y4- z@Q81Ol`SO(aKd3q<4h4`POHgOR97{jPfl2l4%QbWmFNS_Q<_QvmsGRZk|9D^=v=X7 zMoc(sPmXDi4;2P2Rs#=LcU4zGj#ubJ`Y@L(FcN;@%%+KRXu3w7p!X(E5{^zf3T7hN zh~fG!Rd|OIOumw?>)L8=CsE20NkzFv&|5qwmu_OS0KP|K16m}yb_+Jw_b8UFrGn}{ zAC`tZ&p2XBaR+@srCZbP?amE2BO3BV2SCJRL}Qn=D3mi^;7rAoQ>J4v_;HuGb}norzp1?8tNp}TKs+@S zp7T@`3C-aL^i~eM|M>FEJ(?)YtypSmL=f}v{6YKZ_xt@PJ3IJqzu#~E+uz!KQvSyG zgRR{`|3BbCfmrkuN?iPpe*eDhGza(JDc6K+To$+Yr z+0*g%&a-DvpAI(1WU#wSpKXuB!H8^clg;syCr`Gc@w3f-CTGqeX2_CeMo7Vs4?&kdZ-~O`xKgDzN`fse- zhhzvLPxTIN-Ad5%|&i3Z!m-YWC zo<=w}$+Gg#tzakE@gge1oMn2IKBuY7NzDGBQO(0QAq+iwmC95P0e4ItT@&-z^}xvR zs(8eN%-N_=O01Zr;WXzd`@>XFnp{;BqYiDqBJieM@hZ!LoD>O_am`~PPj4uLhmj8P zpNfRUaWG+H&yEX?#Xiu4uy_bD38yhh1A0MI!PCDcEX=v!V`*FlH4jy#7=5}`)#H~m z73Y7|e6UvboL_FG!fP^LleoL19!44z^9z~8d)JFe$YioFPGv$J&0lelp}y|8=^03#^CFc)*aBFC7gVquu|iU5Y~lap{G~p8)tO** z`U(v^i7&|vPm0zD-L0;HeZ%uI9=%{9FK`?Eu81ZSJz)}Z^%QP|p)G4s*_8-9Z|Q}tLl`{m_i?P%j$K`eTCGgl0PReN`4Eq^fus{1hkzk%SElM(3)>KyJUK@g&y9{GX zumQ}p7UoRSoRP&%c}BvjCeS(UUqd^rpu(xkQy|t|tn_AsgChl%>l6p?KVZm6K4LN_ z7%QLpETXAoS zZ_0&iNMXU8BOI(PbL=CRqVCD(E9p@9fAEyLA6Po^OZUXe*YCECTYNih;Q6ffw9^TK zY-S^jghpQs)r}1q%&PPfh|V%+Q7!{hQIdQ@rFIlFpPdHuSKZEn2CS3T5YXkL(YgIP zUt6u}zgf4Fk`C6^JnM@xoTo9xZVdw5;n(sUR9HA_jJ{<_%nxX8I7jXXR%ikiw93M2Qm(~J%9vu? zB`95;0)z;>!e23v^87O5)_Dg?=AU6Xq% z;U@c8Smf~xMoK;q=ECi-s_FYGFpVl%XNbQc%!(ll`u#-zsi$oSgUzR}nHiwY$-7E< zFUuMFFW^1+s{_8qfRmIn=biDl;l=!7z_ z)OS(;05+qXYXI?ZDEF5j9NbiC>KX6p3uc_HvsoY`ayo=g&m2~_7D2Yyc{bP{bP!-O zIs@xVI@8)TWQ66$Pfn>_?k2%U&t(3od5H=SGI3_4|{juP3lH?)!& z=@ssHV}a-1xJ1xwU!;5DM?rJ*Ms2M>3MKk>fsJdopeliiq(DsmOR5FXz;hBM`hW=s zF?l8CNxY(=ey#0)zP1{QUS6b5SJk}{O0@|KA$bC%kW-$sKa}vfwgyK;=wv^FhB=j` z}*R$GoRLSy%Lfs|LBYd$2Jwa~r#&vt|I#+M2UiaHTuRwtvzdruKq%Wc{8E z+c5cUyWrmOt~Z9ixUaq~YnW^i9lz67snh8iZXGe9lc7hmlq8B!a(=-Coz2Yo(J$Q zxzf^VBLob}U?b0NGL;H1L`c*Ih@Mc6gQRV`RDLEy=m%RSTkK*@+ltF$HnH8s{F3Hs zr5+YCE2O5J3N)ODMK-Mku8=kBg;9e~jlZySz=6qj&6tbWgh`dlQ7X!vr987VFAE>O_YykoOfA+q;J#CzM^nZVf`4M_H z$<_vwYw6PG@B(e=637ACz4X^75m%j4B)pW-h3f zklyH=eaJBXlR6Yna8(V-Vi`XPErR@52F&=285YObM3Y6axfP)ueEw(V_VyTgmWu<) zlsc32SF9GPVmRYV?9rND>B8|1C-9x9Zm9c8$;#K)*BY_63}-s~Bf475*uIa0o;^q|62Da@gk4xB z8T5VquayiE72nHrdJOsS9d_%{rNmaaf6j5HoNnmqFubvln=Dt6^4clcgtEm84JU?@ zt%jk)_)Ly``Nf)?U%bLb-h|)UqRVhwN|=Z}wu2aNY}?<-!MY{qhKS^mj9z3OOkP5v zi0mg z$_IOCGHr|oNcIRZHKoT-QAbL{!_M(Wmhc1EU@ z&+^FtjAx$X2Z{Y5SV;6Bt9e1-h4999zd ze=6nj^ZlQvdG78?yKrUBtMm|ZVp=%3b#ZM@*fO5sD(sf-?-c^2v~FAx5MQJN4C5JS z3Wrlgj5tZYFxjF;@9BzKV|UEx`KFLJ1X2X{gRc;H3wsQQd-P9pK3Gg9<_#3o2pP5w z`ZuGn!E(Q&unp>&41X+;#o}2Y*QK;;$}gBGd}swJeKx}_IP4q%U~z= z)N_fgiKwsFHV<;)fCwgeRLo=^&&lZM+Z}f?n7cBHd}q zek?%Ytnh$2HB3zR$opcJ^2=S)2LYVfjp*gJX^*Xik!POlJZcB{!V)f=(F*=kxJ=T+ zcaKW>)5-sp`k%XVUCeL71D8#&g{@xyCGP)MDwV_M`~Oe!Bos#IRij@G$(ytCUdn?=i67k~*RAHQPolL6+o>UgH5Zr*%Md#BD$O8>0?e>y1~eS8 z3?c3(+}|srUu-65w{uHG6{guEd1&Rzkyh5qnl3M&uzjWREnd-DrbAFH2dMl3c#|2G z!tOEOo>dqq7?C^9Z)k48S1@gZtPBqY9^bd*J+%yXh*eFbs(>Wao>ZniKkGm1%75n0 z`>+ea%jLhWmk;(5@?Y002hZ~VDIQf-A0*pX?<4(l1iUyApg|U^e9I~n`vA^m6}}38 z&Htfie$?xo?)Hyo4tNXa625{xj?@4Y@ARr#(U0|eCG>5$eGEJcJB5XM;R{az9Dpj0 zDEhtLuvXlr$oWC06wi5gM^yU#=d+K4R=-xf<9}6E>3YF^1l8%iJL|MQwK@zm{8?2C z?e5#24BD&@>u1e2M=E|*)k2AIHU&vg#i4nLs8O<%NU@h+hPnh^!bSJNF}M zm;*-zg0~^?pw<7>>Px^M~$-*vQF^4jE+nOv6dL zdp2kd2Bh1hH@%OXn2Z-y6^h&2a^H6=J39#qvXP}kbt(F>HdZ0dX9^|z{I|&_P#eDGhN)q+Tq2`-buaPt(}W

pjz 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 literal 0 HcmV?d00001 diff --git a/infra/charts/feast/charts/feast-core/requirements.yaml b/infra/charts/feast/charts/feast-core/requirements.yaml new file mode 100644 index 0000000000..efe9fec508 --- /dev/null +++ b/infra/charts/feast/charts/feast-core/requirements.yaml @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + version: 6.5.5 + repository: "@stable" + condition: postgresql.enabled +- name: kafka + version: 0.20.1 + repository: "@incubator" + condition: kafka.enabled \ No newline at end of file diff --git a/infra/charts/feast-core/templates/_helpers.tpl b/infra/charts/feast/charts/feast-core/templates/_helpers.tpl similarity index 57% rename from infra/charts/feast-core/templates/_helpers.tpl rename to infra/charts/feast/charts/feast-core/templates/_helpers.tpl index aed02bef0f..7c095e11c4 100644 --- a/infra/charts/feast-core/templates/_helpers.tpl +++ b/infra/charts/feast/charts/feast-core/templates/_helpers.tpl @@ -25,33 +25,21 @@ If release name contains chart name it will be used as a full name. {{- end -}} {{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "postgresql.fullname" -}} -{{- $name := default "postgresql" -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} - -{{/* -Create a postgres hostname, if not specifically set by the user. +Create chart name and version as used by the chart label. */}} -{{- define "postgresql.host" -}} -{{- if .Values.postgresql.host -}} -{{- .Values.postgresql.host -}} -{{- else -}} -{{ printf "%s.%s.svc.cluster.local" (include "postgresql.fullname" .) .Release.Namespace }} -{{- end -}} +{{- define "feast-core.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* -Create chart name and version as used by the chart label. +Common labels */}} -{{- define "feast-core.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- define "feast-core.labels" -}} +app.kubernetes.io/name: {{ include "feast-core.name" . }} +helm.sh/chart: {{ include "feast-core.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 }} {{- end -}} diff --git a/infra/charts/feast/charts/feast-core/templates/configmap.yaml b/infra/charts/feast/charts/feast-core/templates/configmap.yaml new file mode 100644 index 0000000000..dcfe6d5a26 --- /dev/null +++ b/infra/charts/feast/charts/feast-core/templates/configmap.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "feast-core.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "feast-core.name" . }} + component: core + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + application.yaml: | +{{- $config := index .Values "application.yaml"}} + +{{- if .Values.postgresql.enabled }} +{{- $datasource := dict "url" (printf "jdbc:postgresql://%s:%s/%s" (printf "%s-postgresql" .Release.Name) (.Values.postgresql.service.port | toString) (.Values.postgresql.postgresqlDatabase)) "driverClassName" "org.postgresql.Driver" }} +{{- $newConfig := dict "spring" (dict "datasource" $datasource) }} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + +{{- if .Values.kafka.enabled }} +{{- $topic := index .Values.kafka.topics 0 }} +{{- $options := dict "topic" $topic.name "replicationFactor" $topic.replicationFactor "partitions" $topic.partitions "bootstrapServers" (printf "%s:9092" (printf "%s-kafka" .Release.Name)) }} +{{- $newConfig := dict "feast" (dict "stream" (dict "type" "kafka" "options" $options))}} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + +{{- toYaml $config | nindent 4 }} diff --git a/infra/charts/feast/charts/feast-core/templates/deployment.yaml b/infra/charts/feast/charts/feast-core/templates/deployment.yaml new file mode 100644 index 0000000000..02a533c263 --- /dev/null +++ b/infra/charts/feast/charts/feast-core/templates/deployment.yaml @@ -0,0 +1,108 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "feast-core.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "feast-core.name" . }} + component: core + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "feast-core.name" . }} + component: core + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "feast-core.name" . }} + component: core + release: {{ .Release.Name }} + spec: + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + + volumes: + - name: {{ template "feast-core.fullname" . }}-config + configMap: + name: {{ template "feast-core.fullname" . }} + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: {{ template "feast-core.fullname" . }}-gcpserviceaccount + secret: + secretName: {{ .Values.gcpServiceAccount.existingSecret.name }} + {{- end }} + + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + + volumeMounts: + - name: {{ template "feast-core.fullname" . }}-config + mountPath: "{{ .Values.springConfigMountPath }}" + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: {{ template "feast-core.fullname" . }}-gcpserviceaccount + mountPath: {{ .Values.gcpServiceAccount.mountPath }} + readOnly: true + {{- end }} + + env: + {{- if .Values.postgresql.enabled }} + - name: SPRING_DATASOURCE_USERNAME + value: {{ .Values.postgresql.postgresqlUsername }} + - name: SPRING_DATASOURCE_PASSWORD + value: {{ .Values.postgresql.postgresqlPassword }} + {{- end }} + + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: GOOGLE_APPLICATION_CREDENTIALS + value: {{ .Values.gcpServiceAccount.mountPath }}/{{ .Values.gcpServiceAccount.existingSecret.key }} + {{- end }} + + command: + - java + {{- range .Values.jvmOptions }} + - {{ . }} + {{- end }} + - -jar + - /opt/feast/feast-core.jar + - "--spring.config.location=file:{{ .Values.springConfigMountPath }}/application.yaml" + + ports: + - name: http + containerPort: {{ .Values.service.http.targetPort }} + - name: grpc + containerPort: {{ .Values.service.grpc.targetPort }} + + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: {{ .Values.service.http.targetPort }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /healthz + port: {{ .Values.service.http.targetPort }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + + resources: + {{- toYaml .Values.resources | nindent 10 }} diff --git a/infra/charts/feast-core/templates/core-ingress.yaml b/infra/charts/feast/charts/feast-core/templates/ingress.yaml similarity index 81% rename from infra/charts/feast-core/templates/core-ingress.yaml rename to infra/charts/feast/charts/feast-core/templates/ingress.yaml index e2cbd0e476..86fc2d3f17 100644 --- a/infra/charts/feast-core/templates/core-ingress.yaml +++ b/infra/charts/feast/charts/feast-core/templates/ingress.yaml @@ -20,9 +20,9 @@ spec: - host: {{ .host | quote }} http: paths: - - path: / - backend: - serviceName: {{ $fullName }} - servicePort: {{ .port | quote }} + - path: / + backend: + serviceName: {{ $fullName }} + servicePort: {{ .port | quote }} {{- end }} {{- end }} \ No newline at end of file diff --git a/infra/charts/feast-core/templates/core-service.yaml b/infra/charts/feast/charts/feast-core/templates/service.yaml similarity index 79% rename from infra/charts/feast-core/templates/core-service.yaml rename to infra/charts/feast/charts/feast-core/templates/service.yaml index c8b53c1228..a649991b7b 100644 --- a/infra/charts/feast-core/templates/core-service.yaml +++ b/infra/charts/feast/charts/feast-core/templates/service.yaml @@ -10,17 +10,17 @@ metadata: heritage: {{ .Release.Service }} {{- with .Values.service.annotations }} annotations: -{{ toYaml . | indent 4 }} + {{ toYaml . | nindent 4 }} {{- end }} spec: type: {{ .Values.service.type }} -{{- if .Values.service.loadBalancerIP }} + {{- if .Values.service.loadBalancerIP }} loadBalancerIP: {{ .Values.service.loadBalancerIP }} -{{- end }} -{{- if .Values.service.loadBalancerSourceRanges }} + {{- end }} + {{- if .Values.service.loadBalancerSourceRanges }} loadBalancerSourceRanges: -{{ toYaml .Values.service.loadBalancerSourceRanges | indent 2 }} -{{- end }} + {{ toYaml .Values.service.loadBalancerSourceRanges | nindent 2 }} + {{- end }} ports: - name: http port: {{ .Values.service.http.port }} @@ -32,3 +32,4 @@ spec: app: {{ template "feast-core.name" . }} component: core release: {{ .Release.Name }} + diff --git a/infra/charts/feast/charts/feast-core/values.yaml b/infra/charts/feast/charts/feast-core/values.yaml new file mode 100644 index 0000000000..b75fddfd69 --- /dev/null +++ b/infra/charts/feast/charts/feast-core/values.yaml @@ -0,0 +1,179 @@ +# postgresql configures Postgresql that is installed as part of Feast Core. +# Refer to https://github.com/helm/charts/tree/c42002a21abf8eff839ff1d2382152bde2bbe596/stable/postgresql +# for additional configuration. +postgresql: + # enabled specifies whether Postgresql should be installed as part of Feast Core. + # + # Feast Core requires a database to store data such as the created FeatureSets + # and job statuses. If enabled, the database and service port specified below + # will override "spring.datasource.url" value in application.yaml. The + # username and password will also be set as environment variables that will + # override "spring.datasource.username/password" in application.yaml. + enabled: true + # postgresqlDatabase is the name of the database used by Feast Core. + postgresqlDatabase: feast + # postgresqlUsername is the username to authenticate to the database. + postgresqlUsername: postgres + # postgresqlPassword is the password to authenticate to the database. + postgresqlPassword: password + service: + # port is the TCP port that Postgresql will listen to + port: 5432 + +# kafka configures Kafka that is installed as part of Feast Core. +# Refer to https://github.com/helm/charts/tree/c42002a21abf8eff839ff1d2382152bde2bbe596/incubator/kafka +# for additional configuration. +kafka: + # enabled specifies whether Kafka should be installed as part of Feast Core. + # + # Feast Core requires a Kafka instance to be set as the default source for + # FeatureRows. If enabled, "feast.stream" option in application.yaml will + # be overridden by this installed Kafka configuration. + enabled: true + topics: + # topic that will be used as default in Feast Core for the default Kafka source. + - name: feast + replicationFactor: 1 + partitions: 1 + +# replicaCount is the number of pods that will be created. +replicaCount: 1 + +# image configures the Docker image for Feast Core +image: + repository: gcr.io/kf-feast/feast-core + tag: 0.3.0-alpha.1 + pullPolicy: IfNotPresent + +# application.yaml is the main configuration for Feast Core application. +# +# Feast Core is a Spring Boot app which uses this yaml configuration file. +# Refer to https://github.com/gojek/feast/blob/79eb4ab5fa3d37102c1dca9968162a98690526ba/core/src/main/resources/application.yml +# for a complete list and description of the configuration. +# +# Note that some properties defined in application.yaml may be overriden by +# Helm under certain conditions. For example, if postgresql and kafka dependencies +# are enabled. +application.yaml: + grpc: + port: 6565 + enable-reflection: true + feast: + jobs: + runner: DirectRunner + options: {} + metrics: + enabled: false + type: prometheus + host: localhost + port: 9091 + stream: + type: kafka + options: + topic: TOPIC + bootstrapServers: HOST:PORT + replicationFactor: 1 + partitions: 1 + spring: + jpa: + properties.hibernate.format_sql: true + hibernate.naming.physical-strategy=org.hibernate.boot.model.naming: PhysicalNamingStrategyStandardImpl + hibernate.ddl-auto: update + datasource: + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://HOST:PORT/DATABASE + username: USERNAME + password: PASSWORD + management: + metrics: + export: + simple: + enabled: false + statsd: + enabled: false + host: localhost + port: 8125 + +# springConfigMountPath is the directory path where application.yaml will be +# mounted in the container. +springConfigMountPath: /etc/feast/feast-core + +# gcpServiceAccount is the service account that Feast Core will use. +gcpServiceAccount: + # useExistingSecret specifies Feast to use an existing secret containing Google + # Cloud service account JSON key file. + useExistingSecret: false + existingSecret: + # name is the secret name of the existing secret for the service account. + name: feast-gcp-service-account + # key is the secret key of the existing secret for the service account. + # key is normally derived from the file name of the JSON key file. + key: key.json + # mountPath is the directory path where the JSON key file will be mounted. + # the value of "existingSecret.key" is file name of the service account file. + mountPath: /etc/gcloud/service-accounts + +# jvmOptions are options that will be passed to the Java Virtual Machine (JVM) +# running Feast Core. +# +# For example, it is good practice to set min and max heap size in JVM. +# https://stackoverflow.com/questions/6902135/side-effect-for-increasing-maxpermsize-and-max-heap-size +# +# Refer to https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html +# to see other JVM options that can be set. +# +# jvmOptions: +# - -Xms1024m +# - -Xmx1024m + +livenessProbe: + enabled: true + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + +readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + successThreshold: 1 + failureThreshold: 5 + +service: + type: ClusterIP + http: + port: 80 + targetPort: 8080 + grpc: + port: 6565 + targetPort: 6565 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + hosts: + # - host: chart-example.local + # port: http + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/infra/charts/feast-serving/.helmignore b/infra/charts/feast/charts/feast-serving/.helmignore similarity index 100% rename from infra/charts/feast-serving/.helmignore rename to infra/charts/feast/charts/feast-serving/.helmignore diff --git a/infra/charts/feast/charts/feast-serving/Chart.yaml b/infra/charts/feast/charts/feast-serving/Chart.yaml new file mode 100644 index 0000000000..f69b3ab826 --- /dev/null +++ b/infra/charts/feast/charts/feast-serving/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for serving component of Feast +name: feast-serving +version: 0.3.0-alpha.1 diff --git a/infra/charts/feast/charts/feast-serving/charts/redis-9.5.0.tgz b/infra/charts/feast/charts/feast-serving/charts/redis-9.5.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..962893a825d6723e5831ad5528d82c00caaa57f1 GIT binary patch literal 27574 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 CvqJg+ literal 0 HcmV?d00001 diff --git a/infra/charts/feast/charts/feast-serving/requirements.yaml b/infra/charts/feast/charts/feast-serving/requirements.yaml new file mode 100644 index 0000000000..fa4c1df4c1 --- /dev/null +++ b/infra/charts/feast/charts/feast-serving/requirements.yaml @@ -0,0 +1,5 @@ +dependencies: +- name: redis + version: 9.5.0 + repository: "@stable" + condition: redis.enabled diff --git a/infra/charts/feast-serving/templates/_helpers.tpl b/infra/charts/feast/charts/feast-serving/templates/_helpers.tpl similarity index 73% rename from infra/charts/feast-serving/templates/_helpers.tpl rename to infra/charts/feast/charts/feast-serving/templates/_helpers.tpl index 72e5388337..49abb6b8e5 100644 --- a/infra/charts/feast-serving/templates/_helpers.tpl +++ b/infra/charts/feast/charts/feast-serving/templates/_helpers.tpl @@ -14,8 +14,6 @@ If release name contains chart name it will be used as a full name. {{- define "feast-serving.fullname" -}} {{- if .Values.fullnameOverride -}} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else if contains "feast" .Release.Name -}} -{{- $name := "serving" }} {{- else -}} {{- $name := default .Chart.Name .Values.nameOverride -}} {{- if contains $name .Release.Name -}} @@ -32,3 +30,16 @@ Create chart name and version as used by the chart label. {{- define "feast-serving.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} + +{{/* +Common labels +*/}} +{{- define "feast-serving.labels" -}} +app.kubernetes.io/name: {{ include "feast-serving.name" . }} +helm.sh/chart: {{ include "feast-serving.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 }} +{{- end -}} diff --git a/infra/charts/feast/charts/feast-serving/templates/configmap.yaml b/infra/charts/feast/charts/feast-serving/templates/configmap.yaml new file mode 100644 index 0000000000..7f11e3e829 --- /dev/null +++ b/infra/charts/feast/charts/feast-serving/templates/configmap.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "feast-serving.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "feast-serving.name" . }} + component: serving + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + application.yaml: | +{{- $config := index .Values "application.yaml" }} + +{{- if .Values.core.enabled }} +{{- $newConfig := dict "feast" (dict "core-host" (printf "%s-feast-core" .Release.Name)) }} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + +{{- $store := index .Values "store.yaml" }} +{{- if eq $store.type "BIGQUERY" }} +{{- $jobStore := dict "host" (printf "%s-redis-headless" .Release.Name) "port" 6379 }} +{{- $newConfig := dict "feast" (dict "jobs" (dict "store-options" $jobStore)) }} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + +{{- toYaml $config | nindent 4 }} + + store.yaml: | +{{- $config := index .Values "store.yaml"}} + +{{- if and .Values.redis.enabled (eq $config.type "REDIS") }} +{{- $newConfig := dict "redis_config" (dict "host" (printf "%s-redis-headless" .Release.Name) "port" .Values.redis.redisPort) }} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + +{{- toYaml $config | nindent 4 }} diff --git a/infra/charts/feast/charts/feast-serving/templates/deployment.yaml b/infra/charts/feast/charts/feast-serving/templates/deployment.yaml new file mode 100644 index 0000000000..c209a75ee5 --- /dev/null +++ b/infra/charts/feast/charts/feast-serving/templates/deployment.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "feast-serving.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "feast-serving.name" . }} + component: serving + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "feast-serving.name" . }} + component: serving + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "feast-serving.name" . }} + component: serving + release: {{ .Release.Name }} + spec: + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + + volumes: + - name: {{ template "feast-serving.fullname" . }}-config + configMap: + name: {{ template "feast-serving.fullname" . }} + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: {{ template "feast-serving.fullname" . }}-gcpserviceaccount + secret: + secretName: {{ .Values.gcpServiceAccount.existingSecret.name }} + {{- end }} + + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + + volumeMounts: + - name: {{ template "feast-serving.fullname" . }}-config + mountPath: "{{ .Values.springConfigMountPath }}" + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: {{ template "feast-serving.fullname" . }}-gcpserviceaccount + mountPath: {{ .Values.gcpServiceAccount.mountPath }} + readOnly: true + {{- end }} + + env: + {{- if .Values.gcpServiceAccount.useExistingSecret }} + - name: GOOGLE_APPLICATION_CREDENTIALS + value: {{ .Values.gcpServiceAccount.mountPath }}/{{ .Values.gcpServiceAccount.existingSecret.key }} + {{- end }} + + command: + - java + {{- range .Values.jvmOptions }} + - {{ . }} + {{- end }} + - -jar + - /opt/feast/feast-serving.jar + - "--spring.config.location=file:{{ .Values.springConfigMountPath }}/application.yaml" + + ports: + - name: http + containerPort: {{ .Values.service.http.targetPort }} + - name: grpc + containerPort: {{ .Values.service.grpc.targetPort }} + + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + exec: + command: ["grpc-health-probe", "-addr=:{{ .Values.service.grpc.targetPort }}"] + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: ["grpc-health-probe", "-addr=:{{ .Values.service.grpc.targetPort }}"] + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + + resources: + {{- toYaml .Values.resources | nindent 10 }} diff --git a/infra/charts/feast-serving/templates/serving-ingress.yaml b/infra/charts/feast/charts/feast-serving/templates/ingress.yaml similarity index 98% rename from infra/charts/feast-serving/templates/serving-ingress.yaml rename to infra/charts/feast/charts/feast-serving/templates/ingress.yaml index 2e64c0c22d..c6b4cb07a8 100644 --- a/infra/charts/feast-serving/templates/serving-ingress.yaml +++ b/infra/charts/feast/charts/feast-serving/templates/ingress.yaml @@ -25,4 +25,4 @@ spec: serviceName: {{ $fullName }} servicePort: {{ .port | quote }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/infra/charts/feast-serving/templates/serving-service.yaml b/infra/charts/feast/charts/feast-serving/templates/service.yaml similarity index 100% rename from infra/charts/feast-serving/templates/serving-service.yaml rename to infra/charts/feast/charts/feast-serving/templates/service.yaml diff --git a/infra/charts/feast/charts/feast-serving/values.yaml b/infra/charts/feast/charts/feast-serving/values.yaml new file mode 100644 index 0000000000..5254015bcc --- /dev/null +++ b/infra/charts/feast/charts/feast-serving/values.yaml @@ -0,0 +1,188 @@ +# redis configures Redis that is installed as part of Feast Serving. +# Refer to https://github.com/helm/charts/tree/99430c4afdc88213c1ca08f40eeb03868ffcc9d7/stable/redis +# for additional configuration +redis: + # enabled specifies whether Redis should be installed as part of Feast Serving. + # + # If enabled, "redis_config" in store.yaml will be overwritten by Helm + # to the configuration in this Redis installation. + enabled: false + # usePassword specifies if password is required to access Redis. Note that + # Feast 0.3 does not support Redis with password. + usePassword: false + # cluster configuration for Redis. + cluster: + # enabled specifies if Redis should be installed in cluster mode. + enabled: false + +# core configures Feast Core in the same parent feast chart that this Feast +# Serving connects to. +core: + # enabled specifies that Feast Serving will use Feast Core installed + # in the same parent feast chart. If enabled, Helm will overwrite + # "feast.core-host" in application.yaml with the correct value. + enabled: true + +# replicaCount is the number of pods that will be created. +replicaCount: 1 + +# image configures the Docker image for Feast Serving +image: + repository: gcr.io/kf-feast/feast-serving + tag: 0.3.0-alpha.1 + pullPolicy: IfNotPresent + +# application.yaml is the main configuration for Feast Serving application. +# +# Feast Core is a Spring Boot app which uses this yaml configuration file. +# Refer to https://github.com/gojek/feast/blob/79eb4ab5fa3d37102c1dca9968162a98690526ba/serving/src/main/resources/application.yml +# for a complete list and description of the configuration. +# +# Note that some properties defined in application.yaml may be overridden by +# Helm under certain conditions. For example, if core is enabled, then +# "feast.core-host" will be overridden. Also, if "type: BIGQUERY" is specified +# in store.yaml, "feast.jobs.store-options" will be overridden as well with +# the default option supported in Feast 0.3. +application.yaml: + feast: + version: 0.3 + core-host: localhost + core-grpc-port: 6565 + tracing: + enabled: false + tracer-name: jaeger + service-name: feast-serving + store: + config-path: /etc/feast/feast-serving/store.yaml + redis-pool-max-size: 128 + redis-pool-max-idle: 64 + jobs: + staging-location: "" + store-type: "" + store-options: {} + grpc: + port: 6566 + enable-reflection: true + spring: + main: + web-application-type: none + +# store.yaml is the configuration for Feast Store. +# +# Refer to this link for description: +# https://github.com/gojek/feast/blob/79eb4ab5fa3d37102c1dca9968162a98690526ba/protos/feast/core/Store.proto +# +# Use the correct store configuration depending on whether the installed +# Feast Serving is "online" or "batch", by uncommenting the correct store.yaml. +# +# Note that if "redis.enabled: true" and "type: REDIS" in store.yaml, +# Helm will override "redis_config" with configuration of Redis installed +# in this chart. +# +# Note that if "type: BIGQUERY" in store.yaml, Helm assumes Feast Online serving +# is also installed with Redis store. Helm will then override "feast.jobs.store-options" +# in application.yaml with the installed Redis store configuration. This is +# because in Feast 0.3, Redis job store is required. +# +# store.yaml: +# name: online +# type: REDIS +# redis_config: +# host: localhost +# port: 6379 +# subscriptions: +# - name: ".*" +# version: ">0" +# +# store.yaml: +# name: bigquery +# type: BIGQUERY +# bigquery_config: +# project_id: PROJECT_ID +# dataset_id: DATASET_ID +# subscriptions: +# - name: ".*" +# version: ">0" + +# springConfigMountPath is the directory path where application.yaml and +# store.yaml will be mounted in the container. +springConfigMountPath: /etc/feast/feast-serving + +# gcpServiceAccount is the service account that Feast Core will use. +gcpServiceAccount: + # useExistingSecret specifies Feast to use an existing secret containing Google + # Cloud service account JSON key file. + useExistingSecret: false + existingSecret: + # name is the secret name of the existing secret for the service account. + name: feast-gcp-service-account + # key is the secret key of the existing secret for the service account. + # key is normally derived from the file name of the JSON key file. + key: key.json + # mountPath is the directory path where the JSON key file will be mounted. + # the value of "existingSecret.key" is file name of the service account file. + mountPath: /etc/gcloud/service-accounts + +# jvmOptions are options that will be passed to the Java Virtual Machine (JVM) +# running Feast Core. +# +# For example, it is good practice to set min and max heap size in JVM. +# https://stackoverflow.com/questions/6902135/side-effect-for-increasing-maxpermsize-and-max-heap-size +# +# Refer to https://docs.oracle.com/cd/E22289_01/html/821-1274/configuring-the-default-jvm-and-java-arguments.html +# to see other JVM options that can be set. +# +# jvmOptions: +# - -Xms768m +# - -Xmx768m + +livenessProbe: + enabled: false + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + +readinessProbe: + enabled: false + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + successThreshold: 1 + failureThreshold: 5 + +service: + type: ClusterIP + http: + port: 80 + targetPort: 8080 + grpc: + port: 6566 + targetPort: 6566 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + hosts: + # - host: chart-example.local + # port: http + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/infra/charts/feast/charts/kafka-0.17.0.tgz b/infra/charts/feast/charts/kafka-0.17.0.tgz deleted file mode 100644 index 5c1b50d5b4fb7bb22b7f3570e11364a9bbfbe9bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30429 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 z 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 YJUvg(kN5ol00030{~wTyX8>LT0H^NdssI20 diff --git a/infra/charts/feast/charts/nginx-ingress-1.24.2.tgz b/infra/charts/feast/charts/nginx-ingress-1.24.2.tgz deleted file mode 100644 index 24513f7d18e8dbbef0bd6be6a9d5d6558bae9a8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20227 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 O0RR6Duko}1jsgI#_wfh- diff --git a/infra/charts/feast/charts/prometheus-pushgateway-1.0.1.tgz b/infra/charts/feast/charts/prometheus-pushgateway-1.0.1.tgz deleted file mode 100644 index 3983a95d6d0fbcfb1349695d3bfa25068fd708b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5433 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 j{qe9ZsQjZ(z#qy(c_Dc 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 z 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" + +feast-serving-batch: + enabled: false diff --git a/infra/charts/feast/values-external-store.yaml b/infra/charts/feast/values-external-store.yaml new file mode 100644 index 0000000000..d012bcec56 --- /dev/null +++ b/infra/charts/feast/values-external-store.yaml @@ -0,0 +1,5 @@ +# TODO @dheryanto +# +# The following are sample values for installing Feast without setting up +# Kafka and Redis stores. In other words, using Feast with external stream +# source and stores. diff --git a/infra/charts/feast/values-production.yaml b/infra/charts/feast/values-production.yaml new file mode 100644 index 0000000000..6b53dc19ea --- /dev/null +++ b/infra/charts/feast/values-production.yaml @@ -0,0 +1,4 @@ +# TODO @dheryanto +# +# The following are sample values for installing Feast for typical production +# environment. diff --git a/infra/charts/feast/values.yaml b/infra/charts/feast/values.yaml index be3b413829..d6a5004606 100644 --- a/infra/charts/feast/values.yaml +++ b/infra/charts/feast/values.yaml @@ -1,303 +1,100 @@ -global: - postgresql: {} -# Feast core -feast-core: - fullnameOverride: "feast-core" - replicaCount: 1 - image: - registry: gcr.io/kf-feast - repository: feast-core - tag: 0.3.0-SNAPSHOT - pullPolicy: Never - - jobs: - runner: DirectRunner - options: {} - ## If using DataflowRunner, the following options are necessary: - # project: my-gcp-project - # tempLocation: gs://my-feast-bucket/temp - # region: us-central1 - # subnetwork: default - metrics: - enabled: true - ## Type of metrics sink. Only prometheus is currently supported. - type: prometheus - ## Host of the metrics sink. In the case of prometheus, this is the host of the prometheus - ## pushGateway to sink metrics to. - host: feast-prometheus-pushgateway - ## Port of the metrics sink. In the case of prometheus, this is the port of the prometheus - ## pushGateway to sink metrics to. - port: 9091 - - stream: - type: kafka - options: - bootstrapServers: feast-kafka:9092 - replicationFactor: 2 - partitions: 4 - - service: - # annotations: [] - http: - port: 80 - targetPort: 8080 - grpc: - port: 6565 - targetPort: 6565 - type: ClusterIP - # loadBalancerIP: - # loadBalancerSourceRanges: - # - 10.0.0.0/8 - port: 80 - - rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - - livenessProbe: - enabled: false - # initialDelaySeconds: 30 - # failureThreshold: 3 - readinessProbe: - initialDelaySeconds: 30 - failureThreshold: 3 +# Feast deployment installs the following components: +# - Feast Core +# - Feast Serving Online +# - Feast Serving Batch +# +# The configuration for different components can be referenced from: +# - charts/feast-core/values.yaml +# - charts/feast-serving/values.yaml +# +# Note that "feast-serving-online" and "feast-serving-batch" are +# aliases to "feast-serving" chart since in typical scenario two instances +# of Feast Serving: online and batch will be deployed. Both described +# using the same chart "feast-serving". +# +# The following are default values for typical Feast deployment, but not +# for production setting. Refer to "values-production.yaml" for recommended +# values in production environment. +# +# Note that the import job by default uses DirectRunner +# https://beam.apache.org/documentation/runners/direct/ +# in this configuration since it allows Feast to run in more environments +# (unlike DataflowRunner which requires Google Cloud services). +# +# A secret containing Google Cloud service account JSON key is required +# in this configuration. +# https://cloud.google.com/iam/docs/creating-managing-service-accounts +# +# The Google Cloud service account must have the following roles: +# - bigquery.dataEditor +# - bigquery.jobUser +# +# Assuming a service account JSON key file has been downloaded to +# (please name the file key.json): +# /home/user/key.json +# +# Run the following command to create the secret in your Kubernetes cluster: +# +# kubectl create secret generic feast-gcp-service-account \ +# --from-file=/home/user/key.json +# - ## A service account if using the dataflow runner or BigQuery. - serviceAccount: - name: my-service-account - key: tbd_staging.json - - ingress: - enabled: false - # annotations: - # kubernetes.io/ingress.class: nginx - # hosts: - # - host: feast-core.gods.wwhatever.local - # port: http - - resources: - # limits: - # cpu: 100m - # memory: 128Mi +feast-core: + enabled: true + jvmOptions: + - -Xms1024m + - -Xmx1024m + resources: requests: - cpu: 100m - memory: 128Mi - - nodeSelector: {} - -# serving -online-serving: - replicaCount: 1 - - image: - registry: gcr.io/kf-feast - repository: feast-serving - tag: 0.3.0-SNAPSHOT - pullPolicy: Never - - fullnameOverride: feast-serving-online - core: - host: feast-core - port: 6565 - - store: - config: - name: serving - type: REDIS - redis_config: - host: feast-redis - port: 6379 - subscriptions: - - name: .* - version: ">0" - - ## For redis serving. Configuration for the redis connection pool. - redisPool: - maxSize: 128 - maxIdle: 8 - - ## Job configuration is necessary if this serving store is used to - ## facilitate batch retrieval of features, which involve async jobs. - jobs: {} - # stagingLocation: gs://feast-bucket/bq/staging - # storeType: REDIS - # storeOptions: - # host: redis.svc.local - # port: 6379 - - tracing: - enabled: false - # tracer-name: jaeger - # service-name: feast-serving - - rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - - service: - # annotations: [] - http: - port: 80 - targetPort: 8080 - grpc: - port: 6565 - targetPort: 6565 - type: ClusterIP - # loadBalancerIP: - # loadBalancerSourceRanges: - # - 10.0.0.0/8 - port: 80 - - rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - - livenessProbe: - enabled: false - # initialDelaySeconds: 30 - # failureThreshold: 3 - readinessProbe: - initialDelaySeconds: 30 - failureThreshold: 3 - - ## A service account if using the dataflow runner or BigQuery. - # serviceAccount: - # name: my-service-account - - ingress: - enabled: false - # annotations: - # kubernetes.io/ingress.class: nginx - # hosts: - # - host: chart-example.local - # port: http - - resources: - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi + cpu: 1000m + memory: 1024Mi + gcpServiceAccount: + useExistingSecret: true + +feast-serving-online: + enabled: true + redis: + enabled: true + jvmOptions: + - -Xms1024m + - -Xmx1024m + resources: requests: - cpu: 100m - memory: 128Mi - - nodeSelector: {} - -warehouse-serving: - replicaCount: 1 - - image: - registry: gcr.io/kf-feast - repository: feast-serving - tag: 0.3.0-SNAPSHOT - pullPolicy: Never - - fullnameOverride: feast-serving-warehouse - core: - host: feast-core - port: 6565 - - store: - config: - name: warehouse - type: BIGQUERY - bigquery_config: - # Replace with your Google Cloud project configuration - projectId: google-project-id - datasetId: bigquery-dataset - subscriptions: - - name: .* - version: ">0" - - ## For redis serving. Configuration for the redis connection pool. - redisPool: - maxSize: 128 - maxIdle: 8 - - ## Job configuration is necessary if this serving store is used to - ## facilitate batch retrieval of features, which involve async jobs. - jobs: - stagingLocation: gs://zl-test-bucket/feast/staging - storeType: REDIS - storeOptions: - host: feast-redis - port: 6379 - - tracing: + cpu: 500m + memory: 1024Mi + store.yaml: + name: redis + type: REDIS + redis_config: + port: 6379 + subscriptions: + - name: ".*" + version: ">0" + +feast-serving-batch: + enabled: true + redis: enabled: false - # tracer-name: jaeger - # service-name: feast-serving - - rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - - service: - # annotations: [] - http: - port: 80 - targetPort: 8080 - grpc: - port: 6566 - targetPort: 6566 - type: ClusterIP - # loadBalancerIP: - # loadBalancerSourceRanges: - # - 10.0.0.0/8 - port: 80 - - rollingUpdate: - maxSurge: 2 - maxUnavailable: 1 - - livenessProbe: - enabled: false - # initialDelaySeconds: 30 - # failureThreshold: 3 - readinessProbe: - initialDelaySeconds: 30 - failureThreshold: 3 - - ## A service account if using the dataflow runner or BigQuery. - serviceAccount: - name: my-service-account - key: tbd_staging.json - - ingress: - enabled: false - # annotations: - # kubernetes.io/ingress.class: nginx - # hosts: - # - host: chart-example.local - # port: http - - resources: - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - requests: - cpu: 100m - memory: 128Mi - - nodeSelector: {} - -kafka: - provision: true + jvmOptions: + - -Xms1024m + - -Xmx1024m resources: requests: - cpu: 200m - memory: 128Mi - -prometheus-pushgateway: - provision: true - -redis: - provision: true - usePassword: false \ No newline at end of file + cpu: 500m + memory: 1024Mi + gcpServiceAccount: + useExistingSecret: true + application.yaml: + feast: + jobs: + staging-location: gs://bucket/path + store-type: REDIS + store.yaml: + name: bigquery + type: BIGQUERY + bigquery_config: + project_id: PROJECT_ID + dataset_id: DATASET_ID + subscriptions: + - name: ".*" + version: ">0" From 31646871699128b4692c9a20b2a70df16fc6f542 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Wed, 6 Nov 2019 15:49:35 +0800 Subject: [PATCH 07/11] Update configmap.yaml for feast core Override bootstrapServer value only if kafka is enabled and kafka.external is disabled --- .../charts/feast/charts/feast-core/templates/configmap.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/infra/charts/feast/charts/feast-core/templates/configmap.yaml b/infra/charts/feast/charts/feast-core/templates/configmap.yaml index dcfe6d5a26..68dc45c057 100644 --- a/infra/charts/feast/charts/feast-core/templates/configmap.yaml +++ b/infra/charts/feast/charts/feast-core/templates/configmap.yaml @@ -21,7 +21,10 @@ data: {{- if .Values.kafka.enabled }} {{- $topic := index .Values.kafka.topics 0 }} -{{- $options := dict "topic" $topic.name "replicationFactor" $topic.replicationFactor "partitions" $topic.partitions "bootstrapServers" (printf "%s:9092" (printf "%s-kafka" .Release.Name)) }} +{{- $options := dict "topic" $topic.name "replicationFactor" $topic.replicationFactor "partitions" $topic.partitions }} +{{- if not .Values.kafka.external.enabled }} +{{- $_ := set $options "bootstrapServers" (printf "%s:9092" (printf "%s-kafka" .Release.Name)) }} +{{- end }} {{- $newConfig := dict "feast" (dict "stream" (dict "type" "kafka" "options" $options))}} {{- $config := mergeOverwrite $config $newConfig }} {{- end }} From cff362a3f23f1825d36d537e8e42c70912e472b8 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Fri, 8 Nov 2019 01:40:13 +0800 Subject: [PATCH 08/11] Update configmap template for feast-serving Support overriding Redis store host with LoadBalancer IP --- .../feast/charts/feast-serving/templates/configmap.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/infra/charts/feast/charts/feast-serving/templates/configmap.yaml b/infra/charts/feast/charts/feast-serving/templates/configmap.yaml index 7f11e3e829..6c22a1016e 100644 --- a/infra/charts/feast/charts/feast-serving/templates/configmap.yaml +++ b/infra/charts/feast/charts/feast-serving/templates/configmap.yaml @@ -33,6 +33,12 @@ data: {{- if and .Values.redis.enabled (eq $config.type "REDIS") }} {{- $newConfig := dict "redis_config" (dict "host" (printf "%s-redis-headless" .Release.Name) "port" .Values.redis.redisPort) }} {{- $config := mergeOverwrite $config $newConfig }} + +{{- if and (eq .Values.redis.master.service.type "LoadBalancer") (not (empty .Values.redis.master.service.loadBalancerIP)) }} +{{- $newConfig := dict "redis_config" (dict "host" .Values.redis.master.service.loadBalancerIP "port" .Values.redis.redisPort) }} +{{- $config := mergeOverwrite $config $newConfig }} +{{- end }} + {{- end }} {{- toYaml $config | nindent 4 }} From e89d0d571532a3803673a7c5d90a3b7c1ded1fab Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Fri, 8 Nov 2019 09:17:26 +0800 Subject: [PATCH 09/11] Set lower default delay time for readiness probes - So pod scaling and startup is faster - In most cases, Core and Feast should not need more than 15 seconds to start up --- infra/charts/feast/charts/feast-core/values.yaml | 2 +- infra/charts/feast/charts/feast-serving/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/charts/feast/charts/feast-core/values.yaml b/infra/charts/feast/charts/feast-core/values.yaml index b75fddfd69..a9d786c2b1 100644 --- a/infra/charts/feast/charts/feast-core/values.yaml +++ b/infra/charts/feast/charts/feast-core/values.yaml @@ -136,7 +136,7 @@ livenessProbe: readinessProbe: enabled: true - initialDelaySeconds: 30 + initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 10 successThreshold: 1 diff --git a/infra/charts/feast/charts/feast-serving/values.yaml b/infra/charts/feast/charts/feast-serving/values.yaml index 5254015bcc..46464893a9 100644 --- a/infra/charts/feast/charts/feast-serving/values.yaml +++ b/infra/charts/feast/charts/feast-serving/values.yaml @@ -146,7 +146,7 @@ livenessProbe: readinessProbe: enabled: false - initialDelaySeconds: 30 + initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 10 successThreshold: 1 From 9ba7c90ddb2d2bb0499e6695ea86ec11432f1181 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Fri, 8 Nov 2019 11:55:35 +0800 Subject: [PATCH 10/11] Update Dockerfile for Feast Core Include exploded/unpacked jar in the production image To be used when staging files when submitting Dataflow jobs --- infra/docker/core/Dockerfile | 21 +++++++++++++++++++++ infra/docker/serving/Dockerfile | 12 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/infra/docker/core/Dockerfile b/infra/docker/core/Dockerfile index 45fbaab1c4..c4cfe34b71 100644 --- a/infra/docker/core/Dockerfile +++ b/infra/docker/core/Dockerfile @@ -1,17 +1,38 @@ +# ============================================================ +# Build stage 1: Builder +# ============================================================ + FROM maven:3.6-jdk-8-slim as builder ARG REVISION=dev COPY . /build WORKDIR /build +# # Setting Maven repository .m2 directory relative to /build folder gives the # user to optionally use cached repository when building the image by copying # the existing .m2 directory to $FEAST_REPO_ROOT/.m2 +# ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" RUN mvn --also-make --projects core,ingestion -Drevision=$REVISION \ -DskipTests=true --batch-mode package +# +# Unpack the jar and copy the files into production Docker image +# for faster startup time when starting Dataflow jobs from Feast Core. +# This is because we need to stage the classes and dependencies when using Dataflow. +# The final size of the production image will be bigger but it seems +# a good tradeoff between speed and size. +# +# https://github.com/gojek/feast/pull/291 +RUN apt-get -qq update && apt-get -y install unar && \ + unar /build/core/target/feast-core-$REVISION.jar -o /build/core/target/ + +# ============================================================ +# Build stage 2: Production +# ============================================================ FROM openjdk:8-jre as production ARG REVISION=dev COPY --from=builder /build/core/target/feast-core-$REVISION.jar /opt/feast/feast-core.jar +COPY --from=builder /build/core/target/feast-core-$REVISION /opt/feast/feast-core CMD ["java",\ "-Xms2048m",\ "-Xmx2048m",\ diff --git a/infra/docker/serving/Dockerfile b/infra/docker/serving/Dockerfile index 7019cf970a..3517183d78 100644 --- a/infra/docker/serving/Dockerfile +++ b/infra/docker/serving/Dockerfile @@ -1,18 +1,30 @@ +# ============================================================ +# Build stage 1: Builder +# ============================================================ + FROM maven:3.6-jdk-8-slim as builder ARG REVISION=dev COPY . /build WORKDIR /build +# # Setting Maven repository .m2 directory relative to /build folder gives the # user to optionally use cached repository when building the image by copying # the existing .m2 directory to $FEAST_REPO_ROOT/.m2 +# ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" RUN mvn --also-make --projects serving -Drevision=$REVISION \ -DskipTests=true --batch-mode package +# ============================================================ +# Build stage 2: Production +# ============================================================ + FROM openjdk:8-jre-alpine as production ARG REVISION=dev +# # Download grpc_health_probe to run health check for Feast Serving # https://kubernetes.io/blog/2018/10/01/health-checking-grpc-servers-on-kubernetes/ +# RUN wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.3.1/grpc_health_probe-linux-amd64 \ -O /usr/bin/grpc-health-probe && \ chmod +x /usr/bin/grpc-health-probe From c6010bdf2477818ca136a92bd600accba5f57c98 Mon Sep 17 00:00:00 2001 From: David Heryanto Date: Fri, 8 Nov 2019 12:19:38 +0800 Subject: [PATCH 11/11] Allow users to specify nodePort in Helm values --- .../feast/charts/feast-core/templates/service.yaml | 6 ++++++ infra/charts/feast/charts/feast-core/values.yaml | 8 ++++++++ .../charts/feast-serving/templates/service.yaml | 12 +++++++++--- infra/charts/feast/charts/feast-serving/values.yaml | 8 ++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/infra/charts/feast/charts/feast-core/templates/service.yaml b/infra/charts/feast/charts/feast-core/templates/service.yaml index a649991b7b..1561398337 100644 --- a/infra/charts/feast/charts/feast-core/templates/service.yaml +++ b/infra/charts/feast/charts/feast-core/templates/service.yaml @@ -25,9 +25,15 @@ spec: - name: http port: {{ .Values.service.http.port }} targetPort: {{ .Values.service.http.targetPort }} + {{- if .Values.service.http.nodePort }} + nodePort: {{ .Values.service.http.nodePort }} + {{- end }} - name: grpc port: {{ .Values.service.grpc.port }} targetPort: {{ .Values.service.grpc.targetPort }} + {{- if .Values.service.grpc.nodePort }} + nodePort: {{ .Values.service.grpc.nodePort }} + {{- end }} selector: app: {{ template "feast-core.name" . }} component: core diff --git a/infra/charts/feast/charts/feast-core/values.yaml b/infra/charts/feast/charts/feast-core/values.yaml index a9d786c2b1..370bf868d7 100644 --- a/infra/charts/feast/charts/feast-core/values.yaml +++ b/infra/charts/feast/charts/feast-core/values.yaml @@ -147,9 +147,17 @@ service: http: port: 80 targetPort: 8080 + # nodePort is the port number that each cluster node will listen to + # https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + # + # nodePort: grpc: port: 6565 targetPort: 6565 + # nodePort is the port number that each cluster node will listen to + # https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + # + # nodePort: ingress: enabled: false diff --git a/infra/charts/feast/charts/feast-serving/templates/service.yaml b/infra/charts/feast/charts/feast-serving/templates/service.yaml index 71b47bfd00..7afdd31b45 100644 --- a/infra/charts/feast/charts/feast-serving/templates/service.yaml +++ b/infra/charts/feast/charts/feast-serving/templates/service.yaml @@ -22,12 +22,18 @@ spec: {{ toYaml .Values.service.loadBalancerSourceRanges | indent 2 }} {{- end }} ports: - - name: grpc - port: {{ .Values.service.grpc.port }} - targetPort: {{ .Values.service.grpc.targetPort }} - name: http port: {{ .Values.service.http.port }} targetPort: {{ .Values.service.http.targetPort }} + {{- if .Values.service.http.nodePort }} + nodePort: {{ .Values.service.http.nodePort }} + {{- end }} + - name: grpc + port: {{ .Values.service.grpc.port }} + targetPort: {{ .Values.service.grpc.targetPort }} + {{- if .Values.service.grpc.nodePort }} + nodePort: {{ .Values.service.grpc.nodePort }} + {{- end }} selector: app: {{ template "feast-serving.name" . }} component: serving diff --git a/infra/charts/feast/charts/feast-serving/values.yaml b/infra/charts/feast/charts/feast-serving/values.yaml index 46464893a9..ffe8684c6c 100644 --- a/infra/charts/feast/charts/feast-serving/values.yaml +++ b/infra/charts/feast/charts/feast-serving/values.yaml @@ -157,9 +157,17 @@ service: http: port: 80 targetPort: 8080 + # nodePort is the port number that each cluster node will listen to + # https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + # + # nodePort: grpc: port: 6566 targetPort: 6566 + # nodePort is the port number that each cluster node will listen to + # https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + # + # nodePort: ingress: enabled: false