Téléverser les fichiers vers "z2"
This commit is contained in:
		
							parent
							
								
									16aa94ff55
								
							
						
					
					
						commit
						b91eb63711
					
				
							
								
								
									
										12
									
								
								z2/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								z2/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| FROM python:3.9-slim | ||||
| 
 | ||||
| WORKDIR /app | ||||
| 
 | ||||
| COPY requirements.txt . | ||||
| RUN pip install --no-cache-dir -r requirements.txt | ||||
| 
 | ||||
| COPY app.py . | ||||
| 
 | ||||
| EXPOSE 5000 | ||||
| 
 | ||||
| CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] | ||||
							
								
								
									
										107
									
								
								z2/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								z2/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | ||||
| # Shopping List Web Application on Kubernetes | ||||
| 
 | ||||
| ## Overview | ||||
| This project deploys a Python shopping list web application using Flask and PostgreSQL on a Kubernetes cluster. The application allows users to create, track, and manage their shopping items in a persistent way. The deployment includes a Namespace, Deployments for both the web application and PostgreSQL database, a StatefulSet (with PersistentVolume and PersistentVolumeClaim), and Service. | ||||
| 
 | ||||
| ## Application Description | ||||
| - Simple shopping list application that allows users to add, mark as purchased, and delete items | ||||
| - Each item can have a quantity associated with it | ||||
| - All data is stored in PostgreSQL for persistence between application restarts | ||||
| - The application uses a Flask web framework with a minimalist interface | ||||
| 
 | ||||
| ## Containers | ||||
| - **simple-web-app**: Runs the Python Flask application on port 5000 | ||||
| - **postgres**: Runs PostgreSQL database to store shopping list items | ||||
| 
 | ||||
| ## Kubernetes Objects | ||||
| - **Namespace**: Isolates all the resources under `my-app` | ||||
| - **Deployment (Web App)**: Manages the stateless web application pods with 2 replicas for high availability | ||||
| - **Deployment (PostgreSQL)**: Manages the PostgreSQL database with persistent storage | ||||
| - **StatefulSet**: Manages stateful application pods that require persistent storage | ||||
| - **PersistentVolume (PV)**: Provides persistent storage from the host (1GB) | ||||
| - **PersistentVolumeClaim (PVC)**: Claims the PV for storage | ||||
| - **Service (Web App)**: Exposes the web application externally via LoadBalancer | ||||
| - **Service (PostgreSQL)**: Headless service for internal database access | ||||
| 
 | ||||
| ## Networking and Storage | ||||
| - Internal service discovery allows the web application to connect to PostgreSQL | ||||
| - PostgreSQL uses persistent storage to maintain shopping list data even if pods are restarted | ||||
| - The web application is exposed externally using a LoadBalancer service | ||||
| 
 | ||||
| ## Container Configuration | ||||
| - The web app container is based on Python and includes Flask and psycopg2 | ||||
| - PostgreSQL container uses the official PostgreSQL image | ||||
| - Resource limits and readiness probes are configured for better stability | ||||
| 
 | ||||
| ## How to Prepare, Run, Pause, and Delete the Application | ||||
| 
 | ||||
| 1. **Prepare the application:** | ||||
|    ```bash | ||||
|    ./prepare-app.sh | ||||
|    ``` | ||||
|    This script builds the Docker image and creates the directory for persistent volume. | ||||
| 
 | ||||
| 2. **Start the application:** | ||||
|    ```bash | ||||
|    ./start-app.sh | ||||
|    ``` | ||||
|    This script creates all necessary Kubernetes objects in the correct order, including PostgreSQL. | ||||
| 
 | ||||
| 3. **Pause or delete the application:** | ||||
|    ```bash | ||||
|    ./stop-app.sh | ||||
|    ``` | ||||
|    This script removes all Kubernetes objects created by `start-app.sh`. | ||||
| 
 | ||||
| ## Accessing the Application | ||||
| To access the application: | ||||
| 
 | ||||
| 1. Find the IP address of your Kubernetes node: | ||||
|    ```bash | ||||
|    kubectl get nodes -o wide | ||||
|    ``` | ||||
| 
 | ||||
