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