diff --git a/z2/Dockerfile b/z2/Dockerfile
new file mode 100644
index 0000000..a62458e
--- /dev/null
+++ b/z2/Dockerfile
@@ -0,0 +1,16 @@
+FROM python:3.9-slim
+
+WORKDIR /app
+
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY app.py .
+
+ENV FLASK_APP=app.py
+ENV FLASK_RUN_HOST=0.0.0.0
+ENV FLASK_RUN_PORT=5000
+
+EXPOSE 5000
+
+CMD ["flask", "run"]
\ No newline at end of file
diff --git a/z2/README.md b/z2/README.md
new file mode 100644
index 0000000..a53d8ac
--- /dev/null
+++ b/z2/README.md
@@ -0,0 +1,60 @@
+# Blog Application with Kubernetes
+
+This project deploys a simple blog application with Flask and PostgreSQL on Kubernetes.
+
+## Application Features
+
+- Create and publish blog articles with title and content
+- View all articles in a responsive interface
+- Delete articles with a single click
+- Persistent storage for database content
+
+## Architecture
+
+The application consists of:
+- Flask web application for creating and deleting blog articles
+- PostgreSQL database to store the articles
+- Kubernetes deployment for orchestration and scaling
+
+## Technologies Used
+
+- **Frontend**: HTML, CSS, Flask Templates
+- **Backend**: Python, Flask
+- **Database**: PostgreSQL
+- **Container**: Docker
+- **Orchestration**: Kubernetes, Minikube
+
+## Deployment Instructions
+
+### Prerequisites
+- Docker
+- Minikube
+- kubectl
+
+### Step 1: Preparation
+Run the preparation script to create the namespace and build the Docker image:
+```
+chmod +x prepare-app.sh
+./prepare-app.sh
+```
+
+### Step 2: Deployment
+Launch the application with:
+```
+chmod +x start-app.sh
+./start-app.sh
+```
+
+### Step 3: Access the Application
+Get the application URL with:
+```
+minikube service blog-app-service -n myapp-namespace --url
+```
+Open this URL in your browser to access the blog application.
+
+### Step 4: Shutdown
+When finished, clean up all resources with:
+```
+chmod +x stop-app.sh
+./stop-app.sh
+```
\ No newline at end of file
diff --git a/z2/app.py b/z2/app.py
new file mode 100644
index 0000000..df8a3e3
--- /dev/null
+++ b/z2/app.py
@@ -0,0 +1,136 @@
+from flask import Flask, request, jsonify
+import os
+import psycopg2
+import time
+
+app = Flask(__name__)
+
+# Database Configuration
+db_host = os.environ.get("DB_HOST", "blog-db-service")
+db_name = os.environ.get("POSTGRES_DB", "blogdb")
+db_user = os.environ.get("POSTGRES_USER", "admin")
+db_password = os.environ.get("POSTGRES_PASSWORD", "password")
+
+def get_db_connection():
+ return psycopg2.connect(host=db_host, database=db_name, user=db_user, password=db_password)
+
+def create_table():
+ max_retries = 10
+ retry_delay = 5 # seconds
+
+ for attempt in range(max_retries):
+ try:
+ print(f"Attempt {attempt+1}/{max_retries} to connect to database...")
+ conn = get_db_connection()
+ cur = conn.cursor()
+ cur.execute('''
+ CREATE TABLE IF NOT EXISTS articles (
+ id SERIAL PRIMARY KEY,
+ title TEXT NOT NULL,
+ content TEXT NOT NULL
+ )
+ ''')
+ conn.commit()
+ cur.close()
+ conn.close()
+ print("Table 'articles' created successfully")
+ return True
+ except Exception as e:
+ print(f"Database connection attempt {attempt+1}/{max_retries} failed: {e}")
+ if attempt < max_retries - 1:
+ print(f"Retrying in {retry_delay} seconds...")
+ time.sleep(retry_delay)
+
+ print("Failed to create table after multiple attempts")
+ return False
+
+# Initialize the variable at startup
+table_created = False
+
+@app.route("/", methods=["GET", "POST"])
+def index():
+ global table_created
+
+ # If the table is not yet created, try to create it
+ if not table_created:
+ table_created = create_table()
+
+ # Check if the table has been created before continuing
+ if not table_created:
+ return "Database connection failed. Please try again later.", 500
+
+ try:
+ conn = get_db_connection()
+ cur = conn.cursor()
+
+ if request.method == "POST":
+ title = request.form.get("title")
+ content = request.form.get("content")
+ if title and content:
+ cur.execute("INSERT INTO articles (title, content) VALUES (%s, %s)", (title, content))
+ conn.commit()
+
+ cur.execute("SELECT * FROM articles ORDER BY id DESC")
+ articles = cur.fetchall()
+ cur.close()
+ conn.close()
+
+ return f"""
+
+
+ My Blog
+
+
+
+
+
+
My Blog
+
+
+
+
Articles
+ {''.join(f'
' for a in articles)}
+
+
+
+
+ """
+ except Exception as e:
+ return f"An error occurred: {str(e)}", 500
+
+@app.route("/delete/", methods=["POST"])
+def delete_article(article_id):
+ try:
+ conn = get_db_connection()
+ cur = conn.cursor()
+ cur.execute("DELETE FROM articles WHERE id = %s", (article_id,))
+ conn.commit()
+ cur.close()
+ conn.close()
+ return ""
+ except Exception as e:
+ return f"An error occurred while deleting: {str(e)}", 500
+
+if __name__ == "__main__":
+ create_table()
+ app.run(host="0.0.0.0", port=5000)
\ No newline at end of file
diff --git a/z2/deployment.yaml b/z2/deployment.yaml
new file mode 100644
index 0000000..c6dd034
--- /dev/null
+++ b/z2/deployment.yaml
@@ -0,0 +1,32 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: blog-app
+ namespace: myapp-namespace
+ labels:
+ app: blog
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: blog
+ template:
+ metadata:
+ labels:
+ app: blog
+ spec:
+ containers:
+ - name: blog-app
+ image: blog-app:latest
+ imagePullPolicy: Never
+ ports:
+ - containerPort: 5000
+ env:
+ - name: DB_HOST
+ value: "blog-db-service"
+ - name: POSTGRES_DB
+ value: "blogdb"
+ - name: POSTGRES_USER
+ value: "admin"
+ - name: POSTGRES_PASSWORD
+ value: "password"
\ No newline at end of file
diff --git a/z2/namespace.yaml b/z2/namespace.yaml
new file mode 100644
index 0000000..e14643a
--- /dev/null
+++ b/z2/namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: myapp-namespace
\ No newline at end of file
diff --git a/z2/prepare-app.sh b/z2/prepare-app.sh
new file mode 100644
index 0000000..5bedeeb
--- /dev/null
+++ b/z2/prepare-app.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Create the namespace
+kubectl apply -f namespace.yaml
+
+# Build the Docker image
+docker build -t blog-app:latest .
+
+# Ensure minikube uses the local image
+eval $(minikube docker-env)
+docker build -t blog-app:latest .
+
+# Start Minikube if it's not already running
+if ! minikube status | grep -q "Running"; then
+ minikube start
+fi
+
+echo "Preparation complete. You can now run ./start-app.sh"
\ No newline at end of file
diff --git a/z2/requirements.txt b/z2/requirements.txt
new file mode 100644
index 0000000..8860e6a
--- /dev/null
+++ b/z2/requirements.txt
@@ -0,0 +1,3 @@
+Flask
+psycopg2-binary
+requests
\ No newline at end of file
diff --git a/z2/service.yaml b/z2/service.yaml
new file mode 100644
index 0000000..6b18866
--- /dev/null
+++ b/z2/service.yaml
@@ -0,0 +1,30 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: blog-app-service
+ namespace: myapp-namespace
+spec:
+ selector:
+ app: blog
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 5000
+ nodePort: 30080
+ type: NodePort
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: blog-db-service
+ namespace: myapp-namespace
+spec:
+ selector:
+ app: blog-db
+ ports:
+ - protocol: TCP
+ port: 5432
+ targetPort: 5432
+ type: ClusterIP
\ No newline at end of file
diff --git a/z2/start-app.sh b/z2/start-app.sh
new file mode 100644
index 0000000..875945d
--- /dev/null
+++ b/z2/start-app.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Create the namespace if it doesn't already exist
+kubectl apply -f namespace.yaml
+
+# Create the statefulset for the database
+kubectl apply -f statefulset.yaml
+
+# Create the deployment for the application
+kubectl apply -f deployment.yaml
+
+# Create the services
+kubectl apply -f service.yaml
+
+# Display created resources
+echo "Resources created:"
+kubectl get all -n myapp-namespace
\ No newline at end of file
diff --git a/z2/statefulset.yaml b/z2/statefulset.yaml
new file mode 100644
index 0000000..e55aa29
--- /dev/null
+++ b/z2/statefulset.yaml
@@ -0,0 +1,40 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: blog-db
+ namespace: myapp-namespace
+spec:
+ serviceName: "blog-db-service"
+ replicas: 1
+ selector:
+ matchLabels:
+ app: blog-db
+ template:
+ metadata:
+ labels:
+ app: blog-db
+ spec:
+ containers:
+ - name: postgres
+ image: postgres:13
+ ports:
+ - containerPort: 5432
+ env:
+ - name: POSTGRES_DB
+ value: "blogdb"
+ - name: POSTGRES_USER
+ value: "admin"
+ - name: POSTGRES_PASSWORD
+ value: "password"
+ volumeMounts:
+ - name: postgres-storage
+ mountPath: /var/lib/postgresql/data
+ subPath: pgdata
+ volumeClaimTemplates:
+ - metadata:
+ name: postgres-storage
+ spec:
+ accessModes: ["ReadWriteOnce"]
+ resources:
+ requests:
+ storage: 1Gi
\ No newline at end of file
diff --git a/z2/stop-app.sh b/z2/stop-app.sh
new file mode 100644
index 0000000..16cd0f3
--- /dev/null
+++ b/z2/stop-app.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Delete services
+kubectl delete -f service.yaml
+
+# Delete deployment
+kubectl delete -f deployment.yaml
+
+# Delete statefulset
+kubectl delete -f statefulset.yaml
+
+# Delete namespace
+kubectl delete -f namespace.yaml
+
+echo "All resources have been deleted."
\ No newline at end of file