| 2. Access the application in your browser at: | ||||
|    ``` | ||||
|    http://<NODE_IP>:80 | ||||
|    ``` | ||||
|    Where `<NODE_IP>` is the IP address of any of your Kubernetes nodes. | ||||
| 
 | ||||
| ## Application Features | ||||
| - Add items with quantity | ||||
| - Mark items as purchased/unpurchased | ||||
| - Delete items | ||||
| - Items list is separated into "to buy" and "purchased" sections | ||||
| - Data persists between sessions and application restarts | ||||
| 
 | ||||
| ## Database Schema | ||||
| The application uses a simple PostgreSQL schema: | ||||
| - Table: `shopping_items` | ||||
| - Fields: | ||||
|   - `id`: Serial primary key | ||||
|   - `item`: Text (item name) | ||||
|   - `quantity`: Integer (defaults to 1) | ||||
|   - `purchased`: Boolean flag (defaults to false) | ||||
| 
 | ||||
| ## Troubleshooting | ||||
| If you encounter issues: | ||||
| 
 | ||||
| 1. Check pod status: | ||||
|    ```bash | ||||
|    kubectl get pods -n my-app | ||||
|    ``` | ||||
| 
 | ||||
| 2. View pod logs: | ||||
|    ```bash | ||||
|    kubectl logs <pod-name> -n my-app | ||||
|    ``` | ||||
| 
 | ||||
| 3. Check service status: | ||||
|    ```bash | ||||
|    kubectl get svc -n my-app | ||||
|    ``` | ||||
| 
 | ||||
| 4. Check database connectivity: | ||||
|    ```bash | ||||
|    kubectl exec -it <web-app-pod-name> -n my-app -- python -c "import psycopg2; conn = psycopg2.connect(host='postgres', dbname='postgres', user='postgres', password='postgres'); print('Connection successful')" | ||||
|    ``` | ||||
							
								
								
									
										173
									
								
								z2/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								z2/app.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | ||||
| from flask import Flask, request, redirect, url_for, render_template_string | ||||
| import os | ||||
| import psycopg2 | ||||
| from psycopg2 import pool | ||||
| 
 | ||||
| app = Flask(__name__) | ||||
| 
 | ||||
| DB_HOST = os.environ.get('DB_HOST', 'localhost') | ||||
| DB_PORT = os.environ.get('DB_PORT', '5432') | ||||
| DB_NAME = os.environ.get('DB_NAME', 'postgres') | ||||
| DB_USER = os.environ.get('DB_USER', 'postgres') | ||||
| DB_PASS = os.environ.get('DB_PASS', 'postgres') | ||||
| 
 | ||||
| connection_pool = psycopg2.pool.SimpleConnectionPool( | ||||
|     1, 10, | ||||
|     host=DB_HOST, | ||||
|     port=DB_PORT, | ||||
|     database=DB_NAME, | ||||
|     user=DB_USER, | ||||
|     password=DB_PASS | ||||
| ) | ||||
| 
 | ||||
| def init_db(): | ||||
|     conn = connection_pool.getconn() | ||||
|     try: | ||||
|         with conn.cursor() as cur: | ||||
|             cur.execute(''' | ||||
|                 CREATE TABLE IF NOT EXISTS shopping_items ( | ||||
|                     id SERIAL PRIMARY KEY, | ||||
|                     item TEXT NOT NULL, | ||||
|                     quantity INTEGER DEFAULT 1, | ||||
|                     purchased BOOLEAN DEFAULT FALSE | ||||
|                 ); | ||||
|             ''') | ||||
|             conn.commit() | ||||
|     except Exception as e: | ||||
|         print(f"Erreur lors de l'initialisation de la base de données: {e}") | ||||
|         conn.rollback() | ||||
|     finally: | ||||
|         connection_pool.putconn(conn) | ||||
| 
 | ||||
