My first basic loadBalancer
This commit is contained in:
20
Dockerfile
Normal file
20
Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Use the official Node.js 18 image as the base image
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
# Set the working directory inside the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package.json and package-lock.json to the working directory
|
||||||
|
COPY package*.json .
|
||||||
|
|
||||||
|
# Install project dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy the rest of the application code to the working directory
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose port 3000 for the application
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["node", "server.js"]
|
||||||
43
docker-compose.yml
Normal file
43
docker-compose.yml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
version: '3.9'
|
||||||
|
services:
|
||||||
|
app-1:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3001:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-1
|
||||||
|
|
||||||
|
app-2:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3002:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-2
|
||||||
|
|
||||||
|
app-3:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3003:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-3
|
||||||
|
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./files/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
218
files/README.md
Normal file
218
files/README.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
### Documentatie Stack Node.js + Docker + Docker Compose + Nginx
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Structura proiect
|
||||||
|
|
||||||
|
```
|
||||||
|
project/
|
||||||
|
│
|
||||||
|
├── Dockerfile # imaginea Node.js
|
||||||
|
├── docker-compose.yml # orchestration containere + Nginx
|
||||||
|
├── nginx.conf # configuratie Nginx
|
||||||
|
├── server.js # cod Node.js
|
||||||
|
├── package.json
|
||||||
|
└── index.html # pagina servita de Node
|
||||||
|
```
|
||||||
|
|
||||||
|
Stack-ul include:
|
||||||
|
|
||||||
|
* Node.js – aplicatie stateless
|
||||||
|
* 3 containere Node, fiecare cu INSTANCE_NAME
|
||||||
|
* Nginx – reverse proxy si load balancer
|
||||||
|
* Docker Compose – orchestrare containere + retea
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 2. Node.js
|
||||||
|
|
||||||
|
## 2.1 server.js
|
||||||
|
|
||||||
|
```js
|
||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const instanceName = process.env.INSTANCE_NAME || 'unknown';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
console.log(`[${instanceName}] Request received`);
|
||||||
|
res.sendFile(path.join(__dirname, 'index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`[${instanceName}] Node app listening on port ${port}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Explicatii:
|
||||||
|
|
||||||
|
* `process.env.INSTANCE_NAME` pentru identificarea containerului
|
||||||
|
* Stateless design – aplicatia nu stie cate instante exista
|
||||||
|
* Log-urile arata care container a servit request-ul
|
||||||
|
* Servește `index.html`
|
||||||
|
|
||||||
|
## 2.2 package.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "node-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 3. Dockerfile
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json .
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY index.html .
|
||||||
|
COPY server.js .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Explicatii:
|
||||||
|
|
||||||
|
* Imagine oficiala Node minimală
|
||||||
|
* COPY package*.json pentru caching optim
|
||||||
|
* EXPOSE 3000 – port intern container
|
||||||
|
* CMD – comanda de start
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 4. Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app-1:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3001:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-1
|
||||||
|
|
||||||
|
app-2:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3002:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-2
|
||||||
|
|
||||||
|
app-3:
|
||||||
|
image: node-app:v1
|
||||||
|
ports:
|
||||||
|
- "3003:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
environment:
|
||||||
|
- INSTANCE_NAME=app-3
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
depends_on:
|
||||||
|
- app-1
|
||||||
|
- app-2
|
||||||
|
- app-3
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
```
|
||||||
|
|
||||||
|
Explicatii:
|
||||||
|
|
||||||
|
* 3 servicii Node identice, fiecare pe port intern 3000
|
||||||
|
* Nginx ascultă pe port 80 și face proxy la Node
|
||||||
|
* `depends_on` pentru startup order
|
||||||
|
* retea comuna
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 5. Nginx Configuration (nginx.conf)
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
events {}
|
||||||
|
|
||||||
|
http {
|
||||||
|
upstream backend {
|
||||||
|
server app-1:3000;
|
||||||
|
server app-2:3000;
|
||||||
|
server app-3:3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://backend;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Explicatii:
|
||||||
|
|
||||||
|
* `upstream backend` = grup backend-uri Node pentru load balancing
|
||||||
|
* `proxy_pass http://backend;` trimite request-ul la unul din backends
|
||||||
|
* Header-ele ajuta Node sa stie IP-ul real
|
||||||
|
* Nginx foloseste portul intern 3000
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6. Workflow
|
||||||
|
|
||||||
|
1. Build Node.js:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t node-app:v1 .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Pornire Compose:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Verificare log-uri:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Test load balancing:
|
||||||
|
|
||||||
|
* [http://localhost](http://localhost)
|
||||||
|
* Refresh repetat → request-urile distribuite între app-1, app-2, app-3
|
||||||
|
|
||||||
|
---
|
||||||
0
files/index.html
Normal file
0
files/index.html
Normal file
22
files/nginx.conf
Normal file
22
files/nginx.conf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
upstream backend {
|
||||||
|
server app-1:3001;
|
||||||
|
server app-2:3002;
|
||||||
|
server app-3:3003;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://backend;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
files/package.json
Normal file
10
files/package.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "node-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
20
files/server.js
Normal file
20
files/server.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
const instanceName = process.env.INSTANCE_NAME || 'unknown';
|
||||||
|
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
console.log(`[${instanceName}] Request received`);
|
||||||
|
res.sendFile(path.join(__dirname, 'index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`[${instanceName}] Node app listening on port ${port}`);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user