Compare commits

...

3 Commits

Author SHA1 Message Date
Charles Mendiburu
8171d3b197 Add of the README.md : explain config about deployment of the app with kuber 2026-04-29 01:10:19 +02:00
Charles Mendiburu
3444a94c5f Modification script files for deployment of the webapp with Kubernetes 2026-04-29 01:08:35 +02:00
Charles Mendiburu
823b9df176 Add files for deployment of the webapp with Kubernetes 2026-04-29 01:07:44 +02:00
9 changed files with 524 additions and 9 deletions

182
z2/README.md Normal file
View File

@ -0,0 +1,182 @@
# Vigimétéo Kubernetes Deployment (z2)
---
## 1. Application description
**Vigimétéo** is a weather monitoring web application.
Users can log in, browse weather stations, consult meteorological data (wind, temperature, pressure…) and manage objects depending on their role.
The stack is made of three services:
- A **React** frontend served by Nginx
- A **Java / Vert.x** REST backend that exposes the API
- A **PostgreSQL** database that stores all data
---
## 2. Containers used
| Container | Image | Role |
|---|---|---|
| `vigimeteo-frontend` | `vigimeteo-frontend:latest` (built from `Front-end/Dockerfile`) | React SPA built with Vite, served by Nginx on port 80 |
| `vigimeteo-backend` | `vigimeteo-backend:latest` (built from `Back-end/Dockerfile`) | Java 17 / Vert.x REST API on port 8888. Connects to PostgreSQL using environment variables |
| `postgres` | `postgres:17-alpine` | PostgreSQL database. Automatically runs `init.sql` on first start to create tables and insert seed data |
| `busybox` (init) | `busybox:1.36` | Temporary init container inside the backend pod. Waits until PostgreSQL port 5432 is open before letting the backend start |
---
## 3. Kubernetes objects
| Kind | Name | Description |
|---|---|---|
| `Namespace` | `vigimeteo` | Isolates all objects of this application from the rest of the cluster |
| `PersistentVolume` | `vigimeteo-db-pv` | 1 Gi storage volume mapped to `~/vigimeteo-db-data` on the host node |
| `PersistentVolumeClaim` | `vigimeteo-db-pvc` | Request for storage, bound to the PV above. Used by the StatefulSet |
| `ConfigMap` | `vigimeteo-db-init` | Holds the SQL init script (`init.sql`). Mounted into the PostgreSQL container |
| `StatefulSet` | `vigimeteo-db` | Manages the PostgreSQL pod. Provides a stable name and stable storage |
| `Deployment` | `vigimeteo-backend` | Manages 2 replicas of the Vert.x backend |
| `Deployment` | `vigimeteo-frontend` | Manages 2 replicas of the Nginx/React frontend |
| `Service` (Headless) | `vigimeteo-db` | Gives the PostgreSQL pod a stable DNS name: `vigimeteo-db.vigimeteo.svc.cluster.local` |
| `Service` (NodePort) | `vigimeteo-backend-service` | Exposes the backend API on port **30888** (accessible from the host) |
| `Service` (NodePort) | `vigimeteo-frontend-service` | Exposes the frontend on port **30500** (accessible from the host) |
---
## 4. Networks and volumes
### Network
Kubernetes creates a virtual internal network for the `vigimeteo` namespace automatically.
- Pods communicate internally using **DNS service names** (e.g. `vigimeteo-db.vigimeteo.svc.cluster.local`).
- The frontend and backend are exposed externally via **NodePort** services.
| Access | Address |
|---|---|
| Frontend (browser) | `http://localhost:30500` |
| Backend API | `http://localhost:30888` |
| Database (internal only) | `vigimeteo-db.vigimeteo.svc.cluster.local:5432` |
### Volume
| Name | Type | Host path | Used by |
|---|---|---|---|
| `vigimeteo-db-pv` | PersistentVolume (hostPath) | `~/vigimeteo-db-data` | PostgreSQL StatefulSet |
The volume is created by `prepare-app.sh` with `mkdir -p ~/vigimeteo-db-data`.
It persists data even after the application is stopped.
---
## 5. Container configuration
### Backend environment variables
The backend connects to the database using these environment variables set in `deployment.yaml`:
| Variable | Value |
|---|---|
| `DB_HOST` | `vigimeteo-db.vigimeteo.svc.cluster.local` |
| `DB_PORT` | `5432` |
| `DB_NAME` | `postgres` |
| `DB_USER` | `postgres` |
| `DB_PASSWORD` | `admin` |
### Backend init container
To avoid connection errors on startup, a `busybox` init container runs first and waits until PostgreSQL accepts connections on port 5432:
```bash
until nc -z vigimeteo-db.vigimeteo.svc.cluster.local 5432; do sleep 3; done
```
### Database init script
The ConfigMap `vigimeteo-db-init` contains `init.sql` and is mounted into `/docker-entrypoint-initdb.d/` inside the PostgreSQL container. PostgreSQL automatically runs all `.sql` files in that folder on first startup.
### Images
Both images are built locally with `imagePullPolicy: IfNotPresent` so Kubernetes never tries to pull them from a registry.
---
## 6. How to run the application
### Prerequisites
- `docker` installed and running
- `kubectl` configured and connected to a cluster
- For **Minikube**: run `eval $(minikube docker-env)` first so images are built inside Minikube's daemon
### Step 1 Prepare (first time only)
```bash
bash prepare-app.sh
```
This creates the PV host directory and builds the two Docker images.
### Step 2 Start
```bash
bash start-app.sh
```
Applies all Kubernetes objects in the correct order and waits for PostgreSQL to be ready before deploying the backend.
### Step 3 Pause / restart
There is no "pause" in Kubernetes. To stop traffic you can scale down replicas:
```bash
kubectl scale deployment vigimeteo-backend vigimeteo-frontend --replicas=0 -n vigimeteo
```
To restart:
```bash
kubectl scale deployment vigimeteo-backend vigimeteo-frontend --replicas=2 -n vigimeteo
```
### Step 4 Delete
```bash
bash stop-app.sh
```
This deletes the namespace (which removes all objects inside it) and the PersistentVolume.
The data folder `~/vigimeteo-db-data` is **not** deleted. To fully clean up:
```bash
rm -rf ~/vigimeteo-db-data
```
---
## 7. How to access the application
Once the app is started, open your browser at:
**http://localhost:30500**
### Test credentials
| Role | Email | Password |
|---|---|---|
| Admin | `admin@a.com` | `azertyuiop` |
| Complexe user | `complexe@gmail.com` | `azertyuiop` |
| Regular user | `user@gmail.com` | `azertyuiop` |
### Verify everything is running
```bash
kubectl get all -n vigimeteo
```
All pods should show `1/1 Running`.
---
## Troubleshooting
**Pod stays `Pending`** → The PVC is not bound. Run `kubectl describe pod -n vigimeteo <pod-name>` and check the events. Make sure `~/vigimeteo-db-data` exists.
**Backend `CrashLoopBackOff`** → Check logs with `kubectl logs -n vigimeteo deployment/vigimeteo-backend`. Usually a DB connection issue.
**Images not found** → For Minikube, run `eval $(minikube docker-env)` before `prepare-app.sh`.