| HTML_TEMPLATE = """ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Liste de Courses</title> | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
| </head> | ||||
| <body> | ||||
|     <h1>Ma Liste de Courses</h1> | ||||
|      | ||||
|     <form action="/add" method="post"> | ||||
|         <input type="text" name="item" placeholder="Article" required> | ||||
|         <input type="number" name="quantity" value="1" min="1"> | ||||
|         <button type="submit">Ajouter</button> | ||||
|     </form> | ||||
|      | ||||
|     <h2>Articles à acheter</h2> | ||||
|     <ul> | ||||
|         {% for item in items %} | ||||
|             {% if not item[3] %} | ||||
|                 <li> | ||||
|                     {{ item[1] }} ({{ item[2] }}) | ||||
|                     <form action="/toggle/{{ item[0] }}" method="post" style="display:inline"> | ||||
|                         <button type="submit">Acheté</button> | ||||
|                     </form> | ||||
|                     <form action="/delete/{{ item[0] }}" method="post" style="display:inline"> | ||||
|                         <button type="submit">Supprimer</button> | ||||
|                     </form> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|         {% endfor %} | ||||
|     </ul> | ||||
|      | ||||
|     <h2>Articles achetés</h2> | ||||
|     <ul> | ||||
|         {% for item in items %} | ||||
|             {% if item[3] %} | ||||
|                 <li> | ||||
|                     {{ item[1] }} ({{ item[2] }}) | ||||
|                     <form action="/toggle/{{ item[0] }}" method="post" style="display:inline"> | ||||
|                         <button type="submit">Non acheté</button> | ||||
|                     </form> | ||||
|                     <form action="/delete/{{ item[0] }}" method="post" style="display:inline"> | ||||
|                         <button type="submit">Supprimer</button> | ||||
|                     </form> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|         {% endfor %} | ||||
|     </ul> | ||||
| </body> | ||||
| </html> | ||||
| """ | ||||
| 
 | ||||
| @app.route('/') | ||||
| def index(): | ||||
|     conn = connection_pool.getconn() | ||||
|     try: | ||||
|         with conn.cursor() as cur: | ||||
|             cur.execute("SELECT id, item, quantity, purchased FROM shopping_items ORDER BY purchased, id") | ||||
|             items = cur.fetchall() | ||||
|     except Exception as e: | ||||
|         print(f"Erreur lors de la récupération des articles: {e}") | ||||
|         items = [] | ||||
|     finally: | ||||
|         connection_pool.putconn(conn) | ||||
|      | ||||
|     return render_template_string(HTML_TEMPLATE, items=items) | ||||
| 
 | ||||
| @app.route('/add', methods=['POST']) | ||||
| def add_item(): | ||||
|     item = request.form.get('item') | ||||
|     quantity = request.form.get('quantity', 1, type=int) | ||||
|      | ||||
|     conn = connection_pool.getconn() | ||||
|     try: | ||||
|         with conn.cursor() as cur: | ||||
|             cur.execute( | ||||
|                 "INSERT INTO shopping_items (item, quantity) VALUES (%s, %s)", | ||||
|                 (item, quantity) | ||||
|             ) | ||||
|             conn.commit() | ||||
|     except Exception as e: | ||||
|         print(f"Erreur lors de l'ajout d'un article: {e}") | ||||
|         conn.rollback() | ||||
|     finally: | ||||
|         connection_pool.putconn(conn) | ||||
|      | ||||
|     return redirect(url_for('index')) | ||||
| 
 | ||||
| @app.route('/toggle/<int:item_id>', methods=['POST']) | ||||
| def toggle_item(item_id): | ||||
|     conn = connection_pool.getconn() | ||||
|     try: | ||||
|         with conn.cursor() as cur: | ||||
|             cur.execute( | ||||
|                 "UPDATE shopping_items SET purchased = NOT purchased WHERE id = %s", | ||||
|                 (item_id,) | ||||
|             ) | ||||
|             conn.commit() | ||||
|     except Exception as e: | ||||
|         print(f"Erreur lors du basculement du statut: {e}") | ||||
|         conn.rollback() | ||||
|     finally: | ||||
|         connection_pool.putconn(conn) | ||||
|      | ||||
|     return redirect(url_for('index')) | ||||
| 
 | ||||
| @app.route('/delete/<int:item_id>', methods=['POST']) | ||||
| def delete_item(item_id): | ||||
|     conn = connection_pool.getconn() | ||||
|     try: | ||||
|         with conn.cursor() as cur: | ||||
|             cur.execute("DELETE FROM shopping_items WHERE id = %s", (item_id,)) | ||||
|             conn.commit() | ||||
|     except Exception as e: | ||||
|         print(f"Erreur lors de la suppression d'un article: {e}") | ||||
|         conn.rollback() | ||||
|     finally: | ||||
|         connection_pool.putconn(conn) | ||||
|      | ||||
|     return redirect(url_for('index')) | ||||
| 
 | ||||
