|
28 | 28 | <a href="https://docs.docker.com/compose/">
|
29 | 29 | <img src="https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=fff&style=for-the-badge" alt="Docker">
|
30 | 30 | </a>
|
| 31 | + <a href="https://nginx.org/en/"> |
| 32 | + <img src="https://img.shields.io/badge/NGINX-009639?logo=nginx&logoColor=fff&style=flat" alt=NGINX> |
| 33 | + </a> |
31 | 34 | </p>
|
32 | 35 |
|
33 | 36 | ## 0. About
|
|
39 | 42 | - [`Redis`](https://redis.io): Open source, in-memory data store used by millions as a cache, message broker and more.
|
40 | 43 | - [`ARQ`](https://arq-docs.helpmanual.io) Job queues and RPC in python with asyncio and redis.
|
41 | 44 | - [`Docker Compose`](https://docs.docker.com/compose/) With a single command, create and start all the services from your configuration.
|
| 45 | +- [`NGINX`](https://nginx.org/en/) High-performance low resource consumption web server used for Reverse Proxy and Load Balancing. |
42 | 46 |
|
43 | 47 | ## 1. Features
|
44 | 48 | - ⚡️ Fully async
|
|
47 | 51 | - 🏬 Easy redis caching
|
48 | 52 | - 👜 Easy client-side caching
|
49 | 53 | - 🚦 ARQ integration for task queue
|
50 |
| -- ⚙️ Efficient querying (only queries what's needed) |
| 54 | +- ⚙️ Efficient querying (only queries what's needed) with support for joins |
51 | 55 | - ⎘ Out of the box pagination support
|
52 | 56 | - 🛑 Rate Limiter dependency
|
53 | 57 | - 👮 FastAPI docs behind authentication and hidden based on the environment
|
54 | 58 | - 🦾 Easily extendable
|
55 | 59 | - 🤸♂️ Flexible
|
56 | 60 | - 🚚 Easy running with docker compose
|
| 61 | +- ⚖️ NGINX Reverse Proxy and Load Balancing |
57 | 62 |
|
58 | 63 | ## 2. Contents
|
59 | 64 | 0. [About](#0-about)
|
|
82 | 87 | 6. [CRUD](#56-crud)
|
83 | 88 | 7. [Routes](#57-routes)
|
84 | 89 | 1. [Paginated Responses](#571-paginated-responses)
|
| 90 | + 2. [HTTP Exceptions](#572-http-exceptions) |
85 | 91 | 8. [Caching](#58-caching)
|
86 | 92 | 9. [More Advanced Caching](#59-more-advanced-caching)
|
87 | 93 | 10. [ARQ Job Queues](#510-arq-job-queues)
|
88 | 94 | 11. [Rate Limiting](#511-rate-limiting)
|
89 | 95 | 12. [Running](#512-running)
|
90 | 96 | 6. [Running in Production](#6-running-in-production)
|
| 97 | + 1. [Uvicorn Workers with Gunicorn](#61-uvicorn-workers-with-gunicorn) |
| 98 | + 2. [Running With NGINX](#62-running-with-nginx) |
| 99 | + 1. [One Server](#621-one-server) |
| 100 | + 2. [Multiple Servers](#622-multiple-servers) |
91 | 101 | 7. [Testing](#7-testing)
|
92 | 102 | 8. [Contributing](#8-contributing)
|
93 | 103 | 9. [References](#9-references)
|
@@ -178,7 +188,7 @@ For ARQ Job Queues:
|
178 | 188 | REDIS_CACHE_HOST="your_host" # default "localhost", if using docker compose you should use "db"
|
179 | 189 | REDIS_CACHE_PORT=6379
|
180 | 190 | ```
|
181 |
| -> **Warning** |
| 191 | +> [!WARNING] |
182 | 192 | > You may use the same redis for both caching and queue while developing, but the recommendation is using two separate containers for production.
|
183 | 193 |
|
184 | 194 | To create the first tier:
|
@@ -1261,31 +1271,172 @@ poetry run arq app.worker.WorkerSettings
|
1261 | 1271 | ```
|
1262 | 1272 |
|
1263 | 1273 | ## 6. Running in Production
|
1264 |
| -In production you probably should run using gunicorn workers: |
| 1274 | +### 6.1 Uvicorn Workers with Gunicorn |
| 1275 | +In production you may want to run using gunicorn to manage uvicorn workers: |
1265 | 1276 | ```sh
|
1266 | 1277 | command: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
1267 | 1278 | ```
|
1268 | 1279 | Here it's running with 4 workers, but you should test it depending on how many cores your machine has.
|
1269 | 1280 |
|
1270 | 1281 | To do this if you are using docker compose, just replace the comment:
|
1271 |
| -This part in docker-compose.yml: |
| 1282 | +This part in `docker-compose.yml`: |
1272 | 1283 | ```python
|
| 1284 | +# docker-compose.yml |
| 1285 | + |
1273 | 1286 | # -------- replace with comment to run with gunicorn --------
|
1274 | 1287 | command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
|
1275 | 1288 | # command: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
1276 | 1289 | ```
|
1277 | 1290 |
|
1278 | 1291 | Should be changed to:
|
1279 | 1292 | ```python
|
| 1293 | +# docker-compose.yml |
| 1294 | + |
1280 | 1295 | # -------- replace with comment to run with uvicorn --------
|
1281 | 1296 | # command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
|
1282 | 1297 | command: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
1283 | 1298 | ```
|
1284 | 1299 |
|
| 1300 | +And the same in `Dockerfile`: |
| 1301 | +This part: |
| 1302 | +```python |
| 1303 | +# Dockerfile |
| 1304 | + |
| 1305 | +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] |
| 1306 | +# CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker". "-b", "0.0.0.0:8000"] |
| 1307 | +``` |
| 1308 | + |
| 1309 | +Should be changed to: |
| 1310 | +```python |
| 1311 | +# Dockerfile |
| 1312 | + |
| 1313 | +# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] |
| 1314 | +CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker". "-b", "0.0.0.0:8000"] |
| 1315 | +``` |
| 1316 | + |
1285 | 1317 | > [!CAUTION]
|
1286 | 1318 | > Do not forget to set the `ENVIRONMENT` in `.env` to `production` unless you want the API docs to be public.
|
1287 | 1319 |
|
1288 |
| -More on running it in production later. |
| 1320 | +### 6.2 Running with NGINX |
| 1321 | +NGINX is a high-performance web server, known for its stability, rich feature set, simple configuration, and low resource consumption. NGINX acts as a reverse proxy, that is, it receives client requests, forwards them to the FastAPI server (running via Uvicorn or Gunicorn), and then passes the responses back to the clients. |
| 1322 | + |
| 1323 | +To run with NGINX, you start by uncommenting the following part in your `docker-compose.yml`: |
| 1324 | +```python |
| 1325 | +# docker-compose.yml |
| 1326 | + |
| 1327 | +... |
| 1328 | + # #-------- uncomment to run with nginx -------- |
| 1329 | + # nginx: |
| 1330 | + # image: nginx:latest |
| 1331 | + # ports: |
| 1332 | + # - "80:80" |
| 1333 | + # volumes: |
| 1334 | + # - ./default.conf:/etc/nginx/conf.d/default.conf |
| 1335 | + # depends_on: |
| 1336 | + # - web |
| 1337 | +... |
| 1338 | +``` |
| 1339 | + |
| 1340 | +Which should be changed to: |
| 1341 | +```python |
| 1342 | +# docker-compose.yml |
| 1343 | + |
| 1344 | +... |
| 1345 | + #-------- uncomment to run with nginx -------- |
| 1346 | + nginx: |
| 1347 | + image: nginx:latest |
| 1348 | + ports: |
| 1349 | + - "80:80" |
| 1350 | + volumes: |
| 1351 | + - ./default.conf:/etc/nginx/conf.d/default.conf |
| 1352 | + depends_on: |
| 1353 | + - web |
| 1354 | +... |
| 1355 | +``` |
| 1356 | + |
| 1357 | +Then comment the following part: |
| 1358 | +```python |
| 1359 | +# docker-compose.yml |
| 1360 | + |
| 1361 | +services: |
| 1362 | + web: |
| 1363 | + ... |
| 1364 | + # -------- Both of the following should be commented to run with nginx -------- |
| 1365 | + command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload |
| 1366 | + # command: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 |
| 1367 | +``` |
| 1368 | + |
| 1369 | +Which becomes: |
| 1370 | +```python |
| 1371 | +# docker-compose.yml |
| 1372 | + |
| 1373 | +services: |
| 1374 | + web: |
| 1375 | + ... |
| 1376 | + # -------- Both of the following should be commented to run with nginx -------- |
| 1377 | + # command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload |
| 1378 | + # command: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 |
| 1379 | +``` |
| 1380 | + |
| 1381 | +Then pick the way you want to run (uvicorn or gunicorn managing uvicorn workers) in `Dockerfile`. |
| 1382 | +The one you want should be uncommented, comment the other one. |
| 1383 | +```python |
| 1384 | +# Dockerfile |
| 1385 | + |
| 1386 | +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] |
| 1387 | +# CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker". "-b", "0.0.0.0:8000"] |
| 1388 | +``` |
| 1389 | + |
| 1390 | +#### 6.2.1 One Server |
| 1391 | +If you want to run with one server only, your setup should be ready. Just make sure the only part that is not a comment in `deafult.conf` is: |
| 1392 | +```python |
| 1393 | +# default.conf |
| 1394 | + |
| 1395 | +# ---------------- Running With One Server ---------------- |
| 1396 | +server { |
| 1397 | + listen 80; |
| 1398 | + |
| 1399 | + location / { |
| 1400 | + proxy_pass http://web:8000; |
| 1401 | + proxy_set_header Host $host; |
| 1402 | + proxy_set_header X-Real-IP $remote_addr; |
| 1403 | + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| 1404 | + proxy_set_header X-Forwarded-Proto $scheme; |
| 1405 | + } |
| 1406 | +} |
| 1407 | +``` |
| 1408 | + |
| 1409 | +#### 6.2.2 Multiple Servers |
| 1410 | +NGINX can distribute incoming network traffic across multiple servers, improving the efficiency and capacity utilization of your application. |
| 1411 | + |
| 1412 | +To run with multiple servers, just comment the `Running With One Server` part in `default.conf` and Uncomment the other one: |
| 1413 | +```python |
| 1414 | +# default.conf |
| 1415 | + |
| 1416 | +# ---------------- Running With One Server ---------------- |
| 1417 | +... |
| 1418 | + |
| 1419 | +# ---------------- To Run with Multiple Servers, Uncomment below ---------------- |
| 1420 | +upstream fastapi_app { |
| 1421 | + server fastapi1:8000; # Replace with actual server names or IP addresses |
| 1422 | + server fastapi2:8000; |
| 1423 | + # Add more servers as needed |
| 1424 | +} |
| 1425 | + |
| 1426 | +server { |
| 1427 | + listen 80; |
| 1428 | + |
| 1429 | + location / { |
| 1430 | + proxy_pass http://fastapi_app; |
| 1431 | + proxy_set_header Host $host; |
| 1432 | + proxy_set_header X-Real-IP $remote_addr; |
| 1433 | + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| 1434 | + proxy_set_header X-Forwarded-Proto $scheme; |
| 1435 | + } |
| 1436 | +} |
| 1437 | +``` |
| 1438 | +> [!WARNING] |
| 1439 | +> Note that we are using `fastapi1:8000` and `fastapi2:8000` as examples, you should replace it with the actual name of your service and the port it's running on. |
1289 | 1440 |
|
1290 | 1441 | ## 7. Testing
|
1291 | 1442 | For tests, ensure you have in `.env`:
|
|
0 commit comments