263 lines
6.3 KiB
Markdown
263 lines
6.3 KiB
Markdown
# Open-Meteo Coordinates Service
|
|
|
|
A FastAPI-based microservice that queries the Open-Meteo Geocoding API to retrieve coordinates for various cities. The service includes caching, Prometheus metrics, and Grafana dashboards for monitoring.
|
|
|
|
## Features
|
|
|
|
- **RESTful API** for retrieving city coordinates
|
|
- **Intelligent caching** to reduce external API calls
|
|
- **Prometheus metrics** for observability
|
|
- **Pre-configured Grafana dashboards** with 5 panels
|
|
- **Docker Compose** setup for easy deployment
|
|
|
|
## Prerequisites
|
|
|
|
- Docker
|
|
- Docker Compose
|
|
|
|
## Quick Start
|
|
|
|
1. **Clone the repository**
|
|
```bash
|
|
cd open-meteo-service
|
|
```
|
|
|
|
2. **Start all services**
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
3. **Access the services**
|
|
- API: http://localhost:8000/docs
|
|
- Prometheus: http://localhost:9090
|
|
- Grafana: http://localhost:3000 (admin/admin)
|
|
|
|
## Helm (Kubernetes)
|
|
|
|
The Helm chart in the `helm` folder deploys the FastAPI app and, by default, Prometheus and Grafana.
|
|
|
|
### What it deploys
|
|
- **App**: FastAPI service with `/healthz` probes and Prometheus scrape annotations
|
|
- **Prometheus**: Scrapes the app metrics at `/metrics`
|
|
- **Grafana**: Pre-provisioned datasource and dashboard for the app metrics
|
|
|
|
### Prerequisites
|
|
- Kubernetes cluster
|
|
- Helm v3
|
|
|
|
### Install
|
|
```bash
|
|
helm install open-meteo-service ./helm
|
|
```
|
|
|
|
### Upgrade
|
|
```bash
|
|
helm upgrade open-meteo-service ./helm
|
|
```
|
|
|
|
### Access the services
|
|
```bash
|
|
kubectl port-forward svc/open-meteo-service-open-meteo-service 8080:8000
|
|
kubectl port-forward svc/open-meteo-service-open-meteo-service-prometheus 9090:9090
|
|
kubectl port-forward svc/open-meteo-service-open-meteo-service-grafana 3000:3000
|
|
```
|
|
|
|
### Values overview
|
|
You can customize the chart via `helm/values.yaml` or `--set` flags.
|
|
|
|
**App values**
|
|
- `image.repository`, `image.tag`, `image.pullPolicy`
|
|
- `service.type`, `service.port`
|
|
- `env.cacheFile`
|
|
- `persistence.enabled`, `persistence.size`, `persistence.storageClassName`
|
|
|
|
**Prometheus values**
|
|
- `prometheus.enabled`
|
|
- `prometheus.image`
|
|
- `prometheus.service.type`, `prometheus.service.port`
|
|
- `prometheus.persistence.enabled`, `prometheus.persistence.size`, `prometheus.persistence.storageClassName`
|
|
|
|
**Grafana values**
|
|
- `grafana.enabled`
|
|
- `grafana.image`
|
|
- `grafana.service.type`, `grafana.service.port`
|
|
- `grafana.adminUser`, `grafana.adminPassword`
|
|
- `grafana.persistence.enabled`, `grafana.persistence.size`, `grafana.persistence.storageClassName`
|
|
|
|
### Example: disable Grafana and Prometheus
|
|
```bash
|
|
helm install open-meteo-service ./helm \
|
|
--set grafana.enabled=false \
|
|
--set prometheus.enabled=false
|
|
```
|
|
|
|
### Example: enable persistence for all components
|
|
```bash
|
|
helm install open-meteo-service ./helm \
|
|
--set persistence.enabled=true \
|
|
--set prometheus.persistence.enabled=true \
|
|
--set grafana.persistence.enabled=true
|
|
```
|
|
|
|
## API Documentation
|
|
|
|
### Endpoints
|
|
|
|
#### `GET /coordinates`
|
|
Retrieve coordinates for all configured cities.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"source": "cache",
|
|
"data": {
|
|
"Tel Aviv": {
|
|
"name": "Tel Aviv",
|
|
"latitude": 32.08088,
|
|
"longitude": 34.78057,
|
|
"country": "Israel"
|
|
},
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `GET /coordinates/{city}`
|
|
Retrieve coordinates for a specific city.
|
|
|
|
**Parameters:**
|
|
- `city` (path) - City name (e.g., "Ashkelon", "London")
|
|
|
|
**Example:**
|
|
```bash
|
|
curl http://localhost:8000/coordinates/Paris
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"source": "open-meteo",
|
|
"data": {
|
|
"name": "Paris",
|
|
"latitude": 48.85341,
|
|
"longitude": 2.3488,
|
|
"country": "France"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `GET /metrics`
|
|
Prometheus metrics endpoint exposing service metrics.
|
|
|
|
**Example:**
|
|
```bash
|
|
curl http://localhost:8000/metrics
|
|
```
|
|
|
|
#### `GET /healthz`
|
|
Health check endpoint.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "ok"
|
|
}
|
|
```
|
|
|
|
## Metrics
|
|
|
|
The service exposes the following Prometheus metrics:
|
|
|
|
### HTTP Metrics
|
|
- **`http_requests_total`** - Counter of total HTTP requests
|
|
- Labels: `endpoint`, `method`, `status`
|
|
|
|
- **`http_request_duration_seconds`** - Histogram of request durations
|
|
- Labels: `endpoint`, `method`
|
|
|
|
### Cache Metrics
|
|
- **`coordinates_cache_hits_total`** - Counter of cache hits
|
|
- **`coordinates_cache_misses_total`** - Counter of cache misses
|
|
|
|
### External API Metrics
|
|
- **`openmeteo_api_calls_total`** - Counter of calls to Open-Meteo Geocoding API
|
|
- Labels: `city`
|
|
|
|
## Grafana Dashboard
|
|
|
|
The pre-configured dashboard includes 5 panels:
|
|
|
|
1. **Request Rate** - Requests per second by endpoint
|
|
2. **Request Duration p95** - 95th percentile latency
|
|
3. **Cache Hits vs Misses** - Cache effectiveness
|
|
4. **Open-Meteo Calls by City** - External API usage per city
|
|
5. **Requests by Status** - HTTP status code distribution
|
|
|
|
Access the dashboard at http://localhost:3000 after logging in with `admin/admin`.
|
|
|
|
## Caching
|
|
|
|
The service uses a local JSON file (`coordinates_cache.json`) to cache city coordinates:
|
|
- Reduces external API calls
|
|
- Shared across all API endpoints
|
|
- Persists between requests (not container restarts)
|
|
- Automatically updated when new cities are queried
|
|
|
|
## Development
|
|
|
|
### Project Structure
|
|
```
|
|
.
|
|
├── app/
|
|
│ ├── main.py # FastAPI application
|
|
│ ├── service.py # Business logic & caching
|
|
│ └── metrics.py # Prometheus metrics definitions
|
|
├── grafana/
|
|
│ ├── provisioning/ # Auto-configured datasources & dashboards
|
|
│ └── dashboards/ # Dashboard JSON definitions
|
|
├── docker-compose.yml # Service orchestration
|
|
├── Dockerfile # Python app container
|
|
├── prometheus.yml # Prometheus scrape configuration
|
|
└── requirements.txt # Python dependencies
|
|
```
|
|
|
|
### Stop Services
|
|
```bash
|
|
docker compose down
|
|
```
|
|
|
|
### View Logs
|
|
```bash
|
|
docker compose logs -f open-meteo-service
|
|
```
|
|
|
|
### Rebuild After Code Changes
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
- `CACHE_FILE` - Path to cache file (default: `coordinates_cache.json`)
|
|
|
|
### Scrape Interval
|
|
Edit `prometheus.yml` to adjust the scrape interval (default: 15s).
|
|
|
|
## Testing
|
|
|
|
Generate test traffic to populate metrics:
|
|
```bash
|
|
# Test all endpoints
|
|
curl http://localhost:8000/coordinates
|
|
curl http://localhost:8000/coordinates/Paris
|
|
curl http://localhost:8000/coordinates/London
|
|
|
|
# Generate load
|
|
for i in {1..10}; do curl -s http://localhost:8000/coordinates > /dev/null; done
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|