Docker web app project
This commit is contained in:
commit
9b52815bce
61
README.md
Normal file
61
README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# 🚀 Docker Multi-Container Web Application
|
||||||
|
|
||||||
|
## 📌 Project Overview
|
||||||
|
This project demonstrates the deployment of a multi-container web application using Docker.
|
||||||
|
|
||||||
|
It includes:
|
||||||
|
- Frontend (Nginx)
|
||||||
|
- Backend (Node.js)
|
||||||
|
- Database (MongoDB)
|
||||||
|
- Mongo Express (DB UI)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Architecture
|
||||||
|
Browser → Frontend → Backend → MongoDB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Technologies Used
|
||||||
|
- Docker
|
||||||
|
- Docker Compose
|
||||||
|
- Node.js
|
||||||
|
- MongoDB
|
||||||
|
- Nginx
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Services and Ports
|
||||||
|
|
||||||
|
| Service | Port |
|
||||||
|
|----------------|------|
|
||||||
|
| Frontend | 8080 |
|
||||||
|
| Backend | 3000 |
|
||||||
|
| MongoDB | 27017 |
|
||||||
|
| Mongo Express | 8081 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Setup
|
||||||
|
|
||||||
|
### Prepare
|
||||||
|
./prepare-app.sh
|
||||||
|
|
||||||
|
### Start
|
||||||
|
./start-app.sh
|
||||||
|
|
||||||
|
### Stop
|
||||||
|
./stop-app.sh
|
||||||
|
|
||||||
|
### Remove
|
||||||
|
./remove-app.sh
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 Persistence
|
||||||
|
MongoDB uses Docker volume (mongo-data), so data is محفوظ after restart.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 👨💻 Author
|
||||||
|
Sabareesan
|
||||||
12
Z1/backend/Dockerfile
Normal file
12
Z1/backend/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM node:18
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json .
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
9
Z1/backend/package.json
Normal file
9
Z1/backend/package.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"mongoose": "^7.0.0",
|
||||||
|
"cors": "^2.8.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Z1/backend/server.js
Normal file
31
Z1/backend/server.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const express = require("express");
|
||||||
|
const mongoose = require("mongoose");
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
const cors = require("cors");
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
mongoose.connect("mongodb://mongo:27017/mydb")
|
||||||
|
.then(() => console.log("MongoDB connected"))
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
|
||||||
|
const Item = mongoose.model("Item", { name: String });
|
||||||
|
|
||||||
|
app.get("/", (req, res) => {
|
||||||
|
res.send("Backend running 🚀");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/add", async (req, res) => {
|
||||||
|
const item = new Item({ name: req.body.name });
|
||||||
|
await item.save();
|
||||||
|
res.send(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/items", async (req, res) => {
|
||||||
|
const items = await Item.find();
|
||||||
|
res.send(items);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000, () => console.log("Server running on port 3000"));
|
||||||
36
Z1/docker-compose.yml
Normal file
36
Z1/docker-compose.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/usr/share/nginx/html
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build: ./backend
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
- mongo
|
||||||
|
|
||||||
|
mongo:
|
||||||
|
image: mongo:6
|
||||||
|
volumes:
|
||||||
|
- mongo-data:/data/db
|
||||||
|
ports:
|
||||||
|
- "27017:27017"
|
||||||
|
|
||||||
|
mongo-express:
|
||||||
|
image: mongo-express
|
||||||
|
ports:
|
||||||
|
- "8081:8081"
|
||||||
|
depends_on:
|
||||||
|
- mongo
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mongo-data:
|
||||||
155
Z1/frontend/index.html
Normal file
155
Z1/frontend/index.html
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Docker Web App</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background: #f4f6f8;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 400px;
|
||||||
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 48%;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-btn {
|
||||||
|
background: #2196F3;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
background: #eee;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>🚀 Docker App</h1>
|
||||||
|
|
||||||
|
<input id="name" placeholder="Enter name..." />
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="add-btn" onclick="add()">Add</button>
|
||||||
|
<button class="load-btn" onclick="load()">Load</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul id="list"></ul>
|
||||||
|
|
||||||
|
<div class="status" id="status"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const API = "http://localhost:3000";
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
const name = document.getElementById("name").value;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
setStatus("⚠️ Please enter a name", "red");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(API + "/add", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: JSON.stringify({ name })
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setStatus("✅ Added successfully");
|
||||||
|
document.getElementById("name").value = "";
|
||||||
|
load();
|
||||||
|
})
|
||||||
|
.catch(() => setStatus("❌ Error adding data", "red"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
fetch(API + "/items")
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
const list = document.getElementById("list");
|
||||||
|
list.innerHTML = "";
|
||||||
|
|
||||||
|
data.forEach(item => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.innerText = item.name;
|
||||||
|
list.appendChild(li);
|
||||||
|
});
|
||||||
|
|
||||||
|
setStatus("📦 Data loaded");
|
||||||
|
})
|
||||||
|
.catch(() => setStatus("❌ Error loading data", "red"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStatus(msg, color="green") {
|
||||||
|
const status = document.getElementById("status");
|
||||||
|
status.innerText = msg;
|
||||||
|
status.style.color = color;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
11
Z1/prepare-app.sh
Normal file
11
Z1/prepare-app.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Preparing application..."
|
||||||
|
|
||||||
|
docker network create app-network 2>/dev/null
|
||||||
|
|
||||||
|
docker volume create mongo-data
|
||||||
|
|
||||||
|
docker-compose build
|
||||||
|
|
||||||
|
echo "Preparation done ✅"
|
||||||
9
Z1/remove-app.sh
Normal file
9
Z1/remove-app.sh
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Removing application..."
|
||||||
|
|
||||||
|
docker-compose down -v
|
||||||
|
docker volume rm mongo-data 2>/dev/null
|
||||||
|
docker network rm app-network 2>/dev/null
|
||||||
|
|
||||||
|
echo "All removed 🧹"
|
||||||
10
Z1/start-app.sh
Normal file
10
Z1/start-app.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Starting application..."
|
||||||
|
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
echo "Application started 🚀"
|
||||||
|
echo "Frontend: http://localhost:8080"
|
||||||
|
echo "Backend: http://localhost:3000"
|
||||||
|
echo "Mongo Express: http://localhost:8081"
|
||||||
7
Z1/stop-app.sh
Normal file
7
Z1/stop-app.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Stopping application..."
|
||||||
|
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
echo "Application stopped ✅"
|
||||||
BIN
Z1/📘 Docker.docx
Normal file
BIN
Z1/📘 Docker.docx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user