Téléverser les fichiers vers "z2"

This commit is contained in:
Antonin Filippi 2025-04-23 07:19:30 +00:00
parent b868e51ed4
commit 0ed027d8f6
13 changed files with 347 additions and 0 deletions

12
z2/Dockerfile Normal file
View 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"]

31
z2/README.md Normal file
View File

@ -0,0 +1,31 @@
# Shopping List Web App on Kubernetes (Local)
This project deploys a Flask-based shopping list app with PostgreSQL on a local Kubernetes cluster (Docker Desktop).
## Prerequisites
- Docker Desktop with Kubernetes enabled
- kubectl configured for `docker-desktop` context
## Files
- `namespace.yaml`: Kubernetes namespace
- `persistent-storage.yaml`: PVC for Postgres data
- `postgres-deployment.yaml` / `postgres-service.yaml`: Postgres setup
- `deployment.yaml` / `service.yaml`: Web app setup
- `prepare-app.sh`: build Docker image
- `start-app.sh`: apply Kubernetes resources
- `stop-app.sh`: delete all resources
## Usage
1. Build the image:
```bash
./prepare-app.sh
2. Deploy to Kubernetes:
```bash
./start-app.sh
3. Access the app:
Open http://localhost:80 in your browser
4. Clean up :
./stop-app.sh

112
z2/app.py Normal file
View File

@ -0,0 +1,112 @@
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.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '5432')
DB_NAME = os.getenv('DB_NAME', 'postgres')
DB_USER = os.getenv('DB_USER', 'postgres')
DB_PASS = os.getenv('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
)
# Initialize database schema
with connection_pool.getconn() as conn:
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()
HTML = """
<!DOCTYPE html>
<html>
<head>
<title>Shopping List</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Shopping List</h1>
<form action="/add" method="post">
<input name="item" placeholder="Item" required>
<input name="quantity" type="number" value="1" min="1">
<button type="submit">Add</button>
</form>
<ul>
{% for id, name, qty, done in items %}
<li>
{{ name }} ({{ qty }})
{% if not done %}
<form action="/toggle/{{ id }}" method="post" style="display:inline">
<button type="submit">Mark Purchased</button>
</form>
{% else %}
<form action="/toggle/{{ id }}" method="post" style="display:inline">
<button type="submit">Unmark</button>
</form>
{% endif %}
<form action="/delete/{{ id }}" method="post" style="display:inline">
<button type="submit">Delete</button>
</form>
</li>
{% endfor %}
</ul>
</body>
</html>
"""
@app.route('/')
def index():
conn = connection_pool.getconn()
with conn.cursor() as cur:
cur.execute("SELECT id, item, quantity, purchased FROM shopping_items ORDER BY purchased, id")
items = cur.fetchall()
connection_pool.putconn(conn)
return render_template_string(HTML, items=items)
@app.route('/add', methods=['POST'])
def add_item():
item = request.form['item']
qty = int(request.form.get('quantity', 1))
conn = connection_pool.getconn()
with conn.cursor() as cur:
cur.execute("INSERT INTO shopping_items (item, quantity) VALUES (%s, %s)", (item, qty))
conn.commit()
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()
with conn.cursor() as cur:
cur.execute("UPDATE shopping_items SET purchased=NOT purchased WHERE id=%s", (item_id,))
conn.commit()
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()
with conn.cursor() as cur:
cur.execute("DELETE FROM shopping_items WHERE id=%s", (item_id,))
conn.commit()
connection_pool.putconn(conn)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

50
z2/deployment.yaml Normal file
View File

@ -0,0 +1,50 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: my-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
initContainers:
- name: wait-for-postgres
image: busybox
command:
- sh
- -c
- |
until nc -z postgres 5432; do
echo "Waiting for PostgreSQL..."
sleep 2
done
containers:
- name: web
# use the LOCAL image you just built, not the one on Docker Hub
image: simple-web-app:latest
imagePullPolicy: IfNotPresent
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
readinessProbe:
httpGet:
path: /
port: 5000
initialDelaySeconds: 15
periodSeconds: 10

4
z2/namespace.yaml Normal file
View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: my-app

View File

@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
namespace: my-app
spec:
accessModes:
- ReadWriteOnce
storageClassName: docker-desktop
resources:
requests:
storage: 1Gi

View File

@ -0,0 +1,33 @@
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
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: postgres
- name: POSTGRES_DB
value: postgres
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
emptyDir: {}

12
z2/postgres-service.yaml Normal file
View File

@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: my-app
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
clusterIP: None

11
z2/prepare-app.sh Normal file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Prepare the environment: build Docker image
set -e
IMAGE_NAME="simple-web-app:latest"
echo "Building Docker image ${IMAGE_NAME}..."
docker build -t ${IMAGE_NAME} .
echo "Preparation complete."

4
z2/requirements.txt Normal file
View File

@ -0,0 +1,4 @@
Flask>=2.0.0
Werkzeug>=2.0.0
gunicorn>=20.1.0
psycopg2-binary>=2.9.3

13
z2/service.yaml Normal file
View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: web
namespace: my-app
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 5000
nodePort: 30080

29
z2/start-app.sh Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Deploy the application to local Kubernetes
set -e
# Ensure kubectl uses the local Docker Desktop cluster
kubectl config use-context docker-desktop
NAMESPACE="my-app"
echo "Creating namespace..."
kubectl apply -f namespace.yaml
# (optional) if youve switched to emptyDir for Postgres storage, skip PVC
# echo "Creating PersistentVolumeClaim..."
# kubectl apply -f persistent-storage.yaml
echo "Deploying PostgreSQL..."
kubectl apply -f postgres-deployment.yaml
kubectl apply -f postgres-service.yaml
echo "Waiting for PostgreSQL pod(s) to be ready..."
kubectl wait --for=condition=ready pod -l app=postgres -n ${NAMESPACE} --timeout=120s
echo "Deploying web application..."
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
echo "Deployment complete. Access the app at http://localhost:30080"

24
z2/stop-app.sh Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Remove the application from local Kubernetes
set -e
kubectl config use-context docker-desktop
NAMESPACE="my-app"
echo "Deleting web application..."
kubectl delete -f service.yaml -n ${NAMESPACE} --ignore-not-found
kubectl delete -f deployment.yaml -n ${NAMESPACE} --ignore-not-found
echo "Deleting PostgreSQL..."
kubectl delete -f postgres-service.yaml -n ${NAMESPACE} --ignore-not-found
kubectl delete -f postgres-deployment.yaml -n ${NAMESPACE} --ignore-not-found
echo "Deleting storage..."
kubectl delete -f persistent-storage.yaml -n ${NAMESPACE} --ignore-not-found
echo "Deleting namespace..."
kubectl delete -f namespace.yaml --ignore-not-found
echo "Cleanup complete."