| with app.app_context(): | ||||
|     try: | ||||
|         init_db() | ||||
|     except Exception as e: | ||||
|         print(f"Impossible d'initialiser la base de données: {e}") | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     port = int(os.environ.get("PORT", 5000)) | ||||
|     app.run(host='0.0.0.0', port=port, debug=True) | ||||
							
								
								
									
										51
									
								
								z2/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								z2/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: web-app-deployment | ||||
|   namespace: my-app | ||||
| spec: | ||||
|   replicas: 2   | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: web-app | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: web-app | ||||
|     spec: | ||||
|       containers: | ||||
|         - name: web-app-container | ||||
|           image: antonin193/simple-web-app:latest | ||||
|           imagePullPolicy: Always | ||||
|           ports: | ||||
|             - containerPort: 5000 | ||||
|           env: | ||||
|             - name: DB_HOST | ||||
|               value: postgres | ||||
|             - name: DB_PORT | ||||
|               value: "5432" | ||||
|             - name: DB_NAME | ||||
|               value: postgres | ||||
|             - name: DB_USER | ||||
|               value: postgres | ||||
|             - name: DB_PASS | ||||
|               value: postgres | ||||
|           resources: | ||||
|             requests: | ||||
|               memory: "64Mi" | ||||
|               cpu: "100m" | ||||
|             limits: | ||||
|               memory: "128Mi" | ||||
|               cpu: "200m" | ||||
|           readinessProbe: | ||||
|             httpGet: | ||||
|               path: / | ||||
|               port: 5000 | ||||
|             initialDelaySeconds: 15 | ||||
|             periodSeconds: 10 | ||||
|           livenessProbe: | ||||
|             httpGet: | ||||
|               path: / | ||||
|               port: 5000 | ||||
|             initialDelaySeconds: 20 | ||||
|             periodSeconds: 20 | ||||
							
								
								
									
										7
									
								
								z2/namespace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								z2/namespace.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| apiVersion: v1 | ||||
| kind: Namespace | ||||
| metadata: | ||||
|   name: my-app | ||||
|   labels: | ||||
|     name: my-app | ||||
|     environment: development | ||||
							
								
								
									
										29
									
								
								z2/persistent-storage.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								z2/persistent-storage.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| apiVersion: v1 | ||||
| kind: PersistentVolume | ||||
| metadata: | ||||
|   name: data-pv | ||||
|   namespace: my-app | ||||
|   labels: | ||||
|     type: local | ||||
| spec: | ||||
|   capacity: | ||||
|     storage: 1Gi | ||||
|   accessModes: | ||||
|     - ReadWriteOnce | ||||
|   persistentVolumeReclaimPolicy: Retain | ||||
|   storageClassName: manual | ||||
|   hostPath: | ||||
|     path: /data/stateful | ||||
| --- | ||||
| apiVersion: v1 | ||||
| kind: PersistentVolumeClaim | ||||
| metadata: | ||||
|   name: data-pvc | ||||
|   namespace: my-app | ||||
| spec: | ||||
|   accessModes: | ||||
|     - ReadWriteOnce | ||||
|   storageClassName: manual | ||||
|   resources: | ||||
|     requests: | ||||
|       storage: 1Gi | ||||
							
								
								
									
										44
									
								
								z2/postgres-deployment.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								z2/postgres-deployment.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: postgres | ||||
