What's Changed
Added
- Auth-proxy routing (#245):
TRUST_AUTH_PROXYconfig flag enables forwarding authenticated requests through an external auth proxy (Authentik, Caddy). When enabled, the API reads the authenticated user identity from theX-Forwarded-User/X-Auth-Request-Userheaders instead of performing its own authentication, removing the need to expose credentials directly to the proxy. Special thanks to @kahnwong for the detailed reproduction information that led to this fix. - Structured logging with
structlog: A newLOG_FORMATconfig option (jsonortext, defaulttext) controls the log output format. JSON mode emits machine-readable structured log lines suitable for log aggregation pipelines (e.g. Loki). Exposed in Helmvalues.yamlviaconfig.logFormat. - DB vacuuming and savings-ledger pruning:
MetricsCompressornow runsVACUUMon the main metrics tables after each compaction cycle. A dedicated pruning pass removes stale hourly-savings-ledger records older than the configured retention window, keeping storage usage bounded on long-running deployments. - Metrics: DB-level pagination for
GET /api/v1/metrics— The endpoint now uses SQLCOUNT(*) + LIMIT/OFFSETinstead of loading the full result set into Python. A newMETRICS_LIST_MAX_RANGE_DAYSconfig (default 30, exposed in Helmvalues.yamlviaconfig.metricsListMaxRangeDays) rejects requests wider than the limit with HTTP 400 to prevent accidental OOM on large clusters. - Repository:
read_combined_metrics_page— New method onCombinedMetricsRepository(base Python fallback + optimised PostgreSQLUNION ALLimplementation) for DB-level paginated reads. - Repository:
read_latest_per_pod— New method returning the single most-recent metric snapshot for each(namespace, pod_name)pair. PostgreSQL implementation usesDISTINCT ONfor efficiency; base class falls back to Python deduplication. - Repository:
aggregate_grouped_row_count— New method returning the number of distinct(group_key × time_bucket)rows a grouped-aggregate export would produce, computed entirely in SQL (COUNT DISTINCT). Implemented for PostgreSQL and SQLite. - Metrics endpoint: Prometheus gauge refresh via
read_latest_per_pod—refresh_metrics_from_dbnow callsread_latest_per_podinstead of loading the full metrics history and deduplicating in Python, eliminating a major OOM source for large clusters.
Changed
- Toolchain: switched from
piptouv— All CI workflows, the Dockerfile, and developer documentation now useuvfor dependency management and virtual-environment creation. Auv.locklockfile replaces the previousrequirements*.txtfiles, ensuring fully reproducible builds across environments. - Settings: replaced
python-dotenvwithpydantic-settings—config.pyis now driven bypydantic-settingsBaseSettings, giving automatic environment-variable parsing with type coercion, validation, and cleaner secret handling.python-dotenvremoved from dependencies. - Type checking: Pyrefly added to pre-commit — Pyrefly static type checker integrated into the pre-commit hook chain. Codebase cleaned up (dead code, redundant imports, incorrect annotations) as part of the initial Pyrefly pass.
- Frontend: metrics page removed — The
/metricsroute and its associated Svelte page have been removed. Dashboard panels reordered accordingly.
Fixed
- API: oversized response headers causing Caddy/Authentik 502/503 errors — Bloated debug and CORS headers removed from all API responses; the fix resolves
upstream sent invalid header50x errors seen behind reverse-proxy setups. - Frontend: donut chart legend overflow — Namespaces beyond the top-N are now collapsed into an
otherslice, preventing the chart legend from overflowing the panel. - Ruff version mismatch in CI — Pinned
ruffversion in CI to match the local configuration, eliminating lint-step failures caused by version skew. - OOM (
OOMKilled, exit code 137) ingreenkube-api—GET /api/v1/metrics,GET /api/v1/report/summary?aggregate=true, and the Prometheus gauge refresh all previously loaded up to 1 M+CombinedMetricobjects into memory. All three paths are now SQL-backed and never materialise full row sets in Python (#239). report/summary?aggregate=trueuses pure SQL — The aggregate summary path callsaggregate_grouped_row_count(SQLCOUNT DISTINCT) instead of invokingaggregate_metrics()over loaded rows, making large date ranges safe regardless of dataset size.- Memory leaks in Kubernetes API client —
NodeCollectorandPodCollectornow explicitly close the asynckubernetes_asyncioAPI client after each collection cycle, preventing handle leaks on long-running pods. - Security: frontend dependency updates —
package.json/package-lock.jsonupdated to remediate Trivy-flagged vulnerabilities in transitive frontend dependencies.
Docker: docker pull greenkube/greenkube:0.2.12
Helm:
helm repo add greenkube https://GreenKubeCloud.github.io/GreenKube
helm repo update
helm install greenkube greenkube/greenkube -n greenkube --create-namespace