Edwin Salguero
commited on
Commit
·
10d71ba
1
Parent(s):
832348e
Enterprise: Clean up directory structure and add proper CI/CD, monitoring, and deployment configurations
Browse files- .github/workflows/ci-cd.yml +109 -0
- Makefile +26 -9
- alerts/alertmanager.yml +0 -21
- docker-compose.yml → deploy/docker/docker-compose.dev.yml +0 -0
- deploy/docker/docker-compose.prod.yml +65 -0
- {kubernetes → deploy/kubernetes}/deployment.yaml +48 -2
- helm/Chart.yaml +0 -17
- infrastructure/alerts/alerts.yml +56 -0
- infrastructure/monitoring/prometheus.yml +62 -0
- monitoring/prometheus.yml +0 -18
- pyproject.toml +127 -0
.github/workflows/ci-cd.yml
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: CI/CD Pipeline
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: [ main, develop ]
|
6 |
+
pull_request:
|
7 |
+
branches: [ main ]
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
test:
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
strategy:
|
13 |
+
matrix:
|
14 |
+
python-version: [3.9, 3.10, 3.11]
|
15 |
+
|
16 |
+
steps:
|
17 |
+
- uses: actions/checkout@v4
|
18 |
+
|
19 |
+
- name: Set up Python ${{ matrix.python-version }}
|
20 |
+
uses: actions/setup-python@v4
|
21 |
+
with:
|
22 |
+
python-version: ${{ matrix.python-version }}
|
23 |
+
|
24 |
+
- name: Install dependencies
|
25 |
+
run: |
|
26 |
+
python -m pip install --upgrade pip
|
27 |
+
pip install -r requirements.txt
|
28 |
+
pip install pre-commit
|
29 |
+
|
30 |
+
- name: Run pre-commit hooks
|
31 |
+
run: pre-commit run --all-files
|
32 |
+
|
33 |
+
- name: Run tests
|
34 |
+
run: |
|
35 |
+
pytest tests/ -v --cov=src --cov-report=xml
|
36 |
+
|
37 |
+
- name: Upload coverage to Codecov
|
38 |
+
uses: codecov/codecov-action@v3
|
39 |
+
with:
|
40 |
+
file: ./coverage.xml
|
41 |
+
|
42 |
+
lint:
|
43 |
+
runs-on: ubuntu-latest
|
44 |
+
steps:
|
45 |
+
- uses: actions/checkout@v4
|
46 |
+
|
47 |
+
- name: Set up Python
|
48 |
+
uses: actions/setup-python@v4
|
49 |
+
with:
|
50 |
+
python-version: 3.9
|
51 |
+
|
52 |
+
- name: Install dependencies
|
53 |
+
run: |
|
54 |
+
pip install flake8 black isort mypy
|
55 |
+
|
56 |
+
- name: Run linting
|
57 |
+
run: |
|
58 |
+
flake8 src/ tests/
|
59 |
+
black --check src/ tests/
|
60 |
+
isort --check-only src/ tests/
|
61 |
+
mypy src/
|
62 |
+
|
63 |
+
security:
|
64 |
+
runs-on: ubuntu-latest
|
65 |
+
steps:
|
66 |
+
- uses: actions/checkout@v4
|
67 |
+
|
68 |
+
- name: Run security scan
|
69 |
+
uses: snyk/actions/python@master
|
70 |
+
env:
|
71 |
+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
72 |
+
with:
|
73 |
+
args: --severity-threshold=high
|
74 |
+
|
75 |
+
build:
|
76 |
+
needs: [test, lint, security]
|
77 |
+
runs-on: ubuntu-latest
|
78 |
+
if: github.ref == 'refs/heads/main'
|
79 |
+
|
80 |
+
steps:
|
81 |
+
- uses: actions/checkout@v4
|
82 |
+
|
83 |
+
- name: Set up Docker Buildx
|
84 |
+
uses: docker/setup-buildx-action@v3
|
85 |
+
|
86 |
+
- name: Build and push Docker image
|
87 |
+
uses: docker/build-push-action@v5
|
88 |
+
with:
|
89 |
+
context: .
|
90 |
+
push: true
|
91 |
+
tags: |
|
92 |
+
ghcr.io/${{ github.repository }}:latest
|
93 |
+
ghcr.io/${{ github.repository }}:${{ github.sha }}
|
94 |
+
cache-from: type=gha
|
95 |
+
cache-to: type=gha,mode=max
|
96 |
+
|
97 |
+
deploy:
|
98 |
+
needs: build
|
99 |
+
runs-on: ubuntu-latest
|
100 |
+
if: github.ref == 'refs/heads/main'
|
101 |
+
environment: production
|
102 |
+
|
103 |
+
steps:
|
104 |
+
- uses: actions/checkout@v4
|
105 |
+
|
106 |
+
- name: Deploy to Kubernetes
|
107 |
+
run: |
|
108 |
+
echo "Deploying to production..."
|
109 |
+
# Add your deployment commands here
|
Makefile
CHANGED
@@ -7,11 +7,12 @@ help: ## Show this help message
|
|
7 |
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
8 |
|
9 |
install: ## Install dependencies
|
10 |
-
pip install -
|
|
|
11 |
pre-commit install
|
12 |
|
13 |
test: ## Run tests
|
14 |
-
pytest tests/ -v --cov=src --cov-report=html
|
15 |
|
16 |
lint: ## Run linting
|
17 |
flake8 src/ tests/
|
@@ -26,6 +27,9 @@ clean: ## Clean build artifacts
|
|
26 |
find . -type d -name "__pycache__" -delete
|
27 |
rm -rf .pytest_cache/
|
28 |
rm -rf htmlcov/
|
|
|
|
|
|
|
29 |
|
30 |
build: ## Build Docker image
|
31 |
docker build -t fred-ml .
|
@@ -33,20 +37,33 @@ build: ## Build Docker image
|
|
33 |
run: ## Run application locally
|
34 |
uvicorn src.main:app --reload --host 0.0.0.0 --port 8000
|
35 |
|
36 |
-
run-docker: ## Run with Docker Compose
|
37 |
-
docker-compose up --build
|
|
|
|
|
|
|
38 |
|
39 |
deploy: ## Deploy to Kubernetes
|
40 |
-
kubectl apply -f kubernetes/
|
41 |
-
|
|
|
|
|
42 |
|
43 |
logs: ## View application logs
|
44 |
-
docker-compose logs -f fred-ml
|
45 |
|
46 |
shell: ## Open shell in container
|
47 |
-
docker-compose exec fred-ml bash
|
48 |
|
49 |
migrate: ## Run database migrations
|
50 |
alembic upgrade head
|
51 |
|
52 |
-
setup-dev: install format lint test ## Setup development environment
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
8 |
|
9 |
install: ## Install dependencies
|
10 |
+
pip install -e .
|
11 |
+
pip install -e ".[dev]"
|
12 |
pre-commit install
|
13 |
|
14 |
test: ## Run tests
|
15 |
+
pytest tests/ -v --cov=src --cov-report=html --cov-report=xml
|
16 |
|
17 |
lint: ## Run linting
|
18 |
flake8 src/ tests/
|
|
|
27 |
find . -type d -name "__pycache__" -delete
|
28 |
rm -rf .pytest_cache/
|
29 |
rm -rf htmlcov/
|
30 |
+
rm -rf build/
|
31 |
+
rm -rf dist/
|
32 |
+
rm -rf *.egg-info/
|
33 |
|
34 |
build: ## Build Docker image
|
35 |
docker build -t fred-ml .
|
|
|
37 |
run: ## Run application locally
|
38 |
uvicorn src.main:app --reload --host 0.0.0.0 --port 8000
|
39 |
|
40 |
+
run-docker: ## Run with Docker Compose (development)
|
41 |
+
docker-compose -f deploy/docker/docker-compose.dev.yml up --build
|
42 |
+
|
43 |
+
run-prod: ## Run with Docker Compose (production)
|
44 |
+
docker-compose -f deploy/docker/docker-compose.prod.yml up --build
|
45 |
|
46 |
deploy: ## Deploy to Kubernetes
|
47 |
+
kubectl apply -f deploy/kubernetes/
|
48 |
+
|
49 |
+
deploy-helm: ## Deploy with Helm
|
50 |
+
helm install fred-ml deploy/helm/
|
51 |
|
52 |
logs: ## View application logs
|
53 |
+
docker-compose -f deploy/docker/docker-compose.dev.yml logs -f fred-ml
|
54 |
|
55 |
shell: ## Open shell in container
|
56 |
+
docker-compose -f deploy/docker/docker-compose.dev.yml exec fred-ml bash
|
57 |
|
58 |
migrate: ## Run database migrations
|
59 |
alembic upgrade head
|
60 |
|
61 |
+
setup-dev: install format lint test ## Setup development environment
|
62 |
+
|
63 |
+
ci: test lint format ## Run CI checks locally
|
64 |
+
|
65 |
+
package: clean build ## Build package for distribution
|
66 |
+
python -m build
|
67 |
+
|
68 |
+
publish: package ## Publish to PyPI
|
69 |
+
twine upload dist/*
|
alerts/alertmanager.yml
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
global:
|
2 |
-
resolve_timeout: 5m
|
3 |
-
|
4 |
-
route:
|
5 |
-
group_by: ['alertname']
|
6 |
-
group_wait: 10s
|
7 |
-
group_interval: 10s
|
8 |
-
repeat_interval: 1h
|
9 |
-
receiver: 'web.hook'
|
10 |
-
|
11 |
-
receivers:
|
12 |
-
- name: 'web.hook'
|
13 |
-
webhook_configs:
|
14 |
-
- url: 'http://127.0.0.1:5001/'
|
15 |
-
|
16 |
-
inhibit_rules:
|
17 |
-
- source_match:
|
18 |
-
severity: 'critical'
|
19 |
-
target_match:
|
20 |
-
severity: 'warning'
|
21 |
-
equal: ['alertname', 'dev', 'instance']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docker-compose.yml → deploy/docker/docker-compose.dev.yml
RENAMED
File without changes
|
deploy/docker/docker-compose.prod.yml
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version: '3.8'
|
2 |
+
|
3 |
+
services:
|
4 |
+
fred-ml:
|
5 |
+
image: ghcr.io/eaname/fredml:latest
|
6 |
+
ports:
|
7 |
+
- "8000:8000"
|
8 |
+
environment:
|
9 |
+
- FRED_API_KEY=${FRED_API_KEY}
|
10 |
+
- ENVIRONMENT=production
|
11 |
+
- LOG_LEVEL=INFO
|
12 |
+
volumes:
|
13 |
+
- ./data:/app/data
|
14 |
+
- ./logs:/app/logs
|
15 |
+
depends_on:
|
16 |
+
- redis
|
17 |
+
- postgres
|
18 |
+
networks:
|
19 |
+
- fred-ml-network
|
20 |
+
restart: unless-stopped
|
21 |
+
|
22 |
+
redis:
|
23 |
+
image: redis:7-alpine
|
24 |
+
ports:
|
25 |
+
- "6379:6379"
|
26 |
+
volumes:
|
27 |
+
- redis_data:/data
|
28 |
+
networks:
|
29 |
+
- fred-ml-network
|
30 |
+
restart: unless-stopped
|
31 |
+
|
32 |
+
postgres:
|
33 |
+
image: postgres:15-alpine
|
34 |
+
environment:
|
35 |
+
POSTGRES_DB: fred_ml
|
36 |
+
POSTGRES_USER: fred_user
|
37 |
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
38 |
+
ports:
|
39 |
+
- "5432:5432"
|
40 |
+
volumes:
|
41 |
+
- postgres_data:/var/lib/postgresql/data
|
42 |
+
networks:
|
43 |
+
- fred-ml-network
|
44 |
+
restart: unless-stopped
|
45 |
+
|
46 |
+
nginx:
|
47 |
+
image: nginx:alpine
|
48 |
+
ports:
|
49 |
+
- "80:80"
|
50 |
+
- "443:443"
|
51 |
+
volumes:
|
52 |
+
- ./nginx.conf:/etc/nginx/nginx.conf
|
53 |
+
depends_on:
|
54 |
+
- fred-ml
|
55 |
+
networks:
|
56 |
+
- fred-ml-network
|
57 |
+
restart: unless-stopped
|
58 |
+
|
59 |
+
volumes:
|
60 |
+
redis_data:
|
61 |
+
postgres_data:
|
62 |
+
|
63 |
+
networks:
|
64 |
+
fred-ml-network:
|
65 |
+
driver: bridge
|
{kubernetes → deploy/kubernetes}/deployment.yaml
RENAMED
@@ -4,6 +4,7 @@ metadata:
|
|
4 |
name: fred-ml
|
5 |
labels:
|
6 |
app: fred-ml
|
|
|
7 |
spec:
|
8 |
replicas: 3
|
9 |
selector:
|
@@ -13,12 +14,14 @@ spec:
|
|
13 |
metadata:
|
14 |
labels:
|
15 |
app: fred-ml
|
|
|
16 |
spec:
|
17 |
containers:
|
18 |
- name: fred-ml
|
19 |
-
image:
|
20 |
ports:
|
21 |
- containerPort: 8000
|
|
|
22 |
env:
|
23 |
- name: FRED_API_KEY
|
24 |
valueFrom:
|
@@ -27,6 +30,8 @@ spec:
|
|
27 |
key: fred-api-key
|
28 |
- name: ENVIRONMENT
|
29 |
value: "production"
|
|
|
|
|
30 |
resources:
|
31 |
requests:
|
32 |
memory: "256Mi"
|
@@ -40,17 +45,35 @@ spec:
|
|
40 |
port: 8000
|
41 |
initialDelaySeconds: 30
|
42 |
periodSeconds: 10
|
|
|
|
|
43 |
readinessProbe:
|
44 |
httpGet:
|
45 |
path: /ready
|
46 |
port: 8000
|
47 |
initialDelaySeconds: 5
|
48 |
periodSeconds: 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
---
|
50 |
apiVersion: v1
|
51 |
kind: Service
|
52 |
metadata:
|
53 |
name: fred-ml-service
|
|
|
|
|
54 |
spec:
|
55 |
selector:
|
56 |
app: fred-ml
|
@@ -58,4 +81,27 @@ spec:
|
|
58 |
- protocol: TCP
|
59 |
port: 80
|
60 |
targetPort: 8000
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
name: fred-ml
|
5 |
labels:
|
6 |
app: fred-ml
|
7 |
+
version: v1.0.0
|
8 |
spec:
|
9 |
replicas: 3
|
10 |
selector:
|
|
|
14 |
metadata:
|
15 |
labels:
|
16 |
app: fred-ml
|
17 |
+
version: v1.0.0
|
18 |
spec:
|
19 |
containers:
|
20 |
- name: fred-ml
|
21 |
+
image: ghcr.io/eaname/fredml:latest
|
22 |
ports:
|
23 |
- containerPort: 8000
|
24 |
+
name: http
|
25 |
env:
|
26 |
- name: FRED_API_KEY
|
27 |
valueFrom:
|
|
|
30 |
key: fred-api-key
|
31 |
- name: ENVIRONMENT
|
32 |
value: "production"
|
33 |
+
- name: LOG_LEVEL
|
34 |
+
value: "INFO"
|
35 |
resources:
|
36 |
requests:
|
37 |
memory: "256Mi"
|
|
|
45 |
port: 8000
|
46 |
initialDelaySeconds: 30
|
47 |
periodSeconds: 10
|
48 |
+
timeoutSeconds: 5
|
49 |
+
failureThreshold: 3
|
50 |
readinessProbe:
|
51 |
httpGet:
|
52 |
path: /ready
|
53 |
port: 8000
|
54 |
initialDelaySeconds: 5
|
55 |
periodSeconds: 5
|
56 |
+
timeoutSeconds: 3
|
57 |
+
failureThreshold: 3
|
58 |
+
volumeMounts:
|
59 |
+
- name: data-volume
|
60 |
+
mountPath: /app/data
|
61 |
+
- name: logs-volume
|
62 |
+
mountPath: /app/logs
|
63 |
+
volumes:
|
64 |
+
- name: data-volume
|
65 |
+
persistentVolumeClaim:
|
66 |
+
claimName: fred-ml-data-pvc
|
67 |
+
- name: logs-volume
|
68 |
+
persistentVolumeClaim:
|
69 |
+
claimName: fred-ml-logs-pvc
|
70 |
---
|
71 |
apiVersion: v1
|
72 |
kind: Service
|
73 |
metadata:
|
74 |
name: fred-ml-service
|
75 |
+
labels:
|
76 |
+
app: fred-ml
|
77 |
spec:
|
78 |
selector:
|
79 |
app: fred-ml
|
|
|
81 |
- protocol: TCP
|
82 |
port: 80
|
83 |
targetPort: 8000
|
84 |
+
name: http
|
85 |
+
type: LoadBalancer
|
86 |
+
---
|
87 |
+
apiVersion: v1
|
88 |
+
kind: PersistentVolumeClaim
|
89 |
+
metadata:
|
90 |
+
name: fred-ml-data-pvc
|
91 |
+
spec:
|
92 |
+
accessModes:
|
93 |
+
- ReadWriteOnce
|
94 |
+
resources:
|
95 |
+
requests:
|
96 |
+
storage: 10Gi
|
97 |
+
---
|
98 |
+
apiVersion: v1
|
99 |
+
kind: PersistentVolumeClaim
|
100 |
+
metadata:
|
101 |
+
name: fred-ml-logs-pvc
|
102 |
+
spec:
|
103 |
+
accessModes:
|
104 |
+
- ReadWriteOnce
|
105 |
+
resources:
|
106 |
+
requests:
|
107 |
+
storage: 5Gi
|
helm/Chart.yaml
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
apiVersion: v2
|
2 |
-
name: fred-ml
|
3 |
-
description: A Helm chart for FRED ML Economic Data Analysis
|
4 |
-
type: application
|
5 |
-
version: 1.0.0
|
6 |
-
appVersion: "1.0.0"
|
7 |
-
keywords:
|
8 |
-
- economics
|
9 |
-
- data-analysis
|
10 |
-
- machine-learning
|
11 |
-
- fred
|
12 |
-
home: https://github.com/EAName/FREDML
|
13 |
-
sources:
|
14 |
-
- https://github.com/EAName/FREDML
|
15 |
-
maintainers:
|
16 |
-
- name: Edwin Salguero
|
17 |
-
email: [email protected]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
infrastructure/alerts/alerts.yml
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
groups:
|
2 |
+
- name: fred-ml
|
3 |
+
rules:
|
4 |
+
- alert: FredMLHighErrorRate
|
5 |
+
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1
|
6 |
+
for: 2m
|
7 |
+
labels:
|
8 |
+
severity: critical
|
9 |
+
annotations:
|
10 |
+
summary: "High error rate detected"
|
11 |
+
description: "Error rate is {{ $value }} errors per second"
|
12 |
+
|
13 |
+
- alert: FredMLHighResponseTime
|
14 |
+
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2
|
15 |
+
for: 2m
|
16 |
+
labels:
|
17 |
+
severity: warning
|
18 |
+
annotations:
|
19 |
+
summary: "High response time detected"
|
20 |
+
description: "95th percentile response time is {{ $value }} seconds"
|
21 |
+
|
22 |
+
- alert: FredMLDown
|
23 |
+
expr: up{job="fred-ml"} == 0
|
24 |
+
for: 1m
|
25 |
+
labels:
|
26 |
+
severity: critical
|
27 |
+
annotations:
|
28 |
+
summary: "FredML service is down"
|
29 |
+
description: "FredML service has been down for more than 1 minute"
|
30 |
+
|
31 |
+
- alert: FredMLHighMemoryUsage
|
32 |
+
expr: (container_memory_usage_bytes{container="fred-ml"} / container_spec_memory_limit_bytes{container="fred-ml"}) > 0.8
|
33 |
+
for: 5m
|
34 |
+
labels:
|
35 |
+
severity: warning
|
36 |
+
annotations:
|
37 |
+
summary: "High memory usage detected"
|
38 |
+
description: "Memory usage is {{ $value | humanizePercentage }}"
|
39 |
+
|
40 |
+
- alert: FredMLHighCPUUsage
|
41 |
+
expr: rate(container_cpu_usage_seconds_total{container="fred-ml"}[5m]) > 0.8
|
42 |
+
for: 5m
|
43 |
+
labels:
|
44 |
+
severity: warning
|
45 |
+
annotations:
|
46 |
+
summary: "High CPU usage detected"
|
47 |
+
description: "CPU usage is {{ $value | humanizePercentage }}"
|
48 |
+
|
49 |
+
- alert: FredMLAPIRateLimit
|
50 |
+
expr: increase(fred_api_rate_limit_exceeded_total[5m]) > 0
|
51 |
+
for: 1m
|
52 |
+
labels:
|
53 |
+
severity: warning
|
54 |
+
annotations:
|
55 |
+
summary: "FRED API rate limit exceeded"
|
56 |
+
description: "API rate limit has been exceeded in the last 5 minutes"
|
infrastructure/monitoring/prometheus.yml
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
global:
|
2 |
+
scrape_interval: 15s
|
3 |
+
evaluation_interval: 15s
|
4 |
+
external_labels:
|
5 |
+
cluster: fred-ml-cluster
|
6 |
+
job: fred-ml
|
7 |
+
|
8 |
+
rule_files:
|
9 |
+
- "alerts.yml"
|
10 |
+
|
11 |
+
scrape_configs:
|
12 |
+
- job_name: 'fred-ml'
|
13 |
+
static_configs:
|
14 |
+
- targets: ['fred-ml-service:8000']
|
15 |
+
metrics_path: '/metrics'
|
16 |
+
scrape_interval: 5s
|
17 |
+
scrape_timeout: 3s
|
18 |
+
honor_labels: true
|
19 |
+
|
20 |
+
- job_name: 'kubernetes-pods'
|
21 |
+
kubernetes_sd_configs:
|
22 |
+
- role: pod
|
23 |
+
relabel_configs:
|
24 |
+
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
|
25 |
+
action: keep
|
26 |
+
regex: true
|
27 |
+
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
|
28 |
+
action: replace
|
29 |
+
target_label: __metrics_path__
|
30 |
+
regex: (.+)
|
31 |
+
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
|
32 |
+
action: replace
|
33 |
+
regex: ([^:]+)(?::\d+)?;(\d+)
|
34 |
+
replacement: $1:$2
|
35 |
+
target_label: __address__
|
36 |
+
|
37 |
+
- job_name: 'kubernetes-service-endpoints'
|
38 |
+
kubernetes_sd_configs:
|
39 |
+
- role: endpoints
|
40 |
+
relabel_configs:
|
41 |
+
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
|
42 |
+
action: keep
|
43 |
+
regex: true
|
44 |
+
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
|
45 |
+
action: replace
|
46 |
+
target_label: __scheme__
|
47 |
+
regex: (https?)
|
48 |
+
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
|
49 |
+
action: replace
|
50 |
+
target_label: __metrics_path__
|
51 |
+
regex: (.+)
|
52 |
+
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
|
53 |
+
action: replace
|
54 |
+
regex: ([^:]+)(?::\d+)?;(\d+)
|
55 |
+
replacement: $1:$2
|
56 |
+
target_label: __address__
|
57 |
+
|
58 |
+
alerting:
|
59 |
+
alertmanagers:
|
60 |
+
- static_configs:
|
61 |
+
- targets:
|
62 |
+
- alertmanager:9093
|
monitoring/prometheus.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
global:
|
2 |
-
scrape_interval: 15s
|
3 |
-
evaluation_interval: 15s
|
4 |
-
|
5 |
-
rule_files:
|
6 |
-
# - "first_rules.yml"
|
7 |
-
# - "second_rules.yml"
|
8 |
-
|
9 |
-
scrape_configs:
|
10 |
-
- job_name: 'fred-ml'
|
11 |
-
static_configs:
|
12 |
-
- targets: ['localhost:8000']
|
13 |
-
metrics_path: '/metrics'
|
14 |
-
scrape_interval: 5s
|
15 |
-
|
16 |
-
- job_name: 'prometheus'
|
17 |
-
static_configs:
|
18 |
-
- targets: ['localhost:9090']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pyproject.toml
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[build-system]
|
2 |
+
requires = ["setuptools>=61.0", "wheel"]
|
3 |
+
build-backend = "setuptools.build_meta"
|
4 |
+
|
5 |
+
[project]
|
6 |
+
name = "fred-ml"
|
7 |
+
version = "1.0.0"
|
8 |
+
description = "Enterprise-grade economic data analysis platform using FRED API"
|
9 |
+
readme = "README.md"
|
10 |
+
license = {text = "MIT"}
|
11 |
+
authors = [
|
12 |
+
{name = "Edwin Salguero", email = "[email protected]"}
|
13 |
+
]
|
14 |
+
maintainers = [
|
15 |
+
{name = "Edwin Salguero", email = "[email protected]"}
|
16 |
+
]
|
17 |
+
keywords = ["economics", "data-analysis", "machine-learning", "fred", "api"]
|
18 |
+
classifiers = [
|
19 |
+
"Development Status :: 5 - Production/Stable",
|
20 |
+
"Intended Audience :: Financial and Insurance Industry",
|
21 |
+
"License :: OSI Approved :: MIT License",
|
22 |
+
"Operating System :: OS Independent",
|
23 |
+
"Programming Language :: Python :: 3",
|
24 |
+
"Programming Language :: Python :: 3.9",
|
25 |
+
"Programming Language :: Python :: 3.10",
|
26 |
+
"Programming Language :: Python :: 3.11",
|
27 |
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
28 |
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
29 |
+
]
|
30 |
+
requires-python = ">=3.9"
|
31 |
+
dependencies = [
|
32 |
+
"fredapi==0.4.2",
|
33 |
+
"pandas==2.1.4",
|
34 |
+
"numpy==1.24.3",
|
35 |
+
"matplotlib==3.7.2",
|
36 |
+
"seaborn==0.12.2",
|
37 |
+
"jupyter==1.0.0",
|
38 |
+
"python-dotenv==1.0.0",
|
39 |
+
"requests==2.31.0",
|
40 |
+
"PyYAML==6.0.2",
|
41 |
+
"APScheduler==3.10.4",
|
42 |
+
"scikit-learn==1.3.0",
|
43 |
+
"scipy==1.11.1",
|
44 |
+
"statsmodels==0.14.0",
|
45 |
+
"fastapi==0.104.1",
|
46 |
+
"uvicorn[standard]==0.24.0",
|
47 |
+
"pydantic==1.10.13",
|
48 |
+
"redis==5.0.1",
|
49 |
+
"psycopg2-binary==2.9.9",
|
50 |
+
"sqlalchemy==2.0.23",
|
51 |
+
"alembic==1.13.0",
|
52 |
+
"prometheus-client==0.19.0",
|
53 |
+
"structlog==23.2.0",
|
54 |
+
]
|
55 |
+
|
56 |
+
[project.optional-dependencies]
|
57 |
+
dev = [
|
58 |
+
"pytest==7.4.0",
|
59 |
+
"pytest-asyncio==0.21.1",
|
60 |
+
"httpx==0.25.2",
|
61 |
+
"black==23.11.0",
|
62 |
+
"flake8==6.1.0",
|
63 |
+
"mypy==1.7.1",
|
64 |
+
"pre-commit==3.6.0",
|
65 |
+
"isort==5.12.0",
|
66 |
+
]
|
67 |
+
|
68 |
+
[project.urls]
|
69 |
+
Homepage = "https://github.com/EAName/FREDML"
|
70 |
+
Documentation = "https://github.com/EAName/FREDML#readme"
|
71 |
+
Repository = "https://github.com/EAName/FREDML.git"
|
72 |
+
"Bug Tracker" = "https://github.com/EAName/FREDML/issues"
|
73 |
+
|
74 |
+
[project.scripts]
|
75 |
+
fred-ml = "src.main:main"
|
76 |
+
|
77 |
+
[tool.black]
|
78 |
+
line-length = 88
|
79 |
+
target-version = ['py39']
|
80 |
+
include = '\.pyi?$'
|
81 |
+
extend-exclude = '''
|
82 |
+
/(
|
83 |
+
# directories
|
84 |
+
\.eggs
|
85 |
+
| \.git
|
86 |
+
| \.hg
|
87 |
+
| \.mypy_cache
|
88 |
+
| \.tox
|
89 |
+
| \.venv
|
90 |
+
| build
|
91 |
+
| dist
|
92 |
+
)/
|
93 |
+
'''
|
94 |
+
|
95 |
+
[tool.isort]
|
96 |
+
profile = "black"
|
97 |
+
multi_line_output = 3
|
98 |
+
line_length = 88
|
99 |
+
known_first_party = ["src"]
|
100 |
+
|
101 |
+
[tool.mypy]
|
102 |
+
python_version = "3.9"
|
103 |
+
warn_return_any = true
|
104 |
+
warn_unused_configs = true
|
105 |
+
disallow_untyped_defs = true
|
106 |
+
disallow_incomplete_defs = true
|
107 |
+
check_untyped_defs = true
|
108 |
+
disallow_untyped_decorators = true
|
109 |
+
no_implicit_optional = true
|
110 |
+
warn_redundant_casts = true
|
111 |
+
warn_unused_ignores = true
|
112 |
+
warn_no_return = true
|
113 |
+
warn_unreachable = true
|
114 |
+
strict_equality = true
|
115 |
+
|
116 |
+
[tool.pytest.ini_options]
|
117 |
+
minversion = "6.0"
|
118 |
+
addopts = "-ra -q --strict-markers --strict-config"
|
119 |
+
testpaths = ["tests"]
|
120 |
+
python_files = ["test_*.py", "*_test.py"]
|
121 |
+
python_classes = ["Test*"]
|
122 |
+
python_functions = ["test_*"]
|
123 |
+
markers = [
|
124 |
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
125 |
+
"integration: marks tests as integration tests",
|
126 |
+
"unit: marks tests as unit tests",
|
127 |
+
]
|