diff --git a/frontend/10-generate-env.sh b/frontend/10-generate-env.sh
index 0fbacc6..222fab2 100644
--- a/frontend/10-generate-env.sh
+++ b/frontend/10-generate-env.sh
@@ -1,7 +1,8 @@
#!/bin/sh
set -e
-TEMPLATE="/etc/env/env.js.template"
+# Template is in dist (copied by Dockerfile builder stage)
+TEMPLATE="/usr/share/nginx/html/env.js.template"
TARGET="/usr/share/nginx/html/env.js"
if [ -f "$TEMPLATE" ]; then
@@ -16,8 +17,16 @@ window.__ENV__ = {
EOF
echo "✓ env.js generated at $TARGET"
else
- echo "No env.js.template found at $TEMPLATE, skipping generation"
+ echo "Warning: env.js.template not found at $TEMPLATE, creating default env.js"
+ # Fallback: create env.js with default value
+ : ${API_BASE:=/api}
+ cat > "$TARGET" <
frontend
+
+
diff --git a/manifests/my-recipes/values.yaml b/manifests/my-recipes/values.yaml
new file mode 100644
index 0000000..3e57958
--- /dev/null
+++ b/manifests/my-recipes/values.yaml
@@ -0,0 +1,96 @@
+global:
+ namespace: my-apps
+ imagePullSecrets: []
+# Backend configuration
+backend:
+ name: backend
+ replicaCount: 1
+ image:
+ repository: harbor.dvirlabs.com/my-apps/my-recipes-backend
+ pullPolicy: IfNotPresent
+ tag: "master-895786b"
+ service:
+ type: ClusterIP
+ port: 8000
+ targetPort: 8000
+ resources:
+ requests:
+ cpu: 100m
+ memory: 128Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ env:
+ PYTHONUNBUFFERED: "1"
+ tag: master-895786b
+# Frontend configuration
+frontend:
+ name: frontend
+ replicaCount: 1
+ image:
+ repository: harbor.dvirlabs.com/my-apps/my-recipes-frontend
+ pullPolicy: IfNotPresent
+ tag: "master-895786b"
+ service:
+ type: ClusterIP
+ port: 80
+ targetPort: 80
+ env:
+ API_BASE: "https://my-recipes.dvirlabs.com/api"
+ resources:
+ requests:
+ cpu: 50m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 256Mi
+ tag: master-bd31ffb
+# PostgreSQL configuration
+postgres:
+ name: db
+ image:
+ repository: postgres
+ tag: "16"
+ pullPolicy: IfNotPresent
+ user: recipes_user
+ password: recipes_password # POC only – later use Secret/ExternalSecret
+ database: recipes_db
+ port: 5432
+ service:
+ type: ClusterIP
+ port: 5432
+ targetPort: 5432
+ persistence:
+ enabled: true
+ accessMode: ReadWriteOnce
+ storageClass: "nfs-client"
+ size: 8Gi
+ resources:
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ limits:
+ cpu: 1000m
+ memory: 1Gi
+# Ingress (top-level, maps frontend/backend paths)
+ingress:
+ enabled: true
+ className: "nginx"
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ nginx.ingress.kubernetes.io/rewrite-target: "/$2"
+ nginx.ingress.kubernetes.io/use-regex: "true"
+ hosts:
+ - host: my-recipes.dvirlabs.com
+ paths:
+ - path: /
+ pathType: Prefix
+ backend: frontend
+ # use a regex to capture and rewrite /api/... to /... on the backend
+ - path: /api(/|$)(.*)
+ pathType: ImplementationSpecific
+ backend: backend
+ tls:
+ - secretName: recipes-tls
+ hosts:
+ - my-recipes.dvirlabs.com
diff --git a/manifests/navix/values.yaml b/manifests/navix/values.yaml
new file mode 100644
index 0000000..e266654
--- /dev/null
+++ b/manifests/navix/values.yaml
@@ -0,0 +1,47 @@
+frontend:
+ image:
+ repository: harbor.dvirlabs.com/my-apps/navix-frontend
+ pullPolicy: IfNotPresent
+ tag: master-e56328b
+ service:
+ type: ClusterIP
+ port: 80
+ ingress:
+ enabled: true
+ className: traefik
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ hosts:
+ - host: navix.dvirlabs.com
+ paths:
+ - path: /
+ pathType: Prefix
+ env:
+ API_BASE: "https://api-navix.dvirlabs.com/api"
+ MINIO_ENDPOINT: "s3.dvirlabs.com"
+ MINIO_BUCKET: "navix-icons"
+backend:
+ image:
+ repository: harbor.dvirlabs.com/my-apps/navix-backend
+ pullPolicy: IfNotPresent
+ tag: master-62a2769
+ service:
+ type: ClusterIP
+ port: 8000
+ env:
+ MINIO_ACCESS_KEY: "your-access-key"
+ MINIO_SECRET_KEY: "your-secret-key"
+ MINIO_ENDPOINT: "s3.dvirlabs.com"
+ MINIO_BUCKET: "navix-icons"
+ ingress:
+ enabled: true
+ className: traefik
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ hosts:
+ - host: api-navix.dvirlabs.com
+ paths:
+ - path: /api
+ pathType: Prefix
diff --git a/my-recipes-chart/Chart.yaml b/my-recipes-chart/Chart.yaml
new file mode 100644
index 0000000..86c815b
--- /dev/null
+++ b/my-recipes-chart/Chart.yaml
@@ -0,0 +1,14 @@
+apiVersion: v2
+name: my-recipes
+description: Complete recipe management application with PostgreSQL, FastAPI backend, and React frontend
+type: application
+version: 1.0.0
+appVersion: "1.0.0"
+keywords:
+ - recipes
+ - fastapi
+ - react
+ - postgresql
+maintainers:
+ - name: Development Team
+
diff --git a/my-recipes-chart/templates/backend-deployment.yaml b/my-recipes-chart/templates/backend-deployment.yaml
new file mode 100644
index 0000000..78e204d
--- /dev/null
+++ b/my-recipes-chart/templates/backend-deployment.yaml
@@ -0,0 +1,69 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.backend.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.backend.name }}
+ component: backend
+spec:
+ replicas: {{ .Values.backend.replicaCount }}
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-{{ .Values.backend.name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.backend.name }}
+ component: backend
+ spec:
+ containers:
+ - name: {{ .Values.backend.name }}
+ image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
+ imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
+ ports:
+ - containerPort: {{ .Values.backend.service.targetPort }}
+ name: http
+ protocol: TCP
+ env:
+ {{- if .Values.backend.env }}
+ {{- range $key, $value := .Values.backend.env }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- end }}
+ envFrom:
+ - secretRef:
+ name: {{ .Release.Name }}-db-credentials
+ startupProbe:
+ httpGet:
+ path: /docs
+ port: http
+ initialDelaySeconds: 15
+ periodSeconds: 5
+ timeoutSeconds: 3
+ failureThreshold: 30
+ livenessProbe:
+ httpGet:
+ path: /docs
+ port: http
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ readinessProbe:
+ httpGet:
+ path: /docs
+ port: http
+ initialDelaySeconds: 10
+ periodSeconds: 5
+ timeoutSeconds: 3
+ failureThreshold: 2
+ resources:
+ requests:
+ cpu: {{ .Values.backend.resources.requests.cpu }}
+ memory: {{ .Values.backend.resources.requests.memory }}
+ limits:
+ cpu: {{ .Values.backend.resources.limits.cpu }}
+ memory: {{ .Values.backend.resources.limits.memory }}
+
diff --git a/my-recipes-chart/templates/backend-service.yaml b/my-recipes-chart/templates/backend-service.yaml
new file mode 100644
index 0000000..6608df6
--- /dev/null
+++ b/my-recipes-chart/templates/backend-service.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.backend.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.backend.name }}
+ component: backend
+spec:
+ type: {{ .Values.backend.service.type }}
+ ports:
+ - port: {{ .Values.backend.service.port }}
+ targetPort: {{ .Values.backend.service.targetPort }}
+ protocol: TCP
+ name: http
+ selector:
+ app: {{ .Release.Name }}-{{ .Values.backend.name }}
diff --git a/my-recipes-chart/templates/db-schema-configmap.yaml b/my-recipes-chart/templates/db-schema-configmap.yaml
index 9b901c9..f99151e 100644
--- a/my-recipes-chart/templates/db-schema-configmap.yaml
+++ b/my-recipes-chart/templates/db-schema-configmap.yaml
@@ -11,7 +11,6 @@ data:
name TEXT NOT NULL,
meal_type TEXT NOT NULL,
time_minutes INTEGER NOT NULL,
- made_by TEXT,
tags JSONB NOT NULL DEFAULT '[]',
ingredients JSONB NOT NULL DEFAULT '[]',
steps JSONB NOT NULL DEFAULT '[]',
@@ -24,9 +23,6 @@ data:
CREATE INDEX IF NOT EXISTS idx_recipes_time_minutes
ON recipes (time_minutes);
- CREATE INDEX IF NOT EXISTS idx_recipes_made_by
- ON recipes (made_by);
-
CREATE INDEX IF NOT EXISTS idx_recipes_tags_jsonb
ON recipes USING GIN (tags);
diff --git a/my-recipes-chart/templates/db-secret.yaml b/my-recipes-chart/templates/db-secret.yaml
new file mode 100644
index 0000000..f4a35f2
--- /dev/null
+++ b/my-recipes-chart/templates/db-secret.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Release.Name }}-db-credentials
+ namespace: {{ .Values.global.namespace }}
+type: Opaque
+stringData:
+ DB_HOST: {{ printf "%s-%s-headless.%s.svc.cluster.local" .Release.Name .Values.postgres.name .Values.global.namespace }}
+ DB_PORT: "{{ .Values.postgres.port }}"
+ DB_NAME: {{ .Values.postgres.database | quote }}
+ DB_USER: {{ .Values.postgres.user | quote }}
+ DB_PASSWORD: {{ .Values.postgres.password | quote }}
+
diff --git a/my-recipes-chart/templates/db-service.yaml b/my-recipes-chart/templates/db-service.yaml
new file mode 100644
index 0000000..5cae43b
--- /dev/null
+++ b/my-recipes-chart/templates/db-service.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ component: database
+spec:
+ clusterIP: None
+ selector:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ ports:
+ - name: postgres
+ port: {{ .Values.postgres.port }}
+ targetPort: {{ .Values.postgres.port }}
+ protocol: TCP
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ component: database
+spec:
+ type: {{ .Values.postgres.service.type }}
+ selector:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ ports:
+ - name: postgres
+ port: {{ .Values.postgres.service.port }}
+ targetPort: {{ .Values.postgres.port }}
+ protocol: TCP
+
diff --git a/my-recipes-chart/templates/db-statefulset.yaml b/my-recipes-chart/templates/db-statefulset.yaml
new file mode 100644
index 0000000..b609270
--- /dev/null
+++ b/my-recipes-chart/templates/db-statefulset.yaml
@@ -0,0 +1,86 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ component: database
+spec:
+ serviceName: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.postgres.name }}
+ component: database
+ spec:
+ containers:
+ - name: postgres
+ image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}"
+ imagePullPolicy: {{ .Values.postgres.image.pullPolicy }}
+ ports:
+ - containerPort: {{ .Values.postgres.port }}
+ name: postgres
+ protocol: TCP
+ env:
+ - name: POSTGRES_USER
+ value: {{ .Values.postgres.user | quote }}
+ - name: POSTGRES_PASSWORD
+ value: {{ .Values.postgres.password | quote }}
+ - name: POSTGRES_DB
+ value: {{ .Values.postgres.database | quote }}
+ - name: PGDATA
+ value: /var/lib/postgresql/data/pgdata
+ volumeMounts:
+ - name: data
+ mountPath: /var/lib/postgresql/data
+ - name: init-sql
+ mountPath: /docker-entrypoint-initdb.d
+ livenessProbe:
+ exec:
+ command:
+ - /bin/sh
+ - -c
+ - pg_isready -U {{ .Values.postgres.user }}
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ readinessProbe:
+ exec:
+ command:
+ - /bin/sh
+ - -c
+ - pg_isready -U {{ .Values.postgres.user }}
+ initialDelaySeconds: 10
+ periodSeconds: 5
+ timeoutSeconds: 3
+ failureThreshold: 2
+ resources:
+ requests:
+ cpu: {{ .Values.postgres.resources.requests.cpu }}
+ memory: {{ .Values.postgres.resources.requests.memory }}
+ limits:
+ cpu: {{ .Values.postgres.resources.limits.cpu }}
+ memory: {{ .Values.postgres.resources.limits.memory }}
+ volumes:
+ - name: init-sql
+ configMap:
+ name: {{ .Release.Name }}-db-schema
+ volumeClaimTemplates:
+ - metadata:
+ name: data
+ spec:
+ accessModes:
+ - {{ .Values.postgres.persistence.accessMode }}
+ resources:
+ requests:
+ storage: {{ .Values.postgres.persistence.size }}
+ {{- if .Values.postgres.persistence.storageClass }}
+ storageClassName: {{ .Values.postgres.persistence.storageClass | quote }}
+ {{- end }}
+
diff --git a/my-recipes-chart/templates/frontend-deployment.yaml b/my-recipes-chart/templates/frontend-deployment.yaml
new file mode 100644
index 0000000..52edc17
--- /dev/null
+++ b/my-recipes-chart/templates/frontend-deployment.yaml
@@ -0,0 +1,70 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ component: frontend
+spec:
+ replicas: {{ .Values.frontend.replicaCount }}
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ component: frontend
+ spec:
+ containers:
+ - name: {{ .Values.frontend.name }}
+ image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
+ imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
+ ports:
+ - containerPort: {{ .Values.frontend.service.targetPort }}
+ name: http
+ protocol: TCP
+ {{- /* compute API_BASE: prefer frontend.env.API_BASE, else use first ingress host */}}
+ {{- $apiBase := "" }}
+ {{- if .Values.frontend.env.API_BASE }}
+ {{- $apiBase = .Values.frontend.env.API_BASE }}
+ {{- else if .Values.ingress.hosts }}
+ {{- $firstHost := index .Values.ingress.hosts 0 }}
+ {{- $apiBase = printf "https://%s/api" $firstHost.host }}
+ {{- end }}
+ env:
+ - name: API_BASE
+ value: {{ $apiBase | quote }}
+ {{- /* include any other env vars provided in values.frontend.env (skip API_BASE to avoid duplicate) */}}
+ {{- with .Values.frontend.env }}
+ {{- range $key, $value := . }}
+ {{- if ne $key "API_BASE" }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ livenessProbe:
+ httpGet:
+ path: /
+ port: http
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ readinessProbe:
+ httpGet:
+ path: /
+ port: http
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ timeoutSeconds: 3
+ failureThreshold: 2
+ resources:
+ requests:
+ cpu: {{ .Values.frontend.resources.requests.cpu }}
+ memory: {{ .Values.frontend.resources.requests.memory }}
+ limits:
+ cpu: {{ .Values.frontend.resources.limits.cpu }}
+ memory: {{ .Values.frontend.resources.limits.memory }}
diff --git a/my-recipes-chart/templates/frontend-service.yaml b/my-recipes-chart/templates/frontend-service.yaml
new file mode 100644
index 0000000..9427830
--- /dev/null
+++ b/my-recipes-chart/templates/frontend-service.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.frontend.name }}
+ component: frontend
+spec:
+ type: {{ .Values.frontend.service.type }}
+ ports:
+ - port: {{ .Values.frontend.service.port }}
+ targetPort: {{ .Values.frontend.service.targetPort }}
+ protocol: TCP
+ name: http
+ selector:
+ app: {{ .Release.Name }}-{{ .Values.frontend.name }}
diff --git a/my-recipes-chart/templates/ingress.yaml b/my-recipes-chart/templates/ingress.yaml
new file mode 100644
index 0000000..aeeea7a
--- /dev/null
+++ b/my-recipes-chart/templates/ingress.yaml
@@ -0,0 +1,48 @@
+{{- if .Values.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ .Release.Name }}
+ namespace: {{ .Values.global.namespace }}
+ labels:
+ app: {{ .Release.Name }}
+ {{- with .Values.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if .Values.ingress.className }}
+ ingressClassName: {{ .Values.ingress.className }}
+ {{- end }}
+ {{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ pathType: {{ .pathType }}
+ backend:
+ service:
+ {{- if eq .backend "frontend" }}
+ name: {{ $.Release.Name }}-{{ $.Values.frontend.name }}
+ port:
+ number: {{ $.Values.frontend.service.port }}
+ {{- else if eq .backend "backend" }}
+ name: {{ $.Release.Name }}-{{ $.Values.backend.name }}
+ port:
+ number: {{ $.Values.backend.service.port }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/my-recipes-chart/values.yaml b/my-recipes-chart/values.yaml
new file mode 100644
index 0000000..f574749
--- /dev/null
+++ b/my-recipes-chart/values.yaml
@@ -0,0 +1,109 @@
+global:
+ namespace: my-apps
+ imagePullSecrets: []
+
+# Backend configuration
+backend:
+ name: backend
+ replicaCount: 2
+ image:
+ repository: harbor.dvirlabs.com/my-apps/my-recipes-backend
+ pullPolicy: IfNotPresent
+ tag: "latest"
+
+ service:
+ type: ClusterIP
+ port: 8000
+ targetPort: 8000
+
+ resources:
+ requests:
+ cpu: 100m
+ memory: 128Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+
+ env:
+ PYTHONUNBUFFERED: "1"
+
+# Frontend configuration
+frontend:
+ name: frontend
+ replicaCount: 2
+ image:
+ repository: harbor.dvirlabs.com/my-apps/my-recipes-frontend
+ pullPolicy: IfNotPresent
+ tag: "latest"
+
+ service:
+ type: ClusterIP
+ port: 80
+ targetPort: 80
+
+ env:
+ API_BASE: "https://my-recipes.dvirlabs.com/api"
+
+ resources:
+ requests:
+ cpu: 50m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 256Mi
+
+# PostgreSQL configuration
+postgres:
+ name: db
+ image:
+ repository: postgres
+ tag: "16-alpine"
+ pullPolicy: IfNotPresent
+
+ user: recipes_user
+ password: recipes_password
+ database: recipes_db
+ port: 5432
+
+ service:
+ type: ClusterIP
+ port: 5432
+ targetPort: 5432
+
+ persistence:
+ enabled: true
+ accessMode: ReadWriteOnce
+ storageClass: "nfs-client"
+ size: 10Gi
+
+ resources:
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ limits:
+ cpu: 1000m
+ memory: 1Gi
+
+# Ingress configuration
+ingress:
+ enabled: true
+ className: "nginx"
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ nginx.ingress.kubernetes.io/rewrite-target: "/$2"
+ nginx.ingress.kubernetes.io/use-regex: "true"
+ hosts:
+ - host: my-recipes.dvirlabs.com
+ paths:
+ - path: /
+ pathType: Prefix
+ backend: frontend
+ # use a regex to capture and rewrite /api/... to /... on the backend
+ - path: /api(/|$)(.*)
+ pathType: ImplementationSpecific
+ backend: backend
+ tls:
+ - secretName: recipes-tls
+ hosts:
+ - my-recipes.dvirlabs.com
+
diff --git a/navix-chart/Chart.yaml b/navix-chart/Chart.yaml
new file mode 100644
index 0000000..96570a8
--- /dev/null
+++ b/navix-chart/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v2
+name: navix
+version: 0.1.0
+description: A DevOps dashboard called Navix
\ No newline at end of file
diff --git a/navix-chart/templates/backend-deployment.yaml b/navix-chart/templates/backend-deployment.yaml
new file mode 100644
index 0000000..35c4627
--- /dev/null
+++ b/navix-chart/templates/backend-deployment.yaml
@@ -0,0 +1,29 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: navix-backend
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: navix-backend
+ template:
+ metadata:
+ labels:
+ app: navix-backend
+ spec:
+ containers:
+ - name: backend
+ image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.tag }}"
+ imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
+ ports:
+ - containerPort: 8000
+ env:
+ - name: MINIO_ACCESS_KEY
+ value: "{{ .Values.backend.env.MINIO_ACCESS_KEY }}"
+ - name: MINIO_SECRET_KEY
+ value: "{{ .Values.backend.env.MINIO_SECRET_KEY }}"
+ - name: MINIO_ENDPOINT
+ value: "{{ .Values.backend.env.MINIO_ENDPOINT }}"
+ - name: MINIO_BUCKET
+ value: "{{ .Values.backend.env.MINIO_BUCKET }}"
\ No newline at end of file
diff --git a/navix-chart/templates/backend-service.yaml b/navix-chart/templates/backend-service.yaml
new file mode 100644
index 0000000..f4e033a
--- /dev/null
+++ b/navix-chart/templates/backend-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: navix-backend
+spec:
+ type: {{ .Values.backend.service.type }}
+ selector:
+ app: navix-backend
+ ports:
+ - port: {{ .Values.backend.service.port }}
+ targetPort: 8000
\ No newline at end of file
diff --git a/navix-chart/templates/frontend-deployment.yaml b/navix-chart/templates/frontend-deployment.yaml
new file mode 100644
index 0000000..1a3340e
--- /dev/null
+++ b/navix-chart/templates/frontend-deployment.yaml
@@ -0,0 +1,27 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: navix-frontend
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: navix-frontend
+ template:
+ metadata:
+ labels:
+ app: navix-frontend
+ spec:
+ containers:
+ - name: frontend
+ image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.tag }}"
+ imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
+ ports:
+ - containerPort: 80
+ env:
+ - name: API_BASE
+ value: {{ .Values.frontend.env.API_BASE | quote }}
+ - name: MINIO_ENDPOINT
+ value: {{ .Values.frontend.env.MINIO_ENDPOINT | quote }}
+ - name: MINIO_BUCKET
+ value: {{ .Values.frontend.env.MINIO_BUCKET | quote }}
diff --git a/navix-chart/templates/frontend-service.yaml b/navix-chart/templates/frontend-service.yaml
new file mode 100644
index 0000000..89f997d
--- /dev/null
+++ b/navix-chart/templates/frontend-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: navix-frontend
+spec:
+ type: {{ .Values.frontend.service.type }}
+ selector:
+ app: navix-frontend
+ ports:
+ - port: {{ .Values.frontend.service.port }}
+ targetPort: 80
\ No newline at end of file
diff --git a/navix-chart/templates/ingress.yaml b/navix-chart/templates/ingress.yaml
new file mode 100644
index 0000000..15822f1
--- /dev/null
+++ b/navix-chart/templates/ingress.yaml
@@ -0,0 +1,57 @@
+{{- if .Values.frontend.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: navix-frontend
+ annotations:
+ {{- range $key, $value := .Values.frontend.ingress.annotations }}
+ {{ $key }}: {{ $value | quote }}
+ {{- end }}
+spec:
+ ingressClassName: {{ .Values.frontend.ingress.className }}
+ rules:
+ {{- range .Values.frontend.ingress.hosts }}
+ - host: {{ .host }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ pathType: {{ .pathType }}
+ backend:
+ service:
+ name: navix-frontend
+ port:
+ number: {{ $.Values.frontend.service.port }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+
+---
+
+{{- if .Values.backend.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: navix-backend
+ annotations:
+ {{- range $key, $value := .Values.backend.ingress.annotations }}
+ {{ $key }}: {{ $value | quote }}
+ {{- end }}
+spec:
+ ingressClassName: {{ .Values.backend.ingress.className }}
+ rules:
+ {{- range .Values.backend.ingress.hosts }}
+ - host: {{ .host }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ pathType: {{ .pathType }}
+ backend:
+ service:
+ name: navix-backend
+ port:
+ number: {{ $.Values.backend.service.port }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/navix-chart/values.yaml b/navix-chart/values.yaml
new file mode 100644
index 0000000..0e67780
--- /dev/null
+++ b/navix-chart/values.yaml
@@ -0,0 +1,48 @@
+frontend:
+ image:
+ repository: harbor.dvirlabs.com/my-apps/navix-front
+ tag: latest
+ pullPolicy: IfNotPresent
+ service:
+ type: ClusterIP
+ port: 80
+ ingress:
+ enabled: true
+ className: traefik
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ hosts:
+ - host: navix.dvirlabs.com
+ paths:
+ - path: /
+ pathType: Prefix
+ env:
+ API_BASE: "https://navix.dvirlabs.com/api"
+ MINIO_ENDPOINT: "s3.dvirlabs.com"
+ MINIO_BUCKET: "navix-icons"
+
+backend:
+ image:
+ repository: harbor.dvirlabs.com/my-apps/navix-back
+ tag: latest
+ pullPolicy: IfNotPresent
+ service:
+ type: ClusterIP
+ port: 8000
+ env:
+ MINIO_ACCESS_KEY: "your-access-key"
+ MINIO_SECRET_KEY: "your-secret-key"
+ MINIO_ENDPOINT: "s3.dvirlabs.com"
+ MINIO_BUCKET: "navix-icons"
+ ingress:
+ enabled: true
+ className: traefik
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ hosts:
+ - host: navix.dvirlabs.com
+ paths:
+ - path: /api
+ pathType: Prefix