reuploading assignments to git
This commit is contained in:
parent
5380e26a33
commit
f7988f1f2d
64
assignment1/README.md
Normal file
64
assignment1/README.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Docker Web Application Deployment
|
||||||
|
|
||||||
|
The application consists of two services:
|
||||||
|
|
||||||
|
1. **Web Service (Nginx):**
|
||||||
|
- Uses the official Nginx image.
|
||||||
|
- Listens on port 80 inside the container and is mapped to host port 8080.
|
||||||
|
2. **Database Service (MySQL 5.7):**
|
||||||
|
- Uses the official MySQL 5.7 image.
|
||||||
|
- Configured with a root password and a default database.
|
||||||
|
- Persists its data using the named volume `mysql-data`.
|
||||||
|
|
||||||
|
## Files Overview
|
||||||
|
|
||||||
|
- **prepare-app.sh:**
|
||||||
|
- Creates the required Docker network (`myapp-net`) and persistent volume (`mysql-data`).
|
||||||
|
- **docker-compose.yaml:**
|
||||||
|
- Defines the two services along with their ports, environment variables, volumes, and restart policies.
|
||||||
|
- **start-app.sh:**
|
||||||
|
- Starts the services using Docker Compose in detached mode.
|
||||||
|
- Displays the URL to access the web service.
|
||||||
|
- **stop-app.sh:**
|
||||||
|
- Stops the running containers without deleting the persistent volume.
|
||||||
|
- **remove-app.sh:**
|
||||||
|
- Removes all the created resources (containers, network, and volume) from the deployment.
|
||||||
|
|
||||||
|
## Deployment Instructions
|
||||||
|
|
||||||
|
1. **Preparation:**
|
||||||
|
- Ensure Docker and Docker Compose are installed.
|
||||||
|
- Make the scripts executable:
|
||||||
|
```bash
|
||||||
|
chmod +x prepare-app.sh start-app.sh stop-app.sh remove-app.sh
|
||||||
|
```
|
||||||
|
- Run the preparation script:
|
||||||
|
```bash
|
||||||
|
./prepare-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Starting the Application:**
|
||||||
|
- Launch the services by running:
|
||||||
|
```bash
|
||||||
|
./start-app.sh
|
||||||
|
```
|
||||||
|
- Open your web browser and navigate to [http://localhost:8080](http://localhost:8080) to see the Nginx welcome page.
|
||||||
|
|
||||||
|
3. **Stopping the Application:**
|
||||||
|
- Stop the services without losing data:
|
||||||
|
```bash
|
||||||
|
./stop-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Removing the Application:**
|
||||||
|
- To completely remove all deployed resources, run:
|
||||||
|
```bash
|
||||||
|
./remove-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- The application uses an external network (`myapp-net`) and a persistent volume (`mysql-data`) that are created in `prepare-app.sh`.
|
||||||
|
- The Nginx container depends on the MySQL container to demonstrate inter-service communication within the `myapp-net` network.
|
||||||
|
- Containers are configured to restart on failure.
|
||||||
|
|
32
assignment1/docker-compose.yaml
Normal file
32
assignment1/docker-compose.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
networks:
|
||||||
|
- myapp-net
|
||||||
|
restart: on-failure
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:5.7
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: example
|
||||||
|
MYSQL_DATABASE: appdb
|
||||||
|
volumes:
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- myapp-net
|
||||||
|
restart: on-failure
|
||||||
|
|
||||||
|
networks:
|
||||||
|
myapp-net:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
external: true
|
||||||
|
|
20
assignment1/prepare-app.sh
Executable file
20
assignment1/prepare-app.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# prepare-app.sh
|
||||||
|
|
||||||
|
if ! docker network ls | grep -w myapp-net >/dev/null; then
|
||||||
|
docker network create myapp-net
|
||||||
|
echo "Created Docker network: myapp-net"
|
||||||
|
else
|
||||||
|
echo "Docker network myapp-net already exists."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if ! docker volume ls | grep -w mysql-data >/dev/null; then
|
||||||
|
docker volume create mysql-data
|
||||||
|
echo "Created Docker volume: mysql-data"
|
||||||
|
else
|
||||||
|
echo "Docker volume mysql-data already exists."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Preparation complete."
|
||||||
|
|
10
assignment1/remove-app.sh
Executable file
10
assignment1/remove-app.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# remove-app.sh
|
||||||
|
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
docker volume rm mysql-data
|
||||||
|
docker network rm myapp-net
|
||||||
|
|
||||||
|
echo "All application resources removed."
|
||||||
|
|
9
assignment1/start-app.sh
Executable file
9
assignment1/start-app.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# start-app.sh
|
||||||
|
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
echo "Application started. Access the web service at http://localhost:8080"
|
||||||
|
|
6
assignment1/stop-app.sh
Executable file
6
assignment1/stop-app.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# stop-app.sh
|
||||||
|
|
||||||
|
docker-compose stop
|
||||||
|
echo "Application services stopped. Persistent data remains intact."
|
||||||
|
|
BIN
assignment2/.prepare-app.sh.swp
Normal file
BIN
assignment2/.prepare-app.sh.swp
Normal file
Binary file not shown.
2
assignment2/Dockerfile
Normal file
2
assignment2/Dockerfile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
COPY weather.html /usr/share/nginx/html/index.html
|
6
assignment2/Dockerfile.api
Normal file
6
assignment2/Dockerfile.api
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FROM node:18-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY server.js .
|
||||||
|
RUN npm init -y && npm install express pg body-parser
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "server.js"]
|
136
assignment2/README.md
Normal file
136
assignment2/README.md
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
# Weather Web App - Kubernetes Deployment
|
||||||
|
|
||||||
|
This project deploys a full-stack weather web application to Kubernetes. It includes:
|
||||||
|
- A frontend website to search weather by city
|
||||||
|
- A backend PostgreSQL database for logging searches
|
||||||
|
- A Node.js API to connect the frontend to the database
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Application Description
|
||||||
|
|
||||||
|
- **Frontend (weather.html):** A responsive, modern web UI that shows current weather data using the OpenWeatherMap API.
|
||||||
|
- **Backend (PostgreSQL):** Stores weather search history via a `weather_log` table.
|
||||||
|
- **API Server (Node.js):** Receives weather data from the frontend and logs it to the PostgreSQL database.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Containers Used
|
||||||
|
|
||||||
|
| Container | Image | Description |
|
||||||
|
|------------------|--------------------|----------------------------------------------|
|
||||||
|
| `weather-frontend` | Custom Nginx-based | Serves the `weather.html` UI |
|
||||||
|
| `postgres` | `postgres:15` | Provides relational database backend |
|
||||||
|
| `weather-api` | Custom Node.js | API that logs weather data to PostgreSQL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ☸️ Kubernetes Objects
|
||||||
|
|
||||||
|
| Object Type | File | Description |
|
||||||
|
|------------------------|----------------------|----------------------------------------------------------------------|
|
||||||
|
| `Namespace` | (inside script) | Isolates resources under `webapp-ns` |
|
||||||
|
| `Deployment` | `deployment.yaml` | Manages frontend app |
|
||||||
|
| `Deployment` | `deployment-api.yaml` | Manages the Node.js API |
|
||||||
|
| `StatefulSet` | `statefulset.yaml` | Manages PostgreSQL instance with persistent volume |
|
||||||
|
| `PersistentVolume` | `statefulset.yaml` | Host-mounted volume for PostgreSQL data |
|
||||||
|
| `PersistentVolumeClaim`| `statefulset.yaml` | Requests storage for StatefulSet |
|
||||||
|
| `Service` | `service.yaml` | Exposes frontend via NodePort |
|
||||||
|
| `Service` | `deployment-api.yaml` | Exposes API via NodePort |
|
||||||
|
| `ConfigMap` | Created by script | Stores `init-db.sql` used to create the `weather_log` table |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Networking & Volumes
|
||||||
|
|
||||||
|
### Virtual Networks:
|
||||||
|
- Kubernetes handles inter-service communication via internal DNS and `ClusterIP` services.
|
||||||
|
- Frontend and backend are externally reachable using `NodePort` services.
|
||||||
|
|
||||||
|
### Volumes:
|
||||||
|
- `PersistentVolume` and `PersistentVolumeClaim` ensure PostgreSQL data is retained.
|
||||||
|
- `ConfigMap` mounts the SQL init script for PostgreSQL setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Container Configurations
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- Dockerfile uses `nginx:alpine`
|
||||||
|
- Serves `weather.html` (renamed as `index.html` inside container)
|
||||||
|
- Exposed on port `80`
|
||||||
|
|
||||||
|
### Node.js API
|
||||||
|
- Built with Node.js 18
|
||||||
|
- Listens on port `3000`
|
||||||
|
- Connects to PostgreSQL using service DNS
|
||||||
|
- Accepts POST requests at `/log` with weather data
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
- `postgres:15` with `weatheruser`, `weatherpass`, and `weatherdb`
|
||||||
|
- Init script creates a `weather_log` table with a sample row
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Use the Application
|
||||||
|
|
||||||
|
### 1. Build Docker Images
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./prepare-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Start the App (create namespace and apply all configs)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./start-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. View the App
|
||||||
|
|
||||||
|
```bash
|
||||||
|
minikube service weather-service -n webapp-ns
|
||||||
|
```
|
||||||
|
|
||||||
|
Or get the NodePort manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get svc -n webapp-ns
|
||||||
|
minikube ip
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open:
|
||||||
|
```
|
||||||
|
http://<minikube-ip>:<frontend-nodeport>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Use the App
|
||||||
|
- Enter a city
|
||||||
|
- Weather will be shown
|
||||||
|
- Data is logged in PostgreSQL automatically
|
||||||
|
|
||||||
|
### 5. Stop and Clean Up
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./stop-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Key Setup
|
||||||
|
|
||||||
|
- Register at [OpenWeatherMap](https://openweathermap.org/api)
|
||||||
|
- Get your free API key
|
||||||
|
- Replace the placeholder in `weather.html`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const apiKey = "YOUR_API_KEY";
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
- Frontend calls OpenWeatherMap and logs data to your backend
|
||||||
|
- PostgreSQL is prepped with a table to store queries
|
||||||
|
- You can expand the API to serve saved data or stats
|
36
assignment2/deployment-api.yaml
Normal file
36
assignment2/deployment-api.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: weather-api
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: weather-api
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: weather-api
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: weather-api
|
||||||
|
image: weather-api:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: weather-api-service
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: weather-api
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 3000
|
||||||
|
targetPort: 3000
|
||||||
|
nodePort: 31000
|
||||||
|
type: NodePort
|
||||||
|
|
22
assignment2/deployment.yaml
Normal file
22
assignment2/deployment.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: weather-frontend
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: weather-frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: weather-frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: weather-frontend
|
||||||
|
image: weather-frontend:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
|
11
assignment2/init-db.sql
Normal file
11
assignment2/init-db.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS weather_log (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
city VARCHAR(100),
|
||||||
|
temperature DECIMAL(5,2),
|
||||||
|
description TEXT,
|
||||||
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO weather_log (city, temperature, description)
|
||||||
|
VALUES ('London', 15.5, 'partly cloudy');
|
||||||
|
|
BIN
assignment2/minikube-linux-amd64
Normal file
BIN
assignment2/minikube-linux-amd64
Normal file
Binary file not shown.
11
assignment2/prepare-app.sh
Executable file
11
assignment2/prepare-app.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
IMAGE_NAME=weather-frontend
|
||||||
|
IMAGE_TAG=latest
|
||||||
|
|
||||||
|
echo "🔧 Building Docker image: $IMAGE_NAME:$IMAGE_TAG"
|
||||||
|
docker build -t $IMAGE_NAME:$IMAGE_TAG .
|
||||||
|
docker build -t weather-api:latest -f Dockerfile.api .
|
||||||
|
|
||||||
|
echo "✅ Build complete."
|
||||||
|
|
35
assignment2/server.js
Normal file
35
assignment2/server.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const { Pool } = require('pg');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
const pool = new Pool({
|
||||||
|
host: 'postgres-0.postgres.webapp-ns.svc.cluster.local',
|
||||||
|
user: 'weatheruser',
|
||||||
|
password: 'weatherpass',
|
||||||
|
database: 'weatherdb',
|
||||||
|
port: 5432
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/log', async (req, res) => {
|
||||||
|
const { city, temperature, description } = req.body;
|
||||||
|
try {
|
||||||
|
await pool.query(
|
||||||
|
'INSERT INTO weather_log (city, temperature, description) VALUES ($1, $2, $3)',
|
||||||
|
[city, temperature, description]
|
||||||
|
);
|
||||||
|
res.status(200).send('Logged!');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).send('Error saving data');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Weather API listening on port ${port}`);
|
||||||
|
});
|
||||||
|
|
14
assignment2/service.yaml
Normal file
14
assignment2/service.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: weather-service
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: weather-frontend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
type: NodePort
|
||||||
|
|
17
assignment2/start-app.sh
Executable file
17
assignment2/start-app.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🚀 Creating namespace 'webapp-ns'..."
|
||||||
|
kubectl create namespace webapp-ns
|
||||||
|
|
||||||
|
echo "📦 Deploying frontend app..."
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
kubectl apply -f service.yaml
|
||||||
|
|
||||||
|
echo "🧾 Creating ConfigMap with init-db.sql..."
|
||||||
|
kubectl create configmap db-init-script --from-file=init-db.sql=init-db.sql -n webapp-ns
|
||||||
|
|
||||||
|
echo "🗄️ Deploying database backend..."
|
||||||
|
kubectl apply -f statefulset.yaml
|
||||||
|
kubectl apply -f deployment-api.yaml
|
||||||
|
|
||||||
|
echo "✅ All resources created."
|
84
assignment2/statefulset.yaml
Normal file
84
assignment2/statefulset.yaml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolume
|
||||||
|
metadata:
|
||||||
|
name: postgres-pv
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
capacity:
|
||||||
|
storage: 1Gi
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
hostPath:
|
||||||
|
path: "/mnt/data/postgres"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: postgres-pvc
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: webapp-ns
|
||||||
|
spec:
|
||||||
|
serviceName: "postgres"
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: postgres
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: init-db
|
||||||
|
image: postgres:15
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: "weatheruser"
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
value: "weatherpass"
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: "weatherdb"
|
||||||
|
volumeMounts:
|
||||||
|
- name: init-script
|
||||||
|
mountPath: /docker-entrypoint-initdb.d
|
||||||
|
- name: postgres-storage
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:15
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: "weatheruser"
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
value: "weatherpass"
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: "weatherdb"
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-storage
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
volumes:
|
||||||
|
- name: init-script
|
||||||
|
configMap:
|
||||||
|
name: db-init-script
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: postgres-storage
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
|
7
assignment2/stop-app.sh
Executable file
7
assignment2/stop-app.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🧼 Deleting all resources in namespace 'webapp-ns'..."
|
||||||
|
kubectl delete namespace webapp-ns
|
||||||
|
|
||||||
|
echo "✅ Cleanup complete."
|
||||||
|
|
122
assignment2/weather.html
Normal file
122
assignment2/weather.html
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Weather Info</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
background: linear-gradient(to right, #e0f7fa, #80deea);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 0.5rem;
|
||||||
|
width: 65%;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.55rem 1rem;
|
||||||
|
background-color: #00796b;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #00695c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#weather {
|
||||||
|
margin-top: 2rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#weather p {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>🌦️ Check the Weather</h1>
|
||||||
|
<input type="text" id="city" placeholder="Enter city" />
|
||||||
|
<button onclick="getWeather()">Get Weather</button>
|
||||||
|
<div id="weather"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function getWeather() {
|
||||||
|
const city = document.getElementById("city").value;
|
||||||
|
const apiKey = "0ef7f5ac4207c6da232b7843eb1a663e";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`
|
||||||
|
);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.cod === 200) {
|
||||||
|
document.getElementById("weather").innerHTML = `
|
||||||
|
<h2>${data.name}, ${data.sys.country}</h2>
|
||||||
|
<p><strong>${data.weather[0].description}</strong></p>
|
||||||
|
<p>🌡️ <strong>${data.main.temp}°C</strong></p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Log to backend
|
||||||
|
await fetch("http://192.168.49.2:31000/log", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
city: data.name,
|
||||||
|
temperature: data.main.temp,
|
||||||
|
description: data.weather[0].description
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
document.getElementById("weather").innerHTML = `<p style="color:red;">City not found!</p>`;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fetch failed:", err);
|
||||||
|
document.getElementById("weather").innerHTML = `<p style="color:red;">Error getting weather data.</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user