opencost-overview.json (44769B)
1 { 2 "__inputs": [], 3 "__requires": [], 4 "annotations": { 5 "list": [] 6 }, 7 "description": "A comprehensive overview dashboard for OpenCost that displays cluster-wide cost metrics including hourly, daily, and monthly costs broken down by resource type (CPU, RAM, PV), instance type, namespace, and individual nodes. Use this dashboard to monitor overall infrastructure spending, identify cost trends, and detect cost anomalies across your Kubernetes cluster. The dashboards were generated using opencost-mixin. https://github.com/adinhodovic/opencost-mixin. Open issues and create feature requests in the repository.", 8 "editable": false, 9 "links": [ 10 { 11 "asDropdown": false, 12 "includeVars": false, 13 "keepTime": true, 14 "tags": [ 15 "opencost", 16 "opencost-mixin" 17 ], 18 "targetBlank": true, 19 "title": "OpenCost", 20 "type": "dashboards" 21 } 22 ], 23 "panels": [ 24 { 25 "collapsed": false, 26 "gridPos": { 27 "h": 1, 28 "w": 24, 29 "x": 0, 30 "y": 0 31 }, 32 "id": 1, 33 "title": "Cluster Summary", 34 "type": "row" 35 }, 36 { 37 "datasource": { 38 "type": "prometheus", 39 "uid": "$datasource" 40 }, 41 "description": "Current hourly infrastructure cost rate across the cluster. This metric provides real-time cost visibility and can be used to project daily and monthly spending. The percentage change helps track cost fluctuations over time.", 42 "fieldConfig": { 43 "defaults": { 44 "decimals": 2, 45 "mappings": [], 46 "thresholds": { 47 "steps": [ 48 { 49 "color": "green", 50 "value": 0 51 } 52 ] 53 }, 54 "unit": "currencyUSD" 55 } 56 }, 57 "gridPos": { 58 "h": 3, 59 "w": 4, 60 "x": 0, 61 "y": 1 62 }, 63 "id": 2, 64 "options": { 65 "graphMode": "none", 66 "percentChangeColorMode": "inverted", 67 "showPercentChange": true 68 }, 69 "pluginVersion": "v11.4.0", 70 "targets": [ 71 { 72 "datasource": { 73 "type": "prometheus", 74 "uid": "${datasource}" 75 }, 76 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) \n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) \n", 77 "instant": false 78 } 79 ], 80 "title": "Hourly Cost", 81 "type": "stat" 82 }, 83 { 84 "datasource": { 85 "type": "prometheus", 86 "uid": "$datasource" 87 }, 88 "description": "Total daily infrastructure cost across the cluster, including compute (CPU, RAM) and storage (PV) costs. The percentage change indicates cost variance compared to the previous period, helping identify sudden cost increases or decreases.", 89 "fieldConfig": { 90 "defaults": { 91 "decimals": 2, 92 "mappings": [], 93 "thresholds": { 94 "steps": [ 95 { 96 "color": "green", 97 "value": 0 98 } 99 ] 100 }, 101 "unit": "currencyUSD" 102 } 103 }, 104 "gridPos": { 105 "h": 3, 106 "w": 4, 107 "x": 4, 108 "y": 1 109 }, 110 "id": 3, 111 "options": { 112 "graphMode": "none", 113 "percentChangeColorMode": "inverted", 114 "showPercentChange": true 115 }, 116 "pluginVersion": "v11.4.0", 117 "targets": [ 118 { 119 "datasource": { 120 "type": "prometheus", 121 "uid": "${datasource}" 122 }, 123 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) * 24\n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 24\n", 124 "instant": false 125 } 126 ], 127 "title": "Daily Cost", 128 "type": "stat" 129 }, 130 { 131 "datasource": { 132 "type": "prometheus", 133 "uid": "$datasource" 134 }, 135 "description": "Projected monthly infrastructure cost based on current hourly rates (730 hours per month). This projection helps with budget planning and cost forecasting. Compare this value against your budget to ensure spending stays within limits.", 136 "fieldConfig": { 137 "defaults": { 138 "decimals": 2, 139 "mappings": [], 140 "thresholds": { 141 "steps": [ 142 { 143 "color": "green", 144 "value": 0 145 } 146 ] 147 }, 148 "unit": "currencyUSD" 149 } 150 }, 151 "gridPos": { 152 "h": 3, 153 "w": 4, 154 "x": 8, 155 "y": 1 156 }, 157 "id": 4, 158 "options": { 159 "graphMode": "none", 160 "percentChangeColorMode": "inverted", 161 "showPercentChange": true 162 }, 163 "pluginVersion": "v11.4.0", 164 "targets": [ 165 { 166 "datasource": { 167 "type": "prometheus", 168 "uid": "${datasource}" 169 }, 170 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) * 730\n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n", 171 "instant": false 172 } 173 ], 174 "title": "Monthly Cost", 175 "type": "stat" 176 }, 177 { 178 "datasource": { 179 "type": "prometheus", 180 "uid": "$datasource" 181 }, 182 "description": "Projected monthly cost for CPU (compute) resources across all cluster nodes. Compare this with RAM costs to understand your compute vs. memory cost ratio and optimize instance type selection accordingly.", 183 "fieldConfig": { 184 "defaults": { 185 "decimals": 2, 186 "mappings": [], 187 "thresholds": { 188 "steps": [ 189 { 190 "color": "green", 191 "value": 0 192 } 193 ] 194 }, 195 "unit": "currencyUSD" 196 } 197 }, 198 "gridPos": { 199 "h": 3, 200 "w": 4, 201 "x": 12, 202 "y": 1 203 }, 204 "id": 5, 205 "options": { 206 "graphMode": "none", 207 "percentChangeColorMode": "inverted", 208 "showPercentChange": true 209 }, 210 "pluginVersion": "v11.4.0", 211 "targets": [ 212 { 213 "datasource": { 214 "type": "prometheus", 215 "uid": "${datasource}" 216 }, 217 "expr": "sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n ) by (node)\n * on(node) group_left()\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n", 218 "instant": false 219 } 220 ], 221 "title": "Monthly CPU Cost", 222 "type": "stat" 223 }, 224 { 225 "datasource": { 226 "type": "prometheus", 227 "uid": "$datasource" 228 }, 229 "description": "Projected monthly cost for RAM (memory) resources across all cluster nodes. This metric helps identify if memory is a significant cost driver and can guide decisions about node sizing and memory allocation strategies.", 230 "fieldConfig": { 231 "defaults": { 232 "decimals": 2, 233 "mappings": [], 234 "thresholds": { 235 "steps": [ 236 { 237 "color": "green", 238 "value": 0 239 } 240 ] 241 }, 242 "unit": "currencyUSD" 243 } 244 }, 245 "gridPos": { 246 "h": 3, 247 "w": 4, 248 "x": 16, 249 "y": 1 250 }, 251 "id": 6, 252 "options": { 253 "graphMode": "none", 254 "percentChangeColorMode": "inverted", 255 "showPercentChange": true 256 }, 257 "pluginVersion": "v11.4.0", 258 "targets": [ 259 { 260 "datasource": { 261 "type": "prometheus", 262 "uid": "${datasource}" 263 }, 264 "expr": "sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n ) by (node)\n / (1024 * 1024 * 1024)\n * on(node) group_left()\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n", 265 "instant": false 266 } 267 ], 268 "title": "Monthly Ram Cost", 269 "type": "stat" 270 }, 271 { 272 "datasource": { 273 "type": "prometheus", 274 "uid": "$datasource" 275 }, 276 "description": "Projected monthly cost for Persistent Volume (storage) resources across the cluster. Monitor this metric to identify unused or oversized volumes that can be optimized to reduce storage costs.", 277 "fieldConfig": { 278 "defaults": { 279 "decimals": 2, 280 "mappings": [], 281 "thresholds": { 282 "steps": [ 283 { 284 "color": "green", 285 "value": 0 286 } 287 ] 288 }, 289 "unit": "currencyUSD" 290 } 291 }, 292 "gridPos": { 293 "h": 3, 294 "w": 4, 295 "x": 20, 296 "y": 1 297 }, 298 "id": 7, 299 "options": { 300 "graphMode": "none", 301 "percentChangeColorMode": "inverted", 302 "showPercentChange": true 303 }, 304 "pluginVersion": "v11.4.0", 305 "targets": [ 306 { 307 "datasource": { 308 "type": "prometheus", 309 "uid": "${datasource}" 310 }, 311 "expr": "sum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n", 312 "instant": false 313 } 314 ], 315 "title": "Monthly PV Cost", 316 "type": "stat" 317 }, 318 { 319 "datasource": { 320 "type": "prometheus", 321 "uid": "$datasource" 322 }, 323 "description": "Hourly cost trend over time showing how infrastructure spending fluctuates throughout the day. Use this to identify cost spikes, correlate costs with workload patterns, and detect autoscaling behavior impact on spending.", 324 "fieldConfig": { 325 "defaults": { 326 "custom": { 327 "fillOpacity": 10 328 }, 329 "unit": "currencyUSD" 330 } 331 }, 332 "gridPos": { 333 "h": 5, 334 "w": 8, 335 "x": 0, 336 "y": 5 337 }, 338 "id": 8, 339 "options": { 340 "legend": { 341 "calcs": [ 342 "mean", 343 "max" 344 ], 345 "displayMode": "table", 346 "placement": "right", 347 "showLegend": true, 348 "sortBy": "Mean", 349 "sortDesc": true 350 }, 351 "tooltip": { 352 "mode": "multi", 353 "sort": "desc" 354 } 355 }, 356 "pluginVersion": "v11.4.0", 357 "targets": [ 358 { 359 "datasource": { 360 "type": "prometheus", 361 "uid": "$datasource" 362 }, 363 "exemplar": false, 364 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) \n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) \n", 365 "legendFormat": "Hourly Cost" 366 } 367 ], 368 "title": "Hourly Cost", 369 "type": "timeseries" 370 }, 371 { 372 "datasource": { 373 "type": "prometheus", 374 "uid": "$datasource" 375 }, 376 "description": "Daily cost trend showing infrastructure spending patterns over multiple days. This view helps identify day-over-day cost changes, weekly patterns, and the impact of infrastructure changes on overall spending.", 377 "fieldConfig": { 378 "defaults": { 379 "custom": { 380 "fillOpacity": 10 381 }, 382 "unit": "currencyUSD" 383 } 384 }, 385 "gridPos": { 386 "h": 5, 387 "w": 8, 388 "x": 8, 389 "y": 5 390 }, 391 "id": 9, 392 "options": { 393 "legend": { 394 "calcs": [ 395 "mean", 396 "max" 397 ], 398 "displayMode": "table", 399 "placement": "right", 400 "showLegend": true, 401 "sortBy": "Mean", 402 "sortDesc": true 403 }, 404 "tooltip": { 405 "mode": "multi", 406 "sort": "desc" 407 } 408 }, 409 "pluginVersion": "v11.4.0", 410 "targets": [ 411 { 412 "datasource": { 413 "type": "prometheus", 414 "uid": "$datasource" 415 }, 416 "exemplar": false, 417 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) * 24\n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 24\n", 418 "legendFormat": "Daily Cost" 419 } 420 ], 421 "title": "Daily Cost", 422 "type": "timeseries" 423 }, 424 { 425 "datasource": { 426 "type": "prometheus", 427 "uid": "$datasource" 428 }, 429 "description": "Monthly cost projection trend over time. This visualization helps track how your projected monthly spending evolves and whether you are staying within budget throughout the billing period.", 430 "fieldConfig": { 431 "defaults": { 432 "custom": { 433 "fillOpacity": 10 434 }, 435 "unit": "currencyUSD" 436 } 437 }, 438 "gridPos": { 439 "h": 5, 440 "w": 8, 441 "x": 16, 442 "y": 5 443 }, 444 "id": 10, 445 "options": { 446 "legend": { 447 "calcs": [ 448 "mean", 449 "max" 450 ], 451 "displayMode": "table", 452 "placement": "right", 453 "showLegend": true, 454 "sortBy": "Mean", 455 "sortDesc": true 456 }, 457 "tooltip": { 458 "mode": "multi", 459 "sort": "desc" 460 } 461 }, 462 "pluginVersion": "v11.4.0", 463 "targets": [ 464 { 465 "datasource": { 466 "type": "prometheus", 467 "uid": "$datasource" 468 }, 469 "exemplar": false, 470 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) * 730\n+\nsum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n", 471 "legendFormat": "Monthly Cost" 472 } 473 ], 474 "title": "Monthly Cost", 475 "type": "timeseries" 476 }, 477 { 478 "datasource": { 479 "type": "prometheus", 480 "uid": "$datasource" 481 }, 482 "description": "Monthly cost distribution across resource types (CPU, RAM, Persistent Volumes). This breakdown shows which resource category consumes the most budget, helping prioritize optimization efforts. For example, if PV costs dominate, focus on storage optimization.", 483 "fieldConfig": { 484 "defaults": { 485 "unit": "currencyUSD" 486 } 487 }, 488 "gridPos": { 489 "h": 5, 490 "w": 8, 491 "x": 0, 492 "y": 10 493 }, 494 "id": 11, 495 "options": { 496 "displayLabels": [ 497 "percent" 498 ], 499 "legend": { 500 "displayMode": "table", 501 "placement": "right", 502 "showLegend": true, 503 "values": [ 504 "percent", 505 "value" 506 ] 507 }, 508 "tooltip": { 509 "mode": "multi", 510 "sort": "desc" 511 } 512 }, 513 "pluginVersion": "v11.4.0", 514 "targets": [ 515 { 516 "datasource": { 517 "type": "prometheus", 518 "uid": "$datasource" 519 }, 520 "expr": "sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n ) by (node)\n * on(node) group_left()\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n", 521 "instant": true, 522 "legendFormat": "CPU" 523 }, 524 { 525 "datasource": { 526 "type": "prometheus", 527 "uid": "$datasource" 528 }, 529 "expr": "sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n ) by (node)\n / (1024 * 1024 * 1024)\n * on(node) group_left()\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n", 530 "instant": true, 531 "legendFormat": "RAM" 532 }, 533 { 534 "datasource": { 535 "type": "prometheus", 536 "uid": "$datasource" 537 }, 538 "expr": "sum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n", 539 "instant": true, 540 "legendFormat": "PV" 541 } 542 ], 543 "title": "Cost by Resource", 544 "type": "piechart" 545 }, 546 { 547 "datasource": { 548 "type": "prometheus", 549 "uid": "$datasource" 550 }, 551 "description": "Top 10 namespaces by monthly cost showing which teams, applications, or environments consume the most resources. Use this to allocate costs to teams, identify expensive applications, and ensure fair resource distribution across the organization.", 552 "fieldConfig": { 553 "defaults": { 554 "unit": "currencyUSD" 555 } 556 }, 557 "gridPos": { 558 "h": 5, 559 "w": 8, 560 "x": 8, 561 "y": 10 562 }, 563 "id": 12, 564 "options": { 565 "displayLabels": [ 566 "percent" 567 ], 568 "legend": { 569 "displayMode": "table", 570 "placement": "right", 571 "showLegend": true, 572 "values": [ 573 "percent", 574 "value" 575 ] 576 }, 577 "tooltip": { 578 "mode": "multi", 579 "sort": "desc" 580 } 581 }, 582 "pluginVersion": "v11.4.0", 583 "targets": [ 584 { 585 "datasource": { 586 "type": "prometheus", 587 "uid": "$datasource" 588 }, 589 "expr": "topk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} * 730\n )\n ) by (namespace)\n)\n", 590 "instant": true, 591 "legendFormat": "{{ namespace }}" 592 } 593 ], 594 "title": "Cost by Namespace", 595 "type": "piechart" 596 }, 597 { 598 "datasource": { 599 "type": "prometheus", 600 "uid": "$datasource" 601 }, 602 "description": "Top 10 instance types by monthly cost showing which VM/node types contribute most to infrastructure spending. This helps evaluate whether your instance type selection is cost-effective and identify opportunities to switch to more economical instance families.", 603 "fieldConfig": { 604 "defaults": { 605 "unit": "currencyUSD" 606 } 607 }, 608 "gridPos": { 609 "h": 5, 610 "w": 8, 611 "x": 16, 612 "y": 10 613 }, 614 "id": 13, 615 "options": { 616 "displayLabels": [ 617 "percent" 618 ], 619 "legend": { 620 "displayMode": "table", 621 "placement": "right", 622 "showLegend": true, 623 "values": [ 624 "percent", 625 "value" 626 ] 627 }, 628 "tooltip": { 629 "mode": "multi", 630 "sort": "desc" 631 } 632 }, 633 "pluginVersion": "v11.4.0", 634 "targets": [ 635 { 636 "datasource": { 637 "type": "prometheus", 638 "uid": "$datasource" 639 }, 640 "expr": "topk(10,\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (instance_type) * 730\n)\n", 641 "instant": true, 642 "legendFormat": "{{ instance_type }}" 643 } 644 ], 645 "title": "Cost by Instance Type", 646 "type": "piechart" 647 }, 648 { 649 "datasource": { 650 "type": "prometheus", 651 "uid": "$datasource" 652 }, 653 "description": "Cost variance comparing current hourly costs against 7-day and 30-day historical averages. Positive values indicate costs are higher than average, negative values indicate lower costs. Use this to detect cost anomalies and unusual spending patterns that may require investigation.", 654 "fieldConfig": { 655 "defaults": { 656 "custom": { 657 "fillOpacity": 10 658 }, 659 "unit": "percentunit" 660 } 661 }, 662 "gridPos": { 663 "h": 5, 664 "w": 12, 665 "x": 0, 666 "y": 15 667 }, 668 "id": 14, 669 "options": { 670 "legend": { 671 "calcs": [ 672 "mean", 673 "max" 674 ], 675 "displayMode": "table", 676 "placement": "right", 677 "showLegend": true, 678 "sortBy": "Mean", 679 "sortDesc": true 680 }, 681 "tooltip": { 682 "mode": "multi", 683 "sort": "desc" 684 } 685 }, 686 "pluginVersion": "v11.4.0", 687 "targets": [ 688 { 689 "datasource": { 690 "type": "prometheus", 691 "uid": "$datasource" 692 }, 693 "exemplar": false, 694 "expr": "(\n avg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [1d:1h]\n )\n -\n avg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [7d:1h]\n )\n)\n/\navg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [7d:1h]\n)\n", 695 "interval": "30m", 696 "legendFormat": "Current hourly cost vs. 7-day average" 697 }, 698 { 699 "datasource": { 700 "type": "prometheus", 701 "uid": "$datasource" 702 }, 703 "exemplar": false, 704 "expr": "(\n avg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [1d:1h]\n )\n -\n avg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [30d:1h]\n )\n)\n/\navg_over_time(\n sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) [30d:1h]\n)\n", 705 "interval": "30m", 706 "legendFormat": "Current hourly cost vs. 30-day average" 707 } 708 ], 709 "title": "Total Cost Variance", 710 "type": "timeseries" 711 }, 712 { 713 "datasource": { 714 "type": "prometheus", 715 "uid": "$datasource" 716 }, 717 "description": "Resource-specific cost variance comparing current CPU, RAM, and PV costs against their 30-day historical averages. This breakdown helps identify which resource type is driving cost changes - useful for pinpointing whether cost increases are due to compute scaling, memory usage, or storage growth.", 718 "fieldConfig": { 719 "defaults": { 720 "custom": { 721 "fillOpacity": 10 722 }, 723 "unit": "percentunit" 724 } 725 }, 726 "gridPos": { 727 "h": 5, 728 "w": 12, 729 "x": 12, 730 "y": 15 731 }, 732 "id": 15, 733 "options": { 734 "legend": { 735 "calcs": [ 736 "mean", 737 "max" 738 ], 739 "displayMode": "table", 740 "placement": "right", 741 "showLegend": true, 742 "sortBy": "Mean", 743 "sortDesc": true 744 }, 745 "tooltip": { 746 "mode": "multi", 747 "sort": "desc" 748 } 749 }, 750 "pluginVersion": "v11.4.0", 751 "targets": [ 752 { 753 "datasource": { 754 "type": "prometheus", 755 "uid": "$datasource" 756 }, 757 "exemplar": false, 758 "expr": "(\n avg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n ) by (node)\n * on(node) group_left()\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [1d:1h]\n )\n -\n avg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n ) by (node)\n * on(node) group_left()\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [30d:1h]\n )\n)\n/\navg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n ) by (node)\n * on(node) group_left()\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [30d:1h]\n)\n", 759 "interval": "30m", 760 "legendFormat": "CPU Cost vs. 30-day average" 761 }, 762 { 763 "datasource": { 764 "type": "prometheus", 765 "uid": "$datasource" 766 }, 767 "exemplar": false, 768 "expr": "(\n avg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n ) by (node)\n / (1024 * 1024 * 1024)\n * on(node) group_left()\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [1d:1h]\n )\n -\n avg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n ) by (node)\n / (1024 * 1024 * 1024)\n * on(node) group_left()\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [30d:1h]\n )\n)\n/\navg_over_time(\n sum(\n sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n ) by (node)\n / (1024 * 1024 * 1024)\n * on(node) group_left()\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node)\n * 730\n)\n [30d:1h]\n)\n", 769 "interval": "30m", 770 "legendFormat": "RAM Cost vs. 30-day average" 771 }, 772 { 773 "datasource": { 774 "type": "prometheus", 775 "uid": "$datasource" 776 }, 777 "exemplar": false, 778 "expr": "(\n avg_over_time(\n (sum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n) [1d:1h]\n )\n -\n avg_over_time(\n (sum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n) [30d:1h]\n )\n)\n/\navg_over_time(\n (sum(\n sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n } / (1024 * 1024 * 1024)\n ) by (persistentvolume)\n * on(persistentvolume) group_left()\n sum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (persistentvolume)\n) * 730\n) [30d:1h]\n)\n", 779 "interval": "30m", 780 "legendFormat": "PV Cost vs. 30-day average" 781 } 782 ], 783 "title": "Resource Cost Variance", 784 "type": "timeseries" 785 }, 786 { 787 "collapsed": false, 788 "gridPos": { 789 "h": 1, 790 "w": 24, 791 "x": 0, 792 "y": 20 793 }, 794 "id": 16, 795 "title": "Cloud Resources", 796 "type": "row" 797 }, 798 { 799 "datasource": { 800 "type": "prometheus", 801 "uid": "$datasource" 802 }, 803 "description": "Detailed breakdown of monthly costs per node, showing CPU cost, RAM cost, and total cost for each node along with instance type and architecture. Sorted by total cost to highlight the most expensive nodes. Use this to identify underutilized expensive nodes that could be downsized or removed.", 804 "fieldConfig": { 805 "defaults": { 806 "thresholds": { 807 "steps": [] 808 }, 809 "unit": "currencyUSD" 810 }, 811 "overrides": [] 812 }, 813 "gridPos": { 814 "h": 10, 815 "w": 16, 816 "x": 0, 817 "y": 21 818 }, 819 "id": 17, 820 "options": { 821 "footer": { 822 "enablePagination": true 823 }, 824 "sortBy": [ 825 { 826 "desc": true, 827 "displayName": "Total Cost" 828 } 829 ] 830 }, 831 "pluginVersion": "v11.4.0", 832 "targets": [ 833 { 834 "datasource": { 835 "type": "prometheus", 836 "uid": "$datasource" 837 }, 838 "expr": "sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"cpu\",\n unit=\"core\"\n }\n) by (node)\n* on(node) group_left(cluster, instance_type, arch)\n sum(\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n }\n ) by (node, instance_type, arch)\n* 730\n", 839 "format": "table", 840 "instant": true 841 }, 842 { 843 "datasource": { 844 "type": "prometheus", 845 "uid": "$datasource" 846 }, 847 "expr": "sum(\n kube_node_status_capacity{\n cluster=\"$cluster\",\njob=\"$job\"\n,\n resource=\"memory\",\n unit=\"byte\"\n }\n) by (node)\n/ (1024 * 1024 * 1024)\n* on(node) group_left(cluster, instance_type, arch)\n sum(\n node_ram_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n ) by (node, instance_type, arch)\n* 730\n", 848 "format": "table", 849 "instant": true 850 }, 851 { 852 "datasource": { 853 "type": "prometheus", 854 "uid": "$datasource" 855 }, 856 "expr": "sum(\n node_total_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n) by (node, instance_type, arch)\n* 730\n", 857 "format": "table", 858 "instant": true 859 } 860 ], 861 "title": "Nodes Monthly Cost", 862 "transformations": [ 863 { 864 "id": "merge" 865 }, 866 { 867 "id": "organize", 868 "options": { 869 "excludeByName": { 870 "Time": true, 871 "job": true 872 }, 873 "indexByName": { 874 "Value #A": 3, 875 "Value #B": 4, 876 "Value #C": 5, 877 "arch": 2, 878 "instance_type": 1, 879 "node": 0 880 }, 881 "renameByName": { 882 "Value #A": "CPU Cost", 883 "Value #B": "RAM Cost", 884 "Value #C": "Total Cost", 885 "arch": "Architecture", 886 "instance_type": "Instance Type", 887 "node": "Node" 888 } 889 } 890 } 891 ], 892 "type": "table" 893 }, 894 { 895 "datasource": { 896 "type": "prometheus", 897 "uid": "$datasource" 898 }, 899 "description": "List of all Persistent Volumes with their capacity (in GiB) and monthly cost, sorted by total cost. Use this to identify large or expensive volumes that may be candidates for cleanup, resizing, or migration to cheaper storage classes.", 900 "fieldConfig": { 901 "defaults": { 902 "thresholds": { 903 "steps": [] 904 }, 905 "unit": "decgbytes" 906 }, 907 "overrides": [ 908 { 909 "matcher": { 910 "id": "byName", 911 "options": "Total Cost" 912 }, 913 "properties": [ 914 { 915 "id": "unit", 916 "value": "currencyUSD" 917 } 918 ] 919 } 920 ] 921 }, 922 "gridPos": { 923 "h": 10, 924 "w": 8, 925 "x": 16, 926 "y": 21 927 }, 928 "id": 18, 929 "options": { 930 "footer": { 931 "enablePagination": true 932 }, 933 "sortBy": [ 934 { 935 "desc": true, 936 "displayName": "Total Cost" 937 } 938 ] 939 }, 940 "pluginVersion": "v11.4.0", 941 "targets": [ 942 { 943 "datasource": { 944 "type": "prometheus", 945 "uid": "$datasource" 946 }, 947 "expr": "sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n / 1024 / 1024 / 1024\n) by (persistentvolume)\n", 948 "format": "table", 949 "instant": true 950 }, 951 { 952 "datasource": { 953 "type": "prometheus", 954 "uid": "$datasource" 955 }, 956 "expr": "sum(\n kube_persistentvolume_capacity_bytes{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n / 1024 / 1024 / 1024\n) by (persistentvolume)\n*\nsum(\n pv_hourly_cost{\n cluster=\"$cluster\",\njob=\"$job\"\n\n }\n * 730\n) by (persistentvolume)\n", 957 "format": "table", 958 "instant": true 959 } 960 ], 961 "title": "Persistent Volumes Monthly Cost", 962 "transformations": [ 963 { 964 "id": "merge" 965 }, 966 { 967 "id": "organize", 968 "options": { 969 "excludeByName": { 970 "Time": true, 971 "job": true 972 }, 973 "indexByName": { 974 "Value #A": 1, 975 "Value #B": 2, 976 "persistentvolume": 0 977 }, 978 "renameByName": { 979 "Value #A": "Total GiB", 980 "Value #B": "Total Cost", 981 "persistentvolume": "Persistent Volume" 982 } 983 } 984 } 985 ], 986 "type": "table" 987 }, 988 { 989 "collapsed": false, 990 "gridPos": { 991 "h": 1, 992 "w": 24, 993 "x": 0, 994 "y": 31 995 }, 996 "id": 19, 997 "title": "Namespace Summary", 998 "type": "row" 999 }, 1000 { 1001 "datasource": { 1002 "type": "prometheus", 1003 "uid": "$datasource" 1004 }, 1005 "description": "Top 10 namespaces by current monthly cost with percentage change compared to 7 days and 30 days ago. Positive percentages indicate cost increases (red), negative percentages indicate cost decreases (green). Click on a namespace name to drill down into detailed pod and container costs. Use this to track namespace-level spending trends and identify teams or applications with growing costs.", 1006 "fieldConfig": { 1007 "defaults": { 1008 "thresholds": { 1009 "steps": [ 1010 { 1011 "color": "green", 1012 "value": 0 1013 }, 1014 { 1015 "color": "yellow", 1016 "value": 5 1017 }, 1018 { 1019 "color": "red", 1020 "value": 10 1021 } 1022 ] 1023 }, 1024 "unit": "currencyUSD" 1025 }, 1026 "overrides": [ 1027 { 1028 "matcher": { 1029 "id": "byName", 1030 "options": "Cost Change vs 7d Ago (%)" 1031 }, 1032 "properties": [ 1033 { 1034 "id": "color", 1035 "value": { 1036 "mode": "thresholds" 1037 } 1038 }, 1039 { 1040 "id": "custom.cellOptions", 1041 "value": { 1042 "type": "color-background" 1043 } 1044 }, 1045 { 1046 "id": "unit", 1047 "value": "percent" 1048 } 1049 ] 1050 }, 1051 { 1052 "matcher": { 1053 "id": "byName", 1054 "options": "Cost Change vs 30d Ago (%)" 1055 }, 1056 "properties": [ 1057 { 1058 "id": "color", 1059 "value": { 1060 "mode": "thresholds" 1061 } 1062 }, 1063 { 1064 "id": "custom.cellOptions", 1065 "value": { 1066 "type": "color-background" 1067 } 1068 }, 1069 { 1070 "id": "unit", 1071 "value": "percent" 1072 } 1073 ] 1074 }, 1075 { 1076 "matcher": { 1077 "id": "byName", 1078 "options": "Namespace" 1079 }, 1080 "properties": [ 1081 { 1082 "id": "links", 1083 "value": [ 1084 { 1085 "targetBlank": true, 1086 "title": "Go To Namespace", 1087 "type": "dashboard", 1088 "url": "/d/opencost-mixin-namespace-jkwq/opencost-namespace?var-job=$job&var-namespace=${__data.fields.Namespace}" 1089 } 1090 ] 1091 } 1092 ] 1093 } 1094 ] 1095 }, 1096 "gridPos": { 1097 "h": 12, 1098 "w": 24, 1099 "x": 0, 1100 "y": 32 1101 }, 1102 "id": 20, 1103 "options": { 1104 "footer": { 1105 "enablePagination": true 1106 }, 1107 "sortBy": [ 1108 { 1109 "desc": true, 1110 "displayName": "Monthly Cost" 1111 } 1112 ] 1113 }, 1114 "pluginVersion": "v11.4.0", 1115 "targets": [ 1116 { 1117 "datasource": { 1118 "type": "prometheus", 1119 "uid": "$datasource" 1120 }, 1121 "expr": "topk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} * 730\n )\n ) by (namespace)\n)\n", 1122 "format": "table", 1123 "instant": true 1124 }, 1125 { 1126 "datasource": { 1127 "type": "prometheus", 1128 "uid": "$datasource" 1129 }, 1130 "expr": "topk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} * 730\n )\n ) by (namespace)\n)\n\n/\ntopk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d * 730\n )\n ) by (namespace)\n)\n\n* 100\n- 100\n", 1131 "format": "table", 1132 "instant": true 1133 }, 1134 { 1135 "datasource": { 1136 "type": "prometheus", 1137 "uid": "$datasource" 1138 }, 1139 "expr": "topk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"}\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} * 730\n )\n ) by (namespace)\n)\n\n/\ntopk(10,\n sum(\n sum(\n container_memory_allocation_bytes{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_ram_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d / (1024 * 1024 * 1024) * 730\n )\n +\n sum(\n container_cpu_allocation{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d\n ) by (namespace, instance)\n * on(instance) group_left()\n (\n node_cpu_hourly_cost{\n cluster=\"$cluster\",\n job=\"$job\"} offset 7d * 730\n )\n ) by (namespace)\n)\n\n* 100\n- 100\n", 1140 "format": "table", 1141 "instant": true 1142 } 1143 ], 1144 "title": "Namespace Monthly Cost", 1145 "transformations": [ 1146 { 1147 "id": "merge" 1148 }, 1149 { 1150 "id": "organize", 1151 "options": { 1152 "excludeByName": { 1153 "Time": true, 1154 "job": true 1155 }, 1156 "indexByName": { 1157 "Value #A": 1, 1158 "Value #B": 2, 1159 "Value #C": 3, 1160 "namespace": 0 1161 }, 1162 "renameByName": { 1163 "Value #A": "Monthly Cost", 1164 "Value #B": "Cost Change vs 7d Ago (%)", 1165 "Value #C": "Cost Change vs 30d Ago (%)", 1166 "namespace": "Namespace" 1167 } 1168 } 1169 } 1170 ], 1171 "type": "table" 1172 } 1173 ], 1174 "schemaVersion": 39, 1175 "tags": [ 1176 "opencost", 1177 "opencost-mixin" 1178 ], 1179 "templating": { 1180 "list": [ 1181 { 1182 "current": { 1183 "selected": true, 1184 "text": "default", 1185 "value": "default" 1186 }, 1187 "label": "Data source", 1188 "name": "datasource", 1189 "query": "prometheus", 1190 "type": "datasource" 1191 }, 1192 { 1193 "datasource": { 1194 "type": "prometheus", 1195 "uid": "${datasource}" 1196 }, 1197 "hide": 2, 1198 "label": "Cluster", 1199 "name": "cluster", 1200 "query": "label_values(opencost_build_info{}, cluster)", 1201 "refresh": 2, 1202 "sort": 1, 1203 "type": "query" 1204 }, 1205 { 1206 "datasource": { 1207 "type": "prometheus", 1208 "uid": "${datasource}" 1209 }, 1210 "includeAll": false, 1211 "label": "Job", 1212 "multi": false, 1213 "name": "job", 1214 "query": "label_values(opencost_build_info{cluster=\"$cluster\"}, job)", 1215 "refresh": 2, 1216 "sort": 1, 1217 "type": "query" 1218 } 1219 ] 1220 }, 1221 "time": { 1222 "from": "now-2d", 1223 "to": "now" 1224 }, 1225 "timezone": "utc", 1226 "title": "OpenCost / Overview", 1227 "uid": "opencost-mixin-kover-jkwq", 1228 "gnetId": 22208 1229 }