Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helm charts for feast jobservice #1081

Merged
merged 7 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ compile-protos-python: install-python-ci-dependencies
@$(foreach dir,$(PROTO_TYPE_SUBDIRS),cd ${ROOT_DIR}/protos; python -m grpc_tools.protoc -I. --python_out=../sdk/python/ --mypy_out=../sdk/python/ feast/$(dir)/*.proto;)
@$(foreach dir,$(PROTO_SERVICE_SUBDIRS),cd ${ROOT_DIR}/protos; python -m grpc_tools.protoc -I. --grpc_python_out=../sdk/python/ feast/$(dir)/*.proto;)
cd ${ROOT_DIR}/protos; python -m grpc_tools.protoc -I. --python_out=../sdk/python/ --mypy_out=../sdk/python/ tensorflow_metadata/proto/v0/*.proto
cd ${ROOT_DIR}/protos; python -m grpc_tools.protoc -I. --python_out=../sdk/python/ --grpc_python_out=../sdk/python/ --mypy_out=../sdk/python/ feast/third_party/grpc/health/v1/*.proto

install-python: compile-protos-python
cd sdk/python; python setup.py develop
Expand Down
4 changes: 4 additions & 0 deletions infra/charts/feast/charts/feast-jobservice/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
description: Feast Job Coontroller manage ingestion jobs.
name: feast-jobservice
version: 0.8-SNAPSHOT
65 changes: 65 additions & 0 deletions infra/charts/feast/charts/feast-jobservice/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
feast-jobservice
==========
Feast Job Service manage ingestion jobs.

Current chart version is `0.8-SNAPSHOT`





## Chart Values

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| envOverrides | object | `{}` | Extra environment variables to set |
| gcpProjectId | string | `""` | Project ID to use when using Google Cloud services such as BigQuery, Cloud Storage and Dataflow |
| gcpServiceAccount.enabled | bool | `false` | Flag to use [service account](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) JSON key |
| gcpServiceAccount.existingSecret.key | string | `"credentials.json"` | Key in the secret data (file name of the service account) |
| gcpServiceAccount.existingSecret.name | string | `"feast-gcp-service-account"` | Name of the existing secret containing the service account |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"gcr.io/kf-feast/feast-jobservice"` | Docker image repository |
| image.tag | string | `"develop"` | Image tag |
| ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress |
| ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth |
| ingress.grpc.class | string | `"nginx"` | Which ingress controller to use |
| ingress.grpc.enabled | bool | `false` | Flag to create an ingress resource for the service |
| ingress.grpc.hosts | list | `[]` | List of hostnames to match when routing requests |
| ingress.grpc.https.enabled | bool | `true` | Flag to enable HTTPS |
| ingress.grpc.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
| ingress.grpc.whitelist | string | `""` | Allowed client IP source ranges |
| ingress.http.annotations | object | `{}` | Extra annotations for the ingress |
| ingress.http.auth.authUrl | string | `"http://auth-server.auth-ns.svc.cluster.local/auth"` | URL to an existing authentication service |
| ingress.http.auth.enabled | bool | `false` | Flag to enable auth |
| ingress.http.class | string | `"nginx"` | Which ingress controller to use |
| ingress.http.enabled | bool | `false` | Flag to create an ingress resource for the service |
| ingress.http.hosts | list | `[]` | List of hostnames to match when routing requests |
| ingress.http.https.enabled | bool | `true` | Flag to enable HTTPS |
| ingress.http.https.secretNames | object | `{}` | Map of hostname to TLS secret name |
| ingress.http.whitelist | string | `""` | Allowed client IP source ranges |
| livenessProbe.enabled | bool | `false` | Flag to enabled the probe |
| livenessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
| livenessProbe.initialDelaySeconds | int | `60` | Delay before the probe is initiated |
| livenessProbe.periodSeconds | int | `10` | How often to perform the probe |
| livenessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
| livenessProbe.timeoutSeconds | int | `5` | When the probe times out |
| logLevel | string | `"WARN"` | Default log level, use either one of `DEBUG`, `INFO`, `WARN` or `ERROR` |
| logType | string | `"Console"` | Log format, either `JSON` or `Console` |
| nodeSelector | object | `{}` | Node labels for pod assignment |
| podLabels | object | `{}` | Labels to be added to Feast Job Service pods |
| prometheus.enabled | bool | `true` | Flag to enable scraping of Feast Job Service metrics |
| readinessProbe.enabled | bool | `true` | Flag to enabled the probe |
| readinessProbe.failureThreshold | int | `5` | Min consecutive failures for the probe to be considered failed |
| readinessProbe.initialDelaySeconds | int | `20` | Delay before the probe is initiated |
| readinessProbe.periodSeconds | int | `10` | How often to perform the probe |
| readinessProbe.successThreshold | int | `1` | Min consecutive success for the probe to be considered successful |
| readinessProbe.timeoutSeconds | int | `10` | When the probe times out |
| replicaCount | int | `1` | Number of pods that will be created |
| resources | object | `{}` | CPU/memory [resource requests/limit](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) |
| service.grpc.nodePort | string | `nil` | Port number that each cluster node will listen to |
| service.grpc.port | int | `6568` | Service port for GRPC requests |
| service.grpc.targetPort | int | `6568` | Container port serving GRPC requests |
| service.http.nodePort | string | `nil` | Port number that each cluster node will listen to |
| service.http.port | int | `80` | Service port for HTTP requests |
| service.http.targetPort | int | `8080` | Container port serving HTTP requests and Prometheus metrics |
| service.type | string | `"ClusterIP"` | Kubernetes service type |
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "feast-jobservice.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- 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 "feast-jobservice.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "feast-jobservice.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Common labels
*/}}
{{- define "feast-jobservice.labels" -}}
app.kubernetes.io/name: {{ include "feast-jobservice.name" . }}
helm.sh/chart: {{ include "feast-jobservice.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 -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{{- /*
This takes an array of three values:
- the top context
- the feast component
- the service protocol
- the ingress context
*/ -}}
{{- define "feast.ingress" -}}
{{- $top := (index . 0) -}}
{{- $component := (index . 1) -}}
{{- $protocol := (index . 2) -}}
{{- $ingressValues := (index . 3) -}}
apiVersion: extensions/v1beta1
kind: Ingress
{{ include "feast.ingress.metadata" . }}
spec:
rules:
{{- range $host := $ingressValues.hosts }}
- host: {{ $host }}
http:
paths:
- path: /
backend:
serviceName: {{ include (printf "feast-%s.fullname" $component) $top }}
servicePort: {{ index $top.Values "service" $protocol "port" }}
{{- end }}
{{- if $ingressValues.https.enabled }}
tls:
{{- range $host := $ingressValues.hosts }}
- secretName: {{ index $ingressValues.https.secretNames $host | default (splitList "." $host | rest | join "-" | printf "%s-tls") }}
hosts:
- {{ $host }}
{{- end }}
{{- end -}}
{{- end -}}

