diff --git a/charts/llm-gateway/Chart.lock b/charts/llm-gateway/Chart.lock new file mode 100644 index 00000000..a42121dd --- /dev/null +++ b/charts/llm-gateway/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: nats + repository: https://nats-io.github.io/k8s/helm/charts/ + version: 1.1.6 +digest: sha256:d7139a23518bd17a525ab93874436431746026fdbcf299b89bfd0a19baea41ab +generated: "2024-03-18T17:01:49.011124+05:30" diff --git a/charts/llm-gateway/Chart.yaml b/charts/llm-gateway/Chart.yaml new file mode 100644 index 00000000..3fb70355 --- /dev/null +++ b/charts/llm-gateway/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: llm-gateway +version: 0.2.3-rc.1 +description: "LLM Gateway deployment chart" +maintainers: + - name: truefoundry +dependencies: + - name: nats + repository: https://nats-io.github.io/k8s/helm/charts/ + version: 1.1.6 + condition: nats.enabled diff --git a/charts/llm-gateway/templates/_helpers.tpl b/charts/llm-gateway/templates/_helpers.tpl new file mode 100644 index 00000000..4f5316fb --- /dev/null +++ b/charts/llm-gateway/templates/_helpers.tpl @@ -0,0 +1,100 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/llm-gateway/templates/clickhouse-installation.yaml b/charts/llm-gateway/templates/clickhouse-installation.yaml new file mode 100644 index 00000000..415a5848 --- /dev/null +++ b/charts/llm-gateway/templates/clickhouse-installation.yaml @@ -0,0 +1,111 @@ +{{- if .Values.clickhouse.enabled -}} +apiVersion: "clickhouse.altinity.com/v1" +kind: "ClickHouseInstallation" +metadata: + name: {{ .Release.Name }} + annotations: + argocd.argoproj.io/sync-options: Prune=false,Delete=false +spec: + defaults: + templates: + serviceTemplate: svc-template + configuration: + clusters: + - name: {{ .Release.Name }} + layout: + shardsCount: {{ .Values.clickhouse.shardsCount }} + replicasCount: {{ .Values.clickhouse.replicasCount }} + templates: + podTemplate: clickhouse-stable + dataVolumeClaimTemplate: clickhouse-data-volume + serviceTemplate: svc-template + zookeeper: + nodes: + - host: {{ tpl .Values.clickhouse.zookeeperHost . }} + port: {{ tpl .Values.clickhouse.zookeeperPort . }} + {{- if .Values.clickhouse.user }} + users: + {{ .Values.clickhouse.user }}/password: {{ required ".Values.clickhouse.password is required" .Values.clickhouse.password }} + {{ .Values.clickhouse.user }}/profile: default + {{ .Values.clickhouse.user }}/quota: default + {{ .Values.clickhouse.user }}/networks/ip: + - 0.0.0.0/0 + - ::/0 + {{- end }} + files: + config.d/named-collections.xml: | + + + + {{- $natsURL := (tpl .Values.clickhouse.nats.url .) }} + {{- $natsSubjects := .Values.clickhouse.nats.subjects }} + {{- $natsUsername := .Values.clickhouse.nats.username }} + {{- $natsPassword := .Values.clickhouse.nats.password }} + {{ $natsURL }} + {{ $natsSubjects }} + {{ $natsUsername }} + {{ $natsPassword }} + JSONEachRow + best_effort + + + + config.d/log_rotation.xml: |- + + + information + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 100M + 5 + 1 + + + templates: + serviceTemplates: + - name: svc-template + generateName: clickhouse-{chi} + spec: + ports: + - name: http + port: 8123 + - name: tcp + port: 9000 + type: ClusterIP + podTemplates: + - name: clickhouse-stable + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: clickhouse.altinity.com/cluster + operator: In + values: + - {{ .Release.Name }} + topologyKey: "kubernetes.io/hostname" + containers: + - name: clickhouse + image: {{ .Values.clickhouse.image }} + resources: + requests: + memory: {{ .Values.clickhouse.resources.requests.memory }} + cpu: {{ .Values.clickhouse.resources.requests.cpu }} + ephemeral-storage: {{ .Values.clickhouse.resources.requests.ephemeralStorage }} + limits: + memory: {{ .Values.clickhouse.resources.limits.memory }} + cpu: {{ .Values.clickhouse.resources.limits.cpu }} + ephemeral-storage: {{ .Values.clickhouse.resources.limits.ephemeralStorage }} + volumeClaimTemplates: + - name: clickhouse-data-volume + spec: + storageClassName: {{ .Values.clickhouse.storage.storageClassName }} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.clickhouse.storage.size }} +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/templates/deployment.yaml b/charts/llm-gateway/templates/deployment.yaml new file mode 100644 index 00000000..339e0d1f --- /dev/null +++ b/charts/llm-gateway/templates/deployment.yaml @@ -0,0 +1,69 @@ +{{- if .Values.llmGatewayEnabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthcheck.liveness.path }} + port: {{ .Values.healthcheck.liveness.port }} + readinessProbe: + httpGet: + path: {{ .Values.healthcheck.readiness.path }} + port: {{ .Values.healthcheck.liveness.port }} + {{- end }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + volumes: + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/templates/ingress.yaml b/charts/llm-gateway/templates/ingress.yaml new file mode 100644 index 00000000..1b0c28f3 --- /dev/null +++ b/charts/llm-gateway/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if and .Values.llmGatewayEnabled .Values.ingress.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: +{{- if .Values.ingress.annotations }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- toYaml .Values.ingress.labels | nindent 4 }} + {{- end }} +spec: + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + + {{- end -}} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end -}} +{{- end -}} diff --git a/charts/llm-gateway/templates/nats-metrics-virtualservice.yaml b/charts/llm-gateway/templates/nats-metrics-virtualservice.yaml new file mode 100644 index 00000000..42f6892f --- /dev/null +++ b/charts/llm-gateway/templates/nats-metrics-virtualservice.yaml @@ -0,0 +1,17 @@ +{{- if .Values.nats.natsMetricsServerHost }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: "{{ .Release.Name }}-nats-metrics" +spec: + hosts: + - {{ .Values.nats.natsMetricsServerHost | quote }} + gateways: + - {{ tpl .Values.nats.gatewayName . }} + http: + - route: + - destination: + host: {{ .Release.Name }}-nats + port: + number: 8222 +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/templates/nats-virtualservice.yaml b/charts/llm-gateway/templates/nats-virtualservice.yaml new file mode 100644 index 00000000..9a0efd68 --- /dev/null +++ b/charts/llm-gateway/templates/nats-virtualservice.yaml @@ -0,0 +1,17 @@ +{{- if .Values.nats.natsServerHost }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: "{{ .Release.Name }}-nats" +spec: + hosts: + - {{ .Values.nats.natsServerHost | quote }} + gateways: + - {{ tpl .Values.nats.gatewayName . }} + http: + - route: + - destination: + host: {{ .Release.Name }}-nats + port: + number: 8080 +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/templates/service.yaml b/charts/llm-gateway/templates/service.yaml new file mode 100644 index 00000000..46bbe8db --- /dev/null +++ b/charts/llm-gateway/templates/service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.llmGatewayEnabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/templates/serviceaccount.yaml b/charts/llm-gateway/templates/serviceaccount.yaml new file mode 100644 index 00000000..13443a8e --- /dev/null +++ b/charts/llm-gateway/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.llmGatewayEnabled .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/llm-gateway/templates/virtualservice.yaml b/charts/llm-gateway/templates/virtualservice.yaml new file mode 100644 index 00000000..d5d0feb0 --- /dev/null +++ b/charts/llm-gateway/templates/virtualservice.yaml @@ -0,0 +1,32 @@ +{{- if and .Values.llmGatewayEnabled .Values.istio.virtualservice.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.istio.virtualservice.annotations }} + annotations: + {{- range $key, $value := .Values.istio.virtualservice.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + {{- range .Values.istio.virtualservice.gateways}} + - {{ . }} + {{- end }} + hosts: + {{- range .Values.istio.virtualservice.hosts}} + - {{ . }} + {{- end }} + http: + - route: + - destination: + host: {{ include "app.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: {{ .Values.service.port }} +{{- end }} \ No newline at end of file diff --git a/charts/llm-gateway/values.yaml b/charts/llm-gateway/values.yaml new file mode 100644 index 00000000..1ac6ee5b --- /dev/null +++ b/charts/llm-gateway/values.yaml @@ -0,0 +1,200 @@ +global: {} +llmGatewayEnabled: true +imageRepository: truefoundrycloud/llm-gateway +replicaCount: 1 +environmentName: default +envSecretName: llm-gateway-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: true + readiness: + port: 8787 + path: / + liveness: + port: 8787 + path: / +resources: + limits: + cpu: 400m + memory: 512Mi + ephemeral-storage: 256Mi + requests: + cpu: 200m + memory: 256Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +topologySpreadConstraints: {} +ingress: + enabled: false + annotations: {} + labels: {} + ingressClassName: istio + tls: [] + hosts: [] +istio: + virtualservice: + enabled: false + annotations: {} + gateways: [] + hosts: [] +service: + type: ClusterIP + port: 8787 + annotations: {} +serviceAccount: + create: true + name: llm-gateway + annotations: {} +extraVolumes: [] +extraVolumeMounts: [] +env: + TRUEFOUNDRY_PUBLIC_ENABLED: '' + SERVICEFOUNDRY_SERVER_URL: https://app.truefoundry.com/api/svc + SFY_USER_API_KEY: ${k8s-secret/truefoundry-creds/TFY_API_KEY} + TOGETHER_AI_API_KEY: '' + AUTH_SERVER_URL: https://auth.truefoundry.com + LOG_LEVEL: info + LOGGING_SINK_CONFIGURATION: '' + DEPLOYED_HOSTNAME: '' + CONTROL_PLANE_NATS_URL: '' +imageTag: 3870a7350078cc00004d9c2c3ee7c8eec9b67393 +nats: + enabled: false + config: + nats: + port: 4222 + merge: + authorization: + users: + - user: admin + password: + permissions: + publish: + - '>' + subscribe: + - '>' + - user: llm-gateway-request-logger + password: + permissions: + publish: + - tfy-model-logs.> + subscribe: + - '>' + - user: clickhouse-request-logs-reader + password: + permissions: + subscribe: + - tfy-model-logs.> + timeout: 5 + cluster: + port: 6222 + enabled: true + replicas: 5 + monitor: + tls: + enabled: false + port: 8222 + enabled: true + jetstream: + enabled: true + fileStore: + dir: /data + pvc: + size: 2Gi + enabled: true + storageClassName: '' + enabled: true + memoryStore: + enabled: true + maxSize: 250Mi + websocket: + port: 8080 + enabled: true + natsBox: + enabled: false + service: + merge: + type: LoadBalancer + ports: + monitor: + enabled: true + container: + image: + tag: 2.10.7-alpine + pullPolicy: IfNotPresent + repository: nats + merge: + resources: + limits: + cpu: 100m + memory: 250Mi + requests: + cpu: 100m + memory: 250Mi + podTemplate: + merge: + spec: + tolerations: + - effect: NoSchedule + key: cloud.google.com/gke-spot + operator: Equal + value: 'true' + - effect: NoSchedule + key: kubernetes.azure.com/scalesetpriority + operator: Equal + value: spot + metadata: + annotations: + prometheus.io/port: '7777' + prometheus.io/scrape: 'true' + topologySpreadConstraints: + kubernetes.io/hostname: + maxSkew: 1 + whenUnsatisfiable: DoNotSchedule + promExporter: + port: 7777 + image: + tag: 0.13.0 + pullPolicy: IfNotPresent + repository: natsio/prometheus-nats-exporter + enabled: true + extraResources: [] + gatewayName: istio-system/tfy-wildcard + natsServerHost: '' + natsMetricsServerHost: '' +clickhouse: + enabled: false + shardsCount: 2 + replicasCount: 2 + user: exampleUser + password: examplePassword + zookeeperHost: zookeeper-headless + zookeeperPort: '2181' + image: clickhouse/clickhouse-server:23.4.2 + resources: + requests: + memory: 1024Mi + cpu: 500m + ephemeralStorage: 1024Mi + limits: + memory: 2048Mi + cpu: 1000m + ephemeralStorage: 2048Mi + storage: + storageClassName: '' + size: 10Gi + nats: + url: >- + http://{{ .Release.Name }}-nats.{{ .Release.Namespace + }}.svc.cluster.local:4222 + subjects: tfy-model-logs.test + username: clickhouse-request-logs-reader + password: diff --git a/charts/mlfoundry-server/Chart.yaml b/charts/mlfoundry-server/Chart.yaml new file mode 100644 index 00000000..a3405b4c --- /dev/null +++ b/charts/mlfoundry-server/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: mlfoundry-server +version: 0.2.103-rc.7 +description: "Helm Chart for MLFoundry" +maintainers: + - name: truefoundry diff --git a/charts/mlfoundry-server/templates/_helpers.tpl b/charts/mlfoundry-server/templates/_helpers.tpl new file mode 100644 index 00000000..4c214159 --- /dev/null +++ b/charts/mlfoundry-server/templates/_helpers.tpl @@ -0,0 +1,101 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/mlfoundry-server/templates/deployment.yaml b/charts/mlfoundry-server/templates/deployment.yaml new file mode 100644 index 00000000..67a525b5 --- /dev/null +++ b/charts/mlfoundry-server/templates/deployment.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + {{- .Values.healthcheck.livenessProbe | toYaml | nindent 12 }} + readinessProbe: + {{- .Values.healthcheck.readinessProbe | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + volumes: + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/charts/mlfoundry-server/templates/ingress.yaml b/charts/mlfoundry-server/templates/ingress.yaml new file mode 100644 index 00000000..1fe0c59d --- /dev/null +++ b/charts/mlfoundry-server/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: +{{- if .Values.ingress.annotations }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- toYaml .Values.ingress.labels | nindent 4 }} + {{- end }} +spec: + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + + {{- end -}} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end -}} +{{- end -}} diff --git a/charts/mlfoundry-server/templates/service.yaml b/charts/mlfoundry-server/templates/service.yaml new file mode 100644 index 00000000..a45d8822 --- /dev/null +++ b/charts/mlfoundry-server/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/mlfoundry-server/templates/serviceaccount.yaml b/charts/mlfoundry-server/templates/serviceaccount.yaml new file mode 100644 index 00000000..a41b8ac6 --- /dev/null +++ b/charts/mlfoundry-server/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/mlfoundry-server/templates/virtualservice.yaml b/charts/mlfoundry-server/templates/virtualservice.yaml new file mode 100644 index 00000000..b220274c --- /dev/null +++ b/charts/mlfoundry-server/templates/virtualservice.yaml @@ -0,0 +1,32 @@ +{{- if .Values.istio.virtualservice.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.istio.virtualservice.annotations }} + annotations: + {{- range $key, $value := .Values.istio.virtualservice.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + {{- range .Values.istio.virtualservice.gateways}} + - {{ . }} + {{- end }} + hosts: + {{- range .Values.istio.virtualservice.hosts}} + - {{ . }} + {{- end }} + http: + - route: + - destination: + host: {{ include "app.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: {{ .Values.service.port }} +{{- end }} \ No newline at end of file diff --git a/charts/mlfoundry-server/values.yaml b/charts/mlfoundry-server/values.yaml new file mode 100644 index 00000000..b95eb251 --- /dev/null +++ b/charts/mlfoundry-server/values.yaml @@ -0,0 +1,89 @@ +global: {} +imageRepository: truefoundrycloud/mlfoundry-server +replicaCount: 1 +environmentName: default +envSecretName: mlfoundry-server-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: true + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 5000 + scheme: HTTP + initialDelaySeconds: 90 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 5000 + scheme: HTTP + initialDelaySeconds: 90 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 +resources: + limits: + cpu: 400m + memory: 2048Mi + ephemeral-storage: 256Mi + requests: + cpu: 200m + memory: 1024Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +topologySpreadConstraints: {} +ingress: + enabled: false + annotations: {} + labels: {} + ingressClassName: istio + tls: [] + hosts: [] +istio: + virtualservice: + enabled: false + annotations: {} + gateways: [] + hosts: [] +service: + type: ClusterIP + port: 5000 + annotations: {} +serviceAccount: + create: true + name: mlfoundry-server + annotations: {} +imageTag: 1ae31419e11b6f9381ce14e6199fd0f4ed59419b +extraVolumes: [] +extraVolumeMounts: [] +env: + DB_NAME: ${k8s-secret/truefoundry-creds/DB_NAME} + DB_USERNAME: ${k8s-secret/truefoundry-creds/DB_USERNAME} + DB_PASSWORD: ${k8s-secret/truefoundry-creds/DB_PASSWORD} + DB_HOST: ${k8s-secret/truefoundry-creds/DB_HOST} + DB_POSTGRES_SCHEMA: mlfoundry + DB_PORT: '5432' + DB_DIALECT: postgresql+psycopg2 + AUTH_SERVER_URL: https://auth.truefoundry.com + ARTIFACT_ROOT: s3://{{ .Values.env.S3_BUCKET_NAME }} + MLFLOW_S3_ENDPOINT_URL: '{{ .Values.env.S3_ENDPOINT_URL }}' + prometheus_multiproc_dir: .prom_metrics + MULTITENANT: 'false' + TENANT_NAME: '{{ .Values.global.tenantName }}' + SVC_FOUNDRY_SERVICE_API_KEY: ${k8s-secret/truefoundry-creds/TFY_API_KEY} + SERVICEFOUNDRY_SERVER_URL: >- + http://{{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:3000 diff --git a/charts/servicefoundry-server/Chart.yaml b/charts/servicefoundry-server/Chart.yaml new file mode 100644 index 00000000..0d69e001 --- /dev/null +++ b/charts/servicefoundry-server/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: servicefoundry-server +version: 0.3.140-rc.13 +description: "Servicefoundry-server deployment chart" +maintainers: + - name: truefoundry diff --git a/charts/servicefoundry-server/templates/_helpers.tpl b/charts/servicefoundry-server/templates/_helpers.tpl new file mode 100644 index 00000000..9572fb55 --- /dev/null +++ b/charts/servicefoundry-server/templates/_helpers.tpl @@ -0,0 +1,132 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} + +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- if (tpl .Values.configs.cicdTemplates .) }} +- name: CICD_TEMPLATES_DIRECTORY + value: /opt/truefoundry/configs/cicd-templates +{{- end }} +{{- end }} + +{{- define "app.volumes" -}} +{{- $volumes := list -}} +{{- if .Values.extraVolumes }} + {{- range .Values.extraVolumes }} + {{- $volumes = append $volumes . }} + {{- end }} +{{- end }} +{{- if (tpl .Values.configs.cicdTemplates .) }} + {{- $volumes = append $volumes (dict "name" "configs-cicd-templates" "configMap" (dict "name" (tpl .Values.configs.cicdTemplates .))) }} +{{- end }} +{{- $volumes | toYaml -}} +{{- end -}} + + +{{- define "app.volumeMounts" -}} +{{- $volumeMounts := list -}} +{{- if .Values.extraVolumeMounts }} + {{- range .Values.extraVolumeMounts }} + {{- $volumeMounts = append $volumeMounts . }} + {{- end }} +{{- end }} +{{- if (tpl .Values.configs.cicdTemplates .) }} + {{- $volumeMounts = append $volumeMounts (dict "name" "configs-cicd-templates" "mountPath" "/opt/truefoundry/configs/cicd-templates") }} +{{- end }} +{{- $volumeMounts | toYaml -}} +{{- end -}} diff --git a/charts/servicefoundry-server/templates/clusterrolebinding.yaml b/charts/servicefoundry-server/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..8523cb17 --- /dev/null +++ b/charts/servicefoundry-server/templates/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.rbac.enabled -}} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app.serviceAccountName" . }}-admin-rbac +subjects: + - kind: ServiceAccount + name: {{ include "app.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/charts/servicefoundry-server/templates/deployment.yaml b/charts/servicefoundry-server/templates/deployment.yaml new file mode 100644 index 00000000..8cd45e21 --- /dev/null +++ b/charts/servicefoundry-server/templates/deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthcheck.liveness.path }} + port: {{ .Values.healthcheck.liveness.port }} + readinessProbe: + httpGet: + path: {{ .Values.healthcheck.readiness.path }} + port: {{ .Values.healthcheck.liveness.port }} + {{- end }} + volumeMounts: + {{- include "app.volumeMounts" . | nindent 12 }} + volumes: + {{- include "app.volumes" . | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/servicefoundry-server/templates/ingress.yaml b/charts/servicefoundry-server/templates/ingress.yaml new file mode 100644 index 00000000..1fe0c59d --- /dev/null +++ b/charts/servicefoundry-server/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: +{{- if .Values.ingress.annotations }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- toYaml .Values.ingress.labels | nindent 4 }} + {{- end }} +spec: + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + + {{- end -}} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end -}} +{{- end -}} diff --git a/charts/servicefoundry-server/templates/service.yaml b/charts/servicefoundry-server/templates/service.yaml new file mode 100644 index 00000000..a45d8822 --- /dev/null +++ b/charts/servicefoundry-server/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/servicefoundry-server/templates/serviceaccount.yaml b/charts/servicefoundry-server/templates/serviceaccount.yaml new file mode 100644 index 00000000..a41b8ac6 --- /dev/null +++ b/charts/servicefoundry-server/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/servicefoundry-server/templates/virtualservice.yaml b/charts/servicefoundry-server/templates/virtualservice.yaml new file mode 100644 index 00000000..b220274c --- /dev/null +++ b/charts/servicefoundry-server/templates/virtualservice.yaml @@ -0,0 +1,32 @@ +{{- if .Values.istio.virtualservice.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.istio.virtualservice.annotations }} + annotations: + {{- range $key, $value := .Values.istio.virtualservice.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + {{- range .Values.istio.virtualservice.gateways}} + - {{ . }} + {{- end }} + hosts: + {{- range .Values.istio.virtualservice.hosts}} + - {{ . }} + {{- end }} + http: + - route: + - destination: + host: {{ include "app.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: {{ .Values.service.port }} +{{- end }} \ No newline at end of file diff --git a/charts/servicefoundry-server/values.yaml b/charts/servicefoundry-server/values.yaml new file mode 100644 index 00000000..c62001cd --- /dev/null +++ b/charts/servicefoundry-server/values.yaml @@ -0,0 +1,146 @@ +global: {} +imageRepository: truefoundrycloud/servicefoundry-server +replicaCount: 1 +environmentName: default +envSecretName: servicefoundry-server-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: true + readiness: + port: 3000 + path: / + liveness: + port: 3000 + path: / +resources: + limits: + cpu: 400m + memory: 512Mi + ephemeral-storage: 256Mi + requests: + cpu: 200m + memory: 256Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +topologySpreadConstraints: {} +ingress: + enabled: false + annotations: {} + labels: {} + ingressClassName: istio + tls: [] + hosts: [] +istio: + virtualservice: + enabled: false + annotations: {} + gateways: [] + hosts: [] +service: + type: ClusterIP + port: 3000 + annotations: {} +serviceAccount: + create: true + name: servicefoundry-server + annotations: {} +extraVolumes: [] +extraVolumeMounts: [] +rbac: + enabled: true +env: + LOG_LEVEL: info + S3_BUCKET_NAME: '' + GS_BUCKET_NAME: '' + AZURE_BLOB_URI: '' + AZURE_BLOB_CONNECTION_STRING: '' + DB_NAME: ${k8s-secret/truefoundry-creds/DB_NAME} + DB_USERNAME: ${k8s-secret/truefoundry-creds/DB_USERNAME} + DB_PASSWORD: ${k8s-secret/truefoundry-creds/DB_PASSWORD} + DB_HOST: ${k8s-secret/truefoundry-creds/DB_HOST} + DB_PORT: '5432' + STRIPE_KEY: '' + STRIPE_WEBHOOK_SECRET: '' + SVC_FOUNDRY_SERVICE_API_KEY: ${k8s-secret/truefoundry-creds/TFY_API_KEY} + PORT: '3000' + SWAGGER_ENABLE: '0' + NODE_ENV: production + GITHUB_PRIVATE_KEY: '' + GITHUB_APP_ID: '' + GITHUB_PAT: '' + BITBUCKET_CLIENT_ID: '' + BITBUCKET_CLIENT_SECRET: '' + GITHUB_INSTALLATION_URL: '' + GITLAB_APP_ID: '' + GITLAB_APP_SECRET: '' + GITLAB_SCOPE: '' + CONTROL_PLANE_URL: '{{ .Values.global.controlPlaneURL }}' + TFY_BUILD_LOGS_URL: '{{ .Values.global.controlPlaneURL }}/api/svc' + TFY_BUILD_WS_URL: '{{ .Values.global.controlPlaneURL }}' + TFY_BUILD_WS_PATH: /api/svc/socket.io + LOKI_URL: http://loki.loki.svc.cluster.local:3100 + AUTH_SERVER_URL: https://auth.truefoundry.com + ISTIO_INJECTION_STATE: disabled + WORKSPACE_PER_USER_WITHOUT_PAYMENT: '-1' + TENANT_NAME: '{{ .Values.global.tenantName }}' + MULTITENANT: 'false' + MANIFEST_SERVICE_URL: >- + http://{{ .Release.Name }}-sfy-manifest-service.{{ .Release.Namespace + }}.svc.cluster.local:8080 + MLFOUNDRY_SERVER_URL: >- + http://{{ .Release.Name }}-mlfoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:5000 + DEFAULT_CLOUD_PROVIDER: aws + MIN_CLI_VERSION: 0.10.9 + OTEL_SERVICE_NAME: sfy-server + NATS_CONTROLPLANE_ACCOUNT_SEED: ${k8s-secret/truefoundry-nats-secret/NATS_CONTROLPLANE_ACCOUNT_SEED} + NATS_URL: >- + http://{{ .Release.Name }}-nats.{{ .Release.Namespace + }}.svc.cluster.local:4222 + SECRET_STORE: aws-ssm + CLUSTER_PROXY_URL: >- + http://{{ .Release.Name }}-tfy-controller.{{ .Release.Namespace + }}.svc.cluster.local:8123 + ENABLE_SERVER_SIDE_APPLY: 'true' + LLM_GATEWAY_URL: '' + TRUEFOUNDRY_PUBLIC_ENABLED: '' + LLM_GATEWAY_CATALOGUE_BASE_URL: https://catalogue.truefoundry.com/llm-gateway/devtest + MAX_REQUEST_SIZE: '' + METRICS_MAX_DATA_POINTS: '60' + PROMETHEUS_SCRAP_INTERVAL_SECONDS: '15' + CONTROL_PLANE_PROMETHEUS_URL: http://prometheus-operated.prometheus.svc.cluster.local:9090/ + MODEL_CATALOGUE_BASE_URL: https://catalogue.truefoundry.com/models + APPLICATION_CATALOGUE_BASE_URL: https://catalogue.truefoundry.com/templates + CLICKHOUSE_HOST: '' + CLICKHOUSE_USER: '' + CLICKHOUSE_PASSWORD: '' + CLICKHOUSE_WAIT_TIMEOUT: 5m + HELM_CHART_EXPORT_DEPENDENCY_LIMIT: '100' + SLACK_ALERT_URL: '' + SLACK_BILLING_ALERT_URL: '' + DB_CONNECTION_POOL_MAX_COUNT: '10' + VCS_INTEGRATION_STATE_OBJECT_HASH_SECRET: '' + BUILD_NAMESPACE: truefoundry + KUBE_CONTEXT: '' + BUILDKIT_SERVICE_URL: >- + {{ .Release.Name }}-tfy-buildkitd-service.{{ .Release.Namespace + }}.svc.cluster.local:1234 + ACCESS_TFY_GATEWAY_MODELS_TENANT_DENY_LIST: '' + MIGRATION_SERVER_URL: https://migration-server.truefoundry.com + AUTOPILOT_ENABLED: 'false' + AUTOPILOT_CONSUMER_BATCH_MAX_MESSAGES: '50' + AUTOPILOT_CONSUMER_MESSAGE_EXPIRY_MS: '10000' + BUILD_CALLBACK_URL: >- + http://{{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:3000 +configs: + cicdTemplates: '{{ .Release.Name }}-cicd-templates-cm' +imageTag: bbeae9d8976c73fcac4af7351839b1ef9937237d diff --git a/charts/sfy-manifest-service/Chart.yaml b/charts/sfy-manifest-service/Chart.yaml new file mode 100644 index 00000000..29f8825a --- /dev/null +++ b/charts/sfy-manifest-service/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: sfy-manifest-service +version: 0.1.119-rc.5 +description: "Sfy manifest service deployment chart" +maintainers: + - name: truefoundry diff --git a/charts/sfy-manifest-service/templates/_helpers.tpl b/charts/sfy-manifest-service/templates/_helpers.tpl new file mode 100644 index 00000000..7da990d1 --- /dev/null +++ b/charts/sfy-manifest-service/templates/_helpers.tpl @@ -0,0 +1,100 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/sfy-manifest-service/templates/deployment.yaml b/charts/sfy-manifest-service/templates/deployment.yaml new file mode 100644 index 00000000..49f07d11 --- /dev/null +++ b/charts/sfy-manifest-service/templates/deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthcheck.liveness.path }} + port: {{ .Values.healthcheck.liveness.port }} + readinessProbe: + httpGet: + path: {{ .Values.healthcheck.readiness.path }} + port: {{ .Values.healthcheck.liveness.port }} + {{- end }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + volumes: + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/sfy-manifest-service/templates/ingress.yaml b/charts/sfy-manifest-service/templates/ingress.yaml new file mode 100644 index 00000000..1fe0c59d --- /dev/null +++ b/charts/sfy-manifest-service/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: +{{- if .Values.ingress.annotations }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- toYaml .Values.ingress.labels | nindent 4 }} + {{- end }} +spec: + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + + {{- end -}} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end -}} +{{- end -}} diff --git a/charts/sfy-manifest-service/templates/service.yaml b/charts/sfy-manifest-service/templates/service.yaml new file mode 100644 index 00000000..d1527128 --- /dev/null +++ b/charts/sfy-manifest-service/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} diff --git a/charts/sfy-manifest-service/templates/serviceaccount.yaml b/charts/sfy-manifest-service/templates/serviceaccount.yaml new file mode 100644 index 00000000..a41b8ac6 --- /dev/null +++ b/charts/sfy-manifest-service/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/sfy-manifest-service/templates/virtualservice.yaml b/charts/sfy-manifest-service/templates/virtualservice.yaml new file mode 100644 index 00000000..b220274c --- /dev/null +++ b/charts/sfy-manifest-service/templates/virtualservice.yaml @@ -0,0 +1,32 @@ +{{- if .Values.istio.virtualservice.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.istio.virtualservice.annotations }} + annotations: + {{- range $key, $value := .Values.istio.virtualservice.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + {{- range .Values.istio.virtualservice.gateways}} + - {{ . }} + {{- end }} + hosts: + {{- range .Values.istio.virtualservice.hosts}} + - {{ . }} + {{- end }} + http: + - route: + - destination: + host: {{ include "app.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: {{ .Values.service.port }} +{{- end }} \ No newline at end of file diff --git a/charts/sfy-manifest-service/values.yaml b/charts/sfy-manifest-service/values.yaml new file mode 100644 index 00000000..0d0809b3 --- /dev/null +++ b/charts/sfy-manifest-service/values.yaml @@ -0,0 +1,83 @@ +global: {} +imageRepository: truefoundrycloud/sfy-manifest-service +replicaCount: 1 +environmentName: default +envSecretName: sfy-manifest-service-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: true + readiness: + port: 8080 + path: /healthy + liveness: + port: 8080 + path: /healthy +resources: + limits: + cpu: 200m + memory: 256Mi + ephemeral-storage: 256Mi + requests: + cpu: 100m + memory: 128Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +topologySpreadConstraints: {} +ingress: + enabled: false + annotations: {} + labels: {} + ingressClassName: istio + tls: [] + hosts: [] +istio: + virtualservice: + enabled: false + annotations: {} + gateways: [] + hosts: [] +service: + type: ClusterIP + port: 8080 + annotations: {} +serviceAccount: + create: true + name: sfy-manifest-service + annotations: {} +extraVolumes: [] +extraVolumeMounts: [] +env: + GIN_MODE: release + PORT: '8080' + SFY_SERVER_URL: >- + http://{{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:3000 + MLF_SERVER_URL: >- + http://{{ .Release.Name }}-mlfoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:5000 + SFY_API_KEY: ${k8s-secret/truefoundry-creds/TFY_API_KEY} + PROCESS_TICKER_PERIOD_SECONDS: '5' + TENANT_NAME: '{{ .Values.global.tenantName }}' + AUTH_SERVER_URL: https://auth.truefoundry.com + HELM_SIZE_LIMIT_BYTES: '307200' + ASYNC_PROCESSOR_SIDECAR_IMAGE: >- + public.ecr.aws/w0y0d8g6/truefoundrycloud/async_processor:35b639ea3db5490f816379de0c92a9a933338cdf + TFY_MODEL_DOWNLOADER_IMAGE: public.ecr.aws/truefoundrycloud/tfy-model-downloader:0.1.4 + APP_CATALOGUE_ENDPOINT: https://catalogue.truefoundry.com/templates/ + AUTOPILOT_PROCESSOR_ENABLED: 'false' + AUTOPILOT_PROCESSOR_NATS_URL: >- + nats://{{ .Release.Name }}-nats.{{ .Release.Namespace + }}.svc.cluster.local:4222 + AUTOPILOT_PROCESSOR_NATS_PULL_MAX_BYTES: '10485760' + AUTOPILOT_PROCESSOR_NATS_ACK_WAIT: '120' + AUTOPILOT_PROCESSOR_PUBLISH_ASYNC_MAX_PENDING: '100' + AUTOPILOT_PROCESSOR_NUMBER_OF_WORKERS: '2' +imageTag: 30a27bc05c9df4485882df2ae773a4f34f134a19 diff --git a/charts/tfy-build/Chart.yaml b/charts/tfy-build/Chart.yaml new file mode 100644 index 00000000..aaa179b0 --- /dev/null +++ b/charts/tfy-build/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: tfy-build +version: 0.4.3 +description: "TFY Build chart" +maintainers: + - name: truefoundry +dependencies: + - condition: tfy-buildkitd-service.enabled + name: tfy-buildkitd-service + repository: https://truefoundry.github.io/infra-charts/ + version: 0.1.3 diff --git a/charts/tfy-build/templates/_helpers.tpl b/charts/tfy-build/templates/_helpers.tpl new file mode 100644 index 00000000..2c618d26 --- /dev/null +++ b/charts/tfy-build/templates/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/tfy-build/templates/build-workflow.yaml b/charts/tfy-build/templates/build-workflow.yaml new file mode 100644 index 00000000..89ccfa4d --- /dev/null +++ b/charts/tfy-build/templates/build-workflow.yaml @@ -0,0 +1,611 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "app.serviceAccountName" . }}-role +rules: + - apiGroups: + - argoproj.io + resources: + - workflowtaskresults + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "app.serviceAccountName" . }}-role-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "app.serviceAccountName" . }}-role +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ include "app.serviceAccountName" . }} +--- +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: build +spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + workflowMetadata: + labelsFrom: + "truefoundry.com/buildName": + expression: workflow.name + entrypoint: build + onExit: exit-handler + arguments: + parameters: + - name: callbackURL + - name: buildSource + - name: buildConfig + - name: dockerRegistryURL + - name: dockerRegistryUsername + - name: dockerRegistryPassword + - name: dockerRepo + - name: dockerTag + - name: buildkitServiceURL + templates: + - name: build + inputs: + parameters: + - name: buildSource + - name: buildConfig + - name: dockerRegistryURL + - name: dockerRegistryUsername + - name: dockerRegistryPassword + - name: dockerRepo + - name: dockerTag + - name: buildkitServiceURL + steps: + - - name: build-and-push + template: build-and-push + arguments: + parameters: + - name: buildSource + value: "{{`{{inputs.parameters.buildSource}}`}}" + - name: buildConfig + value: "{{`{{inputs.parameters.buildConfig}}`}}" + - name: dockerRegistryURL + value: "{{`{{inputs.parameters.dockerRegistryURL}}`}}" + - name: dockerRegistryUsername + value: "{{`{{inputs.parameters.dockerRegistryUsername}}`}}" + - name: dockerRegistryPassword + value: "{{`{{inputs.parameters.dockerRegistryPassword}}`}}" + - name: dockerRepo + value: "{{`{{inputs.parameters.dockerRepo}}`}}" + - name: dockerTag + value: "{{`{{inputs.parameters.dockerTag}}`}}" + - name: buildkitServiceURL + value: "{{`{{inputs.parameters.buildkitServiceURL}}`}}" + - name: build-and-push + metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: 'false' + karpenter.sh/do-not-disrupt: 'true' + karpenter.sh/do-not-evict: 'true' + retryStrategy: + limit: 5 + retryPolicy: "Always" + backoff: + duration: "30" + factor: 2 + maxDuration: "1h" + inputs: + parameters: + - name: buildSource + - name: buildConfig + - name: dockerRegistryURL + - name: dockerRegistryUsername + - name: dockerRegistryPassword + - name: dockerRepo + - name: dockerTag + - name: buildkitServiceURL + volumes: + - name: truefoundry-docker-config + secret: + items: + - key: .dockerconfigjson + path: base_config.json + secretName: truefoundry-image-pull-secret + {{- with .Values.truefoundryWorkflows.extraVolumes }} + {{- toYaml . | nindent 4 }} + {{- end }} + script: + image: truefoundrycloud/sfy-builder:{{ .Values.truefoundryWorkflows.sfyBuilder.version }} + command: [bash] + workingDir: /mnt/vol + {{- with .Values.truefoundryWorkflows.extraEnvs }} + env: + {{- toYaml . | nindent 6 }} + {{- end }} + source: | + #!/bin/bash + set -e -o pipefail + + mkdir -p /root/.docker/ + cp /root/.truefoundry/.docker/base_config.json /root/.docker/config.json + + BUILD_SOURCE='{{`{{inputs.parameters.buildSource}}`}}' + BUILD_TYPE=$(echo $BUILD_SOURCE | jq -r '.type') + + rm -f -R ./source-code + + if [[ $BUILD_TYPE == "remote" ]]; then + REMOTE_URL=$(echo $BUILD_SOURCE | jq -r '.remote_uri') + printf "\033[36m[Start]\033[0m Downloading source code from remote source\n" + mkdir -p source-code + curl -s -o project-files.tar.gz $REMOTE_URL + tar -xf project-files.tar.gz -C source-code + cd source-code + elif [[ $BUILD_TYPE == "git" || $BUILD_TYPE == "github" ]]; then + GIT_URL=$(echo $BUILD_SOURCE | jq -r '.repo_url') + GIT_REF=$(echo $BUILD_SOURCE | jq -r '.ref') + + git config --global url."https://github.com/".insteadOf git@github.com: + git config --global url."https://".insteadOf git:// + + # Example of GIT_URL="https://x-access-token:@github.com/user_name/repo_name" + # Example of TRIMMED_URL="https://github.com/user_name/repo_name" + + TOKEN=$(echo "$GIT_URL" | sed -n 's/.*x-access-token:\([^@]*\).*/\1/p') + TRIMMED_URL=$(echo "$GIT_URL" | sed 's~x-access-token:[^@]*@~~') + + printf "\033[36m[Start]\033[0m Downloading source code from $TRIMMED_URL\n" + + # Set auth token + + git config --system credential.helper store + echo "https://x-access-token:$TOKEN@github.com" > ~/.git-credentials + + git clone --recursive $TRIMMED_URL source-code + cd source-code && git reset --hard $GIT_REF + elif [[ $BUILD_TYPE == "bitbucket" ]]; then + GIT_URL=$(echo $BUILD_SOURCE | jq -r '.repo_url') + GIT_REF=$(echo $BUILD_SOURCE | jq -r '.ref') + + git config --global url."https://bitbucket.org/".insteadOf git@bitbucket.org: + git config --global url."https://".insteadOf git:// + + # Example of GIT_URL="https://x-token-auth:@bitbucket.org/user_name/repo_name" + # Example of TRIMMED_URL="https://bitbucket.org/user_name/repo_name" + + TOKEN=$(echo "$GIT_URL" | sed -n 's/.*x-token-auth:\([^@]*\).*/\1/p') + TRIMMED_URL=$(echo "$GIT_URL" | sed 's~x-token-auth:[^@]*@~~') + + printf "\033[36m[Start]\033[0m Downloading source code from $TRIMMED_URL\n" + + # Set auth token + + git config --system credential.helper store + echo "https://x-token-auth:$TOKEN@bitbucket.org" > ~/.git-credentials + + git clone --recurse-submodules $TRIMMED_URL source-code + cd source-code && git reset --hard $GIT_REF + elif [[ $BUILD_TYPE == "gitlab" ]]; then + GIT_URL=$(echo $BUILD_SOURCE | jq -r '.repo_url') + GIT_REF=$(echo $BUILD_SOURCE | jq -r '.ref') + + git config --global url."https://gitlab.com/".insteadOf git@gitlab.com: + git config --global url."https://".insteadOf git:// + + # Example of GIT_URL="https://oauth2:@gitlab.com/user_name/repo_name" + # Example of TRIMMED_URL="https://gitlab.com/user_name/repo_name" + + TOKEN=$(echo "$GIT_URL" | sed -n 's/.*oauth2:\([^@]*\).*/\1/p') + TRIMMED_URL=$(echo "$GIT_URL" | sed 's~oauth2:[^@]*@~~') + + printf "\033[36m[Start]\033[0m Downloading source code from $TRIMMED_URL\n" + + # Set auth token + + git config --system credential.helper store + echo "https://oauth2:$TOKEN@gitlab.com" > ~/.git-credentials + + git clone --recurse-submodules $TRIMMED_URL source-code + cd source-code && git reset --hard $GIT_REF + elif [[ $BUILD_TYPE == "notebook_build" ]]; then + : + else + printf "{{ .Values.truefoundryWorkflows.logMarkers.error }} Source type '$BUILD_TYPE' not supported.\n" + exit 1 + fi + printf "{{ .Values.truefoundryWorkflows.logMarkers.done }} Download code completed\n" + printf "\033[36m[Start]\033[0m Building and pushing the docker container. Please find the logs below\n" + + DOCKER_PASSWORD=$(echo '{{`{{inputs.parameters.dockerRegistryPassword}}`}}' | base64 -d) + + docker login -u "{{`{{inputs.parameters.dockerRegistryUsername}}`}}" -p $DOCKER_PASSWORD "{{`{{inputs.parameters.dockerRegistryURL}}`}}" 2> /dev/null + + IMAGE="{{`{{inputs.parameters.dockerRegistryURL}}`}}"/"{{`{{inputs.parameters.dockerRepo}}`}}" + + printf "\033[36m[==== Docker logs start ====]\033[0m\n" + docker buildx create --name remote-kubernetes --driver remote tcp://{{`{{inputs.parameters.buildkitServiceURL}}`}} + # image-manifest=true is needed for ecr and works for others - https://github.com/aws/containers-roadmap/issues/876#issuecomment-1665121877 + sfy build --build-config={{`{{inputs.parameters.buildConfig}}`}} --name=$IMAGE:"{{`{{inputs.parameters.dockerTag}}`}}" --tag=$IMAGE:"{{`{{inputs.parameters.dockerTag}}`}}" --tag=$IMAGE:latest --cache-to=type=registry,ref=$IMAGE:cache-latest,image-manifest=true,mode=max --cache-from=type=registry,ref=$IMAGE:cache-latest --build-context tfy-secrets=/var/run/secrets/ --builder=remote-kubernetes --push + printf "\033[36m[==== Docker logs end ====]\033[0m\n" + printf "{{ .Values.truefoundryWorkflows.logMarkers.done }} Docker image built and pushed\n" + volumeMounts: + - name: workdir + mountPath: /mnt/vol + - name: truefoundry-docker-config + mountPath: /root/.truefoundry/.docker/ + {{- with .Values.truefoundryWorkflows.extraVolumeMounts }} + {{- toYaml . | nindent 6 }} + {{- end }} + resources: + {{- toYaml .Values.truefoundryWorkflows.sfyBuilder.resources | nindent 8 }} + - name: exit-handler + inputs: + parameters: + - name: callbackURL + - name: dockerRegistryURL + - name: dockerRepo + - name: dockerTag + - name: dockerRegistryUsername + - name: dockerRegistryPassword + steps: + - - name: success-callback + when: "{{`{{workflow.status}}`}} == Succeeded" + template: send-api-request + arguments: + parameters: + - name: url + value: "{{`{{inputs.parameters.callbackURL}}`}}" + - name: method + value: "PATCH" + - name: payload + value: '{"status": "SUCCEEDED", "imageUri": "{{`{{inputs.parameters.dockerRegistryURL}}`}}/{{`{{inputs.parameters.dockerRepo}}`}}:{{`{{inputs.parameters.dockerTag}}`}}"}' + - name: token + value: "" + - name: failure-callback + when: "{{`{{workflow.status}}`}} != Succeeded" + template: send-api-request + arguments: + parameters: + - name: url + value: "{{`{{inputs.parameters.callbackURL}}`}}" + - name: method + value: "PATCH" + - name: payload + value: '{"status": "FAILED"}' + - name: token + value: "" + - - name: end-marker + template: end-marker + - - name: should-build-soci-index + template: should-build-soci-index + when: >- + '{{ .Values.truefoundryWorkflows.sociIndexBuildAndPush.enabled }}' == 'true' + && + {{`{{workflow.status}}`}} == Succeeded + arguments: + parameters: + - name: dockerRegistryURL + value: "{{`{{inputs.parameters.dockerRegistryURL}}`}}" + - name: dockerRegistryUsername + value: "{{`{{inputs.parameters.dockerRegistryUsername}}`}}" + - name: dockerRegistryPassword + value: "{{`{{inputs.parameters.dockerRegistryPassword}}`}}" + - name: dockerRepo + value: "{{`{{inputs.parameters.dockerRepo}}`}}" + - name: dockerTag + value: "{{`{{inputs.parameters.dockerTag}}`}}" + - - name: build-and-push-soci-index + template: build-and-push-soci-index + when: >- + {{`{{steps.should-build-soci-index.status}}`}} == Succeeded + && + '{{`{{steps.should-build-soci-index.outputs.parameters.result}}`}}' == 'true' + arguments: + parameters: + - name: dockerRegistryURL + value: "{{`{{inputs.parameters.dockerRegistryURL}}`}}" + - name: dockerRegistryUsername + value: "{{`{{inputs.parameters.dockerRegistryUsername}}`}}" + - name: dockerRegistryPassword + value: "{{`{{inputs.parameters.dockerRegistryPassword}}`}}" + - name: dockerRepo + value: "{{`{{inputs.parameters.dockerRepo}}`}}" + - name: dockerTag + value: "{{`{{inputs.parameters.dockerTag}}`}}" + - name: end-marker + retryStrategy: + limit: 5 + retryPolicy: "Always" + backoff: + duration: "30" + factor: 2 + maxDuration: "2m" + script: + resources: + limits: + cpu: 200m + ephemeral-storage: 256Mi + memory: 256Mi + requests: + cpu: 100m + ephemeral-storage: 128Mi + memory: 128Mi + image: ubuntu + command: [bash] + source: | + #!/bin/bash + set -e + if [[ "{{`{{workflow.status}}`}}" == "Succeeded" ]]; then + echo -e "{{ .Values.truefoundryWorkflows.logMarkers.done }} Image Built Successfully." + echo -e "{{ .Values.truefoundryWorkflows.logMarkers.done }} Kubernetes deployment triggered. It may take 5-10s for the application to be live." + else + echo -e "{{ .Values.truefoundryWorkflows.logMarkers.error }} Error occured while building and pushing docker image." + echo -e "{{ .Values.truefoundryWorkflows.logMarkers.error }} Build Image Failed." + fi + echo "PIPELINE_RUN_{{`{{workflow.name}}`}}_ENDED" + - name: send-api-request + retryStrategy: + limit: 20 + retryPolicy: "Always" + backoff: + duration: "30" + factor: 2 + maxDuration: "2m" + inputs: + parameters: + - name: url + - name: method + - name: payload + - name: token + {{- with .Values.truefoundryWorkflows.extraVolumes }} + volumes: + {{- toYaml . | nindent 4 }} + {{- end }} + script: + resources: + limits: + cpu: 200m + ephemeral-storage: 256Mi + memory: 256Mi + requests: + cpu: 100m + ephemeral-storage: 128Mi + memory: 128Mi + image: nyurik/alpine-python3-requests + command: [python3] + {{- with .Values.truefoundryWorkflows.extraEnvs }} + env: + {{- toYaml . | nindent 6 }} + {{- end }} + source: | + import logging + import requests + import sys + import time + import json + + def api_call(): + try: + payload = '{{`{{inputs.parameters.payload}}`}}' + url= "{{`{{inputs.parameters.url}}`}}" + method= "{{`{{inputs.parameters.method}}`}}" + token= "{{`{{inputs.parameters.token}}`}}" + msg = "\033[36m[Start]\033[0m Sending request to url: {} with json {}".format(url, payload) + print(msg) + r = requests.request(method, url=url, json=json.loads(payload), headers={"authorization": "Bearer "+ token}) + r.raise_for_status() + except Exception as e: + print("{{ .Values.truefoundryWorkflows.logMarkers.error }} Error occured while notifying server") + print("Error occured", e) + time.sleep(60) + sys.exit(1) + api_call() + {{- with .Values.truefoundryWorkflows.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 6 }} + {{- end }} + - name: should-build-soci-index + activeDeadlineSeconds: 1800 + metrics: + prometheus: + - name: tfy_build_soci_index_status + help: "SOCI index build and push status" + labels: + - key: name + value: "{{`{{steps.name}}`}}" + - key: status + value: "{{`{{status}}`}}" + when: "{{`{{status}}`}} != Skipped" + counter: + value: "1" + - name: tfy_build_soci_index_duration_sec + help: "SOCI index build and push duration" + labels: + - key: name + value: "{{`{{steps.name}}`}}" + - key: status + value: "{{`{{status}}`}}" + when: "{{`{{status}}`}} != Skipped" + gauge: + value: "{{`{{duration}}`}}" + inputs: + parameters: + - name: dockerRegistryURL + - name: dockerRegistryUsername + - name: dockerRegistryPassword + - name: dockerRepo + - name: dockerTag + retryStrategy: + backoff: + duration: '1' + factor: 2 + maxDuration: 1m + limit: 5 + retryPolicy: Always + outputs: + parameters: + - name: result + valueFrom: + path: /tmp/result + script: + command: [bash] + image: {{ .Values.truefoundryWorkflows.sociIndexBuildAndPush.image }} + resources: + requests: + cpu: 50m + ephemeral-storage: 10Mi + memory: 50Mi + limits: + cpu: 50m + ephemeral-storage: 10Mi + memory: 50Mi + source: | + #!/bin/bash + + set -eu -o pipefail + + ENCODED_PASSWORD="{{`{{inputs.parameters.dockerRegistryPassword}}`}}" + PASSWORD=$(echo $ENCODED_PASSWORD | base64 -d) + USERNAME="{{`{{inputs.parameters.dockerRegistryUsername}}`}}" + REGISTRY="{{`{{inputs.parameters.dockerRegistryURL}}`}}" + REPOSITORY="{{`{{inputs.parameters.dockerRepo}}`}}" + TAG="{{`{{inputs.parameters.dockerTag}}`}}" + IMAGE=$REGISTRY/$REPOSITORY:$TAG + IMAGE_SIZE_THRESHOLD=$(printf '%.0f' {{ .Values.truefoundryWorkflows.sociIndexBuildAndPush.imageSizeThresholdBytes | quote }}) + + docker login -u $USERNAME -p $PASSWORD $REGISTRY 2> /dev/null + + echo Registry is $REGISTRY + + if [[ $REGISTRY != *"amazonaws.com"* ]]; then + echo Registry is not from ECR. Skipping SOCI index creation. + echo -n "false" > /tmp/result + exit 0 + fi + + MANFEST=$(docker manifest inspect --verbose $IMAGE) + IMAGE_SIZE=$(echo $MANFEST | jq '.[] | .OCIManifest.layers | .[] | select(.mediaType | contains("oci.image.layer.v1.tar+gzip")) | .size' | awk '{sum+=$0} END{print sum}') + echo Image Size: $IMAGE_SIZE + echo Threshold: $IMAGE_SIZE_THRESHOLD + + if [[ "$IMAGE_SIZE" -lt "$IMAGE_SIZE_THRESHOLD" ]]; then + echo Image size is less than $IMAGE_SIZE_THRESHOLD. Skipping SOCI index creation. + echo -n "false" > /tmp/result + exit 0 + fi + + echo SOCI index will be built and pushed. + echo -n "true" > /tmp/result + - name: build-and-push-soci-index + activeDeadlineSeconds: 3600 + metrics: + prometheus: + - name: tfy_build_soci_index_status + help: "SOCI index build and push status" + labels: + - key: name + value: "{{`{{steps.name}}`}}" + - key: status + value: "{{`{{status}}`}}" + when: "{{`{{status}}`}} != Skipped" + counter: + value: "1" + - name: tfy_build_soci_index_duration_sec + help: "SOCI index build and push duration" + labels: + - key: name + value: "{{`{{steps.name}}`}}" + - key: status + value: "{{`{{status}}`}}" + when: "{{`{{status}}`}} != Skipped" + gauge: + value: "{{`{{duration}}`}}" + inputs: + parameters: + - name: dockerRegistryURL + - name: dockerRegistryUsername + - name: dockerRegistryPassword + - name: dockerRepo + - name: dockerTag + retryStrategy: + backoff: + duration: '1' + factor: 2 + maxDuration: 1m + limit: 2 + retryPolicy: Always + script: + command: [bash] + image: {{ .Values.truefoundryWorkflows.sociIndexBuildAndPush.image }} + resources: + requests: + cpu: 500m + ephemeral-storage: 10Gi + memory: 700Mi + limits: + cpu: 1000m + ephemeral-storage: 30Gi + memory: 1024Mi + securityContext: + privileged: true + source: | + #!/bin/bash + + set -eu -o pipefail + + ENCODED_PASSWORD="{{`{{inputs.parameters.dockerRegistryPassword}}`}}" + PASSWORD=$(echo $ENCODED_PASSWORD | base64 -d) + USERNAME="{{`{{inputs.parameters.dockerRegistryUsername}}`}}" + REGISTRY="{{`{{inputs.parameters.dockerRegistryURL}}`}}" + REPOSITORY="{{`{{inputs.parameters.dockerRepo}}`}}" + TAG="{{`{{inputs.parameters.dockerTag}}`}}" + IMAGE=$REGISTRY/$REPOSITORY:$TAG + + docker login -u $USERNAME -p $PASSWORD $REGISTRY 2> /dev/null + + echo Starting Containerd + containerd > /dev/null 2>&1 & + sleep 3 + ctr version > /dev/null + + echo Pulling Container Image $IMAGE + + time ctr content fetch -u "$USERNAME:$PASSWORD" \ + --platform=linux/amd64 \ + $IMAGE > /dev/null + + + echo Creating Soci Index + + time soci create --platform=linux/amd64 $IMAGE + + echo Pushing Soci Index + time soci push --platform=linux/amd64 $IMAGE + + echo Done! + {{- with .Values.truefoundryWorkflows.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.truefoundryWorkflows.affinity }} + affinity: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.truefoundryWorkflows.tolerations }} + tolerations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/charts/tfy-build/values.yaml b/charts/tfy-build/values.yaml new file mode 100644 index 00000000..49ef1e42 --- /dev/null +++ b/charts/tfy-build/values.yaml @@ -0,0 +1,38 @@ +global: {} +nameOverride: '' +fullnameOverride: '' +serviceAccount: + create: true + name: tfy-build + annotations: {} +truefoundryWorkflows: + sfyBuilder: + version: 0.7.3 + resources: + limits: + cpu: 1 + ephemeral-storage: 20Gi + memory: 2Gi + requests: + cpu: 200m + ephemeral-storage: 10Gi + memory: 500Mi + extraEnvs: [] + extraVolumeMounts: [] + extraVolumes: [] + affinity: {} + tolerations: {} + nodeSelector: {} + logMarkers: + error: \u001b[31m[Error]\u001b[0m + done: \u001b[32m[Done]\u001b[0m + start: \u001b[36m[Start]\u001b[0m + clientPrefix: + - TFY-CLIENT + supportSlack: >- + https://join.slack.com/t/truefoundry/shared_invite/zt-11ht512jq-nDJq~HJMqc6wBw90JVlo7g + serviceFoundryUiUrl: https://app.truefoundry.com/workspace + sociIndexBuildAndPush: + enabled: false + image: public.ecr.aws/truefoundrycloud/soci-index-builder:0.2.0-rc.1 + imageSizeThresholdBytes: 419430400 diff --git a/charts/tfy-controller/Chart.yaml b/charts/tfy-controller/Chart.yaml new file mode 100644 index 00000000..44f97817 --- /dev/null +++ b/charts/tfy-controller/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: tfy-controller +version: 0.0.19-rc.2 +description: Deployment control loop and Proxy Server Chart" +maintainers: + - name: truefoundry diff --git a/charts/tfy-controller/templates/_helpers.tpl b/charts/tfy-controller/templates/_helpers.tpl new file mode 100644 index 00000000..4f5316fb --- /dev/null +++ b/charts/tfy-controller/templates/_helpers.tpl @@ -0,0 +1,100 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/tfy-controller/templates/deployment.yaml b/charts/tfy-controller/templates/deployment.yaml new file mode 100644 index 00000000..61a848ef --- /dev/null +++ b/charts/tfy-controller/templates/deployment.yaml @@ -0,0 +1,59 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: port-{{ .Values.service.port }} + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthcheck.liveness.path }} + port: {{ .Values.healthcheck.liveness.port }} + readinessProbe: + httpGet: + path: {{ .Values.healthcheck.readiness.path }} + port: {{ .Values.healthcheck.liveness.port }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/tfy-controller/templates/service.yaml b/charts/tfy-controller/templates/service.yaml new file mode 100644 index 00000000..17692108 --- /dev/null +++ b/charts/tfy-controller/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: port-{{ .Values.service.port }} + selector: + {{- include "app.selectorLabels" . | nindent 4 }} diff --git a/charts/tfy-controller/templates/serviceaccount.yaml b/charts/tfy-controller/templates/serviceaccount.yaml new file mode 100644 index 00000000..a41b8ac6 --- /dev/null +++ b/charts/tfy-controller/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/tfy-controller/values.yaml b/charts/tfy-controller/values.yaml new file mode 100644 index 00000000..c71222c3 --- /dev/null +++ b/charts/tfy-controller/values.yaml @@ -0,0 +1,56 @@ +global: {} +imageRepository: truefoundrycloud/tfy-controller +environmentName: default +envSecretName: sfy-manifest-service-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: false +resources: + limits: + cpu: 200m + memory: 256Mi + ephemeral-storage: 256Mi + requests: + cpu: 100m + memory: 128Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +service: + type: ClusterIP + port: 8123 + annotations: {} +serviceAccount: + create: true + name: tfy-controller + annotations: {} +env: + GIN_MODE: release + SFY_SERVER_URL: >- + http://{{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:3000 + SFY_API_KEY: ${k8s-secret/truefoundry-creds/TFY_API_KEY} + SFY_MANIFEST_SERVER_URL: >- + http://{{ .Release.Name }}-sfy-manifest-service.{{ .Release.Namespace + }}.svc.cluster.local:8080 + PROXY_SERVER_PORT: '{{ .Values.service.port }}' + PROXY_SERVER_ENABLED: 'true' + DEPLOYMENT_CONTROLLER_ENABLED: 'true' + MIGRATION_CONTROLLER_ENABLED: 'false' + MIGRATION_CONTROLLER_INTERVAL_MINUTES: '60' + MIGRATION_CONTROLLER_APPLICATION_HEALTH_CHECK_TIMEOUT_MINUTES: '5' + MIGRATION_CONTROLLER_APPLICATION_HEALTH_CHECK_INTERVAL_SECONDS: '20' + TENANT_NAME: '{{ .Values.global.tenantName }}' + AUTH_SERVER_URL: https://auth.truefoundry.com + TFY_AGENT_STATE_BUFFER_PROCESSOR_ENABLED: 'true' + TFY_AGENT_STATE_BUFFER_PROCESSOR_NATS_URL: >- + nats://{{ .Release.Name }}-nats.{{ .Release.Namespace + }}.svc.cluster.local:4222 +imageTag: dc8765d988fd8d0c38ff73aaf9ba085b9c75f553 diff --git a/charts/truefoundry-frontend-app/Chart.yaml b/charts/truefoundry-frontend-app/Chart.yaml new file mode 100644 index 00000000..88757b2e --- /dev/null +++ b/charts/truefoundry-frontend-app/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: truefoundry-frontend-app +version: 0.3.134-rc.4 +description: "Truefoundry-frontend-app deployment chart" +maintainers: + - name: truefoundry diff --git a/charts/truefoundry-frontend-app/templates/_helpers.tpl b/charts/truefoundry-frontend-app/templates/_helpers.tpl new file mode 100644 index 00000000..4f5316fb --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/_helpers.tpl @@ -0,0 +1,100 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.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 "app.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 "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* + Common labels + */}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{- range $name, $value := .Values.commonLabels }} +{{ $name }}: {{ tpl $value $ | quote }} +{{- end }} +{{ include "app.selectorLabels" . }} +{{- if .Values.imageTag }} +app.kubernetes.io/version: {{ .Values.imageTag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* + Selector labels + */}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* + Create the name of the service account to use + */}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* + Parse env from template + */}} +{{- define "app.parseEnv" -}} +{{ tpl (.Values.env | toYaml) . }} +{{- end }} + +{{/* + Create the env file + */}} +{{- define "app.env" }} +{{- range $key, $val := (include "app.parseEnv" .) | fromYaml }} +{{- if and $val (contains "${k8s-secret" ($val | toString)) }} +{{- if eq (regexSplit "/" $val -1 | len) 2 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $.Values.envSecretName }} + key: {{ index (regexSplit "/" $val -1) 1 | trimSuffix "}" }} +{{- else if eq (regexSplit "/" $val -1 | len) 3 }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ index (regexSplit "/" $val -1) 1 }} + key: {{ index (regexSplit "/" $val -1) 2 | trimSuffix "}" }} +{{- else }} +{{- fail "Invalid secret supplied" }} +{{- end }} +{{- else }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/truefoundry-frontend-app/templates/deployment.yaml b/charts/truefoundry-frontend-app/templates/deployment.yaml new file mode 100644 index 00000000..c1bf9893 --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "app.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + {{- include "app.env" . | trim | nindent 12 }} + image: "{{ .Values.imageRepository }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.healthcheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthcheck.liveness.path }} + port: {{ .Values.healthcheck.liveness.port }} + readinessProbe: + httpGet: + path: {{ .Values.healthcheck.readiness.path }} + port: {{ .Values.healthcheck.liveness.port }} + {{- end }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + volumes: + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/charts/truefoundry-frontend-app/templates/ingress.yaml b/charts/truefoundry-frontend-app/templates/ingress.yaml new file mode 100644 index 00000000..1fe0c59d --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: +{{- if .Values.ingress.annotations }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- toYaml .Values.ingress.labels | nindent 4 }} + {{- end }} +spec: + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + + {{- end -}} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end -}} +{{- end -}} diff --git a/charts/truefoundry-frontend-app/templates/llm-gateway-destination-rule.yaml b/charts/truefoundry-frontend-app/templates/llm-gateway-destination-rule.yaml new file mode 100644 index 00000000..7462a030 --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/llm-gateway-destination-rule.yaml @@ -0,0 +1,15 @@ +{{- if .Values.llmGateway.external }} +apiVersion: networking.istio.io/v1beta1 +kind: DestinationRule +metadata: + name: llm-gateway-{{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + namespace: {{ .Release.Namespace }} +spec: + host: {{ tpl .Values.llmGateway.backendHost . }} + trafficPolicy: + tls: + mode: SIMPLE + sni: {{ tpl .Values.llmGateway.backendHost . }} +{{- end }} \ No newline at end of file diff --git a/charts/truefoundry-frontend-app/templates/llm-gateway-service-entry.yaml b/charts/truefoundry-frontend-app/templates/llm-gateway-service-entry.yaml new file mode 100644 index 00000000..178e66ee --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/llm-gateway-service-entry.yaml @@ -0,0 +1,18 @@ +{{- if .Values.llmGateway.external }} +apiVersion: networking.istio.io/v1beta1 +kind: ServiceEntry +metadata: + name: llm-gateway-{{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + namespace: {{ .Release.Namespace }} +spec: + hosts: + - {{ tpl .Values.llmGateway.backendHost . }} + location: MESH_EXTERNAL + ports: + - number: {{ .Values.llmGateway.backendPort }} + protocol: HTTPS + name: https-port + resolution: DNS +{{- end }} \ No newline at end of file diff --git a/charts/truefoundry-frontend-app/templates/service.yaml b/charts/truefoundry-frontend-app/templates/service.yaml new file mode 100644 index 00000000..a45d8822 --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/truefoundry-frontend-app/templates/serviceaccount.yaml b/charts/truefoundry-frontend-app/templates/serviceaccount.yaml new file mode 100644 index 00000000..a41b8ac6 --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml . | indent 4) $ }} +{{- end }} +imagePullSecrets: +{{- if .Values.global.existingTruefoundryImagePullSecretName }} + - name: {{ .Values.global.existingTruefoundryImagePullSecretName }} +{{- else }} + - name: truefoundry-image-pull-secret +{{- end }} +{{- end }} diff --git a/charts/truefoundry-frontend-app/templates/virtualservice.yaml b/charts/truefoundry-frontend-app/templates/virtualservice.yaml new file mode 100644 index 00000000..8738663b --- /dev/null +++ b/charts/truefoundry-frontend-app/templates/virtualservice.yaml @@ -0,0 +1,65 @@ +{{- if .Values.istio.virtualservice.enabled -}} +{{- $serviceName := include "app.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- if .Values.istio.virtualservice.annotations }} + annotations: + {{- range $key, $value := .Values.istio.virtualservice.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + {{- range .Values.istio.virtualservice.gateways}} + - {{ . }} + {{- end }} + hosts: + {{- range .Values.istio.virtualservice.hosts}} + - {{ . }} + {{- end }} + http: + - match: + - uri: + prefix: "/api/svc/socket.io" + rewrite: + uri: /socket.io + route: + - destination: + host: {{ tpl .Values.servicefoundryServerHost . }} + port: + number: 3000 + - match: + - uri: + prefix: "/api/llm/" + rewrite: + uri: / + {{- if .Values.llmGateway.external }} + authority: {{ tpl .Values.llmGateway.backendHost . }} + {{- end }} + route: + - destination: + host: {{ tpl .Values.llmGateway.backendHost . }} + port: + number: {{ .Values.llmGateway.backendPort }} + - match: + - uri: + prefix: /api/proxy-server/ + rewrite: + uri: / + route: + - destination: + host: {{ tpl .Values.proxyServerHost . }} + port: + number: 8123 + - route: + - destination: + host: {{ include "app.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: {{ .Values.service.port }} +{{- end }} diff --git a/charts/truefoundry-frontend-app/values.yaml b/charts/truefoundry-frontend-app/values.yaml new file mode 100644 index 00000000..1217e61c --- /dev/null +++ b/charts/truefoundry-frontend-app/values.yaml @@ -0,0 +1,121 @@ +global: {} +imageRepository: truefoundrycloud/truefoundry-frontend-app +replicaCount: 1 +envSecretName: truefoundry-frontend-app-env-secret +imagePullPolicy: IfNotPresent +nameOverride: '' +fullnameOverride: '' +podAnnotations: {} +podSecurityContext: {} +commonLabels: {} +securityContext: {} +healthcheck: + enabled: false +resources: + limits: + cpu: 200m + memory: 512Mi + ephemeral-storage: 256Mi + requests: + cpu: 100m + memory: 256Mi + ephemeral-storage: 128Mi +nodeSelector: {} +tolerations: {} +affinity: {} +topologySpreadConstraints: {} +service: + type: ClusterIP + port: 5000 + annotations: {} +ingress: + enabled: false + annotations: {} + labels: {} + ingressClassName: istio + tls: [] + hosts: [] +istio: + virtualservice: + enabled: false + annotations: {} + gateways: [] + hosts: [] +serviceAccount: + create: true + name: truefoundry-frontend-app + annotations: {} +imageTag: e31638986fc7f1e5025987f57b78b0ad864d47ae +servicefoundryServerHost: >- + {{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local +llmGateway: + external: false + backendHost: '{{ .Release.Name }}-llm-gateway.{{ .Release.Namespace }}.svc.cluster.local' + backendPort: 8787 +proxyServerHost: '{{ .Release.Name }}-tfy-controller.{{ .Release.Namespace }}.svc.cluster.local' +extraVolumes: [] +extraVolumeMounts: [] +env: + AUTH_SERVER_URL: https://auth.truefoundry.com + NATS_URL: ws://{{ .Release.Name }}-nats.{{ .Release.Namespace }}.svc.cluster.local:443 + MLFOUNDRY_SERVER_URL: >- + http://{{ .Release.Name }}-mlfoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:5000 + SERVICEFOUNDRY_SERVER_URL: >- + http://{{ .Release.Name }}-servicefoundry-server.{{ .Release.Namespace + }}.svc.cluster.local:3000 + TFY_CONTROLLER_URL: >- + http://{{ .Release.Name }}-tfy-controller.{{ .Release.Namespace + }}.svc.cluster.local:8123 + VITE_AUTHSERVER_URL: /api/auth + VITE_MLFOUNDRY_URL: /api/ml + VITE_SVCFOUNDRY_URL: /api/svc + VITE_MONITORINGFOUNDRY_URL: /api/monitoring + VITE_LLM_PLAYGROUND_API_URL: /api/llm + VITE_SOCKET_URL: '' + VITE_NATS_URL: '' + VITE_FUSIONAUTH_URL: https://login.truefoundry.com + VITE_MULTITENANT_ENABLED: 'false' + VITE_TENANT_NAME: '{{ .Values.global.tenantName }}' + VITE_LOGO_URL: '' + VITE_EXPORT_AS_HELM_TYPES: service,volume,helm + VITE_ENABLE_COMPANY_REGISTRATION: 'false' + VITE_ENABLE_FEATURE_RESOURCE_COSTS: 'false' + VITE_STRIPE_PUBLISHABLE_KEY: '' + VITE_CREDIT_CARD_REQUIRED_DOMAINS: '' + VITE_TENANT_BASE_DOMAIN: '' + VITE_MANAGED_CLUSTER_ONBOARDING_ENABLED: 'false' + VITE_MANAGED_CLUSTER_ONBOARDING_SERVICE_URL: '' + VITE_CIVO_RESOURCES_STRING: '' + VITE_CLUSTER_ONBOARDING_FLOW_ENABLED: 'false' + VITE_LLM_PLAYGROUND_ENABLED: 'false' + VITE_LLM_PLAYGROUND_ENABLE_STANDALONE: 'false' + VITE_LLM_PLAYGROUND_ENABLE_REDIRECT: 'false' + VITE_OLD_LLM_PLAYGROUND_PATH: llm-playground + VITE_LLM_PLAYGROUND_PATH: llm-gateway + VITE_ENABLE_SENTRY: 'false' + VITE_SENTRY_DSN: '' + VITE_APEX_DOMAIN: http://truefoundry.com/ + VITE_DATAGRID_LICENSE_KEY: >- + 1562842fe4dffce93855a342848a3609T1JERVI6NDA5ODIsRVhQSVJZPTE2ODA0NzEzNDkwMDAsS0VZVkVSU0lPTj0x + VITE_ENABLE_GOOGLE_ANALYTICS: 'false' + VITE_ENABLE_PAGESENSE: 'false' + VITE_ENABLE_MIXPANEL: 'false' + VITE_SENTRY_AUTH_TOKEN: '' + VITE_SENTRY_ENVIRONMENT: '' + VITE_MIXPANEL_TOKEN: '' + VITE_APP_ENVIRONMENT: '' + VITE_CRISP_WEBSITE_ID: '' + VITE_QA_FOUNDRY_URL: '' + VITE_QA_FOUNDRY_JOB_FQN: '' + VITE_QA_FOUNDRY_ML_REPO: '' + VITE_QA_FOUNDRY_LLM_HOST: '' + VITE_QA_FOUNDRY_LLM_KEY: '' + VITE_DOCS_QA_ENABLE_STANDALONE: 'false' + VITE_DOCS_QA_DELETE_COLLECTIONS: 'false' + VITE_DOCS_QA_STANDALONE_PATH: '' + VITE_DOCS_QA_ENABLE_REDIRECT: 'false' + VITE_DOCS_QA_EMBEDDINGS: '' + VITE_DOCS_QA_MAX_UPLOAD_SIZE_MB: '2' + VITE_ENABLE_SUPERFLOW: 'false' diff --git a/charts/truefoundry/Chart.lock b/charts/truefoundry/Chart.lock new file mode 100644 index 00000000..3dd47112 --- /dev/null +++ b/charts/truefoundry/Chart.lock @@ -0,0 +1,33 @@ +dependencies: +- name: mlfoundry-server + repository: oci://quay.io/truefoundrycharts + version: 0.2.103-rc.5 +- name: servicefoundry-server + repository: oci://quay.io/truefoundrycharts + version: 0.3.140-rc.9 +- name: tfy-configs + repository: https://truefoundry.github.io/infra-charts + version: 0.1.0-rc.6 +- name: truefoundry-frontend-app + repository: oci://quay.io/truefoundrycharts + version: 0.3.134-rc.3 +- name: sfy-manifest-service + repository: oci://quay.io/truefoundrycharts + version: 0.1.119-rc.4 +- name: tfy-build + repository: oci://quay.io/truefoundrycharts + version: 0.4.3 +- name: nats + repository: https://nats-io.github.io/k8s/helm/charts/ + version: 0.19.1 +- name: llm-gateway + repository: oci://quay.io/truefoundrycharts + version: 0.2.2 +- name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 15.2.2 +- name: tfy-controller + repository: oci://quay.io/truefoundrycharts + version: 0.0.19-rc.1 +digest: sha256:28a7b05581f0088c4b9665ce82e5411c98b0cd918a01a6ce97624f52ef64f265 +generated: "2024-05-21T20:52:03.681948+05:30" diff --git a/charts/truefoundry/Chart.yaml b/charts/truefoundry/Chart.yaml new file mode 100644 index 00000000..4ef4e0a3 --- /dev/null +++ b/charts/truefoundry/Chart.yaml @@ -0,0 +1,47 @@ +apiVersion: v2 +name: truefoundry +version: 0.3.204-rc.18 +description: "Truefoundry applications" +maintainers: + - name: truefoundry +dependencies: + - condition: mlfoundry-server.enabled + name: mlfoundry-server + repository: oci://quay.io/truefoundrycharts + version: 0.2.103-rc.6 + - condition: servicefoundry-server.enabled + name: servicefoundry-server + repository: oci://quay.io/truefoundrycharts + version: 0.3.140-rc.12 + - condition: servicefoundry-server.enabled + name: tfy-configs + repository: https://truefoundry.github.io/infra-charts + version: 0.1.0-rc.6 + - condition: truefoundry-frontend-app.enabled + name: truefoundry-frontend-app + repository: oci://quay.io/truefoundrycharts + version: 0.3.134-rc.3 + - condition: sfy-manifest-service.enabled + name: sfy-manifest-service + repository: oci://quay.io/truefoundrycharts + version: 0.1.119-rc.4 + - condition: tfy-build.enabled + name: tfy-build + repository: oci://quay.io/truefoundrycharts + version: 0.4.3 + - condition: nats.enabled + name: nats + repository: https://nats-io.github.io/k8s/helm/charts/ + version: 0.19.1 + - condition: llm-gateway.enabled + name: llm-gateway + repository: oci://quay.io/truefoundrycharts + version: 0.2.2 + - condition: global.dev + name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 15.2.2 + - name: tfy-controller + condition: tfy-controller.enabled + repository: oci://quay.io/truefoundrycharts + version: 0.0.19-rc.1 diff --git a/charts/truefoundry/README.md b/charts/truefoundry/README.md new file mode 100644 index 00000000..4ce995c6 --- /dev/null +++ b/charts/truefoundry/README.md @@ -0,0 +1,2 @@ +# truefoundry helm chart packaged by TrueFoundry +truefoundry is an applications that gets deployed on the kubernetes cluster to spin up the TrueFoundry Control plane \ No newline at end of file diff --git a/charts/truefoundry/templates/bootstrap/configmap.yaml b/charts/truefoundry/templates/bootstrap/configmap.yaml new file mode 100644 index 00000000..077de292 --- /dev/null +++ b/charts/truefoundry/templates/bootstrap/configmap.yaml @@ -0,0 +1,150 @@ +{{- if .Values.truefoundryBootstrap.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: truefoundry-bootstrap-cm + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-2" + "helm.sh/hook-delete-policy": before-hook-creation + "argocd.argoproj.io/hook": PreSync + "argocd.argoproj.io/sync-wave": "-2" + "argocd.argoproj.io/hook-delete-policy": BeforeHookCreation +data: + truefoundry-bootstrap.sh: | + #!/bin/bash + # This script will output one set of creds in the current directory. + # The script creates a nats resolver config file called resolver.conf + TRUEFOUNDRY_NATS_SECRET_NAME=truefoundry-nats-secret + TRUEFOUNDRY_CREDS_SECRET_NAME=truefoundry-creds + print_green() { + echo "$(tput setaf 2)$1$(tput sgr0)" + } + print_yellow() { + echo "$(tput setaf 3)$1$(tput sgr0)" + } + print_red() { + echo "$(tput setaf 1)$1$(tput sgr0)" + } + + # function to install binaries - kubectl, nsc, helm + install_binaries() { + apt update && apt install wget unzip -y \ + && wget https://github.com/nats-io/nsc/releases/download/v2.8.6/nsc-linux-amd64.zip \ + && unzip nsc-linux-amd64.zip \ + && mv nsc /usr/bin/ \ + && wget https://storage.googleapis.com/kubernetes-release/release/v1.29.3/bin/linux/amd64/kubectl \ + && chmod +x kubectl \ + && mv kubectl /usr/bin/ + } + + migrate_nats_seed_to_dedicated_secret() { + # Get the value of NATS_CONTROLPLANE_ACCOUNT_SEED from the secret + NATS_SEED=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.NATS_CONTROLPLANE_ACCOUNT_SEED}' | base64 --decode) + + # Check if the NATS_SEED is empty + if [ -z "$NATS_SEED" ]; then + print_red "NATS_CONTROLPLANE_ACCOUNT_SEED is not set in the secret servicefoundry-env-secret." + exit 1 + fi + + # Create the new secret using the NATS_SEED + kubectl create secret generic $TRUEFOUNDRY_NATS_SECRET_NAME --from-literal=NATS_CONTROLPLANE_ACCOUNT_SEED="$NATS_SEED" -n $TRUEFOUNDRY_NAMESPACE + } + + migrate_truefoundry_creds_to_dedicated_secret() { + # Get the value of NATS_CONTROLPLANE_ACCOUNT_SEED from the secret + DB_HOST=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.DB_HOST}' | base64 --decode) + DB_USERNAME=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.DB_USERNAME}' | base64 --decode) + DB_PASSWORD=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 --decode) + DB_NAME=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.DB_NAME}' | base64 --decode) + TFY_API_KEY=$(kubectl -n $TRUEFOUNDRY_NAMESPACE get secret servicefoundry-server-env-secret -o jsonpath='{.data.SVC_FOUNDRY_SERVICE_API_KEY}' | base64 --decode) + + # Check if the DB creds are empty + if [ -z "$DB_HOST" ] || [ -z "$DB_USERNAME" ] || [ -z "$DB_PASSWORD" ] || [ -z "$DB_NAME" ] || [ -z "$TFY_API_KEY" ]; then + print_red "DB and Tfy API creds not set in the secret servicefoundry-env-secret" + exit 1 + fi + # Create the new secret using the DB creds + kubectl create secret generic $TRUEFOUNDRY_CREDS_SECRET_NAME \ + --from-literal=DB_HOST="$DB_HOST" \ + --from-literal=DB_USERNAME="$DB_USERNAME" \ + --from-literal=DB_PASSWORD="$DB_PASSWORD" \ + --from-literal=DB_NAME="$DB_NAME" \ + --from-literal=TFY_API_KEY="$TFY_API_KEY" \ + -n $TRUEFOUNDRY_NAMESPACE + } + + # check if the following variables are not set + if [ -z "$TRUEFOUNDRY_NAMESPACE" ]; then + print_red "TRUEFOUNDRY_NAMESPACE is not set." + exit 1 + fi + + install_binaries + + kubectl -n $TRUEFOUNDRY_NAMESPACE get cm $TRUEFOUNDRY_NATS_CONFIGMAP + if [ $? -eq 0 ]; then + kubectl -n $TRUEFOUNDRY_NAMESPACE get secret $TRUEFOUNDRY_NATS_SECRET_NAME + if [ $? -eq 0 ]; then + print_red "Secret $TRUEFOUNDRY_NATS_SECRET_NAME already exists. Exiting..." + exit 0 + else + print_yellow "We are going to create the secret $TRUEFOUNDRY_NATS_SECRET_NAME and $TRUEFOUNDRY_CREDS_SECRET_NAME from existing seed. This is a migration scenario dated 2024-05-01" + migrate_nats_seed_to_dedicated_secret + migrate_truefoundry_creds_to_dedicated_secret + exit 0 + fi + fi + print_yellow "$TRUEFOUNDRY_NATS_CONFIGMAP not found. Creating NATS account and configmap..." + + # Setup NSC env + NSC_ROOT=$(pwd)/nsc + export NKEYS_PATH=$NSC_ROOT/nkeys + export NSC_HOME=$NSC_ROOT/accounts + nsc env -s "${NSC_HOME}/nats" + nsc env + + # Create Operator + nsc add operator --sys --name truefoundry + + # Create tfy-controlplane account. The seed for this account is provided as an environment variable + # to servicefoundry-server + nsc add account --name tfy-controlplane + # enable JS + nsc edit account --name tfy-controlplane --js-disk-storage 512M + + # Create user to create a stream. + nsc add user --account tfy-controlplane --name js-creator + nsc generate creds > "${NSC_ROOT}/user.creds" + + # Store account info. + nsc generate config --mem-resolver --config-file "${NSC_ROOT}/resolver.conf" + + # Get seed of the account + NKEYS_EXPORT_DIR=$NSC_ROOT/exported-keys + nsc export keys --account tfy-controlplane --accounts --dir "${NKEYS_EXPORT_DIR}" + NKEYS_FILE_NAME=$(ls "${NKEYS_EXPORT_DIR}" | grep "A*.nk" | head -1) + NKEYS_PATH="${NKEYS_EXPORT_DIR}/${NKEYS_FILE_NAME}" + SEED=$(cat "${NKEYS_PATH}") + cat "${NKEYS_PATH}" > nsc/tfy.seed + + # Create K8s config map to store the account resolver. + # This will be imported by the main config file. + kubectl create configmap $TRUEFOUNDRY_NATS_CONFIGMAP --from-file "nsc/resolver.conf" -n $TRUEFOUNDRY_NAMESPACE -o yaml --dry-run | kubectl apply -f - + + # copy the nats seed to /tfy.seed + NATS_SEED=$(cat nsc/tfy.seed) + + # creating the secret + kubectl create -f -< + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + +############################# +# Settings corresponding to the NATS server +nats: + enabled: true + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + nats: + image: nats:2.10.12-alpine3.19 + advertise: false + jetstream: + enabled: true + memStorage: + enabled: true + size: 1Gi + fileStorage: + enabled: true + storageDirectory: /data + size: 10Gi + accessModes: + - ReadWriteOnce + logging: + debug: true + natsbox: + enabled: false + exporter: + enabled: true + image: + tag: "0.14.0" + reloader: + enabled: true + image: + tag: "0.14.1" + cluster: + enabled: true + replicas: 3 + noAdvertise: true + websocket: + enabled: true + port: 443 + noTLS: true + sameOrigin: false + allowedOrigins: [] + auth: + enabled: true + resolver: + type: memory + configMap: + name: nats-accounts + key: resolver.conf + +############################# +# Settings corresponding to the tfy-build server +tfy-build: + enabled: true + truefoundryWorkflows: + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + tfy-buildkitd-service: + enabled: true + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + +############################# +# Settings corresponding to the llm-gateway +llm-gateway: + enabled: false + replicaCount: 1 + env: {} + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + +############################# +# To further configure the local postgres installation use the following section. +# During cleanup, make sure to remove any stray pvc that might be created. +postgresql: + auth: + existingSecret: "truefoundry-postgresql-auth-secret" + database: "truefoundry" + primary: + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal + +############################# +# Settings specific to tfy-controller. +tfy-controller: + enabled: true + tolerations: + - key: class.truefoundry.io/control-plane + effect: NoSchedule + operator: Exists + - key: "cloud.google.com/gke-spot" + value: "true" + effect: NoSchedule + operator: Equal + - key: kubernetes.azure.com/scalesetpriority + value: spot + effect: NoSchedule + operator: Equal