Compare commits
161 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
267e963c78 | ||
| 9da05bfd37 | |||
| 4dd0f22359 | |||
|
|
af47d88222 | ||
| a8677e6b80 | |||
| 4d83b5f1bf | |||
| 6e772cfb27 | |||
|
|
727848538f | ||
|
|
dc6f55f98a | ||
|
|
d8f1afb242 | ||
|
|
0752a8c568 | ||
|
|
29164ce726 | ||
|
|
4d94ebe87b | ||
|
|
635e9532a2 | ||
| b5a7d339ce | |||
|
|
be1226c59e | ||
|
|
b0166a685d | ||
| 07cd3fa68d | |||
| a5fc28111b | |||
| 7d0dc5fc37 | |||
|
|
763075096a | ||
|
|
c248d5f572 | ||
|
|
902df179ee | ||
| 8e96150165 | |||
| de9710c23d | |||
|
|
8768a5fb69 | ||
|
|
362b1e8737 | ||
| 6718b50efb | |||
| c0ec6b635e | |||
|
|
e9ebf79a0f | ||
|
|
149c630588 | ||
|
|
4308113626 | ||
| 3b55c9171a | |||
| fa9956419b | |||
| 5499a3dc10 | |||
|
|
3ee911535a | ||
|
|
a558d326d8 | ||
| e733d9e558 | |||
| 4c58d13f00 | |||
| 5644e2280b | |||
| 45c772c24f | |||
|
|
9a9b5c5485 | ||
|
|
20338c47b0 | ||
| c7a4b55b25 | |||
| ba035ffc09 | |||
| 9202891edf | |||
|
|
9e6be26651 | ||
|
|
77148d35a2 | ||
|
|
f37c0065f3 | ||
|
|
b47e0c73d7 | ||
|
|
7d2c19f7c4 | ||
|
|
e0b43193f0 | ||
| 55d021c0bb | |||
| 93560892f9 | |||
| 5d1b32d7c6 | |||
| 2c8dc8de71 | |||
| 238920ddf3 | |||
| b22b692d61 | |||
|
|
4cc3dabc76 | ||
|
|
8dde51cc65 | ||
|
|
5ce7c145b4 | ||
|
|
8215eaba95 | ||
|
|
e32de28e42 | ||
|
|
631de40737 | ||
|
|
bfd31d9d4c | ||
|
|
7af9c4c214 | ||
|
|
33d3a77d28 | ||
| 61522f7473 | |||
| ff7ab8b7d0 | |||
| 87b8031125 | |||
| a4dbe26d83 | |||
| 5ff51b67bf | |||
|
|
f0dc531919 | ||
|
|
571c9c83f2 | ||
|
|
60d17e487c | ||
|
|
c44cd39219 | ||
| c2dd6727d5 | |||
| 76c22c5387 | |||
| add56684d9 | |||
|
|
41270e8168 | ||
|
|
b6ffdd18e1 | ||
| a60b4cdafc | |||
| 05c81f13ce | |||
| a736c01260 | |||
| 3306c7c680 | |||
|
|
fe3dd1e208 | ||
|
|
0f7affda8d | ||
|
|
f831e3ec93 | ||
|
|
f585de2541 | ||
|
|
eb299cf1e8 | ||
|
|
949894fe7f | ||
|
|
a43cca4342 | ||
|
|
17039b4e1a | ||
|
|
65861479d0 | ||
|
|
465650ac8e | ||
|
|
0d29d152ac | ||
|
|
c8ad88b31b | ||
|
|
3fce551850 | ||
|
|
d9783fa019 | ||
| 7bb08e35e8 | |||
|
|
b7d1b8cc02 | ||
|
|
58a9e00a2f | ||
|
|
6df8995027 | ||
|
|
8578ec9115 | ||
|
|
6a2d5ef3a5 | ||
|
|
de435c89b4 | ||
|
|
8c98deee90 | ||
|
|
407dce71ab | ||
|
|
07aaa4ce4b | ||
|
|
ca4bc2e53e | ||
|
|
e00d5928c9 | ||
|
|
729ebbb652 | ||
|
|
1bcf7f1737 | ||
| 78a867814c | |||
|
|
aefd555581 | ||
|
|
05230d830f | ||
|
|
00380843c8 | ||
|
|
df7bd62d29 | ||
| ce7ea192fe | |||
| b3db63a778 | |||
| 5a3dfc8597 | |||
| 7f0b0c7a3b | |||
| 36e6ab76d7 | |||
| cf19c6f2e2 | |||
| 436832a419 | |||
| 4b4bf0e57f | |||
| 72f79df2c8 | |||
| 4cb449fdd0 | |||
|
|
47b757ec21 | ||
| c8c7058837 | |||
|
|
a074f23152 | ||
| 17f5a900d5 | |||
|
|
35d3db7400 | ||
| 230c9fc804 | |||
| 32cf8cc602 | |||
|
|
f67a74c160 | ||
| c9a46e8135 | |||
| 58964c69dc | |||
| 7aa72023ba | |||
| e13c6bac3c | |||
| f5cb52c57a | |||
|
|
48322da811 | ||
|
|
42c41ed6b6 | ||
| 3d9bcb4ab4 | |||
| 946beadf2f | |||
| a7659198a4 | |||
|
|
7a23286c16 | ||
|
|
4aef8059ff | ||
|
|
811cb92d3e | ||
| d43480302c | |||
| ce187dbc28 | |||
|
|
0e3769b2c9 | ||
|
|
9997bd36ca | ||
|
|
d35f1a6f7b | ||
|
|
21d1485dca | ||
|
|
e77fc650d5 | ||
|
|
8f23ba466c | ||
|
|
4ec34a920c | ||
|
|
3b15565a9d | ||
|
|
f036e6e2ce | ||
|
|
96dc223290 |
21
argocd-apps/calink.yaml
Normal file
21
argocd-apps/calink.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: calink
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: my-apps
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: charts/calink-chart
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- ../../manifests/calink/values.yaml
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: my-apps
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
21
argocd-apps/dateme.yaml
Normal file
21
argocd-apps/dateme.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: dateme
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: my-apps
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: charts/dateme-chart
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- ../../manifests/dateme/values.yaml
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: my-apps
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/dvirlabs-landing-chart
|
path: charts/dvirlabs-landing-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: manifests/external-secrets
|
path: manifests/external-secrets
|
||||||
directory:
|
directory:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: manifests/extra-resources
|
path: manifests/extra-resources
|
||||||
directory:
|
directory:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/home-assistant
|
path: charts/home-assistant
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
21
argocd-apps/invy.yaml
Normal file
21
argocd-apps/invy.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: invy
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: my-apps
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: charts/invy-chart
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- ../../manifests/invy/values.yaml
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: my-apps
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
21
argocd-apps/ipify.yaml
Normal file
21
argocd-apps/ipify.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: ipify
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: my-apps
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: charts/ipify-chart
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- ../../manifests/ipify/values.yaml
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: my-apps
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/labmap-chart
|
path: charts/labmap-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/my-recipes-chart
|
path: charts/my-recipes-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/navidrome
|
path: charts/navidrome
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/navix-chart
|
path: charts/navix-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/nextcloud-chart
|
path: charts/nextcloud-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/oramap-chart
|
path: charts/oramap-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/pgadmin-chart
|
path: charts/pgadmin-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/tasko-chart
|
path: charts/tasko-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/tennotrade-chart
|
path: charts/tennotrade-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/tunedrop-chart
|
path: charts/tunedrop-chart
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: my-apps
|
project: my-apps
|
||||||
source:
|
source:
|
||||||
repoURL: https://git.dvirlabs.com/dvirlabs/my-apps.git
|
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/my-apps.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: charts/wallos
|
path: charts/wallos
|
||||||
helm:
|
helm:
|
||||||
|
|||||||
6
charts/calink-chart/Chart.yaml
Normal file
6
charts/calink-chart/Chart.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: calink
|
||||||
|
description: Calink calendar event generator
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
43
charts/calink-chart/templates/NOTES.txt
Normal file
43
charts/calink-chart/templates/NOTES.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Thank you for installing {{ .Chart.Name }}!
|
||||||
|
|
||||||
|
Your release is named {{ .Release.Name }}.
|
||||||
|
|
||||||
|
To learn more about the release, try:
|
||||||
|
|
||||||
|
$ helm status {{ .Release.Name }}
|
||||||
|
$ helm get all {{ .Release.Name }}
|
||||||
|
|
||||||
|
{{- if or .Values.frontend.ingress.enabled .Values.backend.ingress.enabled }}
|
||||||
|
|
||||||
|
Calink is accessible at:
|
||||||
|
|
||||||
|
{{- if .Values.frontend.ingress.enabled }}
|
||||||
|
Frontend:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
http{{ if $.Values.frontend.ingress.tls }}s{{ end }}://{{ .host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.backend.ingress.enabled }}
|
||||||
|
Backend API:
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
http{{ if $.Values.backend.ingress.tls }}s{{ end }}://{{ .host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
|
||||||
|
To access Calink, forward the ports:
|
||||||
|
|
||||||
|
kubectl port-forward svc/{{ include "calink.fullname" . }}-frontend 8080:80
|
||||||
|
kubectl port-forward svc/{{ include "calink.fullname" . }}-backend 8000:8000
|
||||||
|
|
||||||
|
Then visit:
|
||||||
|
Frontend: http://localhost:8080
|
||||||
|
Backend: http://localhost:8000
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Backend API documentation is available at:
|
||||||
|
/docs
|
||||||
|
|
||||||
|
Health check endpoint:
|
||||||
|
/health
|
||||||
84
charts/calink-chart/templates/_helpers.tpl
Normal file
84
charts/calink-chart/templates/_helpers.tpl
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.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 "calink.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "calink.chart" . }}
|
||||||
|
{{ include "calink.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- with .Values.commonLabels }}
|
||||||
|
{{ toYaml . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "calink.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Backend labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.backend.labels" -}}
|
||||||
|
{{ include "calink.labels" . }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Backend selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.backend.selectorLabels" -}}
|
||||||
|
{{ include "calink.selectorLabels" . }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Frontend labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.frontend.labels" -}}
|
||||||
|
{{ include "calink.labels" . }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Frontend selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "calink.frontend.selectorLabels" -}}
|
||||||
|
{{ include "calink.selectorLabels" . }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
{{- end }}
|
||||||
59
charts/calink-chart/templates/deployment-backend.yaml
Normal file
59
charts/calink-chart/templates/deployment-backend.yaml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.backend.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.backend.replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "calink.backend.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "calink.backend.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8000
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
{{- toYaml .Values.backend.env | nindent 12 }}
|
||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: {{ .Values.backend.persistence.mountPath }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.backend.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.backend.healthCheck.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.backend.healthCheck.periodSeconds }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.backend.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.backend.healthCheck.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.backend.healthCheck.periodSeconds }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.backend.resources | nindent 12 }}
|
||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "calink.fullname" . }}-backend-data
|
||||||
|
{{- end }}
|
||||||
46
charts/calink-chart/templates/deployment-frontend.yaml
Normal file
46
charts/calink-chart/templates/deployment-frontend.yaml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.frontend.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.frontend.replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "calink.frontend.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "calink.frontend.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.frontend.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.frontend.healthCheck.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.frontend.healthCheck.periodSeconds }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.frontend.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.frontend.healthCheck.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.frontend.healthCheck.periodSeconds }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.frontend.resources | nindent 12 }}
|
||||||
93
charts/calink-chart/templates/ingress.yaml
Normal file
93
charts/calink-chart/templates/ingress.yaml
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{{- if .Values.frontend.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.labels" . | nindent 4 }}
|
||||||
|
component: frontend
|
||||||
|
{{- with .Values.frontend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.frontend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.frontend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "calink.fullname" $ }}-frontend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.frontend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{- if .Values.backend.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.labels" . | nindent 4 }}
|
||||||
|
component: backend
|
||||||
|
{{- with .Values.backend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.backend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.backend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "calink.fullname" $ }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.backend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.backend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
21
charts/calink-chart/templates/pvc.yaml
Normal file
21
charts/calink-chart/templates/pvc.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-backend-data
|
||||||
|
labels:
|
||||||
|
{{- include "calink.backend.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
{{- if .Values.backend.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.backend.persistence.storageClass }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.backend.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
19
charts/calink-chart/templates/service-backend.yaml
Normal file
19
charts/calink-chart/templates/service-backend.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.backend.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.backend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "calink.backend.selectorLabels" . | nindent 4 }}
|
||||||
19
charts/calink-chart/templates/service-frontend.yaml
Normal file
19
charts/calink-chart/templates/service-frontend.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "calink.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "calink.frontend.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.commonAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.frontend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "calink.frontend.selectorLabels" . | nindent 4 }}
|
||||||
99
charts/calink-chart/values.yaml
Normal file
99
charts/calink-chart/values.yaml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
commonLabels: {}
|
||||||
|
commonAnnotations: {}
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: calink-backend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
env:
|
||||||
|
- name: DATABASE_PATH
|
||||||
|
value: "/data/app.db"
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: ""
|
||||||
|
size: 1Gi
|
||||||
|
mountPath: /data
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 8000
|
||||||
|
|
||||||
|
healthCheck:
|
||||||
|
path: /health
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 30
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
# traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
# traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: api-calink.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls: []
|
||||||
|
# - secretName: api-calink-tls
|
||||||
|
# hosts:
|
||||||
|
# - api-calink.example.com
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: calink-frontend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
healthCheck:
|
||||||
|
path: /
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 30
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
# traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
# traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: calink.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls: []
|
||||||
|
# - secretName: calink-tls
|
||||||
|
# hosts:
|
||||||
|
# - calink.example.com
|
||||||
12
charts/dateme-chart/Chart.yaml
Normal file
12
charts/dateme-chart/Chart.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: dating-app
|
||||||
|
description: MVP dating app Helm chart for Kubernetes deployment
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
keywords:
|
||||||
|
- dating
|
||||||
|
- social
|
||||||
|
- chat
|
||||||
|
maintainers:
|
||||||
|
- name: DevOps Team
|
||||||
201
charts/dateme-chart/README.md
Normal file
201
charts/dateme-chart/README.md
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
# Helm Chart README
|
||||||
|
|
||||||
|
## Dating App Helm Chart
|
||||||
|
|
||||||
|
This Helm chart deploys the MVP dating application to Kubernetes with all necessary components.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.19+
|
||||||
|
- Helm 3.0+
|
||||||
|
- Nginx Ingress Controller (for ingress)
|
||||||
|
- Storage provisioner (for PVC)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
#### Basic Installation (Development)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install with default values
|
||||||
|
helm install dating-app ./helm/dating-app -n dating-app --create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Production Installation with Custom Values
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create custom values file
|
||||||
|
cp helm/dating-app/values.yaml my-values.yaml
|
||||||
|
|
||||||
|
# Edit my-values.yaml with your configuration
|
||||||
|
# Then install
|
||||||
|
helm install dating-app ./helm/dating-app -n dating-app --create-namespace -f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Edit `values.yaml` to customize:
|
||||||
|
|
||||||
|
#### Ingress Hosts
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
ingress:
|
||||||
|
host: api.yourdomain.com
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
ingress:
|
||||||
|
host: app.yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Database
|
||||||
|
```yaml
|
||||||
|
postgres:
|
||||||
|
credentials:
|
||||||
|
username: your_user
|
||||||
|
password: your_password
|
||||||
|
database: your_db
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backend Environment
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
environment:
|
||||||
|
JWT_SECRET: your-secret-key
|
||||||
|
CORS_ORIGINS: "https://app.yourdomain.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Frontend API URL
|
||||||
|
```yaml
|
||||||
|
frontend:
|
||||||
|
environment:
|
||||||
|
VITE_API_URL: "https://api.yourdomain.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Storage Classes
|
||||||
|
For cloud deployments (AWS, GCP, etc.), specify storage class:
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
persistence:
|
||||||
|
storageClass: ebs-sc # AWS EBS
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
persistence:
|
||||||
|
storageClass: ebs-sc
|
||||||
|
size: 20Gi
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Replicas and Resources
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
replicas: 2
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upgrading
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade dating-app ./helm/dating-app -f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uninstalling
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall dating-app -n dating-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### AWS Migration
|
||||||
|
|
||||||
|
To deploy to AWS:
|
||||||
|
|
||||||
|
1. **RDS for PostgreSQL**: Disable postgres in chart
|
||||||
|
```yaml
|
||||||
|
postgres:
|
||||||
|
enabled: false
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Update database URL** to RDS endpoint
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: "postgresql://user:password@your-rds-endpoint:5432/dating_app"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **S3 for Media Storage**: Update backend environment
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
environment:
|
||||||
|
MEDIA_STORAGE: s3
|
||||||
|
S3_BUCKET: your-bucket
|
||||||
|
AWS_REGION: us-east-1
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Use AWS Load Balancer Controller** for ingress
|
||||||
|
```yaml
|
||||||
|
ingress:
|
||||||
|
className: aws-alb
|
||||||
|
annotations:
|
||||||
|
alb.ingress.kubernetes.io/scheme: internet-facing
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Use EBS for persistent storage**
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
persistence:
|
||||||
|
storageClass: ebs-sc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
Check pod status:
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n dating-app
|
||||||
|
kubectl logs -n dating-app <pod-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Check services:
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n dating-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Check ingress:
|
||||||
|
```bash
|
||||||
|
kubectl get ingress -n dating-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Port forward for debugging:
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n dating-app svc/backend 8000:8000
|
||||||
|
kubectl port-forward -n dating-app svc/frontend 3000:80
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Initialization
|
||||||
|
|
||||||
|
The backend automatically initializes tables on startup. To verify:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -it -n dating-app <postgres-pod> -- psql -U dating_user -d dating_app -c "\dt"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- This chart is designed to be portable between on-premises and cloud deployments
|
||||||
|
- Modify `values.yaml` for your specific infrastructure
|
||||||
|
- For production, use external secrets management (HashiCorp Vault, AWS Secrets Manager, etc.)
|
||||||
|
- Enable TLS/SSL with cert-manager for production ingress
|
||||||
|
- Configure proper backup strategies for PostgreSQL PVC
|
||||||
80
charts/dateme-chart/templates/backend-deployment.yaml
Normal file
80
charts/dateme-chart/templates/backend-deployment.yaml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
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:
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-postgres
|
||||||
|
image: postgres:16-alpine
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
until pg_isready -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -p {{ .Values.postgres.port }}; do
|
||||||
|
echo "Waiting for PostgreSQL..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "PostgreSQL is ready!"
|
||||||
|
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: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 30
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
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 }}
|
||||||
17
charts/dateme-chart/templates/backend-service.yaml
Normal file
17
charts/dateme-chart/templates/backend-service.yaml
Normal file
@ -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 }}
|
||||||
|
selector:
|
||||||
|
app: {{ .Release.Name }}-{{ .Values.backend.name }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: {{ .Values.backend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
37
charts/dateme-chart/templates/db-migration-job.yaml
Normal file
37
charts/dateme-chart/templates/db-migration-job.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-db-migration
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: migrate
|
||||||
|
image: postgres:16-alpine
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Running DB migration: add display_name to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS display_name TEXT;"
|
||||||
|
echo "Running DB migration: add age to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS age INTEGER;"
|
||||||
|
echo "Running DB migration: add gender to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS gender TEXT;"
|
||||||
|
echo "Running DB migration: add location to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS location TEXT;"
|
||||||
|
echo "Running DB migration: add bio to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS bio TEXT;"
|
||||||
|
echo "Running DB migration: add interests to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS interests TEXT;"
|
||||||
|
echo "Running DB migration: add photos to profiles..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE profiles ADD COLUMN IF NOT EXISTS photos TEXT[];"
|
||||||
|
echo "Running DB migration: add acknowledged_at to likes..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE likes ADD COLUMN IF NOT EXISTS acknowledged_at TIMESTAMP;"
|
||||||
|
echo "Running DB migration: add read_at to messages..."
|
||||||
|
psql -h {{ .Release.Name }}-{{ .Values.postgres.name }}-headless -U {{ .Values.postgres.user }} -d {{ .Values.postgres.database }} -c "ALTER TABLE messages ADD COLUMN IF NOT EXISTS read_at TIMESTAMP;"
|
||||||
|
env:
|
||||||
|
- name: PGPASSWORD
|
||||||
|
value: {{ .Values.postgres.password | quote }}
|
||||||
56
charts/dateme-chart/templates/db-schema-configmap.yaml
Normal file
56
charts/dateme-chart/templates/db-schema-configmap.yaml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-db-schema
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
data:
|
||||||
|
schema.sql: |
|
||||||
|
-- Create users table
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username TEXT UNIQUE NOT NULL,
|
||||||
|
email TEXT UNIQUE NOT NULL,
|
||||||
|
hashed_password TEXT NOT NULL,
|
||||||
|
first_name TEXT,
|
||||||
|
last_name TEXT,
|
||||||
|
age INTEGER,
|
||||||
|
gender TEXT,
|
||||||
|
bio TEXT,
|
||||||
|
profile_picture TEXT,
|
||||||
|
location TEXT,
|
||||||
|
interests TEXT[] DEFAULT '{}',
|
||||||
|
is_active BOOLEAN DEFAULT TRUE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users (username);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users (is_active);
|
||||||
|
|
||||||
|
-- Profiles table for additional user info
|
||||||
|
CREATE TABLE IF NOT EXISTS profiles (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER UNIQUE NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
verified BOOLEAN DEFAULT FALSE,
|
||||||
|
verification_token TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles (user_id);
|
||||||
|
|
||||||
|
-- Matches/Likes table
|
||||||
|
CREATE TABLE IF NOT EXISTS matches (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
matched_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
status TEXT DEFAULT 'pending',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_matches_user_id ON matches (user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_matches_matched_user_id ON matches (matched_user_id);
|
||||||
|
-- Prevent duplicate matches in both directions
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_matches_unique ON matches
|
||||||
|
(LEAST(user_id, matched_user_id), GREATEST(user_id, matched_user_id));
|
||||||
13
charts/dateme-chart/templates/db-secret.yaml
Normal file
13
charts/dateme-chart/templates/db-secret.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-db-credentials
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
DATABASE_URL: postgresql://{{ .Values.postgres.user }}:{{ .Values.postgres.password }}@{{ .Release.Name }}-{{ .Values.postgres.name }}-headless.{{ .Values.global.namespace }}.svc.cluster.local:{{ .Values.postgres.port }}/{{ .Values.postgres.database }}
|
||||||
|
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 }}
|
||||||
35
charts/dateme-chart/templates/db-service.yaml
Normal file
35
charts/dateme-chart/templates/db-service.yaml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
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
|
||||||
84
charts/dateme-chart/templates/db-statefulset.yaml
Normal file
84
charts/dateme-chart/templates/db-statefulset.yaml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
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: 2
|
||||||
|
failureThreshold: 3
|
||||||
|
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
|
||||||
|
defaultMode: 0755
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.postgres.persistence.accessMode }}
|
||||||
|
storageClassName: {{ .Values.postgres.persistence.storageClass }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.postgres.persistence.size }}
|
||||||
71
charts/dateme-chart/templates/frontend-deployment.yaml
Normal file
71
charts/dateme-chart/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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:
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-backend
|
||||||
|
image: busybox:1.35
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Waiting for backend to be ready..."
|
||||||
|
until wget -q -O- http://{{ .Release.Name }}-{{ .Values.backend.name }}:{{ .Values.backend.service.port }}/health > /dev/null 2>&1; do
|
||||||
|
echo "Backend not ready, waiting..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "Backend is ready!"
|
||||||
|
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
|
||||||
|
volumeMounts:
|
||||||
|
- name: env-config
|
||||||
|
mountPath: /usr/share/nginx/html/env.js
|
||||||
|
subPath: env.js
|
||||||
|
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 }}
|
||||||
|
volumes:
|
||||||
|
- name: env-config
|
||||||
|
configMap:
|
||||||
|
name: {{ .Release.Name }}-frontend-env-config
|
||||||
13
charts/dateme-chart/templates/frontend-env-configmap.yaml
Normal file
13
charts/dateme-chart/templates/frontend-env-configmap.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-frontend-env-config
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Release.Name }}-{{ .Values.frontend.name }}
|
||||||
|
component: frontend
|
||||||
|
data:
|
||||||
|
env.js: |
|
||||||
|
window.__ENV__ = {
|
||||||
|
API_BASE: "{{ .Values.frontend.env.API_BASE }}"
|
||||||
|
};
|
||||||
17
charts/dateme-chart/templates/frontend-service.yaml
Normal file
17
charts/dateme-chart/templates/frontend-service.yaml
Normal file
@ -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 }}
|
||||||
|
selector:
|
||||||
|
app: {{ .Release.Name }}-{{ .Values.frontend.name }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: {{ .Values.frontend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
89
charts/dateme-chart/templates/ingress.yaml
Normal file
89
charts/dateme-chart/templates/ingress.yaml
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{{- if .Values.frontend.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-frontend
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Release.Name }}-frontend
|
||||||
|
component: frontend
|
||||||
|
{{- with .Values.frontend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.frontend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.frontend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $.Release.Name }}-{{ $.Values.frontend.name }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.frontend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{- if .Values.backend.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-backend
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Release.Name }}-backend
|
||||||
|
component: backend
|
||||||
|
{{- with .Values.backend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.backend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.backend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $.Release.Name }}-{{ $.Values.backend.name }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.backend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.backend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
79
charts/dateme-chart/values-aws.yaml
Normal file
79
charts/dateme-chart/values-aws.yaml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
---
|
||||||
|
# Example values for AWS deployment
|
||||||
|
# Copy to values-aws.yaml and customize with your AWS details
|
||||||
|
|
||||||
|
global:
|
||||||
|
domain: yourdomain.com
|
||||||
|
|
||||||
|
# Disable built-in PostgreSQL and use RDS instead
|
||||||
|
postgres:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: 123456789.dkr.ecr.us-east-1.amazonaws.com/dating-app-backend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
service:
|
||||||
|
port: 8000
|
||||||
|
type: ClusterIP
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: aws-alb
|
||||||
|
host: api.yourdomain.com
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
||||||
|
environment:
|
||||||
|
# Use RDS endpoint here with updated credentials
|
||||||
|
DATABASE_URL: "postgresql://dating_app_user:Aa123456@your-rds-endpoint.us-east-1.rds.amazonaws.com:5432/dating_app"
|
||||||
|
JWT_SECRET: "your-secure-secret-key"
|
||||||
|
JWT_EXPIRES_MINUTES: "1440"
|
||||||
|
MEDIA_DIR: /app/media
|
||||||
|
CORS_ORIGINS: "https://yourdomain.com,https://api.yourdomain.com"
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 20Gi
|
||||||
|
storageClass: ebs-sc # AWS EBS storage class
|
||||||
|
mountPath: /app/media
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: 123456789.dkr.ecr.us-east-1.amazonaws.com/dating-app-frontend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
type: ClusterIP
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: aws-alb
|
||||||
|
host: yourdomain.com
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
||||||
|
env:
|
||||||
|
API_BASE: "https://api.yourdomain.com"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: aws-alb
|
||||||
|
annotations:
|
||||||
|
alb.ingress.kubernetes.io/scheme: internet-facing
|
||||||
|
alb.ingress.kubernetes.io/target-type: ip
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789:certificate/xxxx"
|
||||||
80
charts/dateme-chart/values-lab.yaml
Normal file
80
charts/dateme-chart/values-lab.yaml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
# Example values for development/lab deployment
|
||||||
|
# Copy to values-dev.yaml and customize
|
||||||
|
|
||||||
|
global:
|
||||||
|
domain: lab.local
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
replicas: 1
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 5Gi
|
||||||
|
storageClass: "" # Use default storage class
|
||||||
|
credentials:
|
||||||
|
username: dating_app_user
|
||||||
|
password: Aa123456
|
||||||
|
database: dating_app
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: dating-app-backend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
service:
|
||||||
|
port: 8000
|
||||||
|
type: ClusterIP
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
host: api.lab.local
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
||||||
|
environment:
|
||||||
|
JWT_SECRET: dev-secret-key-change-in-production
|
||||||
|
JWT_EXPIRES_MINUTES: "1440"
|
||||||
|
MEDIA_DIR: /app/media
|
||||||
|
CORS_ORIGINS: "http://localhost:5173,http://localhost:3000,http://api.lab.local,http://app.lab.local"
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 5Gi
|
||||||
|
storageClass: ""
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: dating-app-frontend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
type: ClusterIP
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
host: app.lab.local
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
||||||
|
env:
|
||||||
|
API_BASE: "http://api.lab.local"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
annotations: {}
|
||||||
125
charts/dateme-chart/values.yaml
Normal file
125
charts/dateme-chart/values.yaml
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# Default values for dateme-chart
|
||||||
|
global:
|
||||||
|
namespace: my-apps
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# Backend configuration
|
||||||
|
backend:
|
||||||
|
name: backend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/dateme-backend
|
||||||
|
pullPolicy: Always
|
||||||
|
tag: develop-latest
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
env:
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: api-dateme.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: api-dateme-tls
|
||||||
|
hosts:
|
||||||
|
- api-dateme.dvirlabs.com
|
||||||
|
|
||||||
|
# Frontend configuration
|
||||||
|
frontend:
|
||||||
|
name: frontend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/dateme-frontend
|
||||||
|
pullPolicy: Always
|
||||||
|
tag: develop-latest
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
env:
|
||||||
|
API_BASE: "https://api-dateme.dvirlabs.com"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: dateme.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: dateme-tls
|
||||||
|
hosts:
|
||||||
|
- dateme.dvirlabs.com
|
||||||
|
externalUrl: "https://dateme.dvirlabs.com"
|
||||||
|
|
||||||
|
# PostgreSQL configuration
|
||||||
|
postgres:
|
||||||
|
name: db
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "16"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
user: dateme_user
|
||||||
|
password: dateme_password
|
||||||
|
database: dateme_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: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# Ingress (top-level, disabled - use component-specific ingress instead)
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: dateme.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: dateme-tls
|
||||||
|
hosts:
|
||||||
|
- dateme.dvirlabs.com
|
||||||
12
charts/invy-chart/Chart.yaml
Normal file
12
charts/invy-chart/Chart.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: invy
|
||||||
|
description: A Helm chart for Invy - Wedding Guest List Management Application
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
keywords:
|
||||||
|
- invy
|
||||||
|
- wedding
|
||||||
|
- guest-management
|
||||||
|
maintainers:
|
||||||
|
- name: dvir
|
||||||
183
charts/invy-chart/README.md
Normal file
183
charts/invy-chart/README.md
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# Invy Helm Chart
|
||||||
|
|
||||||
|
This Helm chart deploys the Invy wedding guest list management application on Kubernetes.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.19+
|
||||||
|
- Helm 3.0+
|
||||||
|
- Persistent Volume provisioner support in the underlying infrastructure (for PostgreSQL)
|
||||||
|
- Ingress controller (Traefik recommended)
|
||||||
|
- Cert-manager (for TLS certificates)
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
This chart deploys the following components:
|
||||||
|
|
||||||
|
- **Frontend**: React + Vite application (Nginx)
|
||||||
|
- **Backend**: FastAPI application
|
||||||
|
- **Database**: PostgreSQL 16
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Add the chart repository (if applicable)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm repo add invy https://your-helm-repo.com
|
||||||
|
helm repo update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install the chart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install with default values
|
||||||
|
helm install invy ./invy-chart -n my-apps --create-namespace
|
||||||
|
|
||||||
|
# Install with custom values
|
||||||
|
helm install invy ./invy-chart -n my-apps --create-namespace -f custom-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The following table lists the configurable parameters and their default values.
|
||||||
|
|
||||||
|
### Global Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `global.namespace` | Namespace for all resources | `my-apps` |
|
||||||
|
| `global.imagePullSecrets` | Image pull secrets | `[]` |
|
||||||
|
|
||||||
|
### Backend Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `backend.image.repository` | Backend image repository | `harbor.dvirlabs.com/my-apps/invy-backend` |
|
||||||
|
| `backend.image.tag` | Backend image tag | `latest` |
|
||||||
|
| `backend.replicaCount` | Number of backend replicas | `1` |
|
||||||
|
| `backend.service.port` | Backend service port | `8000` |
|
||||||
|
| `backend.ingress.enabled` | Enable backend ingress | `true` |
|
||||||
|
| `backend.ingress.hosts[0].host` | Backend ingress hostname | `api-invy.dvirlabs.com` |
|
||||||
|
|
||||||
|
### Frontend Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `frontend.image.repository` | Frontend image repository | `harbor.dvirlabs.com/my-apps/invy-frontend` |
|
||||||
|
| `frontend.image.tag` | Frontend image tag | `latest` |
|
||||||
|
| `frontend.replicaCount` | Number of frontend replicas | `1` |
|
||||||
|
| `frontend.service.port` | Frontend service port | `80` |
|
||||||
|
| `frontend.env.VITE_API_URL` | Backend API URL | `https://api-invy.dvirlabs.com` |
|
||||||
|
| `frontend.ingress.enabled` | Enable frontend ingress | `true` |
|
||||||
|
| `frontend.ingress.hosts[0].host` | Frontend ingress hostname | `invy.dvirlabs.com` |
|
||||||
|
|
||||||
|
### PostgreSQL Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `postgres.user` | PostgreSQL user | `invy_user` |
|
||||||
|
| `postgres.password` | PostgreSQL password | `invy_password` |
|
||||||
|
| `postgres.database` | PostgreSQL database name | `invy_db` |
|
||||||
|
| `postgres.persistence.enabled` | Enable persistence | `true` |
|
||||||
|
| `postgres.persistence.size` | Persistent volume size | `10Gi` |
|
||||||
|
| `postgres.persistence.storageClass` | Storage class | `nfs-client` |
|
||||||
|
|
||||||
|
## Building and Pushing Images
|
||||||
|
|
||||||
|
### Backend Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
docker build -t harbor.dvirlabs.com/my-apps/invy-backend:latest .
|
||||||
|
docker push harbor.dvirlabs.com/my-apps/invy-backend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
docker build --build-arg VITE_API_URL=https://api-invy.dvirlabs.com -t harbor.dvirlabs.com/my-apps/invy-frontend:latest .
|
||||||
|
docker push harbor.dvirlabs.com/my-apps/invy-frontend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade invy ./invy-chart -n my-apps
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall invy -n my-apps
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
Create a `custom-values.yaml` file to override default values:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
tag: "v1.0.0"
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- host: api.mycompany.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
tag: "v1.0.0"
|
||||||
|
env:
|
||||||
|
VITE_API_URL: "https://api.mycompany.com"
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- host: invy.mycompany.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
password: "your-secure-password"
|
||||||
|
persistence:
|
||||||
|
storageClass: "your-storage-class"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install invy ./invy-chart -n my-apps -f custom-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Check pod status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n my-apps
|
||||||
|
```
|
||||||
|
|
||||||
|
### View pod logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backend logs
|
||||||
|
kubectl logs -n my-apps -l app.kubernetes.io/component=backend
|
||||||
|
|
||||||
|
# Frontend logs
|
||||||
|
kubectl logs -n my-apps -l app.kubernetes.io/component=frontend
|
||||||
|
|
||||||
|
# Database logs
|
||||||
|
kubectl logs -n my-apps -l app.kubernetes.io/component=database
|
||||||
|
```
|
||||||
|
|
||||||
|
### Access the database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -it -n my-apps invy-db-0 -- psql -U invy_user -d invy_db
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and feature requests, please open an issue in the repository.
|
||||||
38
charts/invy-chart/templates/NOTES.txt
Normal file
38
charts/invy-chart/templates/NOTES.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Thank you for installing {{ .Chart.Name }}!
|
||||||
|
|
||||||
|
Your release is named {{ .Release.Name }}.
|
||||||
|
|
||||||
|
To learn more about the release, try:
|
||||||
|
|
||||||
|
$ helm status {{ .Release.Name }}
|
||||||
|
$ helm get all {{ .Release.Name }}
|
||||||
|
|
||||||
|
{{- if .Values.frontend.ingress.enabled }}
|
||||||
|
|
||||||
|
Application URLs:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
Frontend: https://{{ .host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
Backend API: https://{{ .host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
|
||||||
|
To access your application:
|
||||||
|
|
||||||
|
1. Get the frontend URL:
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Values.global.namespace }} -l "app.kubernetes.io/name={{ include "invy.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
kubectl --namespace {{ .Values.global.namespace }} port-forward $POD_NAME 8080:80
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
|
||||||
|
2. Get the backend URL:
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Values.global.namespace }} -l "app.kubernetes.io/name={{ include "invy.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=backend" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
kubectl --namespace {{ .Values.global.namespace }} port-forward $POD_NAME 8000:8000
|
||||||
|
echo "Visit http://127.0.0.1:8000 to access the API"
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Database connection:
|
||||||
|
Host: {{ include "invy.fullname" . }}-db
|
||||||
|
Port: {{ .Values.postgres.port }}
|
||||||
|
Database: {{ .Values.postgres.database }}
|
||||||
|
User: {{ .Values.postgres.user }}
|
||||||
60
charts/invy-chart/templates/_helpers.tpl
Normal file
60
charts/invy-chart/templates/_helpers.tpl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "invy.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
*/}}
|
||||||
|
{{- define "invy.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 "invy.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "invy.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "invy.chart" . }}
|
||||||
|
{{ include "invy.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "invy.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "invy.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "invy.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "invy.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
100
charts/invy-chart/templates/backend-deployment.yaml
Normal file
100
charts/invy-chart/templates/backend-deployment.yaml
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.backend.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
{{- with .Values.global.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "invy.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-postgres
|
||||||
|
image: busybox:1.35
|
||||||
|
command: ['sh', '-c', 'until nc -z {{ include "invy.fullname" . }}-db-headless {{ .Values.postgres.port | default 5432 }}; do echo waiting for postgres; sleep 2; done;']
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.backend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: database-url
|
||||||
|
- name: GOOGLE_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: google-client-id
|
||||||
|
- name: GOOGLE_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: google-client-secret
|
||||||
|
- name: WHATSAPP_ACCESS_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: whatsapp-access-token
|
||||||
|
- name: WHATSAPP_PHONE_NUMBER_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: whatsapp-phone-number-id
|
||||||
|
{{- range $key, $value := .Values.backend.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.backend.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
42
charts/invy-chart/templates/backend-ingress.yaml
Normal file
42
charts/invy-chart/templates/backend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.backend.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
{{- with .Values.backend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.backend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.backend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.backend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "invy.fullname" $ }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.backend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
17
charts/invy-chart/templates/backend-service.yaml
Normal file
17
charts/invy-chart/templates/backend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.backend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
126
charts/invy-chart/templates/db-schema-configmap.yaml
Normal file
126
charts/invy-chart/templates/db-schema-configmap.yaml
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-db-schema
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
data:
|
||||||
|
init.sql: |
|
||||||
|
-- Invy — Full Database Init Schema
|
||||||
|
-- Runs only on a FRESH (empty) data directory.
|
||||||
|
-- For existing production DBs run migrate_production.sql manually.
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
-- ── Users ──────────────────────────────────────────────────────────────
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||||
|
|
||||||
|
-- ── Events ─────────────────────────────────────────────────────────────
|
||||||
|
CREATE TABLE IF NOT EXISTS events (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
date TIMESTAMP WITH TIME ZONE,
|
||||||
|
location TEXT,
|
||||||
|
partner1_name TEXT,
|
||||||
|
partner2_name TEXT,
|
||||||
|
venue TEXT,
|
||||||
|
event_time TEXT,
|
||||||
|
guest_link TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_events_created_at ON events(created_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_events_guest_link ON events(guest_link);
|
||||||
|
|
||||||
|
-- ── Event members (authorization) ──────────────────────────────────────
|
||||||
|
CREATE TABLE IF NOT EXISTS event_members (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
|
||||||
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
role TEXT NOT NULL DEFAULT 'admin'
|
||||||
|
CHECK (role IN ('admin', 'editor', 'viewer')),
|
||||||
|
display_name TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(event_id, user_id)
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_event_members_event_id ON event_members(event_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_event_members_user_id ON event_members(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_event_members_event_user ON event_members(event_id, user_id);
|
||||||
|
|
||||||
|
-- ── Guests v2 ──────────────────────────────────────────────────────────
|
||||||
|
CREATE TABLE IF NOT EXISTS guests_v2 (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
|
||||||
|
added_by_user_id UUID NOT NULL REFERENCES users(id),
|
||||||
|
|
||||||
|
first_name TEXT NOT NULL,
|
||||||
|
last_name TEXT NOT NULL DEFAULT '',
|
||||||
|
email TEXT,
|
||||||
|
phone TEXT,
|
||||||
|
phone_number TEXT,
|
||||||
|
|
||||||
|
rsvp_status TEXT NOT NULL DEFAULT 'invited'
|
||||||
|
CHECK (rsvp_status IN ('invited', 'confirmed', 'declined')),
|
||||||
|
meal_preference TEXT,
|
||||||
|
|
||||||
|
has_plus_one BOOLEAN DEFAULT FALSE,
|
||||||
|
plus_one_name TEXT,
|
||||||
|
|
||||||
|
table_number TEXT,
|
||||||
|
side TEXT,
|
||||||
|
|
||||||
|
owner_email TEXT,
|
||||||
|
source TEXT NOT NULL DEFAULT 'manual'
|
||||||
|
CHECK (source IN ('google', 'manual', 'self-service')),
|
||||||
|
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_event_id ON guests_v2(event_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_added_by ON guests_v2(added_by_user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_phone_number ON guests_v2(phone_number);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_event_phone ON guests_v2(event_id, phone_number);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_event_status ON guests_v2(event_id, rsvp_status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_owner_email ON guests_v2(event_id, owner_email);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_guests_v2_source ON guests_v2(event_id, source);
|
||||||
|
|
||||||
|
-- ── RSVP tokens ────────────────────────────────────────────────────────
|
||||||
|
CREATE TABLE IF NOT EXISTS rsvp_tokens (
|
||||||
|
token TEXT PRIMARY KEY,
|
||||||
|
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
|
||||||
|
guest_id UUID REFERENCES guests_v2(id) ON DELETE SET NULL,
|
||||||
|
phone TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
expires_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
used_at TIMESTAMP WITH TIME ZONE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rsvp_tokens_event_id ON rsvp_tokens(event_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rsvp_tokens_guest_id ON rsvp_tokens(guest_id);
|
||||||
|
|
||||||
|
-- ── updated_at trigger ─────────────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE FUNCTION _update_updated_at()
|
||||||
|
RETURNS TRIGGER LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TRIGGER trg_guests_v2_updated_at
|
||||||
|
BEFORE UPDATE ON guests_v2
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION _update_updated_at();
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TRIGGER trg_events_updated_at
|
||||||
|
BEFORE UPDATE ON events
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION _update_updated_at();
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||||
36
charts/invy-chart/templates/db-service.yaml
Normal file
36
charts/invy-chart/templates/db-service.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-db
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.postgres.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.postgres.service.port }}
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
|
name: postgres
|
||||||
|
selector:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-db-headless
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
clusterIP: None
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.postgres.service.port }}
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
|
name: postgres
|
||||||
|
selector:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
131
charts/invy-chart/templates/db-statefulset.yaml
Normal file
131
charts/invy-chart/templates/db-statefulset.yaml
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-db
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "invy.fullname" . }}-db-headless
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 999
|
||||||
|
initContainers:
|
||||||
|
- name: fix-permissions
|
||||||
|
image: busybox:latest
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
chown -R 999:999 /var/lib/postgresql/data || true
|
||||||
|
chmod 700 /var/lib/postgresql/data || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 0
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsNonRoot: true
|
||||||
|
image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.postgres.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: {{ .Values.postgres.port }}
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: postgres-user
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: postgres-password
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
key: postgres-database
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
- name: postgres-run
|
||||||
|
mountPath: /var/run/postgresql
|
||||||
|
- name: init-script
|
||||||
|
mountPath: /docker-entrypoint-initdb.d
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.postgres.resources | nindent 12 }}
|
||||||
|
# Health probes aligned with tasko-chart approach
|
||||||
|
# Use TCP localhost instead of Unix socket to avoid permission issues
|
||||||
|
# Fixed shell variable expansion: $POSTGRES_USER not $(POSTGRES_USER)
|
||||||
|
# Specify database name to avoid "database invy_user does not exist" error
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 30 # Allow up to 150s for slow NFS startup
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
volumes:
|
||||||
|
- name: init-script
|
||||||
|
configMap:
|
||||||
|
name: {{ include "invy.fullname" . }}-db-schema
|
||||||
|
- name: postgres-run
|
||||||
|
emptyDir: {}
|
||||||
|
{{- if .Values.postgres.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: postgres-data
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.postgres.persistence.accessMode }}
|
||||||
|
{{- if .Values.postgres.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.postgres.persistence.storageClass }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.postgres.persistence.size }}
|
||||||
|
{{- else }}
|
||||||
|
- name: postgres-data
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
77
charts/invy-chart/templates/frontend-deployment.yaml
Normal file
77
charts/invy-chart/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.frontend.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
{{- with .Values.global.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "invy.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.frontend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.frontend.env }}
|
||||||
|
env:
|
||||||
|
{{- range $key, $value := .Values.frontend.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
- name: VITE_ADMIN_USERNAME
|
||||||
|
value: {{ .Values.frontend.adminUsername | quote }}
|
||||||
|
- name: VITE_ADMIN_PASSWORD
|
||||||
|
value: {{ .Values.frontend.adminPassword | quote }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.frontend.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
42
charts/invy-chart/templates/frontend-ingress.yaml
Normal file
42
charts/invy-chart/templates/frontend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.frontend.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
{{- with .Values.frontend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.frontend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.frontend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.frontend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "invy.fullname" $ }}-frontend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
17
charts/invy-chart/templates/frontend-service.yaml
Normal file
17
charts/invy-chart/templates/frontend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.frontend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "invy.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
16
charts/invy-chart/templates/secret.yaml
Normal file
16
charts/invy-chart/templates/secret.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.fullname" . }}-secrets
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
postgres-user: {{ .Values.postgres.user | quote }}
|
||||||
|
postgres-password: {{ .Values.postgres.password | quote }}
|
||||||
|
postgres-database: {{ .Values.postgres.database | quote }}
|
||||||
|
database-url: "postgresql://{{ .Values.postgres.user }}:{{ .Values.postgres.password }}@{{ include "invy.fullname" . }}-db:{{ .Values.postgres.port }}/{{ .Values.postgres.database }}"
|
||||||
|
google-client-id: {{ .Values.backend.googleClientId | quote }}
|
||||||
|
google-client-secret: {{ .Values.backend.googleClientSecret | quote }}
|
||||||
|
whatsapp-access-token: {{ .Values.backend.whatsappAccessToken | quote }}
|
||||||
|
whatsapp-phone-number-id: {{ .Values.backend.whatsappPhoneNumberId | quote }}
|
||||||
12
charts/invy-chart/templates/serviceaccount.yaml
Normal file
12
charts/invy-chart/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "invy.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "invy.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
180
charts/invy-chart/values.yaml
Normal file
180
charts/invy-chart/values.yaml
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
global:
|
||||||
|
namespace: my-apps
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# Backend configuration
|
||||||
|
backend:
|
||||||
|
name: backend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/invy-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"
|
||||||
|
GOOGLE_REDIRECT_URI: "https://api-invy.dvirlabs.com/auth/google/callback"
|
||||||
|
FRONTEND_URL: "https://invy.dvirlabs.com"
|
||||||
|
|
||||||
|
# Google OAuth credentials (set these values!)
|
||||||
|
googleClientId: "YOUR_GOOGLE_CLIENT_ID"
|
||||||
|
googleClientSecret: "YOUR_GOOGLE_CLIENT_SECRET"
|
||||||
|
|
||||||
|
# WhatsApp Cloud API credentials (set these values!)
|
||||||
|
whatsappAccessToken: "YOUR_WHATSAPP_ACCESS_TOKEN"
|
||||||
|
whatsappPhoneNumberId: "YOUR_WHATSAPP_PHONE_NUMBER_ID"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: api-invy.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: api-invy-tls
|
||||||
|
hosts:
|
||||||
|
- api-invy.dvirlabs.com
|
||||||
|
|
||||||
|
# Frontend configuration
|
||||||
|
frontend:
|
||||||
|
name: frontend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/invy-frontend
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: "latest"
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
|
||||||
|
env:
|
||||||
|
VITE_API_URL: "https://api-invy.dvirlabs.com"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: invy.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: invy-tls
|
||||||
|
hosts:
|
||||||
|
- invy.dvirlabs.com
|
||||||
|
|
||||||
|
# PostgreSQL configuration
|
||||||
|
postgres:
|
||||||
|
name: db
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "16-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
user: invy_user
|
||||||
|
password: invy_password
|
||||||
|
database: invy_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: false # Individual frontend/backend ingress resources handle routing instead
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: invy.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend: frontend
|
||||||
|
tls:
|
||||||
|
- secretName: invy-tls
|
||||||
|
hosts:
|
||||||
|
- invy.dvirlabs.com
|
||||||
|
|
||||||
|
# Service Account
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Pod annotations
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
# Pod security context
|
||||||
|
podSecurityContext: {}
|
||||||
|
# fsGroup: 2000
|
||||||
|
|
||||||
|
# Container security context
|
||||||
|
securityContext: {}
|
||||||
|
# capabilities:
|
||||||
|
# drop:
|
||||||
|
# - ALL
|
||||||
|
# readOnlyRootFilesystem: true
|
||||||
|
# runAsNonRoot: true
|
||||||
|
# runAsUser: 1000
|
||||||
|
|
||||||
|
# Node selector
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# Tolerations
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# Affinity
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
# Replica count (default for both frontend and backend if not specified)
|
||||||
|
replicaCount: 1
|
||||||
6
charts/ipify-chart/Chart.yaml
Normal file
6
charts/ipify-chart/Chart.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: ipify
|
||||||
|
description: A Helm chart for IP Subnet Calculator application
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
20
charts/ipify-chart/templates/_helpers.tpl
Normal file
20
charts/ipify-chart/templates/_helpers.tpl
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{{- define "ipify.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "ipify.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 }}
|
||||||
|
|
||||||
|
{{- define "ipify.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
41
charts/ipify-chart/templates/backend-deployment.yaml
Normal file
41
charts/ipify-chart/templates/backend-deployment.yaml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.backend.name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Values.backend.name }}
|
||||||
|
component: backend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.backend.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ .Values.backend.name }}
|
||||||
|
component: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ .Values.backend.name }}
|
||||||
|
component: backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- containerPort: {{ .Values.backend.service.targetPort }}
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.backend.resources | nindent 10 }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
17
charts/ipify-chart/templates/backend-service.yaml
Normal file
17
charts/ipify-chart/templates/backend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.backend.name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .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: {{ .Values.backend.name }}
|
||||||
|
component: backend
|
||||||
44
charts/ipify-chart/templates/frontend-deployment.yaml
Normal file
44
charts/ipify-chart/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.frontend.name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Values.frontend.name }}
|
||||||
|
component: frontend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.frontend.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ .Values.frontend.name }}
|
||||||
|
component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ .Values.frontend.name }}
|
||||||
|
component: frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- containerPort: {{ .Values.frontend.service.targetPort }}
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: VITE_API_URL
|
||||||
|
value: {{ .Values.env.backendUrl | quote }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.frontend.resources | nindent 10 }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
17
charts/ipify-chart/templates/frontend-service.yaml
Normal file
17
charts/ipify-chart/templates/frontend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.frontend.name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .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: {{ .Values.frontend.name }}
|
||||||
|
component: frontend
|
||||||
43
charts/ipify-chart/templates/ingress.yaml
Normal file
43
charts/ipify-chart/templates/ingress.yaml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: ipify-ingress
|
||||||
|
annotations:
|
||||||
|
{{- range $key, $value := .Values.ingress.annotations }}
|
||||||
|
{{ $key }}: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- 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 "backend" }}
|
||||||
|
name: {{ $.Values.backend.name }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.backend.service.port }}
|
||||||
|
{{- else }}
|
||||||
|
name: {{ $.Values.frontend.name }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
66
charts/ipify-chart/values.yaml
Normal file
66
charts/ipify-chart/values.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Default values for ipify
|
||||||
|
|
||||||
|
# Backend configuration
|
||||||
|
backend:
|
||||||
|
name: ipify-backend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: ipify-backend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
# Frontend configuration
|
||||||
|
frontend:
|
||||||
|
name: ipify-frontend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: ipify-frontend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# Ingress configuration
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: ipify.example.com
|
||||||
|
paths:
|
||||||
|
- path: /api
|
||||||
|
pathType: Prefix
|
||||||
|
backend: backend
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend: frontend
|
||||||
|
tls:
|
||||||
|
- secretName: ipify-tls
|
||||||
|
hosts:
|
||||||
|
- ipify.example.com
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
env:
|
||||||
|
# Backend URL for frontend to use
|
||||||
|
backendUrl: "https://ipify.example.com/api"
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-add-missing-tables
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
data:
|
||||||
|
add-tables.sql: |
|
||||||
|
-- Create grocery lists table
|
||||||
|
CREATE TABLE IF NOT EXISTS grocery_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
items TEXT[] NOT NULL DEFAULT '{}',
|
||||||
|
owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
is_pinned BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create grocery list shares table
|
||||||
|
CREATE TABLE IF NOT EXISTS grocery_list_shares (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE,
|
||||||
|
shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
can_edit BOOLEAN DEFAULT FALSE,
|
||||||
|
shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(list_id, shared_with_user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id);
|
||||||
|
|
||||||
|
-- Create notifications table
|
||||||
|
CREATE TABLE IF NOT EXISTS notifications (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
message TEXT NOT NULL,
|
||||||
|
related_id INTEGER,
|
||||||
|
is_read BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read);
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-add-missing-tables
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": post-upgrade
|
||||||
|
"helm.sh/hook-weight": "6"
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: add-tables
|
||||||
|
image: postgres:16-alpine
|
||||||
|
env:
|
||||||
|
- name: PGHOST
|
||||||
|
value: {{ .Release.Name }}-db
|
||||||
|
- name: PGPORT
|
||||||
|
value: "{{ .Values.postgres.port }}"
|
||||||
|
- name: PGDATABASE
|
||||||
|
value: {{ .Values.postgres.database }}
|
||||||
|
- name: PGUSER
|
||||||
|
value: {{ .Values.postgres.user }}
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Release.Name }}-db-credentials
|
||||||
|
key: DB_PASSWORD
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Waiting for database to be ready..."
|
||||||
|
until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do
|
||||||
|
echo "Database not ready, waiting..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "Database ready, adding missing tables..."
|
||||||
|
psql -v ON_ERROR_STOP=1 -f /sql/add-tables.sql
|
||||||
|
echo "Tables added successfully!"
|
||||||
|
volumeMounts:
|
||||||
|
- name: sql
|
||||||
|
mountPath: /sql
|
||||||
|
volumes:
|
||||||
|
- name: sql
|
||||||
|
configMap:
|
||||||
|
name: {{ .Release.Name }}-add-missing-tables
|
||||||
33
charts/my-recipes-chart/templates/app-secrets.yaml
Normal file
33
charts/my-recipes-chart/templates/app-secrets.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-app-secrets
|
||||||
|
namespace: {{ .Values.global.namespace }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# Google OAuth
|
||||||
|
GOOGLE_CLIENT_ID: {{ .Values.oauth.google.clientId | quote }}
|
||||||
|
GOOGLE_CLIENT_SECRET: {{ .Values.oauth.google.clientSecret | quote }}
|
||||||
|
GOOGLE_REDIRECT_URI: {{ .Values.oauth.google.redirectUri | quote }}
|
||||||
|
|
||||||
|
# Microsoft Entra ID (Azure AD) OAuth
|
||||||
|
AZURE_CLIENT_ID: {{ .Values.oauth.azure.clientId | quote }}
|
||||||
|
AZURE_CLIENT_SECRET: {{ .Values.oauth.azure.clientSecret | quote }}
|
||||||
|
AZURE_TENANT_ID: {{ .Values.oauth.azure.tenantId | quote }}
|
||||||
|
AZURE_REDIRECT_URI: {{ .Values.oauth.azure.redirectUri | quote }}
|
||||||
|
|
||||||
|
# Email Configuration
|
||||||
|
SMTP_HOST: {{ .Values.email.smtpHost | quote }}
|
||||||
|
SMTP_PORT: {{ .Values.email.smtpPort | quote }}
|
||||||
|
SMTP_USER: {{ .Values.email.smtpUser | quote }}
|
||||||
|
SMTP_PASSWORD: {{ .Values.email.smtpPassword | quote }}
|
||||||
|
SMTP_FROM: {{ .Values.email.smtpFrom | quote }}
|
||||||
|
|
||||||
|
# Frontend URL for redirects
|
||||||
|
FRONTEND_URL: {{ .Values.frontend.externalUrl | quote }}
|
||||||
|
|
||||||
|
# R2 Backup Configuration
|
||||||
|
R2_ENDPOINT: {{ .Values.r2.endpoint | quote }}
|
||||||
|
R2_ACCESS_KEY: {{ .Values.r2.accessKey | quote }}
|
||||||
|
R2_SECRET_KEY: {{ .Values.r2.secretKey | quote }}
|
||||||
|
BACKUP_INTERVAL: {{ .Values.r2.backupInterval | quote }}
|
||||||
@ -25,7 +25,7 @@ spec:
|
|||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
echo "Waiting for database to be ready..."
|
echo "Waiting for database to be ready..."
|
||||||
until pg_isready -h $DB_HOST -U $DB_USER; do
|
until pg_isready -h $DB_HOST -U $DB_USER -d $DB_NAME; do
|
||||||
echo "Database not ready, waiting..."
|
echo "Database not ready, waiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
@ -79,6 +79,8 @@ spec:
|
|||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: {{ .Release.Name }}-db-credentials
|
name: {{ .Release.Name }}-db-credentials
|
||||||
|
- secretRef:
|
||||||
|
name: {{ .Release.Name }}-app-secrets
|
||||||
startupProbe:
|
startupProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /docs
|
path: /docs
|
||||||
|
|||||||
@ -30,6 +30,17 @@ data:
|
|||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
|
-- Add auth_provider column to users if it doesn't exist
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'users' AND column_name = 'auth_provider'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE users ADD COLUMN auth_provider TEXT DEFAULT 'local';
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
-- Verify recipes schema
|
-- Verify recipes schema
|
||||||
SELECT column_name, data_type
|
SELECT column_name, data_type
|
||||||
FROM information_schema.columns
|
FROM information_schema.columns
|
||||||
|
|||||||
@ -14,6 +14,8 @@ data:
|
|||||||
first_name TEXT,
|
first_name TEXT,
|
||||||
last_name TEXT,
|
last_name TEXT,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT NOT NULL,
|
||||||
|
is_admin BOOLEAN DEFAULT FALSE,
|
||||||
|
auth_provider TEXT DEFAULT 'local',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -81,3 +83,52 @@ data:
|
|||||||
ALTER TABLE users ALTER COLUMN display_name SET NOT NULL;
|
ALTER TABLE users ALTER COLUMN display_name SET NOT NULL;
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'users' AND column_name = 'is_admin'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- Create grocery lists table
|
||||||
|
CREATE TABLE IF NOT EXISTS grocery_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
items TEXT[] NOT NULL DEFAULT '{}',
|
||||||
|
owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
is_pinned BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create grocery list shares table
|
||||||
|
CREATE TABLE IF NOT EXISTS grocery_list_shares (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE,
|
||||||
|
shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
can_edit BOOLEAN DEFAULT FALSE,
|
||||||
|
shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(list_id, shared_with_user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id);
|
||||||
|
|
||||||
|
-- Create notifications table
|
||||||
|
CREATE TABLE IF NOT EXISTS notifications (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
message TEXT NOT NULL,
|
||||||
|
related_id INTEGER,
|
||||||
|
is_read BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read);
|
||||||
|
|||||||
@ -26,6 +26,9 @@ backend:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONUNBUFFERED: "1"
|
PYTHONUNBUFFERED: "1"
|
||||||
|
|
||||||
|
# Secrets are created in db-secret.yaml
|
||||||
|
# These are passed via envFrom secretRef
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
@ -85,6 +88,7 @@ frontend:
|
|||||||
- secretName: my-recipes-tls
|
- secretName: my-recipes-tls
|
||||||
hosts:
|
hosts:
|
||||||
- my-recipes.dvirlabs.com
|
- my-recipes.dvirlabs.com
|
||||||
|
externalUrl: "https://my-recipes.dvirlabs.com"
|
||||||
|
|
||||||
# PostgreSQL configuration
|
# PostgreSQL configuration
|
||||||
postgres:
|
postgres:
|
||||||
@ -118,6 +122,34 @@ postgres:
|
|||||||
cpu: 1000m
|
cpu: 1000m
|
||||||
memory: 1Gi
|
memory: 1Gi
|
||||||
|
|
||||||
|
# OAuth Configuration
|
||||||
|
oauth:
|
||||||
|
google:
|
||||||
|
clientId: "143092846986-hsi59m0on2c9rb5qrdoejfceieao2ioc.apps.googleusercontent.com"
|
||||||
|
clientSecret: "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"
|
||||||
|
redirectUri: "https://api-my-recipes.dvirlabs.com/auth/google/callback"
|
||||||
|
|
||||||
|
azure:
|
||||||
|
clientId: "db244cf5-eb11-4738-a2ea-5b0716c9ec0a"
|
||||||
|
clientSecret: "Zad8Q~qRBxaQq8up0lLXAq4pHzrVM2JFGFJhHaDp"
|
||||||
|
tenantId: "consumers"
|
||||||
|
redirectUri: "https://api-my-recipes.dvirlabs.com/auth/azure/callback"
|
||||||
|
|
||||||
|
# Email Configuration
|
||||||
|
email:
|
||||||
|
smtpHost: "smtp.gmail.com"
|
||||||
|
smtpPort: "587"
|
||||||
|
smtpUser: "dvirlabs@gmail.com"
|
||||||
|
smtpPassword: "agaanrhbbazbdytv"
|
||||||
|
smtpFrom: "dvirlabs@gmail.com"
|
||||||
|
|
||||||
|
# R2 Backup Configuration
|
||||||
|
r2:
|
||||||
|
endpoint: "https://d4704b8c40b2f95b2c7bf7ee4ecc52f8.r2.cloudflarestorage.com"
|
||||||
|
accessKey: "" # Set this in my-recipes/values.yaml
|
||||||
|
secretKey: "" # Set this in my-recipes/values.yaml
|
||||||
|
backupInterval: "weekly" # Options: test (1 min), daily, weekly
|
||||||
|
|
||||||
# Ingress configuration
|
# Ingress configuration
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false # Individual frontend/backend ingress resources handle routing instead
|
enabled: false # Individual frontend/backend ingress resources handle routing instead
|
||||||
|
|||||||
@ -26,4 +26,15 @@ spec:
|
|||||||
- name: MINIO_ENDPOINT
|
- name: MINIO_ENDPOINT
|
||||||
value: "{{ .Values.backend.env.MINIO_ENDPOINT }}"
|
value: "{{ .Values.backend.env.MINIO_ENDPOINT }}"
|
||||||
- name: MINIO_BUCKET
|
- name: MINIO_BUCKET
|
||||||
value: "{{ .Values.backend.env.MINIO_BUCKET }}"
|
value: "{{ .Values.backend.env.MINIO_BUCKET }}"
|
||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: navix-backend-data
|
||||||
|
{{- end }}
|
||||||
15
charts/navix-chart/templates/backend-pvc.yaml
Normal file
15
charts/navix-chart/templates/backend-pvc.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{{- if .Values.backend.persistence.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: navix-backend-data
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.backend.persistence.accessMode }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.backend.persistence.size }}
|
||||||
|
{{- if .Values.backend.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.backend.persistence.storageClass }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@ -35,6 +35,11 @@ backend:
|
|||||||
MINIO_SECRET_KEY: "your-secret-key"
|
MINIO_SECRET_KEY: "your-secret-key"
|
||||||
MINIO_ENDPOINT: "s3.dvirlabs.com"
|
MINIO_ENDPOINT: "s3.dvirlabs.com"
|
||||||
MINIO_BUCKET: "navix-icons"
|
MINIO_BUCKET: "navix-icons"
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 1Gi
|
||||||
|
storageClass: ""
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
className: traefik
|
className: traefik
|
||||||
|
|||||||
12
charts/tasko-chart-old/Chart.yaml
Normal file
12
charts/tasko-chart-old/Chart.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: tasko
|
||||||
|
description: A Helm chart for Tasko - Modern Task Management Application
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
keywords:
|
||||||
|
- tasko
|
||||||
|
- task-management
|
||||||
|
- productivity
|
||||||
|
maintainers:
|
||||||
|
- name: dvir
|
||||||
228
charts/tasko-chart-old/README.md
Normal file
228
charts/tasko-chart-old/README.md
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
# Tasko Helm Chart
|
||||||
|
|
||||||
|
Kubernetes Helm chart for deploying Tasko task management application.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Frontend**: React application served by Nginx
|
||||||
|
- URL: https://tasko.dvirlabs.com
|
||||||
|
- Port: 80
|
||||||
|
|
||||||
|
- **Backend**: FastAPI Python application
|
||||||
|
- URL: https://api-tasko.dvirlabs.com
|
||||||
|
- Port: 8000
|
||||||
|
|
||||||
|
- **Database**: PostgreSQL
|
||||||
|
- Managed by Helm subchart
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes cluster (1.19+)
|
||||||
|
- Helm 3.0+
|
||||||
|
- kubectl configured
|
||||||
|
- Nginx Ingress Controller installed
|
||||||
|
- cert-manager installed (for automatic TLS certificates)
|
||||||
|
|
||||||
|
## Building Docker Images
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
docker build -t tasko-frontend:latest .
|
||||||
|
docker tag tasko-frontend:latest <your-registry>/tasko-frontend:latest
|
||||||
|
docker push <your-registry>/tasko-frontend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
docker build -t tasko-backend:latest .
|
||||||
|
docker tag tasko-backend:latest <your-registry>/tasko-backend:latest
|
||||||
|
docker push <your-registry>/tasko-backend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Quick Install with Default Values
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install tasko ./helm/tasko
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install with Custom Values
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install tasko ./helm/tasko -f custom-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install with Custom Image Registry
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install tasko ./helm/tasko \
|
||||||
|
--set frontend.image.repository=<your-registry>/tasko-frontend \
|
||||||
|
--set backend.image.repository=<your-registry>/tasko-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Key Configuration Options
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `frontend.image.repository` | Frontend image repository | `tasko-frontend` |
|
||||||
|
| `frontend.image.tag` | Frontend image tag | `latest` |
|
||||||
|
| `backend.image.repository` | Backend image repository | `tasko-backend` |
|
||||||
|
| `backend.image.tag` | Backend image tag | `latest` |
|
||||||
|
| `frontend.ingress.hosts[0].host` | Frontend hostname | `tasko.dvirlabs.com` |
|
||||||
|
| `backend.ingress.hosts[0].host` | Backend hostname | `api-tasko.dvirlabs.com` |
|
||||||
|
| `postgresql.enabled` | Enable PostgreSQL subchart | `true` |
|
||||||
|
| `postgresql.auth.username` | PostgreSQL username | `tasko_user` |
|
||||||
|
| `postgresql.auth.password` | PostgreSQL password | `tasko_password` |
|
||||||
|
| `postgresql.auth.database` | PostgreSQL database name | `tasko_db` |
|
||||||
|
|
||||||
|
### Custom Values Example
|
||||||
|
|
||||||
|
Create a `custom-values.yaml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: myregistry.io/tasko-frontend
|
||||||
|
tag: "1.0.0"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- host: tasko.mydomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: tasko-frontend-tls
|
||||||
|
hosts:
|
||||||
|
- tasko.mydomain.com
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: myregistry.io/tasko-backend
|
||||||
|
tag: "1.0.0"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- host: api-tasko.mydomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: tasko-backend-tls
|
||||||
|
hosts:
|
||||||
|
- api-tasko.mydomain.com
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
auth:
|
||||||
|
password: "your-secure-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade tasko ./helm/tasko -f custom-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall tasko
|
||||||
|
```
|
||||||
|
|
||||||
|
## DNS Configuration
|
||||||
|
|
||||||
|
Make sure to configure your DNS to point to your Kubernetes cluster's ingress:
|
||||||
|
|
||||||
|
```
|
||||||
|
tasko.dvirlabs.com A/CNAME <your-ingress-ip-or-hostname>
|
||||||
|
api-tasko.dvirlabs.com A/CNAME <your-ingress-ip-or-hostname>
|
||||||
|
```
|
||||||
|
|
||||||
|
## TLS Certificates
|
||||||
|
|
||||||
|
The chart is configured to use cert-manager with Let's Encrypt for automatic TLS certificate provisioning. Make sure you have:
|
||||||
|
|
||||||
|
1. cert-manager installed in your cluster
|
||||||
|
2. A ClusterIssuer named `letsencrypt-prod` configured
|
||||||
|
|
||||||
|
Example ClusterIssuer:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: ClusterIssuer
|
||||||
|
metadata:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
acme:
|
||||||
|
server: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
email: your-email@example.com
|
||||||
|
privateKeySecretRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
solvers:
|
||||||
|
- http01:
|
||||||
|
ingress:
|
||||||
|
class: nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Check Pod Status
|
||||||
|
```bash
|
||||||
|
kubectl get pods -l app.kubernetes.io/name=tasko
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
```bash
|
||||||
|
# Frontend logs
|
||||||
|
kubectl logs -l app.kubernetes.io/component=frontend
|
||||||
|
|
||||||
|
# Backend logs
|
||||||
|
kubectl logs -l app.kubernetes.io/component=backend
|
||||||
|
|
||||||
|
# PostgreSQL logs
|
||||||
|
kubectl logs -l app.kubernetes.io/name=postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Ingress
|
||||||
|
```bash
|
||||||
|
kubectl get ingress
|
||||||
|
kubectl describe ingress tasko-frontend
|
||||||
|
kubectl describe ingress tasko-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Connection Issues
|
||||||
|
```bash
|
||||||
|
# Check if PostgreSQL is running
|
||||||
|
kubectl get pods -l app.kubernetes.io/name=postgresql
|
||||||
|
|
||||||
|
# Test database connection from backend pod
|
||||||
|
kubectl exec -it <backend-pod-name> -- psql $DATABASE_URL -c "SELECT 1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## CORS Configuration
|
||||||
|
|
||||||
|
The backend ingress is pre-configured with CORS headers to allow requests from the frontend domain. The configuration includes:
|
||||||
|
|
||||||
|
- `nginx.ingress.kubernetes.io/cors-allow-origin: "https://tasko.dvirlabs.com"`
|
||||||
|
- `nginx.ingress.kubernetes.io/enable-cors: "true"`
|
||||||
|
|
||||||
|
If you change the frontend domain, update the CORS configuration in `values.yaml`.
|
||||||
|
|
||||||
|
## Production Considerations
|
||||||
|
|
||||||
|
1. **Secrets Management**: Consider using external secret management (e.g., Sealed Secrets, External Secrets Operator)
|
||||||
|
2. **Database Backups**: Set up regular PostgreSQL backups
|
||||||
|
3. **Monitoring**: Add Prometheus/Grafana for monitoring
|
||||||
|
4. **Scaling**: Adjust `replicaCount` for horizontal scaling
|
||||||
|
5. **Resource Limits**: Tune resource requests/limits based on your workload
|
||||||
|
6. **Image Security**: Scan Docker images for vulnerabilities
|
||||||
|
7. **Network Policies**: Implement network policies for additional security
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and questions, please refer to the project repository.
|
||||||
22
charts/tasko-chart-old/templates/NOTES.txt
Normal file
22
charts/tasko-chart-old/templates/NOTES.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
1. Get the frontend application URL by running these commands:
|
||||||
|
{{- if .Values.frontend.ingress.enabled }}
|
||||||
|
https://{{ (index .Values.frontend.ingress.hosts 0).host }}
|
||||||
|
{{- else if contains "NodePort" .Values.frontend.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "tasko.fullname" . }}-frontend)
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.frontend.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "tasko.fullname" . }}-frontend'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "tasko.fullname" . }}-frontend --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.frontend.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.frontend.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "tasko.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
2. Get the backend API URL by running these commands:
|
||||||
|
{{- if .Values.backend.ingress.enabled }}
|
||||||
|
https://{{ (index .Values.backend.ingress.hosts 0).host }}
|
||||||
|
{{- end }}
|
||||||
60
charts/tasko-chart-old/templates/_helpers.tpl
Normal file
60
charts/tasko-chart-old/templates/_helpers.tpl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "tasko.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
*/}}
|
||||||
|
{{- define "tasko.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 "tasko.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "tasko.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "tasko.chart" . }}
|
||||||
|
{{ include "tasko.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "tasko.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "tasko.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "tasko.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "tasko.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
80
charts/tasko-chart-old/templates/backend-deployment.yaml
Normal file
80
charts/tasko-chart-old/templates/backend-deployment.yaml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "tasko.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-postgres
|
||||||
|
image: busybox:1.35
|
||||||
|
command: ['sh', '-c', 'until nc -z {{ include "tasko.fullname" . }}-db-headless {{ .Values.postgres.port | default 5432 }}; do echo waiting for postgres; sleep 2; done;']
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.backend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
|
key: database-url
|
||||||
|
{{- range $key, $value := .Values.backend.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.backend.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
42
charts/tasko-chart-old/templates/backend-ingress.yaml
Normal file
42
charts/tasko-chart-old/templates/backend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.backend.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
{{- with .Values.backend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.backend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.backend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.backend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.backend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "tasko.fullname" $ }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.backend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
17
charts/tasko-chart-old/templates/backend-service.yaml
Normal file
17
charts/tasko-chart-old/templates/backend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.backend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
95
charts/tasko-chart-old/templates/db-schema-configmap.yaml
Normal file
95
charts/tasko-chart-old/templates/db-schema-configmap.yaml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
{{- if .Values.postgres }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-db-schema
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
data:
|
||||||
|
schema.sql: |
|
||||||
|
-- Create users table
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username TEXT UNIQUE NOT NULL,
|
||||||
|
email TEXT UNIQUE NOT NULL,
|
||||||
|
password_hash TEXT NOT NULL,
|
||||||
|
first_name TEXT,
|
||||||
|
last_name TEXT,
|
||||||
|
display_name TEXT UNIQUE NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users (username);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_display_name ON users (display_name);
|
||||||
|
|
||||||
|
-- Create tasks table
|
||||||
|
CREATE TABLE IF NOT EXISTS tasks (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending', -- pending / in_progress / completed / cancelled
|
||||||
|
priority TEXT DEFAULT 'medium', -- low / medium / high / urgent
|
||||||
|
due_date TIMESTAMP,
|
||||||
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
assigned_to INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
completed_at TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Indexes for tasks
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks (status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks (priority);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_user_id ON tasks (user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_assigned_to ON tasks (assigned_to);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks (due_date);
|
||||||
|
|
||||||
|
-- Create tags table
|
||||||
|
CREATE TABLE IF NOT EXISTS tags (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
color TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create task_tags junction table
|
||||||
|
CREATE TABLE IF NOT EXISTS task_tags (
|
||||||
|
task_id INTEGER REFERENCES tasks(id) ON DELETE CASCADE,
|
||||||
|
tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY (task_id, tag_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_task_tags_task_id ON task_tags (task_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_task_tags_tag_id ON task_tags (tag_id);
|
||||||
|
|
||||||
|
-- Add display_name column if it doesn't exist (migration support)
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'users' AND column_name = 'display_name'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE users ADD COLUMN display_name TEXT;
|
||||||
|
-- Set display_name to username for existing users
|
||||||
|
UPDATE users SET display_name = username WHERE display_name IS NULL;
|
||||||
|
ALTER TABLE users ALTER COLUMN display_name SET NOT NULL;
|
||||||
|
ALTER TABLE users ADD CONSTRAINT users_display_name_key UNIQUE (display_name);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- Verify schema
|
||||||
|
SELECT 'Users table:' as info;
|
||||||
|
SELECT column_name, data_type, is_nullable
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'users'
|
||||||
|
ORDER BY ordinal_position;
|
||||||
|
|
||||||
|
SELECT 'Tasks table:' as info;
|
||||||
|
SELECT column_name, data_type, is_nullable
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'tasks'
|
||||||
|
ORDER BY ordinal_position;
|
||||||
|
{{- end }}
|
||||||
38
charts/tasko-chart-old/templates/db-service.yaml
Normal file
38
charts/tasko-chart-old/templates/db-service.yaml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{{- if .Values.postgres }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-db-headless
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: {{ .Values.postgres.service.port }}
|
||||||
|
targetPort: {{ .Values.postgres.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-db
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.postgres.service.type }}
|
||||||
|
selector:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: {{ .Values.postgres.service.port }}
|
||||||
|
targetPort: {{ .Values.postgres.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
87
charts/tasko-chart-old/templates/db-statefulset.yaml
Normal file
87
charts/tasko-chart-old/templates/db-statefulset.yaml
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{{- if .Values.postgres }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-db
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "tasko.fullname" . }}-db-headless
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: database
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/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: {{ include "tasko.fullname" . }}-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 }}
|
||||||
|
{{- end }}
|
||||||
73
charts/tasko-chart-old/templates/frontend-deployment.yaml
Normal file
73
charts/tasko-chart-old/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "tasko.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.frontend.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.frontend.env }}
|
||||||
|
env:
|
||||||
|
{{- range $key, $value := .Values.frontend.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.frontend.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
42
charts/tasko-chart-old/templates/frontend-ingress.yaml
Normal file
42
charts/tasko-chart-old/templates/frontend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.frontend.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
{{- with .Values.frontend.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.frontend.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.frontend.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.frontend.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.frontend.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "tasko.fullname" $ }}-frontend
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
17
charts/tasko-chart-old/templates/frontend-service.yaml
Normal file
17
charts/tasko-chart-old/templates/frontend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.frontend.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "tasko.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
13
charts/tasko-chart-old/templates/secret.yaml
Normal file
13
charts/tasko-chart-old/templates/secret.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: tasko-secrets
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
{{- if .Values.postgres }}
|
||||||
|
database-url: "postgresql://{{ .Values.postgres.user }}:{{ .Values.postgres.password }}@{{ include "tasko.fullname" . }}-db-headless:{{ .Values.postgres.port }}/{{ .Values.postgres.database }}"
|
||||||
|
{{- else if .Values.postgresql }}
|
||||||
|
database-url: "postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ include "tasko.fullname" . }}-postgresql:5432/{{ .Values.postgresql.auth.database }}"
|
||||||
|
{{- end }}
|
||||||
12
charts/tasko-chart-old/templates/serviceaccount.yaml
Normal file
12
charts/tasko-chart-old/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "tasko.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
136
charts/tasko-chart-old/values.yaml
Normal file
136
charts/tasko-chart-old/values.yaml
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
global:
|
||||||
|
namespace: my-apps
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# Backend configuration
|
||||||
|
backend:
|
||||||
|
name: backend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/tasko-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"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: api-tasko.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: api-tasko-tls
|
||||||
|
hosts:
|
||||||
|
- api-tasko.dvirlabs.com
|
||||||
|
|
||||||
|
# Frontend configuration
|
||||||
|
frontend:
|
||||||
|
name: frontend
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: harbor.dvirlabs.com/my-apps/tasko-frontend
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: "latest"
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
|
||||||
|
env:
|
||||||
|
VITE_API_URL: "https://api-tasko.dvirlabs.com"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: tasko.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: tasko-tls
|
||||||
|
hosts:
|
||||||
|
- tasko.dvirlabs.com
|
||||||
|
|
||||||
|
# PostgreSQL configuration
|
||||||
|
postgres:
|
||||||
|
name: db
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "16-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
user: tasko_user
|
||||||
|
password: tasko_password
|
||||||
|
database: tasko_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: false # Individual frontend/backend ingress resources handle routing instead
|
||||||
|
className: "traefik"
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: tasko.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend: frontend
|
||||||
|
tls:
|
||||||
|
- secretName: tasko-tls
|
||||||
|
hosts:
|
||||||
|
- tasko.dvirlabs.com
|
||||||
@ -21,7 +21,7 @@ spec:
|
|||||||
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
||||||
app.kubernetes.io/component: backend
|
app.kubernetes.io/component: backend
|
||||||
spec:
|
spec:
|
||||||
{{- with .Values.imagePullSecrets }}
|
{{- with .Values.global.imagePullSecrets }}
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@ -48,6 +48,21 @@ spec:
|
|||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: {{ include "tasko.fullname" . }}-secrets
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
key: database-url
|
key: database-url
|
||||||
|
- name: GOOGLE_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
|
key: google-client-id
|
||||||
|
- name: GOOGLE_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
|
key: google-client-secret
|
||||||
|
- name: SESSION_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
|
key: session-secret
|
||||||
{{- range $key, $value := .Values.backend.env }}
|
{{- range $key, $value := .Values.backend.env }}
|
||||||
- name: {{ $key }}
|
- name: {{ $key }}
|
||||||
value: {{ $value | quote }}
|
value: {{ $value | quote }}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ spec:
|
|||||||
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
{{- include "tasko.selectorLabels" . | nindent 8 }}
|
||||||
app.kubernetes.io/component: frontend
|
app.kubernetes.io/component: frontend
|
||||||
spec:
|
spec:
|
||||||
{{- with .Values.imagePullSecrets }}
|
{{- with .Values.global.imagePullSecrets }}
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: tasko-secrets
|
name: {{ include "tasko.fullname" . }}-secrets
|
||||||
labels:
|
labels:
|
||||||
{{- include "tasko.labels" . | nindent 4 }}
|
{{- include "tasko.labels" . | nindent 4 }}
|
||||||
type: Opaque
|
type: Opaque
|
||||||
@ -11,3 +11,8 @@ stringData:
|
|||||||
{{- else if .Values.postgresql }}
|
{{- else if .Values.postgresql }}
|
||||||
database-url: "postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ include "tasko.fullname" . }}-postgresql:5432/{{ .Values.postgresql.auth.database }}"
|
database-url: "postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ include "tasko.fullname" . }}-postgresql:5432/{{ .Values.postgresql.auth.database }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
# OAuth Secrets
|
||||||
|
google-client-id: {{ .Values.backend.oauth.google.clientId | quote }}
|
||||||
|
google-client-secret: {{ .Values.backend.oauth.google.clientSecret | quote }}
|
||||||
|
# Session Secret for signing cookies
|
||||||
|
session-secret: {{ .Values.backend.sessionSecret | quote }}
|
||||||
|
|||||||
@ -26,6 +26,18 @@ backend:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONUNBUFFERED: "1"
|
PYTHONUNBUFFERED: "1"
|
||||||
|
ENVIRONMENT: "production"
|
||||||
|
GOOGLE_REDIRECT_URI: "https://api-tasko.dvirlabs.com/auth/google/callback"
|
||||||
|
FRONTEND_URL: "https://tasko.dvirlabs.com"
|
||||||
|
|
||||||
|
# OAuth Configuration (stored as secrets)
|
||||||
|
oauth:
|
||||||
|
google:
|
||||||
|
clientId: "672182384838-vob26vd0qhmf0g9mru4u4sibkqre0rfa.apps.googleusercontent.com"
|
||||||
|
clientSecret: "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"
|
||||||
|
|
||||||
|
# Session secret for signing cookies (generate with: python -c "import secrets; print(secrets.token_hex(32))")
|
||||||
|
sessionSecret: "7f8a9b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a"
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
@ -107,16 +119,15 @@ postgres:
|
|||||||
persistence:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
accessMode: ReadWriteOnce
|
accessMode: ReadWriteOnce
|
||||||
storageClass: "nfs-client"
|
size: 8Gi
|
||||||
size: 10Gi
|
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
memory: 256Mi
|
memory: 128Mi
|
||||||
limits:
|
limits:
|
||||||
cpu: 1000m
|
cpu: 500m
|
||||||
memory: 1Gi
|
memory: 512Mi
|
||||||
|
|
||||||
# Ingress configuration
|
# Ingress configuration
|
||||||
ingress:
|
ingress:
|
||||||
@ -134,3 +145,9 @@ ingress:
|
|||||||
- secretName: tasko-tls
|
- secretName: tasko-tls
|
||||||
hosts:
|
hosts:
|
||||||
- tasko.dvirlabs.com
|
- tasko.dvirlabs.com
|
||||||
|
|
||||||
|
# Service Account configuration
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: ""
|
||||||
|
|||||||
2
manifests/calink/cname.yaml
Normal file
2
manifests/calink/cname.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
enabled: true
|
||||||
|
hostname: calink.dvirlabs.com
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user