diff --git a/k8s/base/backend/deployment.yaml b/k8s/base/backend/deployment.yaml new file mode 100644 index 0000000..93987a5 --- /dev/null +++ b/k8s/base/backend/deployment.yaml @@ -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 diff --git a/k8s/base/backend/service.yaml b/k8s/base/backend/service.yaml new file mode 100644 index 0000000..6c125ad --- /dev/null +++ b/k8s/base/backend/service.yaml @@ -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 diff --git a/k8s/base/frontend/configmap.yaml b/k8s/base/frontend/configmap.yaml new file mode 100644 index 0000000..99b4869 --- /dev/null +++ b/k8s/base/frontend/configmap.yaml @@ -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; + } + } diff --git a/k8s/base/frontend/deployment.yaml b/k8s/base/frontend/deployment.yaml new file mode 100644 index 0000000..f435d99 --- /dev/null +++ b/k8s/base/frontend/deployment.yaml @@ -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 diff --git a/k8s/base/frontend/service.yaml b/k8s/base/frontend/service.yaml new file mode 100644 index 0000000..2317fff --- /dev/null +++ b/k8s/base/frontend/service.yaml @@ -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 diff --git a/k8s/base/kustomization.yaml b/k8s/base/kustomization.yaml new file mode 100644 index 0000000..18ddd8f --- /dev/null +++ b/k8s/base/kustomization.yaml @@ -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 diff --git a/k8s/base/mysql/deployment.yaml b/k8s/base/mysql/deployment.yaml new file mode 100644 index 0000000..8daecd7 --- /dev/null +++ b/k8s/base/mysql/deployment.yaml @@ -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 diff --git a/k8s/base/mysql/pvc.yaml b/k8s/base/mysql/pvc.yaml new file mode 100644 index 0000000..31ebcbf --- /dev/null +++ b/k8s/base/mysql/pvc.yaml @@ -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 diff --git a/k8s/base/mysql/secret.yaml b/k8s/base/mysql/secret.yaml new file mode 100644 index 0000000..d18a516 --- /dev/null +++ b/k8s/base/mysql/secret.yaml @@ -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== diff --git a/k8s/base/mysql/service.yaml b/k8s/base/mysql/service.yaml new file mode 100644 index 0000000..151b2ed --- /dev/null +++ b/k8s/base/mysql/service.yaml @@ -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 diff --git a/k8s/base/namespace.yaml b/k8s/base/namespace.yaml new file mode 100644 index 0000000..2431d64 --- /dev/null +++ b/k8s/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: scrum-manager + labels: + app.kubernetes.io/part-of: scrum-manager