fix: k8s on-premise deployment and session persistence
Some checks failed
scrum-manager/pipeline/head There was a failure building this commit
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user