|   namespace: my-app | ||||
| spec: | ||||
|   replicas: 1 | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: postgres | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: postgres | ||||
|     spec: | ||||
|       containers: | ||||
|         - name: postgres | ||||
|           image: postgres:14 | ||||
|           imagePullPolicy: IfNotPresent | ||||
|           ports: | ||||
|             - containerPort: 5432 | ||||
|           env: | ||||
|             - name: POSTGRES_PASSWORD | ||||
|               value: postgres | ||||
|             - name: POSTGRES_USER | ||||
|               value: postgres | ||||
|             - name: POSTGRES_DB | ||||
|               value: postgres | ||||
|             - name: PGDATA | ||||
|               value: /var/lib/postgresql/data/pgdata | ||||
|           volumeMounts: | ||||
|             - name: postgres-storage | ||||
|               mountPath: /var/lib/postgresql/data | ||||
|           resources: | ||||
|             requests: | ||||
|               memory: "256Mi" | ||||
|               cpu: "200m" | ||||
|             limits: | ||||
|               memory: "512Mi" | ||||
|               cpu: "500m" | ||||
|       volumes: | ||||
|         - name: postgres-storage | ||||
|           persistentVolumeClaim: | ||||
|             claimName: data-pvc | ||||
							
								
								
									
										15
									
								
								z2/postgres-service.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								z2/postgres-service.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| apiVersion: v1 | ||||
| kind: Service | ||||
| metadata: | ||||
|   name: postgres | ||||
|   namespace: my-app | ||||
|   labels: | ||||
|     app: postgres | ||||
| spec: | ||||
|   selector: | ||||
|     app: postgres | ||||
|   ports: | ||||
|     - protocol: TCP | ||||
|       port: 5432 | ||||
|       targetPort: 5432 | ||||
|   clusterIP: None | ||||
							
								
								
									
										22
									
								
								z2/prepare-app.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								z2/prepare-app.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| #!/bin/bash | ||||
| # Script to prepare the application environment | ||||
| 
 | ||||
| export REGION="local" | ||||
| echo "Preparing deployment for region: $REGION" | ||||
| 
 | ||||
| # Make sure scripts are executable | ||||
| chmod +x start-app.sh stop-app.sh | ||||
| 
 | ||||
| # Build and tag Docker image | ||||
| docker build -t simple-web-app:latest . | ||||
| docker tag simple-web-app:latest antonin193/simple-web-app:latest | ||||
| 
 | ||||
| # Push to Docker Hub if needed | ||||
| echo "Pushing image to Docker Hub..." | ||||
| docker push antonin193/simple-web-app:latest | ||||
| 
 | ||||
| # Create directory for persistent volume (Docker Desktop supports hostPath) | ||||
| sudo mkdir -p /data/stateful | ||||
| sudo chmod 777 /data/stateful | ||||
| 
 | ||||
| echo "Preparation complete: Docker image built, tagged, and volume directory created." | ||||
							
								
								
									
										4
									
								
								z2/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								z2/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| Flask>=2.0.0 | ||||
| Werkzeug>=2.0.0 | ||||
| gunicorn>=20.1.0 | ||||
| psycopg2-binary>=2.9.3 | ||||
							
								
								
									
										16
									
								
								z2/service.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								z2/service.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| apiVersion: v1 | ||||
| kind: Service | ||||
| metadata: | ||||
|   name: web-app-service | ||||
|   namespace: my-app | ||||
|   labels: | ||||
|     app: web-app | ||||
| spec: | ||||
|   type: LoadBalancer | ||||
|   selector: | ||||
|     app: web-app | ||||
|   ports: | ||||
|     - protocol: TCP | ||||
|       port: 80  | ||||
|       targetPort: 5000   | ||||
|   sessionAffinity: None  | ||||
							
								
								
									
										82
									
								
								z2/start-app.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								z2/start-app.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | ||||
| #!/bin/bash | ||||
| # Script to deploy the app locally using Docker Desktop + Kubernetes | ||||
| 
 | ||||
| # Set default region (optional but kept for consistency) | ||||
| if [ -z "$REGION" ]; then | ||||
|     export REGION="local" | ||||
|     echo "No region specified. Using default region: $REGION" | ||||
| else | ||||
|     echo "Deploying to region: $REGION" | ||||
| fi | ||||
| 
 | ||||
| # Build Docker image | ||||
| echo "Building Docker image..." | ||||
| docker build -t antonin193/simple-web-app:latest . | ||||
| 
 | ||||
| # Push to Docker Hub (optional for local, but kept if needed across machines) | ||||
| echo "Pushing image to Docker Hub..." | ||||
| docker push antonin193/simple-web-app:latest | ||||
| 
 | ||||
