Téléverser les fichiers vers "z2"
This commit is contained in:
parent
b868e51ed4
commit
0ed027d8f6
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"]
|
31
z2/README.md
Normal file
31
z2/README.md
Normal 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
112
z2/app.py
Normal 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
50
z2/deployment.yaml
Normal 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
4
z2/namespace.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: my-app
|
12
z2/persistent-storage.yaml
Normal file
12
z2/persistent-storage.yaml
Normal 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
|
33
z2/postgres-deployment.yaml
Normal file
33
z2/postgres-deployment.yaml
Normal 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
12
z2/postgres-service.yaml
Normal 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
11
z2/prepare-app.sh
Normal 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
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
|
13
z2/service.yaml
Normal file
13
z2/service.yaml
Normal 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
29
z2/start-app.sh
Normal 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 you’ve 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
24
z2/stop-app.sh
Normal 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."
|
Loading…
Reference in New Issue
Block a user