Skip to content

Commit c6112c2

Browse files
deploy v0.0.2, see CHANGELOG
1 parent 055aafd commit c6112c2

33 files changed

+1845
-35
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
0.0.2 - 2022-12-15
2+
===================
3+
4+
### Features
5+
- Add [Application stack](./generate_data_application/).
6+
- Add CHANGELOG.md.
7+
- Add MAINTAINERS.md.
8+
9+
### Updating
10+
- Update README with the architecture of application stack and a new source.
11+
- Update [agent.yaml](./agent/agent.yaml) for the application stack.
12+
- Change log level for Grafana in [config.ini](./grafana/config.ini).
13+
- Update [Loki config](./loki/loki-config.yaml) for the application stack.
14+
- Update log level for Mimir in [mimir.yaml](./mimir/mimir.yaml).
15+
- Update log level for NGinx in [nginx.conf](./nginx/nginx.conf).
16+
- Update log level for Tempo in [tempo.yaml](./tempo/tempo.yaml).

MAINTAINERS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- [@tonyglandyl28](https://github.com/tonyglandyl28)

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
<img src="./assets/observability.png" alt="Observability" width="500"/>
33
</p>
44

5+
![alt version](https://img.shields.io/badge/Version-0.0.2-violet)
56
![alt production](https://img.shields.io/badge/Production--Ready-No-green)
67
![alt docker](https://img.shields.io/badge/Deployment_tool-Docker--Compose-orange)
8+
![alt ARM](https://img.shields.io/badge/Platform-ARM--M1-red)
79

810
# Why
911

@@ -15,12 +17,20 @@ This for testing purpose.
1517

1618
# Architecture
1719

18-
Mimir, Loki and Tempo are deploy in Monolithic mode with 3 instances of each.
20+
The observability stack is composed by Mimir, Loki and Tempo which are deployed in Monolithic mode with 3 instances of each.
21+
The application stack is composed by a FastAPI application with some routes and PostgreSQL database with 1 table.
22+
Logs are written in a log file, scrape by [Grafana Promtail](https://grafana.com/docs/loki/latest/clients/promtail/) and send to Grafana Agent.
23+
Metrics are exposed via [Prometheus Client](https://github.com/prometheus/client_python) and scraped by Grafana Agent.
24+
Traces are sent via [Opentelemetry SDK](https://github.com/open-telemetry/opentelemetry-python) to Grafana Agent.
25+
Unit tests are performed by [k6.io](https://k6.io).
1926

2027
![alt schema](./assets/Observability-Grafana_Stack.png)
2128

2229
# Prerequisite
2330

31+
This repository is run on Mac M1 (ARM architecture).
32+
If you want to use another architecture, be sure to modify the Dockerfiles which import arm binary (ex. promtail on the app Dockerfile).
33+
2434
1. Install [Docker](https://docs.docker.com/engine/install/).
2535
2. Create Docker network :
2636
`docker network create observability-network`
@@ -29,10 +39,12 @@ Mimir, Loki and Tempo are deploy in Monolithic mode with 3 instances of each.
2939

3040
1. Clone this repository :
3141
`git clone https://github.com/tonyglandyl28/observability_docker.git`
32-
2. Build & deploy :
42+
2. Build & deploy observability stack :
3343
`docker-compose --profile grafana up --build`
3444
3. Access to Grafana for visualization :
3545
*http://localhost:3000*
46+
4. Build & deploy application stack :
47+
`docker-compose --profile application up --build`
3648

3749
# How to send logs/metrics/traces
3850

@@ -73,9 +85,9 @@ Grafana --> Nginx : 4702 --> Mimir : 3703
7385
# TODO
7486

7587
- Tests Prometheus Exemplars.
76-
- Add comments in YAML & Docker files.
88+
- ~~Add comments in YAML & Docker files.~~ (v0.0.2)
7789
- Add Alert Manager.
78-
- Add a data generator (logs, metrics, traces) - a React frontend with FastApi & PostgreSQL backend.
90+
- Add a data generator (logs, metrics, traces) - a React frontend ~~with FastApi & PostgreSQL backend~~. v(0.0.2)
7991
- Create dashboards for these application stack.
8092
- Configure all components for distributed installation.
8193

@@ -89,4 +101,5 @@ Grafana --> Nginx : 4702 --> Mimir : 3703
89101
| [<img src="./assets/loki.png" alt="Grafana Loki" width="200"/>](https://grafana.com/docs/loki/latest/) | v2.7.0 | Used to store Logs (like Elasticsearch). Based on https://github.com/grafana/loki/tree/main/examples/getting-started |
90102
| [<img src="./assets/grafana.png" alt="Grafana" width="200"/>](https://grafana.com/docs/grafana/latest/) | v9.3.1 | Used to visualize data (like Kibana). Based on https://github.com/grafana/grafana |
91103
| [<img src="./assets/minio.png" alt="Minio" width="200"/>](https://min.io) | Latest | Used to load balance traffic between each instance (on Cloud, use S3, Google Cloud Storage or similar). Based on https://github.com/minio/minio |
92-
| [<img src="./assets/nginx.png" alt="NGinx" width="200"/>](https://www.nginx.com/) | Latest | Used to load balance traffic between each instance. Based on https://github.com/nginx/nginx |
104+
| [<img src="./assets/nginx.png" alt="NGinx" width="200"/>](https://www.nginx.com/) | Latest | Used to load balance traffic between each instance. Based on https://github.com/nginx/nginx |
105+
| [<img src="./assets/blueswen.png" alt="Blueswen" width="200"/>](https://github.com/Blueswen/fastapi-observability) | Latest | Used to configure FastAPI application. Thanks to [@Blueswen](https://github.com/blueswen) |

agent/agent.yaml

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,43 @@
11
server:
2-
log_level: "debug"
3-
log_format: "logfmt"
2+
log_level: debug
3+
log_format: logfmt
44

55
metrics:
66
global:
77
scrape_interval: 5s
88
external_labels:
9-
cluster: demo
10-
namespace: demo
9+
cluster: test
10+
namespace: monitoring
1111
remote_write:
1212
- url: http://nginx:3702/api/v1/push
1313
send_exemplars: true
1414
# Add X-Scope-OrgID header so that Mimir knows what tenant the remote write data should be stored in.
15-
# In this case, our tenant is "myapp"
15+
# In this case, our tenant is "backend"
1616
headers:
17-
X-Scope-OrgID: myapp
17+
X-Scope-OrgID: backend
1818
wal_directory: "/tmp/agent/prom"
1919
configs:
20-
- name: "myapp-metrics"
20+
- name: "backend-metrics"
2121
scrape_configs:
22-
- job_name: "agentprometheus"
22+
- job_name: "backend_fastapi"
2323
static_configs:
24-
- targets: ['api:8000']
24+
- targets: ['backend:5050']
25+
# - name: "myapp-metrics"
26+
# scrape_configs:
27+
# - job_name: "backend_flask"
28+
# static_configs:
29+
# - targets: ['api:8000']
2530

2631
logs:
2732
configs:
28-
- name: "myapp-logs"
33+
- name: "backend-logs"
2934
clients:
3035
- url: http://nginx:3502/loki/api/v1/push
3136
positions:
3237
filename: "/tmp/agent/loki.yaml"
3338
scrape_configs:
3439
# This value should be a problem --> https://github.com/grafana/loki/issues/7275
35-
- job_name: "agentloki"
40+
- job_name: "backend_fastapi"
3641
loki_push_api:
3742
server:
3843
http_listen_port: 3501
@@ -41,12 +46,12 @@ logs:
4146

4247
traces:
4348
configs:
44-
- name: "myapp-traces"
49+
- name: "backend-traces"
4550
attributes:
4651
actions:
4752
- action: insert
4853
key: tempo.attribute.labels
49-
value: "grafana_agent"
54+
value: "backend_fastapi"
5055
receivers:
5156
otlp:
5257
protocols:

assets/blueswen.png

151 KB
Loading

docker-compose.yaml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ services:
7474
- "./grafana/dashboard.yaml:/etc/grafana/provisioning/dashboards/default.yaml"
7575
- "./grafana/catalogue.json:/var/lib/grafana/dashboards/catalogue.json"
7676
- "./grafana/container_process.json:/var/lib/grafana/dashboards/container_process.json"
77+
- "./grafana/config.ini:/etc/grafana/grafana.ini"
7778
labels:
7879
namespace: monitoring
7980
environment:
@@ -284,3 +285,63 @@ services:
284285
######################################################################################
285286
######################################################################################
286287
# TODO Add Alert Manager
288+
289+
######################################################################################
290+
######################################################################################
291+
############################## BACKEND APPLICATION ###################################
292+
######################################################################################
293+
######################################################################################
294+
backend:
295+
profiles:
296+
- application
297+
container_name: backend
298+
image: backend
299+
build:
300+
context: generate_data_application/backend
301+
dockerfile: Dockerfile
302+
ports:
303+
- 5050:5050
304+
- 8000:8000
305+
depends_on:
306+
- db
307+
labels:
308+
namespace: monitoring
309+
310+
######################################################################################
311+
######################################################################################
312+
############################## DATABASE APPLICATION ##################################
313+
######################################################################################
314+
######################################################################################
315+
db:
316+
profiles:
317+
- application
318+
container_name: db
319+
image: db
320+
build:
321+
context: generate_data_application/db
322+
dockerfile: Dockerfile
323+
volumes:
324+
- ./generate_data_application/db/postgres.conf:/etc/postgresql/postgresql.conf
325+
command: postgres -c config_file=/etc/postgresql/postgresql.conf
326+
ports:
327+
- 5432:5432
328+
labels:
329+
namespace: monitoring
330+
331+
######################################################################################
332+
######################################################################################
333+
################################### Unit tests #######################################
334+
######################################################################################
335+
######################################################################################
336+
k6:
337+
profiles:
338+
- application
339+
container_name: k6
340+
image: k6
341+
build:
342+
context: generate_data_application/load_tests
343+
dockerfile: Dockerfile
344+
depends_on:
345+
- backend
346+
labels:
347+
namespace: monitoring
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM python:bullseye
2+
RUN apt-get update && apt-get install --no-install-recommends -y systemctl=1.4.4181-1.1 \
3+
&& apt-get clean \
4+
&& rm -rf /var/lib/apt/lists/*
5+
WORKDIR /usr/local/bin/
6+
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]
7+
8+
# Configure Promtail to send logs to Grafana Agent
9+
RUN curl -s -q https://api.github.com/repos/grafana/loki/releases/latest | grep browser_download_url | cut -d '"' -f 4 | grep promtail-linux-arm64.zip | wget -i - && \
10+
unzip promtail-linux-arm64.zip && \
11+
mv ./promtail-linux-arm64 ./promtail
12+
COPY config/promtail-config.yaml /etc/promtail/
13+
RUN useradd --system promtail
14+
COPY config/promtail.service /etc/systemd/system/
15+
16+
# Configure FastAPI application
17+
WORKDIR /usr/src/app
18+
RUN chmod a+rwx /usr/src/app
19+
COPY config/requirements.txt ./
20+
RUN pip install --no-cache-dir -r requirements.txt
21+
COPY app .
22+
COPY config/start.sh ./config/
23+
EXPOSE 5050
24+
CMD ["/bin/sh", "./config/start.sh"]
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Function to define FastAPI routes
3+
"""
4+
5+
from fastapi import APIRouter, Depends, HTTPException
6+
from sqlalchemy.orm import Session
7+
from sqlalchemy.exc import OperationalError
8+
from schemas import ClientsBase, Clients
9+
from responsesSettings import responsesMessages
10+
import connection, crud_clients
11+
from observability import LOGGER, tracer
12+
13+
traces = tracer.get_tracer(__name__)
14+
15+
LOGGER = LOGGER.getChild(__name__)
16+
17+
router = APIRouter(
18+
tags=["clients"],
19+
responses={
20+
400: responsesMessages['400'],
21+
403: responsesMessages['403'],
22+
404: responsesMessages['404'],
23+
405: responsesMessages['405'],
24+
422: responsesMessages['422'],
25+
500: responsesMessages['500']
26+
}
27+
)
28+
29+
def get_db():
30+
"""
31+
Database connexion
32+
"""
33+
db = connection.SessionLocal()
34+
try:
35+
LOGGER.debug("Open database connexion")
36+
yield db
37+
finally:
38+
LOGGER.debug("Close database connexion")
39+
db.close()
40+
41+
@router.post(path="/clients",
42+
response_model=Clients,
43+
status_code=201,
44+
summary="Client creation"
45+
)
46+
async def post_client(client: ClientsBase, db: Session = Depends(get_db)):
47+
"""
48+
Create client with all parameters :
49+
50+
- **firstname**: Firstname of the client
51+
- **lastname**: Lastname of the client
52+
"""
53+
with traces.start_as_current_span("Router GET client by ID"):
54+
LOGGER.info("Start POST Client")
55+
new_client = crud_clients.create(db=db, client=client)
56+
return new_client
57+
58+
@router.get(path="/clients",
59+
response_model=list[Clients],
60+
status_code=200,
61+
summary="List clients"
62+
)
63+
async def get_clients(db: Session = Depends(get_db)):
64+
"""
65+
List all clients
66+
"""
67+
with traces.start_as_current_span("Router GET clients List"):
68+
LOGGER.info("Start GET Clients List")
69+
try:
70+
list_clients = crud_clients.get_list(db=db)
71+
return list_clients
72+
except OperationalError as error:
73+
LOGGER.error(error)
74+
return ""
75+
76+
@router.get(path="/clients/{client_id}",
77+
response_model=Clients,
78+
status_code=200,
79+
summary="Details for specific client")
80+
async def get_client(client_id: str, db: Session = Depends(get_db)):
81+
"""
82+
Details for specific client
83+
"""
84+
with traces.start_as_current_span("Router GET client by ID"):
85+
LOGGER.info("Start GET Client by ID")
86+
client = crud_clients.get_client(db=db, client_id=client_id)
87+
LOGGER.debug("Return client : %s" % str(client))
88+
return client
89+
90+
@router.put(path="/clients/{client_id}",
91+
response_model=Clients,
92+
status_code=200,
93+
summary="Modify details for a specific client")
94+
async def put_client(client_id: str, client: ClientsBase, db: Session = Depends(get_db)):
95+
"""
96+
Modify details for a specific client :
97+
98+
- **firstname**: Firstname of the client
99+
- **lastname**: Lastname of the client
100+
"""
101+
with traces.start_as_current_span("Router Modify clients by ID"):
102+
LOGGER.info("Start PUT Client by ID")
103+
try:
104+
modify_client = crud_clients.put(db=db, client_id=client_id, client=client)
105+
return modify_client
106+
except OperationalError as error:
107+
LOGGER.error(error)
108+
return ""
109+
110+
@router.delete(path="/clients/{client_id}",
111+
response_model=None,
112+
status_code=204,
113+
summary="Delete a specific client"
114+
)
115+
async def delete_client(client_id: str, db: Session = Depends(get_db)):
116+
"""
117+
Delete a specific client
118+
"""
119+
with traces.start_as_current_span("Router DELETE clients by ID"):
120+
LOGGER.info("Start DELETE Client by ID")
121+
delete_client = crud_clients.get_client(db=db, client_id=client_id)
122+
if delete_client is None:
123+
raise HTTPException(status_code=405)
124+
crud_clients.delete(db=db, client_id=client_id)
125+
return None

0 commit comments

Comments
 (0)