| # Create Kubernetes Namespace | ||||
| echo "Creating namespace..." | ||||
| kubectl apply -f namespace.yaml | ||||
| 
 | ||||
| # Create PersistentVolume and PersistentVolumeClaim | ||||
| echo "Creating persistent storage..." | ||||
| kubectl apply -f persistent-storage.yaml | ||||
| 
 | ||||
| # Wait briefly for resources to be established | ||||
| sleep 2 | ||||
| 
 | ||||
| # Deploy PostgreSQL first | ||||
| echo "Creating PostgreSQL Deployment and Service..." | ||||
| kubectl apply -f postgres-deployment.yaml | ||||
| kubectl apply -f postgres-service.yaml | ||||
| 
 | ||||
| # Wait for PostgreSQL to be ready | ||||
| echo "Waiting for PostgreSQL to be ready..." | ||||
| kubectl wait --for=condition=ready pod -l app=postgres -n my-app --timeout=120s | ||||
| 
 | ||||
| # Deploy application | ||||
| echo "Creating Deployment..." | ||||
| kubectl apply -f deployment.yaml | ||||
| 
 | ||||
| echo "Creating StatefulSet..." | ||||
| kubectl apply -f statefulset.yaml | ||||
| 
 | ||||
| echo "Creating Service..." | ||||
| kubectl apply -f service.yaml | ||||
| 
 | ||||
| # Wait for LoadBalancer IP (Docker Desktop uses host network so it's usually localhost) | ||||
| echo "Waiting for LoadBalancer to obtain an external IP (or localhost for Docker Desktop)..." | ||||
| external_ip="" | ||||
| attempt=0 | ||||
| max_attempts=4 | ||||
| 
 | ||||
| while [ -z "$external_ip" ] && [ $attempt -lt $max_attempts ]; do | ||||
|     sleep 10 | ||||
|     attempt=$((attempt+1)) | ||||
|     external_ip=$(kubectl get svc web-app-service -n my-app --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}" 2>/dev/null) | ||||
|      | ||||
|     if [ -z "$external_ip" ]; then | ||||
|         echo "Waiting for external IP... Attempt $attempt of $max_attempts" | ||||
|     fi | ||||
| done | ||||
| 
 | ||||
| # Fallback to localhost if no external IP is found (common in Docker Desktop) | ||||
| if [ -z "$external_ip" ]; then | ||||
|     external_ip="localhost" | ||||
|     echo "" | ||||
|     echo "==========================================================" | ||||
|     echo "Could not get external IP from LoadBalancer. Defaulting to localhost." | ||||
|     echo "You can try accessing your app at: http://localhost:80" | ||||
|     echo "Or check service status manually with:" | ||||
|     echo "kubectl get svc web-app-service -n my-app" | ||||
|     echo "==========================================================" | ||||
| else | ||||
|     echo "" | ||||
|     echo "==========================================================" | ||||
|     echo "Application deployed successfully!" | ||||
|     echo "You can try accessing your app at: http://localhost:80" | ||||
|     echo "==========================================================" | ||||
| fi | ||||
							
								
								
									
										59
									
								
								z2/statefulset.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								z2/statefulset.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| apiVersion: apps/v1 | ||||
| kind: StatefulSet | ||||
| metadata: | ||||
|   name: stateful-app | ||||
|   namespace: my-app | ||||
| spec: | ||||
|   serviceName: "stateful-app" | ||||
|   replicas: 1 | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: stateful-app | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: stateful-app | ||||
|     spec: | ||||
|       containers: | ||||
|         - name: stateful-app-container | ||||
|           image: antonin193/simple-web-app:latest | ||||
|           imagePullPolicy: Always | ||||
|           ports: | ||||
|             - containerPort: 5000 | ||||
|           env: | ||||
|             - name: DB_HOST | ||||
|               value: postgres | ||||
|             - name: DB_PORT | ||||
|               value: "5432" | ||||
|             - name: DB_NAME | ||||
|               value: postgres | ||||
|             - name: DB_USER | ||||
|               value: postgres | ||||
|             - name: DB_PASS | ||||
|               value: postgres | ||||
|           resources: | ||||
|             requests: | ||||
|               memory: "64Mi" | ||||
|               cpu: "100m" | ||||
|             limits: | ||||
|               memory: "128Mi" | ||||
|               cpu: "200m" | ||||
|           volumeMounts: | ||||
|             - name: app-storage | ||||
|               mountPath: /data   | ||||
|           readinessProbe: | ||||
|             httpGet: | ||||
|               path: / | ||||
|               port: 5000 | ||||
|             initialDelaySeconds: 15 | ||||
|             periodSeconds: 20 | ||||
|   volumeClaimTemplates: | ||||
|     - metadata: | ||||
|         name: app-storage | ||||
|       spec: | ||||
|         accessModes: | ||||
|           - ReadWriteOnce | ||||
|         storageClassName: manual | ||||
|         resources: | ||||
|           requests: | ||||
|             storage: 1Gi | ||||
							
								
								
									
										55
									
								
								z2/stop-app.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								z2/stop-app.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| #!/bin/bash | ||||