View File

@ -0,0 +1,52 @@
# ─────────────────────────────────────────────────────────────────────────────
# Deployment Vert.x Backend (2 replicas)
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: apps/v1
kind: Deployment
metadata:
name: vigimeteo-backend
namespace: vigimeteo
labels:
app: vigimeteo-backend
spec:
replicas: 2
selector:
matchLabels:
app: vigimeteo-backend
template:
metadata:
labels:
app: vigimeteo-backend
spec:
initContainers:
# Wait until PostgreSQL is ready before starting the backend
- name: wait-for-db
image: busybox:1.36
command:
- sh
- -c
- |
until nc -z vigimeteo-db.vigimeteo.svc.cluster.local 5432; do
echo "Waiting for PostgreSQL...";
sleep 3;
done;
echo "PostgreSQL is ready."
containers:
- name: vigimeteo-backend
image: vigimeteo-backend:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8888
name: http
env:
- name: DB_HOST
value: "vigimeteo-db.vigimeteo.svc.cluster.local"
- name: DB_PORT
value: "5432"
- name: DB_NAME
value: "postgres"
- name: DB_USER
value: "postgres"
- name: DB_PASSWORD
value: "admin"

7
z2/namespace.yaml Normal file
View File

@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: vigimeteo
labels:
app: vigimeteo
environment: production

View File

@ -1,4 +1,20 @@
#!/bin/bash
# Prepare the app: create the storage directory and build the Docker images
set -e
echo "╔══════════════════════════════════════════╗"
echo "║ Vigimétéo Prepare App ║"
echo "╚══════════════════════════════════════════╝"
echo "Preparing app..."
docker compose build
echo "App is prepared."
# 1 - Create the directory used by the PersistentVolume
mkdir -p ~/vigimeteo-db-data
# 2 - Build Docker images
docker build -t vigimeteo-backend:latest ./Back-end
docker build -t vigimeteo-frontend:latest ./Front-end
echo ""
echo "════════════════════════════════════════════"
echo " Preparation complete! Run ./start-app.sh"
echo "════════════════════════════════════════════"

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo "Removed app."
docker compose down -v --rmi local

91
z2/service.yaml Normal file
View File

@ -0,0 +1,91 @@
# ─────────────────────────────────────────────────────────────────────────────
# Deployment React/Nginx Frontend (2 replicas)
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: apps/v1
kind: Deployment
metadata:
name: vigimeteo-frontend
namespace: vigimeteo
labels:
app: vigimeteo-frontend
spec:
replicas: 2
selector:
matchLabels:
app: vigimeteo-frontend
template:
metadata:
labels:
app: vigimeteo-frontend
spec:
containers:
- name: vigimeteo-frontend
image: vigimeteo-frontend:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
### part bellow recommanded by ia for health check
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 15
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"
---
# ─────────────────────────────────────────────────────────────────────────────
# Service Backend ClusterIP (internal access only)
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: Service
metadata:
name: vigimeteo-backend-service
namespace: vigimeteo
labels:
app: vigimeteo-backend
spec:
type: NodePort
selector:
app: vigimeteo-backend
ports:
- name: http
protocol: TCP
port: 8888
targetPort: 8888
nodePort: 30888
---
# ─────────────────────────────────────────────────────────────────────────────
# Service Frontend NodePort (external access via <nodeIP>:30500)
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: Service
metadata:
name: vigimeteo-frontend-service
namespace: vigimeteo
labels:
app: vigimeteo-frontend
spec:
type: NodePort
selector:
app: vigimeteo-frontend
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30500