{{- define "feast.ingress.metadata" -}}
{{- $commonMetadata := fromYaml (include "common.metadata" (first .)) }}
{{- $overrides := fromYaml (include "feast.ingress.metadata-overrides" .) -}}
{{- toYaml (merge $overrides $commonMetadata) -}}
{{- end -}}

{{- define "feast.ingress.metadata-overrides" -}}
{{- $top := (index . 0) -}}
{{- $component := (index . 1) -}}
{{- $protocol := (index . 2) -}}
{{- $ingressValues := (index . 3) -}}
{{- $commonFullname := include "common.fullname" $top }}
metadata:
name: {{ $commonFullname }}-{{ $component }}-{{ $protocol }}
annotations:
kubernetes.io/ingress.class: {{ $ingressValues.class | quote }}
{{- if (and (eq $ingressValues.class "nginx") $ingressValues.auth.enabled) }}
nginx.ingress.kubernetes.io/auth-url: {{ $ingressValues.auth.authUrl | quote }}
nginx.ingress.kubernetes.io/auth-response-headers: "x-auth-request-email, x-auth-request-user"
nginx.ingress.kubernetes.io/auth-signin: "https://{{ $ingressValues.auth.signinHost | default (splitList "." (index $ingressValues.hosts 0) | rest | join "." | printf "auth.%s")}}/oauth2/start?rd=/r/$host/$request_uri"
{{- end }}
{{- if (and (eq $ingressValues.class "nginx") $ingressValues.whitelist) }}
nginx.ingress.kubernetes.io/whitelist-source-range: {{ $ingressValues.whitelist | quote -}}
{{- end }}
{{- if (and (eq $ingressValues.class "nginx") (eq $protocol "grpc") ) }}
# TODO: Allow choice of GRPC/GRPCS
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
{{- end }}
{{- if $ingressValues.annotations -}}
{{ include "common.annote" $ingressValues.annotations | indent 4 }}
{{- end }}
{{- end -}}
117 changes: 117 additions & 0 deletions infra/charts/feast/charts/feast-jobservice/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "feast-jobservice.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "feast-jobservice.name" . }}
component: jobservice
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "feast-jobservice.name" . }}
component: jobservice
release: {{ .Release.Name }}
template:
metadata:
{{- if .Values.prometheus.enabled }}
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "{{ .Values.service.http.targetPort }}"
prometheus.io/scrape: "true"
{{- end }}
labels:
app: {{ template "feast-jobservice.name" . }}
component: jobservice
release: {{ .Release.Name }}
{{- if .Values.podLabels }}
{{ toYaml .Values.podLabels | nindent 8 }}
{{- end }}
spec:
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}

