From 4c58d13f00a14967f47af1ba32f46bbc403eaeb8 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Sun, 22 Feb 2026 15:14:10 +0200 Subject: [PATCH] Update tasko --- charts/tasko-chart-old/Chart.yaml | 12 + charts/tasko-chart-old/README.md | 228 ++++++++++++++++++ charts/tasko-chart-old/templates/NOTES.txt | 22 ++ charts/tasko-chart-old/templates/_helpers.tpl | 60 +++++ .../templates/backend-deployment.yaml | 80 ++++++ .../templates/backend-ingress.yaml | 42 ++++ .../templates/backend-service.yaml | 17 ++ .../templates/db-schema-configmap.yaml | 95 ++++++++ .../tasko-chart-old/templates/db-service.yaml | 38 +++ .../templates/db-statefulset.yaml | 87 +++++++ .../templates/frontend-deployment.yaml | 73 ++++++ .../templates/frontend-ingress.yaml | 42 ++++ .../templates/frontend-service.yaml | 17 ++ charts/tasko-chart-old/templates/secret.yaml | 13 + .../templates/serviceaccount.yaml | 12 + charts/tasko-chart-old/values.yaml | 136 +++++++++++ .../templates/backend-deployment.yaml | 15 ++ charts/tasko-chart/templates/secret.yaml | 7 +- charts/tasko-chart/values.yaml | 13 +- manifests/tasko/values.yaml | 65 ++++- 20 files changed, 1060 insertions(+), 14 deletions(-) create mode 100644 charts/tasko-chart-old/Chart.yaml create mode 100644 charts/tasko-chart-old/README.md create mode 100644 charts/tasko-chart-old/templates/NOTES.txt create mode 100644 charts/tasko-chart-old/templates/_helpers.tpl create mode 100644 charts/tasko-chart-old/templates/backend-deployment.yaml create mode 100644 charts/tasko-chart-old/templates/backend-ingress.yaml create mode 100644 charts/tasko-chart-old/templates/backend-service.yaml create mode 100644 charts/tasko-chart-old/templates/db-schema-configmap.yaml create mode 100644 charts/tasko-chart-old/templates/db-service.yaml create mode 100644 charts/tasko-chart-old/templates/db-statefulset.yaml create mode 100644 charts/tasko-chart-old/templates/frontend-deployment.yaml create mode 100644 charts/tasko-chart-old/templates/frontend-ingress.yaml create mode 100644 charts/tasko-chart-old/templates/frontend-service.yaml create mode 100644 charts/tasko-chart-old/templates/secret.yaml create mode 100644 charts/tasko-chart-old/templates/serviceaccount.yaml create mode 100644 charts/tasko-chart-old/values.yaml diff --git a/charts/tasko-chart-old/Chart.yaml b/charts/tasko-chart-old/Chart.yaml new file mode 100644 index 0000000..ebda231 --- /dev/null +++ b/charts/tasko-chart-old/Chart.yaml @@ -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 diff --git a/charts/tasko-chart-old/README.md b/charts/tasko-chart-old/README.md new file mode 100644 index 0000000..a55f413 --- /dev/null +++ b/charts/tasko-chart-old/README.md @@ -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 /tasko-frontend:latest +docker push /tasko-frontend:latest +``` + +### Backend +```bash +cd backend +docker build -t tasko-backend:latest . +docker tag tasko-backend:latest /tasko-backend:latest +docker push /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=/tasko-frontend \ + --set backend.image.repository=/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 +api-tasko.dvirlabs.com A/CNAME +``` + +## 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 -- 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. diff --git a/charts/tasko-chart-old/templates/NOTES.txt b/charts/tasko-chart-old/templates/NOTES.txt new file mode 100644 index 0000000..9f9ca7e --- /dev/null +++ b/charts/tasko-chart-old/templates/NOTES.txt @@ -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 }} diff --git a/charts/tasko-chart-old/templates/_helpers.tpl b/charts/tasko-chart-old/templates/_helpers.tpl new file mode 100644 index 0000000..e017b94 --- /dev/null +++ b/charts/tasko-chart-old/templates/_helpers.tpl @@ -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 }} diff --git a/charts/tasko-chart-old/templates/backend-deployment.yaml b/charts/tasko-chart-old/templates/backend-deployment.yaml new file mode 100644 index 0000000..43ccbb1 --- /dev/null +++ b/charts/tasko-chart-old/templates/backend-deployment.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/backend-ingress.yaml b/charts/tasko-chart-old/templates/backend-ingress.yaml new file mode 100644 index 0000000..08fe558 --- /dev/null +++ b/charts/tasko-chart-old/templates/backend-ingress.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/backend-service.yaml b/charts/tasko-chart-old/templates/backend-service.yaml new file mode 100644 index 0000000..0f7ecae --- /dev/null +++ b/charts/tasko-chart-old/templates/backend-service.yaml @@ -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 diff --git a/charts/tasko-chart-old/templates/db-schema-configmap.yaml b/charts/tasko-chart-old/templates/db-schema-configmap.yaml new file mode 100644 index 0000000..272752a --- /dev/null +++ b/charts/tasko-chart-old/templates/db-schema-configmap.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/db-service.yaml b/charts/tasko-chart-old/templates/db-service.yaml new file mode 100644 index 0000000..ccd3c3d --- /dev/null +++ b/charts/tasko-chart-old/templates/db-service.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/db-statefulset.yaml b/charts/tasko-chart-old/templates/db-statefulset.yaml new file mode 100644 index 0000000..50ddcc5 --- /dev/null +++ b/charts/tasko-chart-old/templates/db-statefulset.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/frontend-deployment.yaml b/charts/tasko-chart-old/templates/frontend-deployment.yaml new file mode 100644 index 0000000..96e00b9 --- /dev/null +++ b/charts/tasko-chart-old/templates/frontend-deployment.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/frontend-ingress.yaml b/charts/tasko-chart-old/templates/frontend-ingress.yaml new file mode 100644 index 0000000..675fb17 --- /dev/null +++ b/charts/tasko-chart-old/templates/frontend-ingress.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/frontend-service.yaml b/charts/tasko-chart-old/templates/frontend-service.yaml new file mode 100644 index 0000000..b29779c --- /dev/null +++ b/charts/tasko-chart-old/templates/frontend-service.yaml @@ -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 diff --git a/charts/tasko-chart-old/templates/secret.yaml b/charts/tasko-chart-old/templates/secret.yaml new file mode 100644 index 0000000..5291fb8 --- /dev/null +++ b/charts/tasko-chart-old/templates/secret.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/templates/serviceaccount.yaml b/charts/tasko-chart-old/templates/serviceaccount.yaml new file mode 100644 index 0000000..cf6a127 --- /dev/null +++ b/charts/tasko-chart-old/templates/serviceaccount.yaml @@ -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 }} diff --git a/charts/tasko-chart-old/values.yaml b/charts/tasko-chart-old/values.yaml new file mode 100644 index 0000000..e155c3a --- /dev/null +++ b/charts/tasko-chart-old/values.yaml @@ -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 diff --git a/charts/tasko-chart/templates/backend-deployment.yaml b/charts/tasko-chart/templates/backend-deployment.yaml index 43ccbb1..5293b14 100644 --- a/charts/tasko-chart/templates/backend-deployment.yaml +++ b/charts/tasko-chart/templates/backend-deployment.yaml @@ -48,6 +48,21 @@ spec: secretKeyRef: name: {{ include "tasko.fullname" . }}-secrets 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 }} - name: {{ $key }} value: {{ $value | quote }} diff --git a/charts/tasko-chart/templates/secret.yaml b/charts/tasko-chart/templates/secret.yaml index 5291fb8..ab08fc3 100644 --- a/charts/tasko-chart/templates/secret.yaml +++ b/charts/tasko-chart/templates/secret.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Secret metadata: - name: tasko-secrets + name: {{ include "tasko.fullname" . }}-secrets labels: {{- include "tasko.labels" . | nindent 4 }} type: Opaque @@ -11,3 +11,8 @@ stringData: {{- 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 }} + # 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 }} diff --git a/charts/tasko-chart/values.yaml b/charts/tasko-chart/values.yaml index e155c3a..b8b5811 100644 --- a/charts/tasko-chart/values.yaml +++ b/charts/tasko-chart/values.yaml @@ -1,6 +1,5 @@ global: namespace: my-apps - imagePullSecrets: [] # Backend configuration backend: @@ -26,6 +25,18 @@ backend: env: 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: enabled: true diff --git a/manifests/tasko/values.yaml b/manifests/tasko/values.yaml index 9045963..b8b5811 100644 --- a/manifests/tasko/values.yaml +++ b/manifests/tasko/values.yaml @@ -1,17 +1,20 @@ global: namespace: my-apps + # Backend configuration backend: name: backend replicaCount: 1 image: repository: harbor.dvirlabs.com/my-apps/tasko-backend - pullPolicy: Always - tag: master-7a34f5f + pullPolicy: IfNotPresent + tag: "latest" + service: type: ClusterIP port: 8000 targetPort: 8000 + resources: requests: cpu: 100m @@ -19,8 +22,22 @@ backend: limits: cpu: 500m memory: 512Mi + env: 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: enabled: true className: "traefik" @@ -37,20 +54,24 @@ backend: - 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: Always - tag: master-7a34f5f + pullPolicy: IfNotPresent + tag: "latest" + service: type: ClusterIP port: 80 targetPort: 80 + env: VITE_API_URL: "https://api-tasko.dvirlabs.com" + resources: requests: cpu: 50m @@ -58,6 +79,7 @@ frontend: limits: cpu: 200m memory: 256Mi + ingress: enabled: true className: "traefik" @@ -74,6 +96,7 @@ frontend: - secretName: tasko-tls hosts: - tasko.dvirlabs.com + # PostgreSQL configuration postgres: name: db @@ -81,26 +104,44 @@ postgres: 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 - size: 8Gi - storageClass: "" + storageClass: "nfs-client" + size: 10Gi + resources: requests: cpu: 100m - memory: 128Mi + memory: 256Mi limits: - cpu: 500m - memory: 512Mi -# Use default ServiceAccount (has harbor-creds imagePullSecret) -serviceAccount: - create: false + 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