View File

@ -1,4 +1,39 @@
#!/bin/bash
echo "Running app ..."
docker compose up -d
echo "The app is available at http://localhost:5000"
# Deploy all Kubernetes objects for Vigimeteo
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NS="vigimeteo"
echo "╔══════════════════════════════════════════╗"
echo "║ Vigimétéo Start App ║"
echo "╚══════════════════════════════════════════╝"
echo "Starting app..."
# 1. Create the namespace
kubectl apply -f namespace.yaml
# 2. Create the ConfigMap from the SQL init script, then apply storage and database
kubectl create configmap vigimeteo-db-init \
--from-file=init.sql=sql/init_db.sql \
-n vigimeteo \
--dry-run=client -o yaml | kubectl apply -f -
kubectl apply -f statefulset.yaml
# 3. Wait for the database to be ready before starting the backend
echo "Waiting for PostgreSQL to be ready..."
kubectl rollout status statefulset/vigimeteo-db -n vigimeteo --timeout=120s
# 4. Deploy the backend and frontend
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# ── Summary ───────────────────────────────────────────────────────────────────
echo ""
echo "════════════════════════════════════════════"
echo " All objects deployed in namespace: $NS"
echo ""
kubectl get all -n "$NS"
echo ""
echo "App deployed! Available at http://localhost:30500"

116
z2/statefulset.yaml Normal file
View File

@ -0,0 +1,116 @@
# ─────────────────────────────────────────────────────────────────────────────
# PersistentVolume host-path volume for PostgreSQL data
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: PersistentVolume
metadata:
name: vigimeteo-db-pv
namespace: vigimeteo
labels:
app: vigimeteo-db
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /home/cytech/vigimeteo-db-data
---
# ─────────────────────────────────────────────────────────────────────────────
# PersistentVolumeClaim claimed by the StatefulSet below
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vigimeteo-db-pvc
namespace: vigimeteo
labels:
app: vigimeteo-db
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual
resources:
requests:
storage: 1Gi
---
# ─────────────────────────────────────────────────────────────────────────────
# StatefulSet single PostgreSQL replica
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: vigimeteo-db
namespace: vigimeteo
labels:
app: vigimeteo-db
spec:
serviceName: vigimeteo-db
replicas: 1
selector:
matchLabels:
app: vigimeteo-db
template:
metadata:
labels:
app: vigimeteo-db
spec:
containers:
- name: postgres
image: postgres:17-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_USER
value: "postgres"
- name: POSTGRES_PASSWORD
value: "admin"
- name: POSTGRES_DB
value: "postgres"
volumeMounts:
- name: vigimeteo-db-storage
mountPath: /var/lib/postgresql/data
- name: vigimeteo-db-init
mountPath: /docker-entrypoint-initdb.d
readinessProbe:
exec:
command: ["pg_isready", "-U", "postgres"]
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
exec:
command: ["pg_isready", "-U", "postgres"]
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: vigimeteo-db-storage
persistentVolumeClaim:
claimName: vigimeteo-db-pvc
- name: vigimeteo-db-init
configMap:
name: vigimeteo-db-init
---
# ─────────────────────────────────────────────────────────────────────────────
# Headless Service required by the StatefulSet
# ─────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: Service
metadata:
name: vigimeteo-db
namespace: vigimeteo
labels:
app: vigimeteo-db
spec:
clusterIP: None # headless stable DNS name for StatefulSet pods
selector:
app: vigimeteo-db
ports:
- name: postgres
port: 5432
targetPort: 5432

View File

@ -1,3 +1,22 @@
#!/bin/bash
# Remove all Kubernetes objects for Vigimeteo
set -e
echo "╔══════════════════════════════════════════╗"
echo "║ Vigimétéo Stop App ║"
echo "╚══════════════════════════════════════════╝"
echo "Stopping app..."
docker compose stop
# 1- Deleting the namespace removes everything inside it automatically
kubectl delete namespace vigimeteo --ignore-not-found
# 2 - The PersistentVolume is cluster-scoped so it must be deleted separately
kubectl delete pv vigimeteo-db-pv --ignore-not-found
echo ""
echo "════════════════════════════════════════════"
echo " All Vigimeteo Kubernetes objects removed."
echo " Note: ~/vigimeteo-db-data was NOT deleted."
echo " Run: rm -rf ~/vigimeteo-db-data to clean up."
echo "════════════════════════════════════════════"
echo "App stopped."