diff --git a/incubator/kubeless/Chart.yaml b/incubator/kubeless/Chart.yaml new file mode 100644 index 0000000000..84e584756e --- /dev/null +++ b/incubator/kubeless/Chart.yaml @@ -0,0 +1,18 @@ +name: kubeless +version: 0.2.0 +appVersion: v0.3.1 +description: Kubeless is a Kubernetes-native serverless framework. It runs on top of your Kubernetes cluster and allows you to deploy small unit of code without having to build container images. +icon: https://cloud.githubusercontent.com/assets/4056725/25480209/1d5bf83c-2b48-11e7-8db8-bcd650f31297.png +apiVersion: v1 +home: http://kubeless.io/ +engine: gotpl +sources: +- https://github.com/kubeless/kubeless +keywords: +- kubeless +- serverless +- function-as-a-service +- faas +maintainers: +- name: Bitnami + email: containers@bitnami.com diff --git a/incubator/kubeless/OWNERS b/incubator/kubeless/OWNERS new file mode 100644 index 0000000000..0422341019 --- /dev/null +++ b/incubator/kubeless/OWNERS @@ -0,0 +1,8 @@ +approvers: +- prydonius +- tompizmor +- sameersbn +reviewers: +- prydonius +- tompizmor +- sameersbn \ No newline at end of file diff --git a/incubator/kubeless/README.md b/incubator/kubeless/README.md new file mode 100644 index 0000000000..d868ca1b47 --- /dev/null +++ b/incubator/kubeless/README.md @@ -0,0 +1,98 @@ +# Kubeless + +[Kubeless](http://kubeless.io/) is a Kubernetes-native serverless framework. It runs on top of your Kubernetes cluster and allows you to deploy small unit of code without having to build container images. With kubeless you can build advanced applications that tie together services using functions. + +## TL;DR; + +```bash +$ helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com/ +$ helm install --namespace kubeless incubator/kubeless +``` + +## Introduction + +This chart bootstraps a [Kubeless](https://github.com/kubeless/kubeless) and a [Kubeless-UI](https://github.com/kubeless/kubeless-ui) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Kubernetes 1.7+ with Beta APIs enabled +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install --name my-release --namespace kubeless incubator/kubeless +``` + +> **NOTE** +> +> While the chart supports deploying Kubeless to any namespace, Kubeless expects to be deployed under a namespace named `kubeless`. + +The command deploys Kubernetes on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```bash +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +The following tables lists the configurable parameters of the Kubeless chart and their default values. + +| Parameter | Description | Default | +|------------------------------------------|-------------------------------|-------------------------------| +| `controller.deployment.image.repository` | Controller image | `bitnami/kubeless-controller` | +| `controller.deployment.image.pullPolicy` | Controller image pull policy | `IfNotPresent` | +| `controller.deployment.replicaCount` | Number of replicas | `1` | +| `ui.enabled` | Kubeless UI component | `false` | +| `ui.deployment.ui.image.repository` | Kubeless UI image | `bitnami/kubeless-ui` | +| `ui.deployment.ui.image.pullPolicy` | Kubeless UI image pull policy | `IfNotPresent` | +| `ui.deployment.proxy.image.repository` | Proxy image | `kelseyhightower/kubectl` | +| `ui.deployment.proxy.image.pullPolicy` | Proxy image pull policy | `IfNotPresent` | +| `ui.deployment.replicaCount` | Number of replicas | `1` | +| `ui.service.name` | Service name | `ui-port` | +| `ui.service.type` | Kubernetes service name | `NodePort` | +| `ui.service.externalPort` | Service external port | `3000` | +| `zookeeper.statefulSet.image.repository` | Zookeeper image | `bitnami/zookeeper` | +| `zookeeper.statefulSet.image.pullPolicy` | Zookeeper image pull policy | `IfNotPresent` | +| `zookeeper.statefulSet.replicaCount` | Number of replicas | `1` | +| `kafka.statefulSet.image.repository` | Kafka image | `bitnami/kafka` | +| `kafka.statefulSet.image.pullPolicy` | Kafka image pull policy | `IfNotPresent` | +| `kafka.statefulSet.replicaCount` | Number of replicas | `1` | + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```bash +$ helm install --name my-release --set service.name=ui-service,service,externalPort=4000 --namespace kubeless incubator/kubeless +``` + +The above command sets the Kubeless service name to `ui-service` and the external port to `4000`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```bash +$ helm install --name my-release -f values.yaml --namespace kubeless incubator/kubeless +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Kubeless UI + +The [Kubeless UI](https://github.com/kubeless/kubeless-ui) component is disabled by default. In order to enable it set the ui.enabled property to true. For example, + +```bash +$ helm install --name my-release --set ui.enabled=true --namespace kubeless incubator/kubeless +``` + +## Persistence + +The Kafka and Zookeeper images stores the data and configurations at the `/bitnami/kafka` and `/bitnami/zookeeper` path of the container. diff --git a/incubator/kubeless/templates/NOTES.txt b/incubator/kubeless/templates/NOTES.txt new file mode 100644 index 0000000000..a1c3d015fe --- /dev/null +++ b/incubator/kubeless/templates/NOTES.txt @@ -0,0 +1,33 @@ +{{- if .Values.ui.enabled }} +== Access the Kubeless UI URL: + +{{- if contains "LoadBalancer" .Values.ui.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w ui' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "kubeless.fullname" . }}-ui -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + export SERVICE_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "kubeless.fullname" . }}-ui -o jsonpath='{.spec.ports[0].port}') + echo http://$SERVICE_IP:$SERVICE_PORT/ +{{- else if contains "ClusterIP" .Values.ui.service.type }} + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "controller={{ template "kubeless.fullname" . }}-ui" -o jsonpath="{.items[0].metadata.name}") + echo http://127.0.0.1:3000 + kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME 3000:3000 + +{{- end }} + +{{- if contains "NodePort" .Values.ui.service.type }} + + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "kubeless.fullname" . }}-ui) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + +{{- end }} +{{- end }} +== Deploy function + +In order to deploy a function you need the kubeless binary. +You can download it from the kubeless repo: + +https://github.com/kubeless/kubeless diff --git a/incubator/kubeless/templates/_helpers.tpl b/incubator/kubeless/templates/_helpers.tpl new file mode 100644 index 0000000000..86edebc8b2 --- /dev/null +++ b/incubator/kubeless/templates/_helpers.tpl @@ -0,0 +1,29 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kubeless.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). +*/}} +{{- define "kubeless.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- /* +Credit: @technosophos +https://github.com/technosophos/common-chart/ +labels.standard prints the standard Helm labels. +The standard labels are frequently used in metadata. +*/ -}} +{{- define "labels.standard" -}} +app: {{ template "kubeless.name" . }} +heritage: {{ .Release.Service | quote }} +release: {{ .Release.Name | quote }} +chart: {{ .Chart.Name }}-{{ .Chart.Version }} +{{- end -}} diff --git a/incubator/kubeless/templates/cluster-role-binding.yaml b/incubator/kubeless/templates/cluster-role-binding.yaml new file mode 100644 index 0000000000..c217269033 --- /dev/null +++ b/incubator/kubeless/templates/cluster-role-binding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kubeless.fullname" . }}-controller-deployer + labels: +{{ include "labels.standard" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubeless-controller-deployer +subjects: +- kind: ServiceAccount + name: controller-acct +{{- end}} diff --git a/incubator/kubeless/templates/cluster-role.yaml b/incubator/kubeless/templates/cluster-role.yaml new file mode 100644 index 0000000000..095c2385cf --- /dev/null +++ b/incubator/kubeless/templates/cluster-role.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: {{ template "kubeless.fullname" . }}-controller-deployer + labels: +{{ include "labels.standard" . | indent 4 }} +rules: +- apiGroups: + - '*' + resources: + - services + - deployments + - functions + - configmaps + - pods + - replicasets + verbs: + - '*' +{{- end}} diff --git a/incubator/kubeless/templates/controller-deployment.yaml b/incubator/kubeless/templates/controller-deployment.yaml new file mode 100644 index 0000000000..71e5a6c6a1 --- /dev/null +++ b/incubator/kubeless/templates/controller-deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ template "kubeless.fullname" . }}-controller + labels: +{{ include "labels.standard" . | indent 4 }} + kubeless: controller +spec: + selector: + matchLabels: + kubeless: controller + replicas: {{ .Values.controller.deployment.replicaCount }} + template: + metadata: + labels: + kubeless: controller + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: controller + image: "{{ .Values.controller.deployment.image.repository }}:{{ .Values.controller.deployment.image.tag }}" + imagePullPolicy: {{ .Values.controller.deployment.image.pullPolicy }} + resources: +{{ toYaml .Values.controller.resources | indent 10 }} +{{- if .Values.rbac.create }} + serviceAccountName: controller-acct +{{- end }} diff --git a/incubator/kubeless/templates/function-crd.yaml b/incubator/kubeless/templates/function-crd.yaml new file mode 100644 index 0000000000..67ca61542c --- /dev/null +++ b/incubator/kubeless/templates/function-crd.yaml @@ -0,0 +1,15 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +description: Kubernetes Native Serverless Framework +kind: CustomResourceDefinition +metadata: + name: functions.k8s.io + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + group: k8s.io + names: + kind: Function + plural: functions + singular: function + scope: Namespaced + version: v1 diff --git a/incubator/kubeless/templates/kafka-headless-svc.yaml b/incubator/kubeless/templates/kafka-headless-svc.yaml new file mode 100644 index 0000000000..15f3eb668f --- /dev/null +++ b/incubator/kubeless/templates/kafka-headless-svc.yaml @@ -0,0 +1,15 @@ +# A headless service to create DNS records +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kubeless.fullname" . }}-broker + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + ports: + - port: 9092 + clusterIP: None + selector: + kubeless: kafka + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} diff --git a/incubator/kubeless/templates/kafka-stateful.yaml b/incubator/kubeless/templates/kafka-stateful.yaml new file mode 100644 index 0000000000..434d3b6a29 --- /dev/null +++ b/incubator/kubeless/templates/kafka-stateful.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1beta1 +kind: StatefulSet +metadata: + name: {{ template "kubeless.fullname" . }}-kafka + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + serviceName: "{{ template "kubeless.fullname" . }}-broker" + replicas: {{ .Values.kafka.statefulSet.replicaCount }} + template: + metadata: + labels: + kubeless: kafka + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} + spec: + terminationGracePeriodSeconds: 10 + initContainers: + - name: "fix-non-root-permissions" + image: "busybox" + imagePullPolicy: "Always" + command: [ "chmod", "-R", "g+rwX", "/bitnami" ] + volumeMounts: + - name: datadir + mountPath: /bitnami + containers: + - name: broker + image: "{{ .Values.kafka.statefulSet.image.repository }}:{{ .Values.kafka.statefulSet.image.tag }}" + imagePullPolicy: {{ .Values.kafka.statefulSet.image.pullPolicy }} + resources: +{{ toYaml .Values.kafka.resources | indent 10 }} + env: + - name: KAFKA_ADVERTISED_HOST_NAME + value: broker.{{ .Release.Namespace }} + - name: KAFKA_ADVERTISED_PORT + value: "9092" + - name: KAFKA_PORT + value: "9092" + - name: KAFKA_ZOOKEEPER_CONNECT + value: zookeeper.{{ .Release.Namespace }}:2181 + - name: ALLOW_PLAINTEXT_LISTENER + value: "yes" + ports: + - containerPort: 9092 + name: kafka-port + readinessProbe: + tcpSocket: + port: kafka-port + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: kafka-port + initialDelaySeconds: 30 + periodSeconds: 20 + volumeMounts: + - name: datadir + mountPath: /bitnami/kafka + volumeClaimTemplates: + - metadata: + name: datadir + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi diff --git a/incubator/kubeless/templates/kafka-svc.yaml b/incubator/kubeless/templates/kafka-svc.yaml new file mode 100644 index 0000000000..c6571e7b52 --- /dev/null +++ b/incubator/kubeless/templates/kafka-svc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: kafka + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + ports: + - name: kafka-port + port: 9092 + targetPort: kafka-port + selector: + kubeless: kafka + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} diff --git a/incubator/kubeless/templates/service-account.yaml b/incubator/kubeless/templates/service-account.yaml new file mode 100644 index 0000000000..4bfd2b9c5d --- /dev/null +++ b/incubator/kubeless/templates/service-account.yaml @@ -0,0 +1,8 @@ +{{- if .Values.rbac.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kubeless.fullname" . }}-controller-account + labels: +{{ include "labels.standard" . | indent 4 }} +{{- end }} diff --git a/incubator/kubeless/templates/ui-deployment.yaml b/incubator/kubeless/templates/ui-deployment.yaml new file mode 100644 index 0000000000..49feaeac94 --- /dev/null +++ b/incubator/kubeless/templates/ui-deployment.yaml @@ -0,0 +1,45 @@ +{{- if .Values.ui.enabled }} +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ template "kubeless.fullname" . }}-ui + labels: +{{ include "labels.standard" . | indent 4 }} + component: ui +spec: + replicas: {{ .Values.controller.deployment.replicaCount }} + template: + metadata: + labels: + component: ui + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} + spec: + containers: + - name: ui + image: "{{ .Values.ui.deployment.ui.image.repository }}:{{ .Values.ui.deployment.ui.image.tag }}" + imagePullPolicy: {{ .Values.ui.deployment.ui.image.pullPolicy }} + ports: + - containerPort: 3000 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 20 + - name: proxy + image: "{{ .Values.ui.deployment.proxy.image.repository }}:{{ .Values.ui.deployment.proxy.image.tag }}" + imagePullPolicy: {{ .Values.ui.deployment.proxy.image.pullPolicy }} + args: + - proxy + - "-p" + - "8080" +{{- end }} diff --git a/incubator/kubeless/templates/ui-svc.yaml b/incubator/kubeless/templates/ui-svc.yaml new file mode 100644 index 0000000000..00dd24f1b0 --- /dev/null +++ b/incubator/kubeless/templates/ui-svc.yaml @@ -0,0 +1,21 @@ +{{- if .Values.ui.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kubeless.fullname" . }}-ui + labels: +{{ include "labels.standard" . | indent 4 }} + controller: {{ template "kubeless.fullname" . }}-ui +spec: + ports: + - name: {{ .Values.ui.service.name }} + port: {{ .Values.ui.service.externalPort }} + protocol: TCP + targetPort: 3000 + selector: + component: ui + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} + sessionAffinity: None + type: {{ .Values.ui.service.type }} +{{- end }} diff --git a/incubator/kubeless/templates/zk-headless-svc.yaml b/incubator/kubeless/templates/zk-headless-svc.yaml new file mode 100644 index 0000000000..c612dbe463 --- /dev/null +++ b/incubator/kubeless/templates/zk-headless-svc.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kubeless.fullname" . }}-zoo + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + ports: + - port: 2888 + name: peer + - port: 3888 + name: leader-election + clusterIP: None + selector: + kubeless: zookeeper + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} diff --git a/incubator/kubeless/templates/zk-stateful.yaml b/incubator/kubeless/templates/zk-stateful.yaml new file mode 100644 index 0000000000..d2d4274351 --- /dev/null +++ b/incubator/kubeless/templates/zk-stateful.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1beta1 +kind: StatefulSet +metadata: + name: {{ template "kubeless.fullname" . }}-zoo + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + serviceName: "{{ template "kubeless.fullname" . }}-zoo" + replicas: {{ .Values.zookeeper.statefulSet.replicaCount }} + template: + metadata: + labels: + kubeless: zookeeper + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} + spec: + terminationGracePeriodSeconds: 10 + initContainers: + - name: "fix-non-root-permissions" + image: "busybox" + imagePullPolicy: "Always" + command: [ "chmod", "-R", "g+rwX", "/bitnami" ] + volumeMounts: + - name: datadir + mountPath: /bitnami + containers: + - name: zookeeper + image: "{{ .Values.zookeeper.statefulSet.image.repository }}:{{ .Values.zookeeper.statefulSet.image.tag }}" + imagePullPolicy: {{ .Values.zookeeper.statefulSet.image.pullPolicy }} + resources: +{{ toYaml .Values.zookeeper.resources | indent 10 }} + env: + - name: ZOO_SERVERS + value: server.1=zoo-0.zoo:2888:3888:participant + - name: ALLOW_ANONYMOUS_LOGIN + value: "yes" + ports: + - containerPort: 2181 + name: client + - containerPort: 2888 + name: peer + - containerPort: 3888 + name: leader-election + readinessProbe: + tcpSocket: + port: client + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: client + initialDelaySeconds: 15 + periodSeconds: 20 + volumeMounts: + - name: datadir + mountPath: /bitnami/zookeeper + volumeClaimTemplates: + - metadata: + name: datadir + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi diff --git a/incubator/kubeless/templates/zk-svc.yaml b/incubator/kubeless/templates/zk-svc.yaml new file mode 100644 index 0000000000..45c46efcdd --- /dev/null +++ b/incubator/kubeless/templates/zk-svc.yaml @@ -0,0 +1,15 @@ +# Headless service is for PetSet DNS, this one is for clients +apiVersion: v1 +kind: Service +metadata: + name: zookeeper + labels: +{{ include "labels.standard" . | indent 4 }} +spec: + ports: + - port: 2181 + name: client + selector: + kubeless: zookeeper + app: {{ template "kubeless.name" . }} + release: {{ .Release.Name | quote }} diff --git a/incubator/kubeless/values.yaml b/incubator/kubeless/values.yaml new file mode 100644 index 0000000000..8e50fbbd6f --- /dev/null +++ b/incubator/kubeless/values.yaml @@ -0,0 +1,82 @@ +# Default values for kubeless. +## RBAC configuration +rbac: + create: false + +## Controller configuration +controller: + deployment: + replicaCount: 1 + image: + repository: bitnami/kubeless-controller + tag: v0.3.1 + pullPolicy: IfNotPresent + ## Kubeless Controller resource requests and limits + ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: {} + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 500m + # memory: 512Mi + +## UI configuration +ui: + enabled: false + deployment: + replicaCount: 1 + ui: + image: + repository: bitnami/kubeless-ui + tag: v0.1.0 + pullPolicy: IfNotPresent + proxy: + image: + repository: kelseyhightower/kubectl + tag: 1.4.0 + pullPolicy: IfNotPresent + + service: + name: ui-port + type: NodePort + externalPort: 3000 + +## Zookeeper configuration +zookeeper: + statefulSet: + replicaCount: 1 + image: + repository: bitnami/zookeeper + tag: 3.4.10-r6 + pullPolicy: IfNotPresent + ## Zookeeper server resource requests and limits + ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: {} + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 500m + # memory: 512Mi + +## Kafka configuration +kafka: + statefulSet: + replicaCount: 1 + image: + repository: bitnami/kafka + tag: 1.0.0-r2 + pullPolicy: IfNotPresent + ## Kafka server resource requests and limits + ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: {} + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 500m + # memory: 512Mi