| # Delete Kubernetes objects in reverse order | ||||
| 
 | ||||
| # Check if REGION environment variable is set | ||||
| if [ -z "$REGION" ]; then | ||||
|     # Default region if not set | ||||
|     export REGION="westeurope" | ||||
|     echo "No region specified. Using default region: $REGION" | ||||
| else | ||||
|     echo "Stopping application in region: $REGION" | ||||
| fi | ||||
| 
 | ||||
| # For AKS deployments, make sure we're connected to the right cluster | ||||
| if command -v az &> /dev/null; then | ||||
|     echo "Checking AKS connection for region $REGION..." | ||||
|     # You might need to adjust these parameters based on your specific Azure setup | ||||
|     RESOURCE_GROUP="flask-rg-$REGION" | ||||
|     CLUSTER_NAME="flask-aks-$REGION" | ||||
|      | ||||
|     # Try to connect to the Azure cluster | ||||
|     if ! az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --overwrite-existing 2>/dev/null; then | ||||
|         echo "Warning: Could not connect to AKS cluster in $REGION. Continuing with current kubectl context." | ||||
|     else | ||||
|         echo "Successfully connected to AKS cluster in $REGION" | ||||
|     fi | ||||
| fi | ||||
| 
 | ||||
| echo "Stopping application..." | ||||
| 
 | ||||
| # Delete Service first to stop incoming traffic | ||||
| kubectl delete -f service.yaml 2>/dev/null || echo "Service could not be deleted or does not exist." | ||||
| 
 | ||||
| # Delete StatefulSet and wait for pods to terminate | ||||
| kubectl delete -f statefulset.yaml 2>/dev/null || echo "StatefulSet could not be deleted or does not exist." | ||||
| 
 | ||||
| # Delete Deployment | ||||
| kubectl delete -f deployment.yaml 2>/dev/null || echo "Deployment could not be deleted or does not exist." | ||||
| 
 | ||||
| # Delete PostgreSQL objects | ||||
| kubectl delete -f postgres-service.yaml 2>/dev/null || echo "PostgreSQL service could not be deleted or does not exist." | ||||
| kubectl delete -f postgres-deployment.yaml 2>/dev/null || echo "PostgreSQL deployment could not be deleted or does not exist." | ||||
| 
 | ||||
| # Wait for pods to terminate | ||||
| echo "Waiting for pods to terminate..." | ||||
| kubectl wait --for=delete pod --selector=app=web-app -n my-app --timeout=60s 2>/dev/null || true | ||||
| kubectl wait --for=delete pod --selector=app=stateful-app -n my-app --timeout=60s 2>/dev/null || true | ||||
| kubectl wait --for=delete pod --selector=app=postgres -n my-app --timeout=60s 2>/dev/null || true | ||||
| 
 | ||||
| # Delete PersistentVolume and PersistentVolumeClaim | ||||
| kubectl delete -f persistent-storage.yaml 2>/dev/null || echo "PersistentVolume and PersistentVolumeClaim could not be deleted or do not exist." | ||||
| 
 | ||||
| # Delete Namespace (this will delete all resources in the namespace) | ||||
| kubectl delete -f namespace.yaml 2>/dev/null || echo "Namespace could not be deleted or does not exist." | ||||
| 
 | ||||
| echo "Application stopped in region $REGION: All Kubernetes objects have been deleted." | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user