fix: k8s on-premise deployment and session persistence
Some checks failed
scrum-manager/pipeline/head There was a failure building this commit

Database fixes:
- Add hostPath.type=DirectoryOrCreate so kubelet auto-creates /mnt/data/mysql
- Add fsGroup=999 so MySQL process can write to the hostPath volume
- Add MYSQL_ROOT_HOST=% to allow backend pods to authenticate as root
- Fix liveness/readiness probes to include credentials (-p$MYSQL_ROOT_PASSWORD)
- Increase probe initialDelaySeconds (30/60s) for slow first-run init
- Add 15s grace sleep in backend initContainer after MySQL TCP is up
- Add persistentVolumeReclaimPolicy=Retain to prevent accidental data loss
- Explicit accessModes+resources in PVC patch to avoid list merge ambiguity
- Add nodeAffinity comment in PV for multi-node cluster guidance

Ingress/nginx fixes:
- Remove broken rewrite-target=/ that was rewriting all paths (incl /api) to /
- Route /socket.io directly to backend for WebSocket support
- Add /socket.io/ proxy location to both nginx.conf and K8s ConfigMap

Frontend fix:
- Persist currentUser to localStorage on login so page refresh no longer
  clears session and redirects users back to the login page

Tooling:
- Add k8s/overlays/on-premise/deploy.sh for one-command deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
tusuii
2026-02-27 21:00:10 +05:30
parent fa8efe874e
commit 73bd35173c
9 changed files with 222 additions and 129 deletions

View File

@@ -24,14 +24,14 @@ spec:
- sh
- -c
- |
echo "Waiting for MySQL port to open..."
echo "Waiting for MySQL TCP to be available..."
until nc -z mysql 3306; do
echo "MySQL not ready yet, retrying in 5s..."
sleep 5
echo "MySQL not reachable yet, retrying in 3s..."
sleep 3
done
echo "Port open — waiting 15s for MySQL to finish initializing..."
echo "MySQL TCP is up. Waiting 15s for full initialization..."
sleep 15
echo "MySQL is ready!"
echo "Proceeding to start backend."
containers:
- name: backend
image: scrum-backend:latest
@@ -48,12 +48,12 @@ spec:
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_USER # matches new secret key
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_PASSWORD # matches new secret key
key: DB_PASSWORD
- name: DB_NAME
valueFrom:
secretKeyRef:
@@ -72,7 +72,7 @@ spec:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 30
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
@@ -80,7 +80,7 @@ spec:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 15
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 5
failureThreshold: 5

View File

@@ -14,11 +14,6 @@ data:
root /usr/share/nginx/html;
index index.html;
# Serve static files
location / {
try_files $uri $uri/ /index.html;
}
# Proxy API requests to backend service
location /api/ {
proxy_pass http://backend:3001;
@@ -27,5 +22,23 @@ data:
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 60s;
}
# Proxy Socket.io (real-time notifications)
location /socket.io/ {
proxy_pass http://backend:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 3600s;
}
# Serve static files — React SPA catch-all
location / {
try_files $uri $uri/ /index.html;
}
}

View File

@@ -8,7 +8,7 @@ metadata:
spec:
replicas: 1
strategy:
type: Recreate
type: Recreate # MySQL requires Recreate since PVC is ReadWriteOnce
selector:
matchLabels:
app.kubernetes.io/name: mysql
@@ -19,6 +19,11 @@ spec:
app.kubernetes.io/name: mysql
app.kubernetes.io/component: database
spec:
# fsGroup 999 = mysql group in the container image.
# Without this, the hostPath volume is owned by root and MySQL
# cannot write to /var/lib/mysql → pod CrashLoops immediately.
securityContext:
fsGroup: 999
containers:
- name: mysql
image: mysql:8.0
@@ -36,16 +41,9 @@ spec:
secretKeyRef:
name: mysql-secret
key: DB_NAME
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_USER
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_PASSWORD
# Allow root to connect from backend pods (any host), not just localhost.
- name: MYSQL_ROOT_HOST
value: "%"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
@@ -58,86 +56,26 @@ spec:
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping", "-h", "localhost"]
initialDelaySeconds: 90
periodSeconds: 15
command:
- sh
- -c
- mysqladmin ping -h 127.0.0.1 -u root -p"$MYSQL_ROOT_PASSWORD" --silent
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command: ["mysqladmin", "ping", "-h", "localhost"]
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
command:
- sh
- -c
- mysqladmin ping -h 127.0.0.1 -u root -p"$MYSQL_ROOT_PASSWORD" --silent
# MySQL 8.0 first-run initialization takes 30-60s on slow disks.
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 10
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: mysql-data-pvc
# apiVersion: apps/v1
# kind: Deployment
# metadata:
# name: mysql
# labels:
# app.kubernetes.io/name: mysql
# app.kubernetes.io/component: database
# spec:
# replicas: 1
# strategy:
# type: Recreate
# selector:
# matchLabels:
# app.kubernetes.io/name: mysql
# app.kubernetes.io/component: database
# template:
# metadata:
# labels:
# app.kubernetes.io/name: mysql
# app.kubernetes.io/component: database
# spec:
# containers:
# - name: mysql
# image: mysql:8.0
# ports:
# - containerPort: 3306
# name: mysql
# env:
# - name: MYSQL_ROOT_PASSWORD
# valueFrom:
# secretKeyRef:
# name: mysql-secret
# key: MYSQL_ROOT_PASSWORD
# - name: MYSQL_DATABASE
# valueFrom:
# secretKeyRef:
# name: mysql-secret
# key: DB_NAME
# volumeMounts:
# - name: mysql-data
# mountPath: /var/lib/mysql
# resources:
# requests:
# cpu: 250m
# memory: 512Mi
# limits:
# cpu: "1"
# memory: 1Gi
# livenessProbe:
# exec:
# command: ["mysqladmin", "ping", "-h", "localhost"]
# initialDelaySeconds: 90 # was 30 — must survive full init
# periodSeconds: 15
# timeoutSeconds: 5
# failureThreshold: 3
# readinessProbe:
# exec:
# command: ["mysqladmin", "ping", "-h", "localhost"]
# initialDelaySeconds: 60 # was 10 — critical fix
# periodSeconds: 10
# timeoutSeconds: 5
# failureThreshold: 5
# volumes:
# - name: mysql-data
# persistentVolumeClaim:
# claimName: mysql-data-pvc