feat: add Kubernetes Kustomize deployment manifests

Add k8s/base/ directory with Kustomize manifests for deploying
the scrum-manager application to Kubernetes:

- Namespace (scrum-manager)
- MySQL: Deployment, Service, PVC, Secret
- Backend: Deployment (2 replicas) with init container, Service
- Frontend: Deployment (2 replicas), Service (NodePort), ConfigMap (nginx.conf)

All deployments include resource requests/limits, liveness/readiness
probes, and proper label selectors.
This commit is contained in:
tusuii
2026-02-16 12:25:56 +05:30
parent 892a2ceba1
commit 2db45de4c4
11 changed files with 359 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
labels:
app.kubernetes.io/name: backend
app.kubernetes.io/component: api
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: backend
app.kubernetes.io/component: api
template:
metadata:
labels:
app.kubernetes.io/name: backend
app.kubernetes.io/component: api
spec:
initContainers:
- name: wait-for-mysql
image: busybox:1.36
command:
- sh
- -c
- |
echo "Waiting for MySQL to be ready..."
until nc -z mysql 3306; do
echo "MySQL is not ready yet, retrying in 3s..."
sleep 3
done
echo "MySQL is ready!"
containers:
- name: backend
image: scrum-backend:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3001
name: http
env:
- name: DB_HOST
value: mysql
- name: DB_PORT
value: "3306"
- name: DB_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: DB_PASSWORD
- name: DB_NAME
valueFrom:
secretKeyRef:
name: mysql-secret
key: DB_NAME
- name: PORT
value: "3001"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 5

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: backend
labels:
app.kubernetes.io/name: backend
app.kubernetes.io/component: api
spec:
type: ClusterIP
ports:
- port: 3001
targetPort: 3001
protocol: TCP
name: http
selector:
app.kubernetes.io/name: backend
app.kubernetes.io/component: api

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-nginx-config
labels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
data:
default.conf: |
server {
listen 80;
server_name localhost;
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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

View File

@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
labels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
template:
metadata:
labels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
spec:
containers:
- name: frontend
image: scrum-frontend:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
readOnly: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumes:
- name: nginx-config
configMap:
name: frontend-nginx-config

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web

View File

@@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: scrum-manager
labels:
- pairs:
app.kubernetes.io/part-of: scrum-manager
app.kubernetes.io/managed-by: kustomize
includeSelectors: true
resources:
- namespace.yaml
# MySQL
- mysql/secret.yaml
- mysql/pvc.yaml
- mysql/deployment.yaml
- mysql/service.yaml
# Backend
- backend/deployment.yaml
- backend/service.yaml
# Frontend
- frontend/configmap.yaml
- frontend/deployment.yaml
- frontend/service.yaml

View File

@@ -0,0 +1,74 @@
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 # MySQL requires Recreate since PVC is ReadWriteOnce
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: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 5
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: mysql-data-pvc

13
k8s/base/mysql/pvc.yaml Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data-pvc
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/component: database
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/component: database
type: Opaque
data:
# Base64 encoded values — change these for production!
# echo -n 'scrumpass' | base64 => c2NydW1wYXNz
# echo -n 'root' | base64 => cm9vdA==
# echo -n 'scrum_manager' | base64 => c2NydW1fbWFuYWdlcg==
MYSQL_ROOT_PASSWORD: c2NydW1wYXNz
DB_USER: cm9vdA==
DB_PASSWORD: c2NydW1wYXNz
DB_NAME: c2NydW1fbWFuYWdlcg==

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/component: database
spec:
type: ClusterIP
ports:
- port: 3306
targetPort: 3306
protocol: TCP
name: mysql
selector:
app.kubernetes.io/name: mysql
app.kubernetes.io/component: database

6
k8s/base/namespace.yaml Normal file
View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: scrum-manager
labels:
app.kubernetes.io/part-of: scrum-manager