{{- if .Values.gcpServiceAccount.enabled }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to hardcode the GCP specific fields here still? I think we want to move away from this (if we support AWS)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@woop we should probably handle that in another PR to get this one unblocked.

  • All services (core, serving, jupyter) have the gcp-specific fields, so we need to figure out the overall solution here, not just for job service
  • Looks like for AWS @oavdeev wrote the terraform script that uses envOverrides to override some environment variables, and he won't need to hardcode any AWS-specific stuff. However, this approach can't be used readily, since we don't have terraform for GCP deployment & some of these gcp fields are used outside env variables right now. Therefore I don't have a clear alternative to move these variables to.
  • It won't affect AWS deployment in the short term, so we can temporarily leave it here

Let me know what you think!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, lets go ahead with cleaning this up in another PR.

volumes:
- name: {{ template "feast-jobservice.fullname" . }}-gcp-service-account
secret:
secretName: {{ .Values.gcpServiceAccount.existingSecret.name }}
{{- end }}

containers:
- name: {{ .Chart.Name }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{ .Values.image.pullPolicy }}

{{- if .Values.gcpServiceAccount.enabled }}
volumeMounts:
- name: {{ template "feast-jobservice.fullname" . }}-gcp-service-account
mountPath: /etc/secrets/google
readOnly: true
{{- end }}

env:
- name: LOG_TYPE
value: {{ .Values.logType | quote }}
- name: LOG_LEVEL
value: {{ .Values.logLevel | quote }}

{{- if .Values.gcpServiceAccount.enabled }}
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /etc/secrets/google/{{ .Values.gcpServiceAccount.existingSecret.key }}
{{- end }}

{{- if .Values.gcpProjectId }}
- name: GOOGLE_CLOUD_PROJECT
value: {{ .Values.gcpProjectId | quote }}
{{- end }}

{{- range $key, $value := .Values.envOverrides }}
- name: {{ printf "%s" $key | replace "." "_" | upper | quote }}
{{- if eq (kindOf $value) "map" }}
valueFrom:
{{- toYaml $value | nindent 12 }}
{{- else }}
value: {{ $value | quote }}
{{- end }}
{{- end }}

command:
- feast
- server
ports:
- name: http
containerPort: {{ .Values.service.http.targetPort }}
- name: grpc
containerPort: {{ .Values.service.grpc.targetPort }}

{{- if .Values.livenessProbe.enabled }}
livenessProbe:
exec:
command: ["/usr/bin/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: ["/usr/bin/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 }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{- if .Values.ingress.http.enabled -}}
{{ template "feast.ingress" (list . "jobservice" "http" .Values.ingress.http) }}
{{- end }}
---
{{ if .Values.ingress.grpc.enabled -}}
{{ template "feast.ingress" (list . "jobservice" "grpc" .Values.ingress.grpc) }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "feast-jobservice.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "feast-jobservice.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.service.annotations }}
annotations:
{{ toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
{{- if .Values.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}
{{- if .Values.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml .Values.service.loadBalancerSourceRanges | nindent 2 }}
{{- end }}
ports:
- 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-jobservice.name" . }}
component: jobservice
release: {{ .Release.Name }}

Loading