From 1e6a785552caa0ca10b87cf8f55e97857c8403d8 Mon Sep 17 00:00:00 2001 From: timn Date: Thu, 18 Jun 2026 13:49:46 +0200 Subject: [PATCH 1/8] add resource constraint for deployment --- helm/bytebite/templates/grocery-db-statefulset.yaml | 7 +++++++ helm/bytebite/templates/user-db-statefulset.yaml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/helm/bytebite/templates/grocery-db-statefulset.yaml b/helm/bytebite/templates/grocery-db-statefulset.yaml index 50ac2e8..67a819f 100644 --- a/helm/bytebite/templates/grocery-db-statefulset.yaml +++ b/helm/bytebite/templates/grocery-db-statefulset.yaml @@ -18,6 +18,13 @@ spec: - name: grocery-db image: "{{ .Values.groceryDb.image.repository }}:{{ .Values.groceryDb.image.tag }}" imagePullPolicy: {{ .Values.groceryDb.image.pullPolicy }} + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "200m" + memory: "256Mi" ports: - containerPort: 5432 env: diff --git a/helm/bytebite/templates/user-db-statefulset.yaml b/helm/bytebite/templates/user-db-statefulset.yaml index e8f21c2..2744584 100644 --- a/helm/bytebite/templates/user-db-statefulset.yaml +++ b/helm/bytebite/templates/user-db-statefulset.yaml @@ -18,6 +18,13 @@ spec: - name: user-db image: "{{ .Values.userDb.image.repository }}:{{ .Values.userDb.image.tag }}" imagePullPolicy: {{ .Values.userDb.image.pullPolicy }} + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "200m" + memory: "256Mi" ports: - containerPort: 5432 env: From e2a13fd41fd346d0d56a1de7488f9ec58f27790a Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 13:25:46 +0200 Subject: [PATCH 2/8] enable deploying from non-main branch via manual trigger --- .github/workflows/test-build-push.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-build-push.yml b/.github/workflows/test-build-push.yml index eeb4f32..9ed9313 100644 --- a/.github/workflows/test-build-push.yml +++ b/.github/workflows/test-build-push.yml @@ -1,6 +1,7 @@ name: Test, Build and Push Images -# Runs tests and builds images on every branch. Only pushes to the registry on main. +# Runs tests and builds images on every branch. +# Pushes to the registry only on main, or on a manual workflow_dispatch run. on: push: branches: @@ -93,7 +94,7 @@ jobs: with: context: ${{ matrix.context }} file: ${{ matrix.context }}/Dockerfile - push: ${{ github.ref == 'refs/heads/main' }} + push: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha From f714f0c1f4d375ba0dfae230f3dfaead3b8b88be Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 13:41:08 +0200 Subject: [PATCH 3/8] k8s deploy: set db tags --- .github/workflows/deploy-k8s.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-k8s.yml b/.github/workflows/deploy-k8s.yml index 763970d..66a6670 100644 --- a/.github/workflows/deploy-k8s.yml +++ b/.github/workflows/deploy-k8s.yml @@ -61,6 +61,8 @@ jobs: --set userService.image.tag=${{ steps.vars.outputs.image_tag }} \ --set groceryService.image.tag=${{ steps.vars.outputs.image_tag }} \ --set genai.image.tag=${{ steps.vars.outputs.image_tag }} \ + --set userDb.image.tag=${{ steps.vars.outputs.image_tag }} \ + --set groceryDb.image.tag=${{ steps.vars.outputs.image_tag }} \ --set genai.logosKey="${{ secrets.LOGOS_KEY }}" \ --set genai.openaiApiKey="${{ secrets.OPENAI_API_KEY }}" \ --set userDb.password="${{ secrets.USER_DB_PASSWORD }}" \ From 55384b207dc4a098b99a4fadf76a653dd026802c Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 16:27:45 +0200 Subject: [PATCH 4/8] fixed kubernetes quota issue --- helm/bytebite/templates/grocery-db-statefulset.yaml | 8 ++++---- helm/bytebite/templates/user-db-statefulset.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/helm/bytebite/templates/grocery-db-statefulset.yaml b/helm/bytebite/templates/grocery-db-statefulset.yaml index 67a819f..5b90003 100644 --- a/helm/bytebite/templates/grocery-db-statefulset.yaml +++ b/helm/bytebite/templates/grocery-db-statefulset.yaml @@ -20,11 +20,11 @@ spec: imagePullPolicy: {{ .Values.groceryDb.image.pullPolicy }} resources: limits: - cpu: "500m" - memory: "512Mi" - requests: - cpu: "200m" + cpu: "250m" memory: "256Mi" + requests: + cpu: "100m" + memory: "128Mi" ports: - containerPort: 5432 env: diff --git a/helm/bytebite/templates/user-db-statefulset.yaml b/helm/bytebite/templates/user-db-statefulset.yaml index 2744584..6ee0280 100644 --- a/helm/bytebite/templates/user-db-statefulset.yaml +++ b/helm/bytebite/templates/user-db-statefulset.yaml @@ -20,11 +20,11 @@ spec: imagePullPolicy: {{ .Values.userDb.image.pullPolicy }} resources: limits: - cpu: "500m" - memory: "512Mi" - requests: - cpu: "200m" + cpu: "250m" memory: "256Mi" + requests: + cpu: "100m" + memory: "128Mi" ports: - containerPort: 5432 env: From 8c3cc5822ad4ce537462e55d3b02095c1f4ddbc7 Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 17:36:56 +0200 Subject: [PATCH 5/8] removed atomic from k8s deployment --- .github/workflows/deploy-k8s.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/deploy-k8s.yml b/.github/workflows/deploy-k8s.yml index 66a6670..8d1c0af 100644 --- a/.github/workflows/deploy-k8s.yml +++ b/.github/workflows/deploy-k8s.yml @@ -66,5 +66,4 @@ jobs: --set genai.logosKey="${{ secrets.LOGOS_KEY }}" \ --set genai.openaiApiKey="${{ secrets.OPENAI_API_KEY }}" \ --set userDb.password="${{ secrets.USER_DB_PASSWORD }}" \ - --set groceryDb.password="${{ secrets.GROCERY_DB_PASSWORD }}" \ - --atomic + --set groceryDb.password="${{ secrets.GROCERY_DB_PASSWORD }}" From 3d276250bab2d78b45b987f4c61646874ba9ee79 Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 18:27:07 +0200 Subject: [PATCH 6/8] switched from statefulsets to db deployments --- ...fulset.yaml => grocery-db-deployment.yaml} | 19 +++++++++---------- ...atefulset.yaml => user-db-deployment.yaml} | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) rename helm/bytebite/templates/{grocery-db-statefulset.yaml => grocery-db-deployment.yaml} (77%) rename helm/bytebite/templates/{user-db-statefulset.yaml => user-db-deployment.yaml} (77%) diff --git a/helm/bytebite/templates/grocery-db-statefulset.yaml b/helm/bytebite/templates/grocery-db-deployment.yaml similarity index 77% rename from helm/bytebite/templates/grocery-db-statefulset.yaml rename to helm/bytebite/templates/grocery-db-deployment.yaml index 5b90003..9e2097b 100644 --- a/helm/bytebite/templates/grocery-db-statefulset.yaml +++ b/helm/bytebite/templates/grocery-db-deployment.yaml @@ -1,11 +1,14 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: name: bytebite-grocery-db namespace: {{ .Values.namespace }} spec: - serviceName: grocery-db replicas: 1 + # Ephemeral DB (emptyDir): recreate the pod rather than rolling, so two + # instances never run at once and each start gets a clean database. + strategy: + type: Recreate selector: matchLabels: app: bytebite-grocery-db @@ -40,11 +43,7 @@ spec: volumeMounts: - name: grocery-db-data mountPath: /var/lib/postgresql/data - volumeClaimTemplates: - - metadata: - name: grocery-db-data - spec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 1Gi \ No newline at end of file + volumes: + # Ephemeral storage: the database is recreated on every pod start. + - name: grocery-db-data + emptyDir: {} \ No newline at end of file diff --git a/helm/bytebite/templates/user-db-statefulset.yaml b/helm/bytebite/templates/user-db-deployment.yaml similarity index 77% rename from helm/bytebite/templates/user-db-statefulset.yaml rename to helm/bytebite/templates/user-db-deployment.yaml index 6ee0280..5824b49 100644 --- a/helm/bytebite/templates/user-db-statefulset.yaml +++ b/helm/bytebite/templates/user-db-deployment.yaml @@ -1,11 +1,14 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: name: bytebite-user-db namespace: {{ .Values.namespace }} spec: - serviceName: user-db replicas: 1 + # Ephemeral DB (emptyDir): recreate the pod rather than rolling, so two + # instances never run at once and each start gets a clean database. + strategy: + type: Recreate selector: matchLabels: app: bytebite-user-db @@ -40,11 +43,7 @@ spec: volumeMounts: - name: user-db-data mountPath: /var/lib/postgresql/data - volumeClaimTemplates: - - metadata: - name: user-db-data - spec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 1Gi \ No newline at end of file + volumes: + # Ephemeral storage: the database is recreated on every pod start. + - name: user-db-data + emptyDir: {} \ No newline at end of file From 7342d0f0372a3f62bf10142375d8e14989bf2479 Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 23:01:25 +0200 Subject: [PATCH 7/8] kubernetes: fix ports and jwt --- .github/workflows/deploy-k8s.yml | 3 ++- helm/bytebite/templates/api-gateway-deployment.yaml | 9 +++++++++ .../templates/grocery-service-deployment.yaml | 4 ++++ helm/bytebite/templates/secret.yaml | 13 ++++++++++++- .../bytebite/templates/user-service-deployment.yaml | 13 +++++++++++++ helm/bytebite/values.yaml | 6 ++++++ 6 files changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-k8s.yml b/.github/workflows/deploy-k8s.yml index 8d1c0af..84c544f 100644 --- a/.github/workflows/deploy-k8s.yml +++ b/.github/workflows/deploy-k8s.yml @@ -66,4 +66,5 @@ jobs: --set genai.logosKey="${{ secrets.LOGOS_KEY }}" \ --set genai.openaiApiKey="${{ secrets.OPENAI_API_KEY }}" \ --set userDb.password="${{ secrets.USER_DB_PASSWORD }}" \ - --set groceryDb.password="${{ secrets.GROCERY_DB_PASSWORD }}" + --set groceryDb.password="${{ secrets.GROCERY_DB_PASSWORD }}" \ + --set jwt.secret="${{ secrets.JWT_SECRET }}" diff --git a/helm/bytebite/templates/api-gateway-deployment.yaml b/helm/bytebite/templates/api-gateway-deployment.yaml index 84d2f67..134abfe 100644 --- a/helm/bytebite/templates/api-gateway-deployment.yaml +++ b/helm/bytebite/templates/api-gateway-deployment.yaml @@ -31,3 +31,12 @@ spec: value: "http://grocery-service:{{ .Values.groceryService.service.port }}" - name: USER_SERVICE_BASE_URL value: "http://user-service:{{ .Values.userService.service.port }}" + {{- if .Values.jwt.secret }} + # Shared JWT secret (verifies tokens). Must match user-service. Only + # injected when set; otherwise the app's built-in default applies. + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: jwt-secret + key: jwt-secret + {{- end }} diff --git a/helm/bytebite/templates/grocery-service-deployment.yaml b/helm/bytebite/templates/grocery-service-deployment.yaml index cbab032..2099d0c 100644 --- a/helm/bytebite/templates/grocery-service-deployment.yaml +++ b/helm/bytebite/templates/grocery-service-deployment.yaml @@ -27,6 +27,10 @@ spec: ports: - containerPort: {{ .Values.groceryService.service.targetPort }} env: + # The app's dev default port is 8082; override it so it listens on + # the container/Service port (8080), matching the api-gateway route. + - name: SERVER_PORT + value: "{{ .Values.groceryService.service.targetPort }}" - name: GENAI_BASE_URL value: "http://genai-service:{{ .Values.genai.service.port }}" - name: SPRING_DATASOURCE_URL diff --git a/helm/bytebite/templates/secret.yaml b/helm/bytebite/templates/secret.yaml index 76976eb..12692a2 100644 --- a/helm/bytebite/templates/secret.yaml +++ b/helm/bytebite/templates/secret.yaml @@ -16,4 +16,15 @@ metadata: type: Opaque data: user-db-password: {{ .Values.userDb.password | b64enc | quote }} - grocery-db-password: {{ .Values.groceryDb.password | b64enc | quote }} \ No newline at end of file + grocery-db-password: {{ .Values.groceryDb.password | b64enc | quote }} +{{- if .Values.jwt.secret }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: jwt-secret + namespace: {{ .Values.namespace }} +type: Opaque +data: + jwt-secret: {{ .Values.jwt.secret | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/helm/bytebite/templates/user-service-deployment.yaml b/helm/bytebite/templates/user-service-deployment.yaml index 34561db..674b646 100644 --- a/helm/bytebite/templates/user-service-deployment.yaml +++ b/helm/bytebite/templates/user-service-deployment.yaml @@ -27,6 +27,19 @@ spec: ports: - containerPort: {{ .Values.userService.service.targetPort }} env: + # The app's dev default port is 8083; override it so it listens on + # the container/Service port (8080), matching the api-gateway route. + - name: SERVER_PORT + value: "{{ .Values.userService.service.targetPort }}" + {{- if .Values.jwt.secret }} + # Shared JWT secret (signs tokens). Must match the api-gateway. Only + # injected when set; otherwise the app's built-in default applies. + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: jwt-secret + key: jwt-secret + {{- end }} - name: SPRING_DATASOURCE_URL value: "jdbc:postgresql://user-db:5432/{{ .Values.userDb.name }}" - name: SPRING_DATASOURCE_USERNAME diff --git a/helm/bytebite/values.yaml b/helm/bytebite/values.yaml index 7cc5417..ae5c85e 100644 --- a/helm/bytebite/values.yaml +++ b/helm/bytebite/values.yaml @@ -76,6 +76,12 @@ groceryDb: user: bytebite_grocery password: "" +# Shared JWT signing/verification secret for user-service (signs) and +# api-gateway (verifies). Must be >=32 chars. Leave empty to fall back to the +# apps' built-in dev default; set via --set jwt.secret / a GitHub secret for real deploys. +jwt: + secret: "" + ingress: enabled: true className: "nginx" From ef80f41fcf3f2117245dced1ed9b17f9d9e2a6b1 Mon Sep 17 00:00:00 2001 From: timn Date: Fri, 19 Jun 2026 23:18:30 +0200 Subject: [PATCH 8/8] add logos field in env.example --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index ed6ed73..3cf29da 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ OPENAI_API_KEY=sk-... +LOGOS_KEY=lg-... \ No newline at end of file