Skip to content

Commit a074309

Browse files
committed
fc
0 parents  commit a074309

11 files changed

+1278
-0
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env

Diff for: Dockerfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:3.9-slim
2+
3+
WORKDIR /app
4+
5+
COPY requirements.txt .
6+
RUN pip install --no-cache-dir -r requirements.txt
7+
8+
COPY . .
9+
10+
EXPOSE 8080
11+
12+
CMD ["python", "main.py"]

Diff for: Dockerfile.nginx

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
FROM nginx:1.22.1
2+
3+
ENV NGINX_VERSION="1.22.1"
4+
ENV NGINX_VTS_VERSION="0.2.2"
5+
6+
# Install build dependencies and add nginx source repository
7+
RUN apt-get update \
8+
&& apt-get install -y gnupg2 \
9+
&& curl -s http://nginx.org/packages/keys/nginx_signing.key | apt-key add - \
10+
&& echo "deb-src http://nginx.org/packages/debian/ bullseye nginx" >> /etc/apt/sources.list
11+
12+
# Download nginx source and install build dependencies
13+
RUN apt-get update \
14+
&& apt-get install -y dpkg-dev curl \
15+
&& mkdir -p /opt/rebuildnginx \
16+
&& chmod 0777 /opt/rebuildnginx \
17+
&& cd /opt/rebuildnginx \
18+
&& su --preserve-environment -s /bin/bash -c "apt-get source nginx=${NGINX_VERSION}" _apt \
19+
&& apt-get build-dep -y nginx=${NGINX_VERSION}
20+
21+
# Download and integrate VTS module
22+
RUN cd /opt \
23+
&& curl -sL https://github.com/vozlt/nginx-module-vts/archive/v${NGINX_VTS_VERSION}.tar.gz | tar -xz \
24+
&& sed -i -r -e "s/\.\/configure(.*)/.\/configure\1 --add-module=\/opt\/nginx-module-vts-${NGINX_VTS_VERSION}/" \
25+
/opt/rebuildnginx/nginx-${NGINX_VERSION}/debian/rules \
26+
&& cd /opt/rebuildnginx/nginx-${NGINX_VERSION} \
27+
&& dpkg-buildpackage -b \
28+
&& cd /opt/rebuildnginx \
29+
&& dpkg --install nginx_${NGINX_VERSION}-1~bullseye_amd64.deb
30+
31+
# Cleanup
32+
RUN apt-get remove --purge -y dpkg-dev curl \
33+
&& apt-get -y --purge autoremove \
34+
&& rm -rf /var/lib/apt/lists/* \
35+
&& rm -rf /opt/rebuildnginx \
36+
&& rm -rf /opt/nginx-module-vts-${NGINX_VTS_VERSION}
37+
38+
CMD ["nginx", "-g", "daemon off;"]

Diff for: README.md

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Nginx Load Balancing Demo with VTS Module
2+
3+
This project demonstrates load balancing between two FastAPI services using Nginx with the Virtual Host Traffic Status (VTS) module for monitoring.
4+
Prerequisites
5+
6+
- Docker
7+
- docker-compose
8+
- curl (for testing)
9+
10+
## Quick Start
11+
12+
Create necessary configuration files as shown in the project structure.
13+
14+
Build and start the services:
15+
16+
```
17+
docker-compose up --build
18+
```
19+
20+
## Accessing Services
21+
22+
Test the basic endpoint:
23+
``` bash
24+
curl http://localhost:8000/
25+
```
26+
27+
Create a new item:
28+
``` bash
29+
curl -X POST http://localhost:8000/item \
30+
-H "Content-Type: application/json" \
31+
-d '{"name": "test item", "price": 10.99, "desc": "A test item"}'
32+
```
33+
34+
Get all items:
35+
```
36+
curl http://localhost:8000/items
37+
```
38+
39+
## Monitoring
40+
41+
### VTS Module Features
42+
43+
- Access detailed traffic statistics at `/status`
44+
- Monitor request counts, bandwidth usage, and response times
45+
- View per-server metrics for load balancing
46+
47+
### Basic Nginx Status
48+
49+
- Access basic Nginx metrics at `/nginx_status`
50+
- View current connections and request statistics
51+
52+
### Load Balancer Configuration
53+
The Nginx load balancer is configured with:
54+
55+
- Round-robin distribution between two FastAPI servers
56+
- HTTP headers for tracking (X-Real-IP, X-Forwarded-For)
57+
- Server identification header (X-Served-By)
58+
- Access restrictions for status pages
59+
60+
61+

Diff for: __pycache__/main.cpython-310.pyc

1.22 KB
Binary file not shown.

Diff for: __pycache__/main.cpython-39.pyc

1.19 KB
Binary file not shown.

Diff for: docker-compose.yaml

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
version: '3'
2+
services:
3+
nginx:
4+
build:
5+
context: .
6+
dockerfile: Dockerfile.nginx
7+
ports:
8+
- "8000:80"
9+
volumes:
10+
- type: bind
11+
source: ./nginx.conf
12+
target: /etc/nginx/nginx.conf
13+
read_only: true
14+
networks:
15+
- app_network
16+
healthcheck:
17+
test: ["CMD", "curl", "-f", "http://localhost/nginx_status"]
18+
interval: 30s
19+
timeout: 10s
20+
retries: 3
21+
22+
fastapi1:
23+
build:
24+
context: .
25+
dockerfile: Dockerfile
26+
networks:
27+
- app_network
28+
environment:
29+
- SERVER_NAME=server1
30+
command: python main.py
31+
32+
fastapi2:
33+
build:
34+
context: .
35+
dockerfile: Dockerfile
36+
networks:
37+
- app_network
38+
environment:
39+
- SERVER_NAME=server2
40+
command: python main.py
41+
42+
networks:
43+
app_network:
44+
driver: bridge

Diff for: main.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from pydantic import BaseModel
2+
from fastapi import FastAPI
3+
from typing import List
4+
import uvicorn
5+
6+
7+
class Item(BaseModel):
8+
name: str
9+
price: float
10+
desc: str
11+
12+
class ItemList(BaseModel):
13+
all_items: List[Item]
14+
15+
items = ItemList
16+
17+
app = FastAPI()
18+
19+
@app.get("/")
20+
def index():
21+
return "Hi mom"
22+
23+
@app.post("/item")
24+
def create_item(item: Item):
25+
items.all_items.append(item)
26+
return {"message": "Item added successfully"}
27+
28+
@app.get("/items")
29+
def get_all_items():
30+
return items
31+
32+
if __name__ == "__main__":
33+
uvicorn.run(app, host="0.0.0.0", port=8080)

Diff for: nginx.conf

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
user nginx;
2+
worker_processes 1;
3+
error_log /var/log/nginx/error.log warn;
4+
pid /var/run/nginx.pid;
5+
6+
events {
7+
worker_connections 1024;
8+
}
9+
10+
http {
11+
include /etc/nginx/mime.types;
12+
default_type application/octet-stream;
13+
14+
# VTS (Virtual Host Traffic Status) configuration
15+
vhost_traffic_status_zone;
16+
vhost_traffic_status_filter_by_host on;
17+
18+
upstream fastapi_servers {
19+
server fastapi1:8080;
20+
server fastapi2:8080;
21+
}
22+
23+
server {
24+
listen 80;
25+
server_name localhost;
26+
27+
# VTS status page
28+
location /status {
29+
vhost_traffic_status_display;
30+
vhost_traffic_status_display_format html;
31+
access_log off;
32+
allow 127.0.0.1;
33+
allow 10.0.0.0/8;
34+
allow 172.16.0.0/12;
35+
allow 192.168.0.0/16;
36+
deny all;
37+
}
38+
39+
# Original stub status endpoint
40+
location /nginx_status {
41+
stub_status on;
42+
access_log off;
43+
allow 127.0.0.1;
44+
allow 10.0.0.0/8;
45+
allow 172.16.0.0/12;
46+
allow 192.168.0.0/16;
47+
deny all;
48+
}
49+
50+
location / {
51+
proxy_pass http://fastapi_servers;
52+
proxy_set_header Host $host;
53+
proxy_set_header X-Real-IP $remote_addr;
54+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
55+
proxy_set_header X-Forwarded-Proto $scheme;
56+
add_header X-Served-By $upstream_addr;
57+
}
58+
}
59+
60+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
61+
'$status $body_bytes_sent "$http_referer" '
62+
'"$http_user_agent" "$http_x_forwarded_for"';
63+
access_log /var/log/nginx/access.log main;
64+
sendfile on;
65+
keepalive_timeout 65;
66+
}

Diff for: requirements.txt

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
annotated-types==0.7.0
2+
anyio==4.6.2.post1
3+
beautifulsoup4==4.12.3
4+
bs4==0.0.2
5+
certifi==2024.8.30
6+
charset-normalizer==3.4.0
7+
click==8.1.7
8+
exceptiongroup==1.2.2
9+
fastapi==0.115.4
10+
h11==0.14.0
11+
idna==3.10
12+
markdown-it-py==3.0.0
13+
mdurl==0.1.2
14+
pip-search==0.0.12
15+
pydantic==2.9.2
16+
pydantic_core==2.23.4
17+
Pygments==2.18.0
18+
requests==2.32.3
19+
rich==13.9.4
20+
sniffio==1.3.1
21+
soupsieve==2.6
22+
starlette==0.41.2
23+
typing_extensions==4.12.2
24+
urllib3==2.2.3
25+
uvicorn==0.32.0

0 commit comments

Comments
 (0)