├── .gitignore ├── LICENSE ├── README.md ├── artillery-config.yaml ├── monitoring-stack ├── .helmignore ├── Chart.lock ├── Chart.yaml ├── dashboards │ ├── k8s-monitoring.json │ └── nodejs.json ├── datasources │ └── prometheus.yaml ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── dashboard-configmap.yaml │ └── datasources-configmaps.yaml └── values.yaml ├── proxy ├── .helmignore ├── Chart.lock ├── Chart.yaml ├── dashboards │ └── ingress-controller.json ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ └── dashboard-configmap.yaml └── values.yaml └── service-example ├── .dockerignore ├── .helmignore ├── Dockerfile ├── chart ├── Chart.yaml ├── dashboards │ └── service-example.json ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── dashboard-configmap.yaml │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ │ └── test-connection.yaml └── values.yaml ├── package-lock.json ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 wolmi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # monitoring-the-easy-way 2 | 3 | This repository includes all the content needed to make the workshop of the same name, the main goal is to have a working environment to learn an practices monitoring concepts. 4 | 5 | The tools needed to deploy and use this repository on the next list: 6 | 7 | * Docker Desktop (https://www.docker.com/products/docker-desktop) 8 | * Helm 3 (https://helm.sh/docs/intro/quickstart/) 9 | * Your favorite web browser 10 | * Your favorite text editor 11 | 12 | # Setup local environment 13 | 14 | ## Configure Docker Desktop 15 | 16 | All the workshop is based on the usage of [Docker](https://www.docker.com/) containers and for explaining better the concepts we will use [Kuberentes](https://kubernetes.io/), 17 | in order to not needing an online deployment on a cloud provider, we need to activate the Kubernetes feature included on Docker Desktop. 18 | 19 | First, you have to install Docker Desktop following the [documentation](https://www.docker.com/products/docker-desktop) 20 | 21 | You only need to access the Docker preferences and navigate to the Kubernetes section to activate. It will take some minutes to be ready depending on your computer and internet bandwidth. 22 | 23 | ## Configure Helm 24 | 25 | When the local Kubernetes context is ready you can start with the Helm configuration to have your environment ready. 26 | 27 | At the moment of preparing this workshop, the current Helm version is 3 and because of that, all the steps are based on that specific version. 28 | 29 | To install Helm as a local command you should follow the [quickstart](https://helm.sh/docs/intro/quickstart/) documentation and add at least one repository to start installing charts. 30 | 31 | ```bash 32 | helm repo add stable https://charts.helm.sh/stable 33 | ``` 34 | 35 | ### Extra repositories 36 | 37 | AS a more complete environment 4 more repositories can be added to have acces to more charts: 38 | 39 | ```bash 40 | helm repo add kiwigrid https://kiwigrid.github.io 41 | helm repo add grafana https://grafana.github.io/helm-charts 42 | helm repo add prometheus-comunity https://prometheus-community.github.io/helm-charts 43 | helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx 44 | ``` 45 | 46 | Don't forget to update your repository list 47 | 48 | ```bash 49 | helm repo update 50 | ``` 51 | 52 | # Installing the tools 53 | 54 | First we need to create a namespace. 55 | 56 | ```bash 57 | kubectl create namespace monitoring-easy 58 | ``` 59 | And set the new namespaces the current context. 60 | 61 | ```bash 62 | kubectl config set-context --current --namespace=monitoring-easy 63 | ``` 64 | 65 | ## Install ingress controller 66 | 67 | To make the access more ease we have prepared a basic ingress-controller using the comunity version of Nginx ingress controller, you can install it localy using next command: 68 | 69 | ```bash 70 | helm install proxy proxy 71 | ``` 72 | 73 | ## Install grafana and prometheus 74 | 75 | In order to install the tools needed you can simply run next commend to install the chart that aready includes Grafana and Prometheus as dependencies and will leave the cluster ready 76 | to start colecting and showing data. 77 | 78 | ```bash 79 | cd monitoring-stack 80 | helm dependency update 81 | helm install monitoring-stack . 82 | ``` 83 | 84 | You can now see how the diferent services are created and starts creating the pods needed. When all services are on running state you can connect to your grafana for the first time and you need 85 | to run next commands to obtain the right port to connect and the random admin password generated during the installation process. 86 | 87 | ```bash 88 | kubectl get secrets monitoring-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo 89 | ``` 90 | 91 | ```bash 92 | export GRAFANA_PORT=$(kubectl get service -o jsonpath="{.spec.ports[0].nodePort}" monitoring-stack-grafana) 93 | echo http://localhost:$GRAFANA_PORT 94 | ``` 95 | 96 | # Install example service 97 | 98 | This repository includes a basic server example that can be used to generate metrics and test the environment. You can install using next command: 99 | 100 | ```bash 101 | cd service-example 102 | helm install lab chart 103 | ``` 104 | 105 | # Install artillery 106 | 107 | To demonstrate the different metris a benchmark tool is needed, one easy way to perform a load test is to use [artillery](https://artillery.io/) you can install it by running next command: 108 | 109 | ```bash 110 | sudo npm install -g artillery --allow-root --unsafe-perm=true 111 | ``` 112 | -------------------------------------------------------------------------------- /artillery-config.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | target: http://service-example.localhost 3 | phases: 4 | - duration: 100 5 | arrivalRate: 3 6 | 7 | scenarios: 8 | - flow: 9 | - get: 10 | url: "/checkout" 11 | - flow: 12 | - get: 13 | url: "/bad" 14 | -------------------------------------------------------------------------------- /monitoring-stack/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /monitoring-stack/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: grafana 3 | repository: https://grafana.github.io/helm-charts 4 | version: 6.0.1 5 | - name: prometheus 6 | repository: https://prometheus-community.github.io/helm-charts/ 7 | version: 11.16.7 8 | digest: sha256:80d047792107d98ae97860aa25cdac8b48226318e7f26860e9615391652c491d 9 | generated: "2020-11-03T02:38:47.430328+01:00" 10 | -------------------------------------------------------------------------------- /monitoring-stack/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: monitoring-stack 3 | description: A Helm chart for Kubernetes monitoring stack as starting point for learning 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | appVersion: 1.16.0 24 | 25 | dependencies: 26 | - name: grafana 27 | version: "6.0.1" 28 | repository: "https://grafana.github.io/helm-charts" 29 | - name: prometheus 30 | version: "11.16.7" 31 | repository: "https://prometheus-community.github.io/helm-charts/" 32 | 33 | -------------------------------------------------------------------------------- /monitoring-stack/dashboards/k8s-monitoring.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "type": "dashboard" 12 | } 13 | ] 14 | }, 15 | "description": "Monitors Kubernetes cluster using Prometheus. Shows overall cluster CPU / Memory / Filesystem usage as well as individual pod, containers, systemd services statistics. Uses cAdvisor metrics only.", 16 | "editable": true, 17 | "gnetId": 315, 18 | "graphTooltip": 0, 19 | "id": 1, 20 | "iteration": 1604327360006, 21 | "links": [], 22 | "panels": [ 23 | { 24 | "collapsed": false, 25 | "datasource": null, 26 | "gridPos": { 27 | "h": 1, 28 | "w": 24, 29 | "x": 0, 30 | "y": 0 31 | }, 32 | "id": 33, 33 | "panels": [], 34 | "title": "Network I/O pressure", 35 | "type": "row" 36 | }, 37 | { 38 | "aliasColors": {}, 39 | "bars": false, 40 | "dashLength": 10, 41 | "dashes": false, 42 | "datasource": "Prometheus", 43 | "decimals": 2, 44 | "editable": true, 45 | "error": false, 46 | "fieldConfig": { 47 | "defaults": { 48 | "custom": {} 49 | }, 50 | "overrides": [] 51 | }, 52 | "fill": 1, 53 | "fillGradient": 0, 54 | "grid": {}, 55 | "gridPos": { 56 | "h": 6, 57 | "w": 24, 58 | "x": 0, 59 | "y": 1 60 | }, 61 | "height": "200px", 62 | "hiddenSeries": false, 63 | "id": 32, 64 | "isNew": true, 65 | "legend": { 66 | "alignAsTable": false, 67 | "avg": true, 68 | "current": true, 69 | "max": false, 70 | "min": false, 71 | "rightSide": false, 72 | "show": false, 73 | "sideWidth": 200, 74 | "sort": "current", 75 | "sortDesc": true, 76 | "total": false, 77 | "values": true 78 | }, 79 | "lines": true, 80 | "linewidth": 2, 81 | "links": [], 82 | "nullPointMode": "connected", 83 | "options": { 84 | "alertThreshold": true 85 | }, 86 | "percentage": false, 87 | "pluginVersion": "7.2.1", 88 | "pointradius": 5, 89 | "points": false, 90 | "renderer": "flot", 91 | "seriesOverrides": [], 92 | "spaceLength": 10, 93 | "stack": false, 94 | "steppedLine": false, 95 | "targets": [ 96 | { 97 | "expr": "sum (rate (container_network_receive_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[1m]))", 98 | "interval": "10s", 99 | "intervalFactor": 1, 100 | "legendFormat": "Received", 101 | "metric": "network", 102 | "refId": "A", 103 | "step": 10 104 | }, 105 | { 106 | "expr": "- sum (rate (container_network_transmit_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[1m]))", 107 | "interval": "10s", 108 | "intervalFactor": 1, 109 | "legendFormat": "Sent", 110 | "metric": "network", 111 | "refId": "B", 112 | "step": 10 113 | } 114 | ], 115 | "thresholds": [], 116 | "timeFrom": null, 117 | "timeRegions": [], 118 | "timeShift": null, 119 | "title": "Network I/O pressure", 120 | "tooltip": { 121 | "msResolution": false, 122 | "shared": true, 123 | "sort": 0, 124 | "value_type": "cumulative" 125 | }, 126 | "type": "graph", 127 | "xaxis": { 128 | "buckets": null, 129 | "mode": "time", 130 | "name": null, 131 | "show": true, 132 | "values": [] 133 | }, 134 | "yaxes": [ 135 | { 136 | "format": "Bps", 137 | "label": null, 138 | "logBase": 1, 139 | "max": null, 140 | "min": null, 141 | "show": true 142 | }, 143 | { 144 | "format": "Bps", 145 | "label": null, 146 | "logBase": 1, 147 | "max": null, 148 | "min": null, 149 | "show": false 150 | } 151 | ], 152 | "yaxis": { 153 | "align": false, 154 | "alignLevel": null 155 | } 156 | }, 157 | { 158 | "collapsed": false, 159 | "datasource": null, 160 | "gridPos": { 161 | "h": 1, 162 | "w": 24, 163 | "x": 0, 164 | "y": 7 165 | }, 166 | "id": 34, 167 | "panels": [], 168 | "title": "Total usage", 169 | "type": "row" 170 | }, 171 | { 172 | "cacheTimeout": null, 173 | "colorBackground": false, 174 | "colorValue": true, 175 | "colors": [ 176 | "rgba(50, 172, 45, 0.97)", 177 | "rgba(237, 129, 40, 0.89)", 178 | "rgba(245, 54, 54, 0.9)" 179 | ], 180 | "datasource": "Prometheus", 181 | "editable": true, 182 | "error": false, 183 | "fieldConfig": { 184 | "defaults": { 185 | "custom": {} 186 | }, 187 | "overrides": [] 188 | }, 189 | "format": "percent", 190 | "gauge": { 191 | "maxValue": 100, 192 | "minValue": 0, 193 | "show": true, 194 | "thresholdLabels": false, 195 | "thresholdMarkers": true 196 | }, 197 | "gridPos": { 198 | "h": 5, 199 | "w": 8, 200 | "x": 0, 201 | "y": 8 202 | }, 203 | "height": "180px", 204 | "id": 4, 205 | "interval": null, 206 | "isNew": true, 207 | "links": [], 208 | "mappingType": 1, 209 | "mappingTypes": [ 210 | { 211 | "name": "value to text", 212 | "value": 1 213 | }, 214 | { 215 | "name": "range to text", 216 | "value": 2 217 | } 218 | ], 219 | "maxDataPoints": 100, 220 | "nullPointMode": "connected", 221 | "nullText": null, 222 | "postfix": "", 223 | "postfixFontSize": "50%", 224 | "prefix": "", 225 | "prefixFontSize": "50%", 226 | "rangeMaps": [ 227 | { 228 | "from": "null", 229 | "text": "N/A", 230 | "to": "null" 231 | } 232 | ], 233 | "sparkline": { 234 | "fillColor": "rgba(31, 118, 189, 0.18)", 235 | "full": false, 236 | "lineColor": "rgb(31, 120, 193)", 237 | "show": false 238 | }, 239 | "tableColumn": "", 240 | "targets": [ 241 | { 242 | "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) / sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"}) * 100", 243 | "interval": "10s", 244 | "intervalFactor": 1, 245 | "refId": "A", 246 | "step": 10 247 | } 248 | ], 249 | "thresholds": "65, 90", 250 | "title": "Cluster memory usage", 251 | "type": "singlestat", 252 | "valueFontSize": "80%", 253 | "valueMaps": [ 254 | { 255 | "op": "=", 256 | "text": "N/A", 257 | "value": "null" 258 | } 259 | ], 260 | "valueName": "current" 261 | }, 262 | { 263 | "cacheTimeout": null, 264 | "colorBackground": false, 265 | "colorValue": true, 266 | "colors": [ 267 | "rgba(50, 172, 45, 0.97)", 268 | "rgba(237, 129, 40, 0.89)", 269 | "rgba(245, 54, 54, 0.9)" 270 | ], 271 | "datasource": "Prometheus", 272 | "decimals": 2, 273 | "editable": true, 274 | "error": false, 275 | "fieldConfig": { 276 | "defaults": { 277 | "custom": {} 278 | }, 279 | "overrides": [] 280 | }, 281 | "format": "percent", 282 | "gauge": { 283 | "maxValue": 100, 284 | "minValue": 0, 285 | "show": true, 286 | "thresholdLabels": false, 287 | "thresholdMarkers": true 288 | }, 289 | "gridPos": { 290 | "h": 5, 291 | "w": 8, 292 | "x": 8, 293 | "y": 8 294 | }, 295 | "height": "180px", 296 | "id": 6, 297 | "interval": null, 298 | "isNew": true, 299 | "links": [], 300 | "mappingType": 1, 301 | "mappingTypes": [ 302 | { 303 | "name": "value to text", 304 | "value": 1 305 | }, 306 | { 307 | "name": "range to text", 308 | "value": 2 309 | } 310 | ], 311 | "maxDataPoints": 100, 312 | "nullPointMode": "connected", 313 | "nullText": null, 314 | "postfix": "", 315 | "postfixFontSize": "50%", 316 | "prefix": "", 317 | "prefixFontSize": "50%", 318 | "rangeMaps": [ 319 | { 320 | "from": "null", 321 | "text": "N/A", 322 | "to": "null" 323 | } 324 | ], 325 | "sparkline": { 326 | "fillColor": "rgba(31, 118, 189, 0.18)", 327 | "full": false, 328 | "lineColor": "rgb(31, 120, 193)", 329 | "show": false 330 | }, 331 | "tableColumn": "", 332 | "targets": [ 333 | { 334 | "expr": "sum (rate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) / sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"}) * 100", 335 | "interval": "10s", 336 | "intervalFactor": 1, 337 | "refId": "A", 338 | "step": 10 339 | } 340 | ], 341 | "thresholds": "65, 90", 342 | "title": "Cluster CPU usage (1m avg)", 343 | "type": "singlestat", 344 | "valueFontSize": "80%", 345 | "valueMaps": [ 346 | { 347 | "op": "=", 348 | "text": "N/A", 349 | "value": "null" 350 | } 351 | ], 352 | "valueName": "current" 353 | }, 354 | { 355 | "cacheTimeout": null, 356 | "colorBackground": false, 357 | "colorValue": true, 358 | "colors": [ 359 | "rgba(50, 172, 45, 0.97)", 360 | "rgba(237, 129, 40, 0.89)", 361 | "rgba(245, 54, 54, 0.9)" 362 | ], 363 | "datasource": "Prometheus", 364 | "decimals": 2, 365 | "editable": true, 366 | "error": false, 367 | "fieldConfig": { 368 | "defaults": { 369 | "custom": {} 370 | }, 371 | "overrides": [] 372 | }, 373 | "format": "percent", 374 | "gauge": { 375 | "maxValue": 100, 376 | "minValue": 0, 377 | "show": true, 378 | "thresholdLabels": false, 379 | "thresholdMarkers": true 380 | }, 381 | "gridPos": { 382 | "h": 5, 383 | "w": 8, 384 | "x": 16, 385 | "y": 8 386 | }, 387 | "height": "180px", 388 | "id": 7, 389 | "interval": null, 390 | "isNew": true, 391 | "links": [], 392 | "mappingType": 1, 393 | "mappingTypes": [ 394 | { 395 | "name": "value to text", 396 | "value": 1 397 | }, 398 | { 399 | "name": "range to text", 400 | "value": 2 401 | } 402 | ], 403 | "maxDataPoints": 100, 404 | "nullPointMode": "connected", 405 | "nullText": null, 406 | "postfix": "", 407 | "postfixFontSize": "50%", 408 | "prefix": "", 409 | "prefixFontSize": "50%", 410 | "rangeMaps": [ 411 | { 412 | "from": "null", 413 | "text": "N/A", 414 | "to": "null" 415 | } 416 | ], 417 | "sparkline": { 418 | "fillColor": "rgba(31, 118, 189, 0.18)", 419 | "full": false, 420 | "lineColor": "rgb(31, 120, 193)", 421 | "show": false 422 | }, 423 | "tableColumn": "", 424 | "targets": [ 425 | { 426 | "expr": "sum (container_fs_usage_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) / sum (container_fs_limit_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) * 100", 427 | "interval": "10s", 428 | "intervalFactor": 1, 429 | "legendFormat": "", 430 | "metric": "", 431 | "refId": "A", 432 | "step": 10 433 | } 434 | ], 435 | "thresholds": "65, 90", 436 | "title": "Cluster filesystem usage", 437 | "type": "singlestat", 438 | "valueFontSize": "80%", 439 | "valueMaps": [ 440 | { 441 | "op": "=", 442 | "text": "N/A", 443 | "value": "null" 444 | } 445 | ], 446 | "valueName": "current" 447 | }, 448 | { 449 | "cacheTimeout": null, 450 | "colorBackground": false, 451 | "colorValue": false, 452 | "colors": [ 453 | "rgba(50, 172, 45, 0.97)", 454 | "rgba(237, 129, 40, 0.89)", 455 | "rgba(245, 54, 54, 0.9)" 456 | ], 457 | "datasource": "Prometheus", 458 | "decimals": 2, 459 | "editable": true, 460 | "error": false, 461 | "fieldConfig": { 462 | "defaults": { 463 | "custom": {} 464 | }, 465 | "overrides": [] 466 | }, 467 | "format": "bytes", 468 | "gauge": { 469 | "maxValue": 100, 470 | "minValue": 0, 471 | "show": false, 472 | "thresholdLabels": false, 473 | "thresholdMarkers": true 474 | }, 475 | "gridPos": { 476 | "h": 3, 477 | "w": 4, 478 | "x": 0, 479 | "y": 13 480 | }, 481 | "height": "1px", 482 | "id": 9, 483 | "interval": null, 484 | "isNew": true, 485 | "links": [], 486 | "mappingType": 1, 487 | "mappingTypes": [ 488 | { 489 | "name": "value to text", 490 | "value": 1 491 | }, 492 | { 493 | "name": "range to text", 494 | "value": 2 495 | } 496 | ], 497 | "maxDataPoints": 100, 498 | "nullPointMode": "connected", 499 | "nullText": null, 500 | "postfix": "", 501 | "postfixFontSize": "20%", 502 | "prefix": "", 503 | "prefixFontSize": "20%", 504 | "rangeMaps": [ 505 | { 506 | "from": "null", 507 | "text": "N/A", 508 | "to": "null" 509 | } 510 | ], 511 | "sparkline": { 512 | "fillColor": "rgba(31, 118, 189, 0.18)", 513 | "full": false, 514 | "lineColor": "rgb(31, 120, 193)", 515 | "show": false 516 | }, 517 | "tableColumn": "", 518 | "targets": [ 519 | { 520 | "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", 521 | "interval": "10s", 522 | "intervalFactor": 1, 523 | "refId": "A", 524 | "step": 10 525 | } 526 | ], 527 | "thresholds": "", 528 | "title": "Used", 529 | "type": "singlestat", 530 | "valueFontSize": "50%", 531 | "valueMaps": [ 532 | { 533 | "op": "=", 534 | "text": "N/A", 535 | "value": "null" 536 | } 537 | ], 538 | "valueName": "current" 539 | }, 540 | { 541 | "cacheTimeout": null, 542 | "colorBackground": false, 543 | "colorValue": false, 544 | "colors": [ 545 | "rgba(50, 172, 45, 0.97)", 546 | "rgba(237, 129, 40, 0.89)", 547 | "rgba(245, 54, 54, 0.9)" 548 | ], 549 | "datasource": "Prometheus", 550 | "decimals": 2, 551 | "editable": true, 552 | "error": false, 553 | "fieldConfig": { 554 | "defaults": { 555 | "custom": {} 556 | }, 557 | "overrides": [] 558 | }, 559 | "format": "bytes", 560 | "gauge": { 561 | "maxValue": 100, 562 | "minValue": 0, 563 | "show": false, 564 | "thresholdLabels": false, 565 | "thresholdMarkers": true 566 | }, 567 | "gridPos": { 568 | "h": 3, 569 | "w": 4, 570 | "x": 4, 571 | "y": 13 572 | }, 573 | "height": "1px", 574 | "id": 10, 575 | "interval": null, 576 | "isNew": true, 577 | "links": [], 578 | "mappingType": 1, 579 | "mappingTypes": [ 580 | { 581 | "name": "value to text", 582 | "value": 1 583 | }, 584 | { 585 | "name": "range to text", 586 | "value": 2 587 | } 588 | ], 589 | "maxDataPoints": 100, 590 | "nullPointMode": "connected", 591 | "nullText": null, 592 | "postfix": "", 593 | "postfixFontSize": "50%", 594 | "prefix": "", 595 | "prefixFontSize": "50%", 596 | "rangeMaps": [ 597 | { 598 | "from": "null", 599 | "text": "N/A", 600 | "to": "null" 601 | } 602 | ], 603 | "sparkline": { 604 | "fillColor": "rgba(31, 118, 189, 0.18)", 605 | "full": false, 606 | "lineColor": "rgb(31, 120, 193)", 607 | "show": false 608 | }, 609 | "tableColumn": "", 610 | "targets": [ 611 | { 612 | "expr": "sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"})", 613 | "interval": "10s", 614 | "intervalFactor": 1, 615 | "refId": "A", 616 | "step": 10 617 | } 618 | ], 619 | "thresholds": "", 620 | "title": "Total", 621 | "type": "singlestat", 622 | "valueFontSize": "50%", 623 | "valueMaps": [ 624 | { 625 | "op": "=", 626 | "text": "N/A", 627 | "value": "null" 628 | } 629 | ], 630 | "valueName": "current" 631 | }, 632 | { 633 | "cacheTimeout": null, 634 | "colorBackground": false, 635 | "colorValue": false, 636 | "colors": [ 637 | "rgba(50, 172, 45, 0.97)", 638 | "rgba(237, 129, 40, 0.89)", 639 | "rgba(245, 54, 54, 0.9)" 640 | ], 641 | "datasource": "Prometheus", 642 | "decimals": 2, 643 | "editable": true, 644 | "error": false, 645 | "fieldConfig": { 646 | "defaults": { 647 | "custom": {} 648 | }, 649 | "overrides": [] 650 | }, 651 | "format": "none", 652 | "gauge": { 653 | "maxValue": 100, 654 | "minValue": 0, 655 | "show": false, 656 | "thresholdLabels": false, 657 | "thresholdMarkers": true 658 | }, 659 | "gridPos": { 660 | "h": 3, 661 | "w": 4, 662 | "x": 8, 663 | "y": 13 664 | }, 665 | "height": "1px", 666 | "id": 11, 667 | "interval": null, 668 | "isNew": true, 669 | "links": [], 670 | "mappingType": 1, 671 | "mappingTypes": [ 672 | { 673 | "name": "value to text", 674 | "value": 1 675 | }, 676 | { 677 | "name": "range to text", 678 | "value": 2 679 | } 680 | ], 681 | "maxDataPoints": 100, 682 | "nullPointMode": "connected", 683 | "nullText": null, 684 | "postfix": " cores", 685 | "postfixFontSize": "30%", 686 | "prefix": "", 687 | "prefixFontSize": "50%", 688 | "rangeMaps": [ 689 | { 690 | "from": "null", 691 | "text": "N/A", 692 | "to": "null" 693 | } 694 | ], 695 | "sparkline": { 696 | "fillColor": "rgba(31, 118, 189, 0.18)", 697 | "full": false, 698 | "lineColor": "rgb(31, 120, 193)", 699 | "show": false 700 | }, 701 | "tableColumn": "", 702 | "targets": [ 703 | { 704 | "expr": "sum (rate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m]))", 705 | "interval": "10s", 706 | "intervalFactor": 1, 707 | "refId": "A", 708 | "step": 10 709 | } 710 | ], 711 | "thresholds": "", 712 | "title": "Used", 713 | "type": "singlestat", 714 | "valueFontSize": "50%", 715 | "valueMaps": [ 716 | { 717 | "op": "=", 718 | "text": "N/A", 719 | "value": "null" 720 | } 721 | ], 722 | "valueName": "current" 723 | }, 724 | { 725 | "cacheTimeout": null, 726 | "colorBackground": false, 727 | "colorValue": false, 728 | "colors": [ 729 | "rgba(50, 172, 45, 0.97)", 730 | "rgba(237, 129, 40, 0.89)", 731 | "rgba(245, 54, 54, 0.9)" 732 | ], 733 | "datasource": "Prometheus", 734 | "decimals": 2, 735 | "editable": true, 736 | "error": false, 737 | "fieldConfig": { 738 | "defaults": { 739 | "custom": {} 740 | }, 741 | "overrides": [] 742 | }, 743 | "format": "none", 744 | "gauge": { 745 | "maxValue": 100, 746 | "minValue": 0, 747 | "show": false, 748 | "thresholdLabels": false, 749 | "thresholdMarkers": true 750 | }, 751 | "gridPos": { 752 | "h": 3, 753 | "w": 4, 754 | "x": 12, 755 | "y": 13 756 | }, 757 | "height": "1px", 758 | "id": 12, 759 | "interval": null, 760 | "isNew": true, 761 | "links": [], 762 | "mappingType": 1, 763 | "mappingTypes": [ 764 | { 765 | "name": "value to text", 766 | "value": 1 767 | }, 768 | { 769 | "name": "range to text", 770 | "value": 2 771 | } 772 | ], 773 | "maxDataPoints": 100, 774 | "nullPointMode": "connected", 775 | "nullText": null, 776 | "postfix": " cores", 777 | "postfixFontSize": "30%", 778 | "prefix": "", 779 | "prefixFontSize": "50%", 780 | "rangeMaps": [ 781 | { 782 | "from": "null", 783 | "text": "N/A", 784 | "to": "null" 785 | } 786 | ], 787 | "sparkline": { 788 | "fillColor": "rgba(31, 118, 189, 0.18)", 789 | "full": false, 790 | "lineColor": "rgb(31, 120, 193)", 791 | "show": false 792 | }, 793 | "tableColumn": "", 794 | "targets": [ 795 | { 796 | "expr": "sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"})", 797 | "interval": "10s", 798 | "intervalFactor": 1, 799 | "refId": "A", 800 | "step": 10 801 | } 802 | ], 803 | "thresholds": "", 804 | "title": "Total", 805 | "type": "singlestat", 806 | "valueFontSize": "50%", 807 | "valueMaps": [ 808 | { 809 | "op": "=", 810 | "text": "N/A", 811 | "value": "null" 812 | } 813 | ], 814 | "valueName": "current" 815 | }, 816 | { 817 | "cacheTimeout": null, 818 | "colorBackground": false, 819 | "colorValue": false, 820 | "colors": [ 821 | "rgba(50, 172, 45, 0.97)", 822 | "rgba(237, 129, 40, 0.89)", 823 | "rgba(245, 54, 54, 0.9)" 824 | ], 825 | "datasource": "Prometheus", 826 | "decimals": 2, 827 | "editable": true, 828 | "error": false, 829 | "fieldConfig": { 830 | "defaults": { 831 | "custom": {} 832 | }, 833 | "overrides": [] 834 | }, 835 | "format": "bytes", 836 | "gauge": { 837 | "maxValue": 100, 838 | "minValue": 0, 839 | "show": false, 840 | "thresholdLabels": false, 841 | "thresholdMarkers": true 842 | }, 843 | "gridPos": { 844 | "h": 3, 845 | "w": 4, 846 | "x": 16, 847 | "y": 13 848 | }, 849 | "height": "1px", 850 | "id": 13, 851 | "interval": null, 852 | "isNew": true, 853 | "links": [], 854 | "mappingType": 1, 855 | "mappingTypes": [ 856 | { 857 | "name": "value to text", 858 | "value": 1 859 | }, 860 | { 861 | "name": "range to text", 862 | "value": 2 863 | } 864 | ], 865 | "maxDataPoints": 100, 866 | "nullPointMode": "connected", 867 | "nullText": null, 868 | "postfix": "", 869 | "postfixFontSize": "50%", 870 | "prefix": "", 871 | "prefixFontSize": "50%", 872 | "rangeMaps": [ 873 | { 874 | "from": "null", 875 | "text": "N/A", 876 | "to": "null" 877 | } 878 | ], 879 | "sparkline": { 880 | "fillColor": "rgba(31, 118, 189, 0.18)", 881 | "full": false, 882 | "lineColor": "rgb(31, 120, 193)", 883 | "show": false 884 | }, 885 | "tableColumn": "", 886 | "targets": [ 887 | { 888 | "expr": "sum (container_fs_usage_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", 889 | "interval": "10s", 890 | "intervalFactor": 1, 891 | "refId": "A", 892 | "step": 10 893 | } 894 | ], 895 | "thresholds": "", 896 | "title": "Used", 897 | "type": "singlestat", 898 | "valueFontSize": "50%", 899 | "valueMaps": [ 900 | { 901 | "op": "=", 902 | "text": "N/A", 903 | "value": "null" 904 | } 905 | ], 906 | "valueName": "current" 907 | }, 908 | { 909 | "cacheTimeout": null, 910 | "colorBackground": false, 911 | "colorValue": false, 912 | "colors": [ 913 | "rgba(50, 172, 45, 0.97)", 914 | "rgba(237, 129, 40, 0.89)", 915 | "rgba(245, 54, 54, 0.9)" 916 | ], 917 | "datasource": "Prometheus", 918 | "decimals": 2, 919 | "editable": true, 920 | "error": false, 921 | "fieldConfig": { 922 | "defaults": { 923 | "custom": {} 924 | }, 925 | "overrides": [] 926 | }, 927 | "format": "bytes", 928 | "gauge": { 929 | "maxValue": 100, 930 | "minValue": 0, 931 | "show": false, 932 | "thresholdLabels": false, 933 | "thresholdMarkers": true 934 | }, 935 | "gridPos": { 936 | "h": 3, 937 | "w": 4, 938 | "x": 20, 939 | "y": 13 940 | }, 941 | "height": "1px", 942 | "id": 14, 943 | "interval": null, 944 | "isNew": true, 945 | "links": [], 946 | "mappingType": 1, 947 | "mappingTypes": [ 948 | { 949 | "name": "value to text", 950 | "value": 1 951 | }, 952 | { 953 | "name": "range to text", 954 | "value": 2 955 | } 956 | ], 957 | "maxDataPoints": 100, 958 | "nullPointMode": "connected", 959 | "nullText": null, 960 | "postfix": "", 961 | "postfixFontSize": "50%", 962 | "prefix": "", 963 | "prefixFontSize": "50%", 964 | "rangeMaps": [ 965 | { 966 | "from": "null", 967 | "text": "N/A", 968 | "to": "null" 969 | } 970 | ], 971 | "sparkline": { 972 | "fillColor": "rgba(31, 118, 189, 0.18)", 973 | "full": false, 974 | "lineColor": "rgb(31, 120, 193)", 975 | "show": false 976 | }, 977 | "tableColumn": "", 978 | "targets": [ 979 | { 980 | "expr": "sum (container_fs_limit_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", 981 | "interval": "10s", 982 | "intervalFactor": 1, 983 | "refId": "A", 984 | "step": 10 985 | } 986 | ], 987 | "thresholds": "", 988 | "title": "Total", 989 | "type": "singlestat", 990 | "valueFontSize": "50%", 991 | "valueMaps": [ 992 | { 993 | "op": "=", 994 | "text": "N/A", 995 | "value": "null" 996 | } 997 | ], 998 | "valueName": "current" 999 | }, 1000 | { 1001 | "collapsed": false, 1002 | "datasource": null, 1003 | "gridPos": { 1004 | "h": 1, 1005 | "w": 24, 1006 | "x": 0, 1007 | "y": 16 1008 | }, 1009 | "id": 35, 1010 | "panels": [], 1011 | "title": "Pods CPU usage", 1012 | "type": "row" 1013 | }, 1014 | { 1015 | "aliasColors": {}, 1016 | "bars": false, 1017 | "dashLength": 10, 1018 | "dashes": false, 1019 | "datasource": "Prometheus", 1020 | "decimals": 3, 1021 | "editable": true, 1022 | "error": false, 1023 | "fieldConfig": { 1024 | "defaults": { 1025 | "custom": {} 1026 | }, 1027 | "overrides": [] 1028 | }, 1029 | "fill": 0, 1030 | "fillGradient": 0, 1031 | "grid": {}, 1032 | "gridPos": { 1033 | "h": 7, 1034 | "w": 24, 1035 | "x": 0, 1036 | "y": 17 1037 | }, 1038 | "height": "", 1039 | "hiddenSeries": false, 1040 | "id": 17, 1041 | "isNew": true, 1042 | "legend": { 1043 | "alignAsTable": true, 1044 | "avg": true, 1045 | "current": true, 1046 | "max": false, 1047 | "min": false, 1048 | "rightSide": true, 1049 | "show": true, 1050 | "sort": "current", 1051 | "sortDesc": true, 1052 | "total": false, 1053 | "values": true 1054 | }, 1055 | "lines": true, 1056 | "linewidth": 2, 1057 | "links": [], 1058 | "nullPointMode": "connected", 1059 | "options": { 1060 | "alertThreshold": true 1061 | }, 1062 | "percentage": false, 1063 | "pluginVersion": "7.2.1", 1064 | "pointradius": 5, 1065 | "points": false, 1066 | "renderer": "flot", 1067 | "seriesOverrides": [], 1068 | "spaceLength": 10, 1069 | "stack": false, 1070 | "steppedLine": true, 1071 | "targets": [ 1072 | { 1073 | "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name)", 1074 | "interval": "10s", 1075 | "intervalFactor": 1, 1076 | "legendFormat": "{{ pod_name }}", 1077 | "metric": "container_cpu", 1078 | "refId": "A", 1079 | "step": 10 1080 | } 1081 | ], 1082 | "thresholds": [], 1083 | "timeFrom": null, 1084 | "timeRegions": [], 1085 | "timeShift": null, 1086 | "title": "Pods CPU usage (1m avg)", 1087 | "tooltip": { 1088 | "msResolution": true, 1089 | "shared": true, 1090 | "sort": 2, 1091 | "value_type": "cumulative" 1092 | }, 1093 | "type": "graph", 1094 | "xaxis": { 1095 | "buckets": null, 1096 | "mode": "time", 1097 | "name": null, 1098 | "show": true, 1099 | "values": [] 1100 | }, 1101 | "yaxes": [ 1102 | { 1103 | "format": "none", 1104 | "label": "cores", 1105 | "logBase": 1, 1106 | "max": null, 1107 | "min": null, 1108 | "show": true 1109 | }, 1110 | { 1111 | "format": "short", 1112 | "label": null, 1113 | "logBase": 1, 1114 | "max": null, 1115 | "min": null, 1116 | "show": false 1117 | } 1118 | ], 1119 | "yaxis": { 1120 | "align": false, 1121 | "alignLevel": null 1122 | } 1123 | }, 1124 | { 1125 | "collapsed": true, 1126 | "datasource": null, 1127 | "gridPos": { 1128 | "h": 1, 1129 | "w": 24, 1130 | "x": 0, 1131 | "y": 24 1132 | }, 1133 | "id": 36, 1134 | "panels": [ 1135 | { 1136 | "aliasColors": {}, 1137 | "bars": false, 1138 | "datasource": "Prometheus", 1139 | "decimals": 3, 1140 | "editable": true, 1141 | "error": false, 1142 | "fill": 0, 1143 | "grid": {}, 1144 | "gridPos": { 1145 | "h": 7, 1146 | "w": 24, 1147 | "x": 0, 1148 | "y": 24 1149 | }, 1150 | "height": "", 1151 | "id": 23, 1152 | "isNew": true, 1153 | "legend": { 1154 | "alignAsTable": true, 1155 | "avg": true, 1156 | "current": true, 1157 | "max": false, 1158 | "min": false, 1159 | "rightSide": true, 1160 | "show": true, 1161 | "sort": "current", 1162 | "sortDesc": true, 1163 | "total": false, 1164 | "values": true 1165 | }, 1166 | "lines": true, 1167 | "linewidth": 2, 1168 | "links": [], 1169 | "nullPointMode": "connected", 1170 | "percentage": false, 1171 | "pointradius": 5, 1172 | "points": false, 1173 | "renderer": "flot", 1174 | "seriesOverrides": [], 1175 | "stack": false, 1176 | "steppedLine": true, 1177 | "targets": [ 1178 | { 1179 | "expr": "sum (rate (container_cpu_usage_seconds_total{systemd_service_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (systemd_service_name)", 1180 | "hide": false, 1181 | "interval": "10s", 1182 | "intervalFactor": 1, 1183 | "legendFormat": "{{ systemd_service_name }}", 1184 | "metric": "container_cpu", 1185 | "refId": "A", 1186 | "step": 10 1187 | } 1188 | ], 1189 | "thresholds": [], 1190 | "timeFrom": null, 1191 | "timeShift": null, 1192 | "title": "System services CPU usage (1m avg)", 1193 | "tooltip": { 1194 | "msResolution": true, 1195 | "shared": true, 1196 | "sort": 2, 1197 | "value_type": "cumulative" 1198 | }, 1199 | "type": "graph", 1200 | "xaxis": { 1201 | "show": true 1202 | }, 1203 | "yaxes": [ 1204 | { 1205 | "format": "none", 1206 | "label": "cores", 1207 | "logBase": 1, 1208 | "max": null, 1209 | "min": null, 1210 | "show": true 1211 | }, 1212 | { 1213 | "format": "short", 1214 | "label": null, 1215 | "logBase": 1, 1216 | "max": null, 1217 | "min": null, 1218 | "show": false 1219 | } 1220 | ] 1221 | } 1222 | ], 1223 | "title": "System services CPU usage", 1224 | "type": "row" 1225 | }, 1226 | { 1227 | "collapsed": true, 1228 | "datasource": null, 1229 | "gridPos": { 1230 | "h": 1, 1231 | "w": 24, 1232 | "x": 0, 1233 | "y": 25 1234 | }, 1235 | "id": 37, 1236 | "panels": [ 1237 | { 1238 | "aliasColors": {}, 1239 | "bars": false, 1240 | "datasource": "Prometheus", 1241 | "decimals": 3, 1242 | "editable": true, 1243 | "error": false, 1244 | "fill": 0, 1245 | "grid": {}, 1246 | "gridPos": { 1247 | "h": 7, 1248 | "w": 24, 1249 | "x": 0, 1250 | "y": 25 1251 | }, 1252 | "height": "", 1253 | "id": 24, 1254 | "isNew": true, 1255 | "legend": { 1256 | "alignAsTable": true, 1257 | "avg": true, 1258 | "current": true, 1259 | "hideEmpty": false, 1260 | "hideZero": false, 1261 | "max": false, 1262 | "min": false, 1263 | "rightSide": true, 1264 | "show": true, 1265 | "sideWidth": null, 1266 | "sort": "current", 1267 | "sortDesc": true, 1268 | "total": false, 1269 | "values": true 1270 | }, 1271 | "lines": true, 1272 | "linewidth": 2, 1273 | "links": [], 1274 | "nullPointMode": "connected", 1275 | "percentage": false, 1276 | "pointradius": 5, 1277 | "points": false, 1278 | "renderer": "flot", 1279 | "seriesOverrides": [], 1280 | "stack": false, 1281 | "steppedLine": true, 1282 | "targets": [ 1283 | { 1284 | "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",name=~\"^k8s_.*\",container_name!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, pod_name)", 1285 | "hide": false, 1286 | "interval": "10s", 1287 | "intervalFactor": 1, 1288 | "legendFormat": "pod: {{ pod_name }} | {{ container_name }}", 1289 | "metric": "container_cpu", 1290 | "refId": "A", 1291 | "step": 10 1292 | }, 1293 | { 1294 | "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", 1295 | "hide": false, 1296 | "interval": "10s", 1297 | "intervalFactor": 1, 1298 | "legendFormat": "docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", 1299 | "metric": "container_cpu", 1300 | "refId": "B", 1301 | "step": 10 1302 | }, 1303 | { 1304 | "expr": "sum (rate (container_cpu_usage_seconds_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", 1305 | "interval": "10s", 1306 | "intervalFactor": 1, 1307 | "legendFormat": "rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", 1308 | "metric": "container_cpu", 1309 | "refId": "C", 1310 | "step": 10 1311 | } 1312 | ], 1313 | "thresholds": [], 1314 | "timeFrom": null, 1315 | "timeShift": null, 1316 | "title": "Containers CPU usage (1m avg)", 1317 | "tooltip": { 1318 | "msResolution": true, 1319 | "shared": true, 1320 | "sort": 2, 1321 | "value_type": "cumulative" 1322 | }, 1323 | "type": "graph", 1324 | "xaxis": { 1325 | "show": true 1326 | }, 1327 | "yaxes": [ 1328 | { 1329 | "format": "none", 1330 | "label": "cores", 1331 | "logBase": 1, 1332 | "max": null, 1333 | "min": null, 1334 | "show": true 1335 | }, 1336 | { 1337 | "format": "short", 1338 | "label": null, 1339 | "logBase": 1, 1340 | "max": null, 1341 | "min": null, 1342 | "show": false 1343 | } 1344 | ] 1345 | } 1346 | ], 1347 | "title": "Containers CPU usage", 1348 | "type": "row" 1349 | }, 1350 | { 1351 | "collapsed": true, 1352 | "datasource": null, 1353 | "gridPos": { 1354 | "h": 1, 1355 | "w": 24, 1356 | "x": 0, 1357 | "y": 26 1358 | }, 1359 | "id": 38, 1360 | "panels": [ 1361 | { 1362 | "aliasColors": {}, 1363 | "bars": false, 1364 | "datasource": "Prometheus", 1365 | "decimals": 3, 1366 | "editable": true, 1367 | "error": false, 1368 | "fill": 0, 1369 | "grid": {}, 1370 | "gridPos": { 1371 | "h": 14, 1372 | "w": 24, 1373 | "x": 0, 1374 | "y": 26 1375 | }, 1376 | "id": 20, 1377 | "isNew": true, 1378 | "legend": { 1379 | "alignAsTable": true, 1380 | "avg": true, 1381 | "current": true, 1382 | "max": false, 1383 | "min": false, 1384 | "rightSide": false, 1385 | "show": true, 1386 | "sort": "current", 1387 | "sortDesc": true, 1388 | "total": false, 1389 | "values": true 1390 | }, 1391 | "lines": true, 1392 | "linewidth": 2, 1393 | "links": [], 1394 | "nullPointMode": "connected", 1395 | "percentage": false, 1396 | "pointradius": 5, 1397 | "points": false, 1398 | "renderer": "flot", 1399 | "seriesOverrides": [], 1400 | "stack": false, 1401 | "steppedLine": true, 1402 | "targets": [ 1403 | { 1404 | "expr": "sum (rate (container_cpu_usage_seconds_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", 1405 | "hide": false, 1406 | "interval": "10s", 1407 | "intervalFactor": 1, 1408 | "legendFormat": "{{ id }}", 1409 | "metric": "container_cpu", 1410 | "refId": "A", 1411 | "step": 10 1412 | } 1413 | ], 1414 | "thresholds": [], 1415 | "timeFrom": null, 1416 | "timeShift": null, 1417 | "title": "All processes CPU usage (1m avg)", 1418 | "tooltip": { 1419 | "msResolution": true, 1420 | "shared": true, 1421 | "sort": 2, 1422 | "value_type": "cumulative" 1423 | }, 1424 | "type": "graph", 1425 | "xaxis": { 1426 | "show": true 1427 | }, 1428 | "yaxes": [ 1429 | { 1430 | "format": "none", 1431 | "label": "cores", 1432 | "logBase": 1, 1433 | "max": null, 1434 | "min": null, 1435 | "show": true 1436 | }, 1437 | { 1438 | "format": "short", 1439 | "label": null, 1440 | "logBase": 1, 1441 | "max": null, 1442 | "min": null, 1443 | "show": false 1444 | } 1445 | ] 1446 | } 1447 | ], 1448 | "repeat": null, 1449 | "title": "All processes CPU usage", 1450 | "type": "row" 1451 | }, 1452 | { 1453 | "collapsed": false, 1454 | "datasource": null, 1455 | "gridPos": { 1456 | "h": 1, 1457 | "w": 24, 1458 | "x": 0, 1459 | "y": 27 1460 | }, 1461 | "id": 39, 1462 | "panels": [], 1463 | "title": "Pods memory usage", 1464 | "type": "row" 1465 | }, 1466 | { 1467 | "aliasColors": {}, 1468 | "bars": false, 1469 | "dashLength": 10, 1470 | "dashes": false, 1471 | "datasource": "Prometheus", 1472 | "decimals": 2, 1473 | "editable": true, 1474 | "error": false, 1475 | "fieldConfig": { 1476 | "defaults": { 1477 | "custom": {} 1478 | }, 1479 | "overrides": [] 1480 | }, 1481 | "fill": 0, 1482 | "fillGradient": 0, 1483 | "grid": {}, 1484 | "gridPos": { 1485 | "h": 7, 1486 | "w": 24, 1487 | "x": 0, 1488 | "y": 28 1489 | }, 1490 | "hiddenSeries": false, 1491 | "id": 25, 1492 | "isNew": true, 1493 | "legend": { 1494 | "alignAsTable": true, 1495 | "avg": true, 1496 | "current": true, 1497 | "max": false, 1498 | "min": false, 1499 | "rightSide": true, 1500 | "show": true, 1501 | "sideWidth": 200, 1502 | "sort": "current", 1503 | "sortDesc": true, 1504 | "total": false, 1505 | "values": true 1506 | }, 1507 | "lines": true, 1508 | "linewidth": 2, 1509 | "links": [], 1510 | "nullPointMode": "connected", 1511 | "options": { 1512 | "alertThreshold": true 1513 | }, 1514 | "percentage": false, 1515 | "pluginVersion": "7.2.1", 1516 | "pointradius": 5, 1517 | "points": false, 1518 | "renderer": "flot", 1519 | "seriesOverrides": [], 1520 | "spaceLength": 10, 1521 | "stack": false, 1522 | "steppedLine": true, 1523 | "targets": [ 1524 | { 1525 | "expr": "sum (container_memory_working_set_bytes{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}) by (pod_name)", 1526 | "interval": "10s", 1527 | "intervalFactor": 1, 1528 | "legendFormat": "{{ pod_name }}", 1529 | "metric": "container_memory_usage:sort_desc", 1530 | "refId": "A", 1531 | "step": 10 1532 | } 1533 | ], 1534 | "thresholds": [], 1535 | "timeFrom": null, 1536 | "timeRegions": [], 1537 | "timeShift": null, 1538 | "title": "Pods memory usage", 1539 | "tooltip": { 1540 | "msResolution": false, 1541 | "shared": true, 1542 | "sort": 2, 1543 | "value_type": "cumulative" 1544 | }, 1545 | "type": "graph", 1546 | "xaxis": { 1547 | "buckets": null, 1548 | "mode": "time", 1549 | "name": null, 1550 | "show": true, 1551 | "values": [] 1552 | }, 1553 | "yaxes": [ 1554 | { 1555 | "format": "bytes", 1556 | "label": null, 1557 | "logBase": 1, 1558 | "max": null, 1559 | "min": null, 1560 | "show": true 1561 | }, 1562 | { 1563 | "format": "short", 1564 | "label": null, 1565 | "logBase": 1, 1566 | "max": null, 1567 | "min": null, 1568 | "show": false 1569 | } 1570 | ], 1571 | "yaxis": { 1572 | "align": false, 1573 | "alignLevel": null 1574 | } 1575 | }, 1576 | { 1577 | "collapsed": true, 1578 | "datasource": null, 1579 | "gridPos": { 1580 | "h": 1, 1581 | "w": 24, 1582 | "x": 0, 1583 | "y": 35 1584 | }, 1585 | "id": 40, 1586 | "panels": [ 1587 | { 1588 | "aliasColors": {}, 1589 | "bars": false, 1590 | "datasource": "Prometheus", 1591 | "decimals": 2, 1592 | "editable": true, 1593 | "error": false, 1594 | "fill": 0, 1595 | "grid": {}, 1596 | "gridPos": { 1597 | "h": 7, 1598 | "w": 24, 1599 | "x": 0, 1600 | "y": 35 1601 | }, 1602 | "id": 26, 1603 | "isNew": true, 1604 | "legend": { 1605 | "alignAsTable": true, 1606 | "avg": true, 1607 | "current": true, 1608 | "max": false, 1609 | "min": false, 1610 | "rightSide": true, 1611 | "show": true, 1612 | "sideWidth": 200, 1613 | "sort": "current", 1614 | "sortDesc": true, 1615 | "total": false, 1616 | "values": true 1617 | }, 1618 | "lines": true, 1619 | "linewidth": 2, 1620 | "links": [], 1621 | "nullPointMode": "connected", 1622 | "percentage": false, 1623 | "pointradius": 5, 1624 | "points": false, 1625 | "renderer": "flot", 1626 | "seriesOverrides": [], 1627 | "stack": false, 1628 | "steppedLine": true, 1629 | "targets": [ 1630 | { 1631 | "expr": "sum (container_memory_working_set_bytes{systemd_service_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (systemd_service_name)", 1632 | "interval": "10s", 1633 | "intervalFactor": 1, 1634 | "legendFormat": "{{ systemd_service_name }}", 1635 | "metric": "container_memory_usage:sort_desc", 1636 | "refId": "A", 1637 | "step": 10 1638 | } 1639 | ], 1640 | "thresholds": [], 1641 | "timeFrom": null, 1642 | "timeShift": null, 1643 | "title": "System services memory usage", 1644 | "tooltip": { 1645 | "msResolution": false, 1646 | "shared": true, 1647 | "sort": 2, 1648 | "value_type": "cumulative" 1649 | }, 1650 | "type": "graph", 1651 | "xaxis": { 1652 | "show": true 1653 | }, 1654 | "yaxes": [ 1655 | { 1656 | "format": "bytes", 1657 | "label": null, 1658 | "logBase": 1, 1659 | "max": null, 1660 | "min": null, 1661 | "show": true 1662 | }, 1663 | { 1664 | "format": "short", 1665 | "label": null, 1666 | "logBase": 1, 1667 | "max": null, 1668 | "min": null, 1669 | "show": false 1670 | } 1671 | ] 1672 | } 1673 | ], 1674 | "title": "System services memory usage", 1675 | "type": "row" 1676 | }, 1677 | { 1678 | "collapsed": true, 1679 | "datasource": null, 1680 | "gridPos": { 1681 | "h": 1, 1682 | "w": 24, 1683 | "x": 0, 1684 | "y": 36 1685 | }, 1686 | "id": 41, 1687 | "panels": [ 1688 | { 1689 | "aliasColors": {}, 1690 | "bars": false, 1691 | "datasource": "Prometheus", 1692 | "decimals": 2, 1693 | "editable": true, 1694 | "error": false, 1695 | "fill": 0, 1696 | "grid": {}, 1697 | "gridPos": { 1698 | "h": 7, 1699 | "w": 24, 1700 | "x": 0, 1701 | "y": 36 1702 | }, 1703 | "id": 27, 1704 | "isNew": true, 1705 | "legend": { 1706 | "alignAsTable": true, 1707 | "avg": true, 1708 | "current": true, 1709 | "max": false, 1710 | "min": false, 1711 | "rightSide": true, 1712 | "show": true, 1713 | "sideWidth": 200, 1714 | "sort": "current", 1715 | "sortDesc": true, 1716 | "total": false, 1717 | "values": true 1718 | }, 1719 | "lines": true, 1720 | "linewidth": 2, 1721 | "links": [], 1722 | "nullPointMode": "connected", 1723 | "percentage": false, 1724 | "pointradius": 5, 1725 | "points": false, 1726 | "renderer": "flot", 1727 | "seriesOverrides": [], 1728 | "stack": false, 1729 | "steppedLine": true, 1730 | "targets": [ 1731 | { 1732 | "expr": "sum (container_memory_working_set_bytes{image!=\"\",name=~\"^k8s_.*\",container_name!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}) by (container_name, pod_name)", 1733 | "interval": "10s", 1734 | "intervalFactor": 1, 1735 | "legendFormat": "pod: {{ pod_name }} | {{ container_name }}", 1736 | "metric": "container_memory_usage:sort_desc", 1737 | "refId": "A", 1738 | "step": 10 1739 | }, 1740 | { 1741 | "expr": "sum (container_memory_working_set_bytes{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, name, image)", 1742 | "interval": "10s", 1743 | "intervalFactor": 1, 1744 | "legendFormat": "docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", 1745 | "metric": "container_memory_usage:sort_desc", 1746 | "refId": "B", 1747 | "step": 10 1748 | }, 1749 | { 1750 | "expr": "sum (container_memory_working_set_bytes{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, rkt_container_name)", 1751 | "interval": "10s", 1752 | "intervalFactor": 1, 1753 | "legendFormat": "rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", 1754 | "metric": "container_memory_usage:sort_desc", 1755 | "refId": "C", 1756 | "step": 10 1757 | } 1758 | ], 1759 | "thresholds": [], 1760 | "timeFrom": null, 1761 | "timeShift": null, 1762 | "title": "Containers memory usage", 1763 | "tooltip": { 1764 | "msResolution": false, 1765 | "shared": true, 1766 | "sort": 2, 1767 | "value_type": "cumulative" 1768 | }, 1769 | "type": "graph", 1770 | "xaxis": { 1771 | "show": true 1772 | }, 1773 | "yaxes": [ 1774 | { 1775 | "format": "bytes", 1776 | "label": null, 1777 | "logBase": 1, 1778 | "max": null, 1779 | "min": null, 1780 | "show": true 1781 | }, 1782 | { 1783 | "format": "short", 1784 | "label": null, 1785 | "logBase": 1, 1786 | "max": null, 1787 | "min": null, 1788 | "show": false 1789 | } 1790 | ] 1791 | } 1792 | ], 1793 | "title": "Containers memory usage", 1794 | "type": "row" 1795 | }, 1796 | { 1797 | "collapsed": true, 1798 | "datasource": null, 1799 | "gridPos": { 1800 | "h": 1, 1801 | "w": 24, 1802 | "x": 0, 1803 | "y": 37 1804 | }, 1805 | "id": 42, 1806 | "panels": [ 1807 | { 1808 | "aliasColors": {}, 1809 | "bars": false, 1810 | "datasource": "Prometheus", 1811 | "decimals": 2, 1812 | "editable": true, 1813 | "error": false, 1814 | "fill": 0, 1815 | "grid": {}, 1816 | "gridPos": { 1817 | "h": 14, 1818 | "w": 24, 1819 | "x": 0, 1820 | "y": 37 1821 | }, 1822 | "id": 28, 1823 | "isNew": true, 1824 | "legend": { 1825 | "alignAsTable": true, 1826 | "avg": true, 1827 | "current": true, 1828 | "max": false, 1829 | "min": false, 1830 | "rightSide": false, 1831 | "show": true, 1832 | "sideWidth": 200, 1833 | "sort": "current", 1834 | "sortDesc": true, 1835 | "total": false, 1836 | "values": true 1837 | }, 1838 | "lines": true, 1839 | "linewidth": 2, 1840 | "links": [], 1841 | "nullPointMode": "connected", 1842 | "percentage": false, 1843 | "pointradius": 5, 1844 | "points": false, 1845 | "renderer": "flot", 1846 | "seriesOverrides": [], 1847 | "stack": false, 1848 | "steppedLine": true, 1849 | "targets": [ 1850 | { 1851 | "expr": "sum (container_memory_working_set_bytes{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) by (id)", 1852 | "interval": "10s", 1853 | "intervalFactor": 1, 1854 | "legendFormat": "{{ id }}", 1855 | "metric": "container_memory_usage:sort_desc", 1856 | "refId": "A", 1857 | "step": 10 1858 | } 1859 | ], 1860 | "thresholds": [], 1861 | "timeFrom": null, 1862 | "timeShift": null, 1863 | "title": "All processes memory usage", 1864 | "tooltip": { 1865 | "msResolution": false, 1866 | "shared": true, 1867 | "sort": 2, 1868 | "value_type": "cumulative" 1869 | }, 1870 | "type": "graph", 1871 | "xaxis": { 1872 | "show": true 1873 | }, 1874 | "yaxes": [ 1875 | { 1876 | "format": "bytes", 1877 | "label": null, 1878 | "logBase": 1, 1879 | "max": null, 1880 | "min": null, 1881 | "show": true 1882 | }, 1883 | { 1884 | "format": "short", 1885 | "label": null, 1886 | "logBase": 1, 1887 | "max": null, 1888 | "min": null, 1889 | "show": false 1890 | } 1891 | ] 1892 | } 1893 | ], 1894 | "title": "All processes memory usage", 1895 | "type": "row" 1896 | }, 1897 | { 1898 | "collapsed": false, 1899 | "datasource": null, 1900 | "gridPos": { 1901 | "h": 1, 1902 | "w": 24, 1903 | "x": 0, 1904 | "y": 38 1905 | }, 1906 | "id": 43, 1907 | "panels": [], 1908 | "title": "Pods network I/O", 1909 | "type": "row" 1910 | }, 1911 | { 1912 | "aliasColors": {}, 1913 | "bars": false, 1914 | "dashLength": 10, 1915 | "dashes": false, 1916 | "datasource": "Prometheus", 1917 | "decimals": 2, 1918 | "editable": true, 1919 | "error": false, 1920 | "fieldConfig": { 1921 | "defaults": { 1922 | "custom": {} 1923 | }, 1924 | "overrides": [] 1925 | }, 1926 | "fill": 1, 1927 | "fillGradient": 0, 1928 | "grid": {}, 1929 | "gridPos": { 1930 | "h": 7, 1931 | "w": 24, 1932 | "x": 0, 1933 | "y": 39 1934 | }, 1935 | "hiddenSeries": false, 1936 | "id": 16, 1937 | "isNew": true, 1938 | "legend": { 1939 | "alignAsTable": true, 1940 | "avg": true, 1941 | "current": true, 1942 | "max": false, 1943 | "min": false, 1944 | "rightSide": true, 1945 | "show": true, 1946 | "sideWidth": 200, 1947 | "sort": "current", 1948 | "sortDesc": true, 1949 | "total": false, 1950 | "values": true 1951 | }, 1952 | "lines": true, 1953 | "linewidth": 2, 1954 | "links": [], 1955 | "nullPointMode": "connected", 1956 | "options": { 1957 | "alertThreshold": true 1958 | }, 1959 | "percentage": false, 1960 | "pluginVersion": "7.2.1", 1961 | "pointradius": 5, 1962 | "points": false, 1963 | "renderer": "flot", 1964 | "seriesOverrides": [], 1965 | "spaceLength": 10, 1966 | "stack": false, 1967 | "steppedLine": false, 1968 | "targets": [ 1969 | { 1970 | "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name)", 1971 | "interval": "10s", 1972 | "intervalFactor": 1, 1973 | "legendFormat": "-> {{ pod_name }}", 1974 | "metric": "network", 1975 | "refId": "A", 1976 | "step": 10 1977 | }, 1978 | { 1979 | "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name)", 1980 | "interval": "10s", 1981 | "intervalFactor": 1, 1982 | "legendFormat": "<- {{ pod_name }}", 1983 | "metric": "network", 1984 | "refId": "B", 1985 | "step": 10 1986 | } 1987 | ], 1988 | "thresholds": [], 1989 | "timeFrom": null, 1990 | "timeRegions": [], 1991 | "timeShift": null, 1992 | "title": "Pods network I/O (1m avg)", 1993 | "tooltip": { 1994 | "msResolution": false, 1995 | "shared": true, 1996 | "sort": 2, 1997 | "value_type": "cumulative" 1998 | }, 1999 | "type": "graph", 2000 | "xaxis": { 2001 | "buckets": null, 2002 | "mode": "time", 2003 | "name": null, 2004 | "show": true, 2005 | "values": [] 2006 | }, 2007 | "yaxes": [ 2008 | { 2009 | "format": "Bps", 2010 | "label": null, 2011 | "logBase": 1, 2012 | "max": null, 2013 | "min": null, 2014 | "show": true 2015 | }, 2016 | { 2017 | "format": "short", 2018 | "label": null, 2019 | "logBase": 1, 2020 | "max": null, 2021 | "min": null, 2022 | "show": false 2023 | } 2024 | ], 2025 | "yaxis": { 2026 | "align": false, 2027 | "alignLevel": null 2028 | } 2029 | }, 2030 | { 2031 | "collapsed": true, 2032 | "datasource": null, 2033 | "gridPos": { 2034 | "h": 1, 2035 | "w": 24, 2036 | "x": 0, 2037 | "y": 46 2038 | }, 2039 | "id": 44, 2040 | "panels": [ 2041 | { 2042 | "aliasColors": {}, 2043 | "bars": false, 2044 | "datasource": "Prometheus", 2045 | "decimals": 2, 2046 | "editable": true, 2047 | "error": false, 2048 | "fill": 1, 2049 | "grid": {}, 2050 | "gridPos": { 2051 | "h": 7, 2052 | "w": 24, 2053 | "x": 0, 2054 | "y": 46 2055 | }, 2056 | "id": 30, 2057 | "isNew": true, 2058 | "legend": { 2059 | "alignAsTable": true, 2060 | "avg": true, 2061 | "current": true, 2062 | "max": false, 2063 | "min": false, 2064 | "rightSide": true, 2065 | "show": true, 2066 | "sideWidth": 200, 2067 | "sort": "current", 2068 | "sortDesc": true, 2069 | "total": false, 2070 | "values": true 2071 | }, 2072 | "lines": true, 2073 | "linewidth": 2, 2074 | "links": [], 2075 | "nullPointMode": "connected", 2076 | "percentage": false, 2077 | "pointradius": 5, 2078 | "points": false, 2079 | "renderer": "flot", 2080 | "seriesOverrides": [], 2081 | "stack": false, 2082 | "steppedLine": false, 2083 | "targets": [ 2084 | { 2085 | "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, pod_name)", 2086 | "hide": false, 2087 | "interval": "10s", 2088 | "intervalFactor": 1, 2089 | "legendFormat": "-> pod: {{ pod_name }} | {{ container_name }}", 2090 | "metric": "network", 2091 | "refId": "B", 2092 | "step": 10 2093 | }, 2094 | { 2095 | "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, pod_name)", 2096 | "hide": false, 2097 | "interval": "10s", 2098 | "intervalFactor": 1, 2099 | "legendFormat": "<- pod: {{ pod_name }} | {{ container_name }}", 2100 | "metric": "network", 2101 | "refId": "D", 2102 | "step": 10 2103 | }, 2104 | { 2105 | "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", 2106 | "hide": false, 2107 | "interval": "10s", 2108 | "intervalFactor": 1, 2109 | "legendFormat": "-> docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", 2110 | "metric": "network", 2111 | "refId": "A", 2112 | "step": 10 2113 | }, 2114 | { 2115 | "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", 2116 | "hide": false, 2117 | "interval": "10s", 2118 | "intervalFactor": 1, 2119 | "legendFormat": "<- docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", 2120 | "metric": "network", 2121 | "refId": "C", 2122 | "step": 10 2123 | }, 2124 | { 2125 | "expr": "sum (rate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", 2126 | "hide": false, 2127 | "interval": "10s", 2128 | "intervalFactor": 1, 2129 | "legendFormat": "-> rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", 2130 | "metric": "network", 2131 | "refId": "E", 2132 | "step": 10 2133 | }, 2134 | { 2135 | "expr": "- sum (rate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", 2136 | "hide": false, 2137 | "interval": "10s", 2138 | "intervalFactor": 1, 2139 | "legendFormat": "<- rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", 2140 | "metric": "network", 2141 | "refId": "F", 2142 | "step": 10 2143 | } 2144 | ], 2145 | "thresholds": [], 2146 | "timeFrom": null, 2147 | "timeShift": null, 2148 | "title": "Containers network I/O (1m avg)", 2149 | "tooltip": { 2150 | "msResolution": false, 2151 | "shared": true, 2152 | "sort": 2, 2153 | "value_type": "cumulative" 2154 | }, 2155 | "type": "graph", 2156 | "xaxis": { 2157 | "show": true 2158 | }, 2159 | "yaxes": [ 2160 | { 2161 | "format": "Bps", 2162 | "label": null, 2163 | "logBase": 1, 2164 | "max": null, 2165 | "min": null, 2166 | "show": true 2167 | }, 2168 | { 2169 | "format": "short", 2170 | "label": null, 2171 | "logBase": 1, 2172 | "max": null, 2173 | "min": null, 2174 | "show": false 2175 | } 2176 | ] 2177 | } 2178 | ], 2179 | "title": "Containers network I/O", 2180 | "type": "row" 2181 | }, 2182 | { 2183 | "collapsed": true, 2184 | "datasource": null, 2185 | "gridPos": { 2186 | "h": 1, 2187 | "w": 24, 2188 | "x": 0, 2189 | "y": 47 2190 | }, 2191 | "id": 45, 2192 | "panels": [ 2193 | { 2194 | "aliasColors": {}, 2195 | "bars": false, 2196 | "datasource": "Prometheus", 2197 | "decimals": 2, 2198 | "editable": true, 2199 | "error": false, 2200 | "fill": 1, 2201 | "grid": {}, 2202 | "gridPos": { 2203 | "h": 14, 2204 | "w": 24, 2205 | "x": 0, 2206 | "y": 47 2207 | }, 2208 | "id": 29, 2209 | "isNew": true, 2210 | "legend": { 2211 | "alignAsTable": true, 2212 | "avg": true, 2213 | "current": true, 2214 | "max": false, 2215 | "min": false, 2216 | "rightSide": false, 2217 | "show": true, 2218 | "sideWidth": 200, 2219 | "sort": "current", 2220 | "sortDesc": true, 2221 | "total": false, 2222 | "values": true 2223 | }, 2224 | "lines": true, 2225 | "linewidth": 2, 2226 | "links": [], 2227 | "nullPointMode": "connected", 2228 | "percentage": false, 2229 | "pointradius": 5, 2230 | "points": false, 2231 | "renderer": "flot", 2232 | "seriesOverrides": [], 2233 | "stack": false, 2234 | "steppedLine": false, 2235 | "targets": [ 2236 | { 2237 | "expr": "sum (rate (container_network_receive_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", 2238 | "interval": "10s", 2239 | "intervalFactor": 1, 2240 | "legendFormat": "-> {{ id }}", 2241 | "metric": "network", 2242 | "refId": "A", 2243 | "step": 10 2244 | }, 2245 | { 2246 | "expr": "- sum (rate (container_network_transmit_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", 2247 | "interval": "10s", 2248 | "intervalFactor": 1, 2249 | "legendFormat": "<- {{ id }}", 2250 | "metric": "network", 2251 | "refId": "B", 2252 | "step": 10 2253 | } 2254 | ], 2255 | "thresholds": [], 2256 | "timeFrom": null, 2257 | "timeShift": null, 2258 | "title": "All processes network I/O (1m avg)", 2259 | "tooltip": { 2260 | "msResolution": false, 2261 | "shared": true, 2262 | "sort": 2, 2263 | "value_type": "cumulative" 2264 | }, 2265 | "type": "graph", 2266 | "xaxis": { 2267 | "show": true 2268 | }, 2269 | "yaxes": [ 2270 | { 2271 | "format": "Bps", 2272 | "label": null, 2273 | "logBase": 1, 2274 | "max": null, 2275 | "min": null, 2276 | "show": true 2277 | }, 2278 | { 2279 | "format": "short", 2280 | "label": null, 2281 | "logBase": 1, 2282 | "max": null, 2283 | "min": null, 2284 | "show": false 2285 | } 2286 | ] 2287 | } 2288 | ], 2289 | "title": "All processes network I/O", 2290 | "type": "row" 2291 | } 2292 | ], 2293 | "refresh": "10s", 2294 | "schemaVersion": 26, 2295 | "style": "dark", 2296 | "tags": [ 2297 | "kubernetes" 2298 | ], 2299 | "templating": { 2300 | "list": [ 2301 | { 2302 | "allValue": ".*", 2303 | "current": { 2304 | "selected": false, 2305 | "text": "All", 2306 | "value": "$__all" 2307 | }, 2308 | "datasource": "Prometheus", 2309 | "definition": "", 2310 | "hide": 0, 2311 | "includeAll": true, 2312 | "label": null, 2313 | "multi": false, 2314 | "name": "Node", 2315 | "options": [], 2316 | "query": "label_values(kubernetes_io_hostname)", 2317 | "refresh": 1, 2318 | "regex": "", 2319 | "skipUrlSync": false, 2320 | "sort": 0, 2321 | "tagValuesQuery": "", 2322 | "tags": [], 2323 | "tagsQuery": "", 2324 | "type": "query", 2325 | "useTags": false 2326 | } 2327 | ] 2328 | }, 2329 | "time": { 2330 | "from": "now-5m", 2331 | "to": "now" 2332 | }, 2333 | "timepicker": { 2334 | "refresh_intervals": [ 2335 | "5s", 2336 | "10s", 2337 | "30s", 2338 | "1m", 2339 | "5m", 2340 | "15m", 2341 | "30m", 2342 | "1h", 2343 | "2h", 2344 | "1d" 2345 | ], 2346 | "time_options": [ 2347 | "5m", 2348 | "15m", 2349 | "1h", 2350 | "6h", 2351 | "12h", 2352 | "24h", 2353 | "2d", 2354 | "7d", 2355 | "30d" 2356 | ] 2357 | }, 2358 | "timezone": "browser", 2359 | "title": "Kubernetes cluster monitoring (via Prometheus)", 2360 | "uid": "Lp_zhShGk", 2361 | "version": 1 2362 | } 2363 | -------------------------------------------------------------------------------- /monitoring-stack/dashboards/nodejs.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "Prometheus", 5 | "label": "prometheus", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "6.0.1" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "prometheus", 28 | "name": "Prometheus", 29 | "version": "5.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "singlestat", 34 | "name": "Singlestat", 35 | "version": "5.0.0" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "builtIn": 1, 42 | "datasource": "-- Grafana --", 43 | "enable": true, 44 | "hide": true, 45 | "iconColor": "rgba(0, 211, 255, 1)", 46 | "name": "Annotations & Alerts", 47 | "type": "dashboard" 48 | } 49 | ] 50 | }, 51 | "description": "node.js prometheus client basic metrics", 52 | "editable": true, 53 | "gnetId": 11159, 54 | "graphTooltip": 0, 55 | "id": null, 56 | "iteration": 1573392431370, 57 | "links": [], 58 | "panels": [ 59 | { 60 | "aliasColors": {}, 61 | "bars": false, 62 | "dashLength": 10, 63 | "dashes": false, 64 | "datasource": "Prometheus", 65 | "fill": 1, 66 | "gridPos": { 67 | "h": 7, 68 | "w": 10, 69 | "x": 0, 70 | "y": 0 71 | }, 72 | "id": 6, 73 | "legend": { 74 | "alignAsTable": true, 75 | "avg": true, 76 | "current": true, 77 | "max": true, 78 | "min": true, 79 | "show": true, 80 | "total": false, 81 | "values": true 82 | }, 83 | "lines": true, 84 | "linewidth": 1, 85 | "links": [], 86 | "nullPointMode": "null", 87 | "paceLength": 10, 88 | "percentage": false, 89 | "pointradius": 2, 90 | "points": false, 91 | "renderer": "flot", 92 | "seriesOverrides": [], 93 | "stack": false, 94 | "steppedLine": false, 95 | "targets": [ 96 | { 97 | "expr": "irate(process_cpu_user_seconds_total{instance=~\"$instance\"}[$__range]) * 100", 98 | "format": "time_series", 99 | "intervalFactor": 1, 100 | "legendFormat": "User CPU - {{instance}}", 101 | "refId": "A" 102 | }, 103 | { 104 | "expr": "irate(process_cpu_system_seconds_total{instance=~\"$instance\"}[$__range]) * 100", 105 | "format": "time_series", 106 | "intervalFactor": 1, 107 | "legendFormat": "Sys CPU - {{instance}}", 108 | "refId": "B" 109 | } 110 | ], 111 | "thresholds": [], 112 | "timeFrom": null, 113 | "timeRegions": [], 114 | "timeShift": null, 115 | "title": "Process CPU Usage", 116 | "tooltip": { 117 | "shared": true, 118 | "sort": 0, 119 | "value_type": "individual" 120 | }, 121 | "type": "graph", 122 | "xaxis": { 123 | "buckets": null, 124 | "mode": "time", 125 | "name": null, 126 | "show": true, 127 | "values": [] 128 | }, 129 | "yaxes": [ 130 | { 131 | "format": "percent", 132 | "label": null, 133 | "logBase": 1, 134 | "max": null, 135 | "min": null, 136 | "show": true 137 | }, 138 | { 139 | "format": "short", 140 | "label": null, 141 | "logBase": 1, 142 | "max": null, 143 | "min": null, 144 | "show": true 145 | } 146 | ], 147 | "yaxis": { 148 | "align": false, 149 | "alignLevel": null 150 | } 151 | }, 152 | { 153 | "aliasColors": {}, 154 | "bars": false, 155 | "dashLength": 10, 156 | "dashes": false, 157 | "datasource": "Prometheus", 158 | "fill": 1, 159 | "gridPos": { 160 | "h": 7, 161 | "w": 9, 162 | "x": 10, 163 | "y": 0 164 | }, 165 | "id": 8, 166 | "legend": { 167 | "alignAsTable": true, 168 | "avg": true, 169 | "current": true, 170 | "max": true, 171 | "min": true, 172 | "show": true, 173 | "total": false, 174 | "values": true 175 | }, 176 | "lines": true, 177 | "linewidth": 1, 178 | "links": [], 179 | "nullPointMode": "null", 180 | "paceLength": 10, 181 | "percentage": false, 182 | "pointradius": 2, 183 | "points": false, 184 | "renderer": "flot", 185 | "seriesOverrides": [], 186 | "stack": false, 187 | "steppedLine": false, 188 | "targets": [ 189 | { 190 | "expr": "nodejs_eventloop_lag_seconds{instance=~\"$instance\"}", 191 | "format": "time_series", 192 | "intervalFactor": 1, 193 | "legendFormat": "{{instance}}", 194 | "refId": "A" 195 | } 196 | ], 197 | "thresholds": [], 198 | "timeFrom": null, 199 | "timeRegions": [], 200 | "timeShift": null, 201 | "title": "Event Loop Lag", 202 | "tooltip": { 203 | "shared": true, 204 | "sort": 0, 205 | "value_type": "individual" 206 | }, 207 | "type": "graph", 208 | "xaxis": { 209 | "buckets": null, 210 | "mode": "time", 211 | "name": null, 212 | "show": true, 213 | "values": [] 214 | }, 215 | "yaxes": [ 216 | { 217 | "format": "s", 218 | "label": null, 219 | "logBase": 1, 220 | "max": null, 221 | "min": null, 222 | "show": true 223 | }, 224 | { 225 | "format": "short", 226 | "label": null, 227 | "logBase": 1, 228 | "max": null, 229 | "min": null, 230 | "show": true 231 | } 232 | ], 233 | "yaxis": { 234 | "align": false, 235 | "alignLevel": null 236 | } 237 | }, 238 | { 239 | "cacheTimeout": null, 240 | "colorBackground": false, 241 | "colorValue": false, 242 | "colors": [ 243 | "#299c46", 244 | "rgba(237, 129, 40, 0.89)", 245 | "#d44a3a" 246 | ], 247 | "datasource": "Prometheus", 248 | "format": "none", 249 | "gauge": { 250 | "maxValue": 100, 251 | "minValue": 0, 252 | "show": false, 253 | "thresholdLabels": false, 254 | "thresholdMarkers": true 255 | }, 256 | "gridPos": { 257 | "h": 3, 258 | "w": 5, 259 | "x": 19, 260 | "y": 0 261 | }, 262 | "id": 2, 263 | "interval": "", 264 | "links": [], 265 | "mappingType": 1, 266 | "mappingTypes": [ 267 | { 268 | "name": "value to text", 269 | "value": 1 270 | }, 271 | { 272 | "name": "range to text", 273 | "value": 2 274 | } 275 | ], 276 | "maxDataPoints": 100, 277 | "nullPointMode": "connected", 278 | "nullText": null, 279 | "postfix": "", 280 | "postfixFontSize": "50%", 281 | "prefix": "", 282 | "prefixFontSize": "50%", 283 | "rangeMaps": [ 284 | { 285 | "from": "null", 286 | "text": "N/A", 287 | "to": "null" 288 | } 289 | ], 290 | "sparkline": { 291 | "fillColor": "rgba(31, 118, 189, 0.18)", 292 | "full": false, 293 | "lineColor": "rgb(31, 120, 193)", 294 | "show": false 295 | }, 296 | "tableColumn": "__name__", 297 | "targets": [ 298 | { 299 | "expr": "sum(nodejs_version_info{instance=~\"$instance\"}) by (version)", 300 | "format": "time_series", 301 | "instant": false, 302 | "interval": "", 303 | "intervalFactor": 1, 304 | "legendFormat": "{{version}}", 305 | "refId": "A" 306 | } 307 | ], 308 | "thresholds": "", 309 | "timeFrom": null, 310 | "timeShift": null, 311 | "title": "Node.js Version", 312 | "type": "singlestat", 313 | "valueFontSize": "80%", 314 | "valueMaps": [ 315 | { 316 | "op": "=", 317 | "text": "N/A", 318 | "value": "null" 319 | } 320 | ], 321 | "valueName": "name" 322 | }, 323 | { 324 | "cacheTimeout": null, 325 | "colorBackground": false, 326 | "colorValue": false, 327 | "colors": [ 328 | "#299c46", 329 | "rgba(237, 129, 40, 0.89)", 330 | "#d44a3a" 331 | ], 332 | "datasource": "Prometheus", 333 | "format": "none", 334 | "gauge": { 335 | "maxValue": 100, 336 | "minValue": 0, 337 | "show": false, 338 | "thresholdLabels": false, 339 | "thresholdMarkers": true 340 | }, 341 | "gridPos": { 342 | "h": 4, 343 | "w": 5, 344 | "x": 19, 345 | "y": 3 346 | }, 347 | "id": 4, 348 | "interval": null, 349 | "links": [], 350 | "mappingType": 1, 351 | "mappingTypes": [ 352 | { 353 | "name": "value to text", 354 | "value": 1 355 | }, 356 | { 357 | "name": "range to text", 358 | "value": 2 359 | } 360 | ], 361 | "maxDataPoints": 100, 362 | "nullPointMode": "connected", 363 | "nullText": null, 364 | "postfix": "", 365 | "postfixFontSize": "50%", 366 | "prefix": "", 367 | "prefixFontSize": "50%", 368 | "rangeMaps": [ 369 | { 370 | "from": "null", 371 | "text": "N/A", 372 | "to": "null" 373 | } 374 | ], 375 | "sparkline": { 376 | "fillColor": "rgba(31, 118, 189, 0.18)", 377 | "full": false, 378 | "lineColor": "#F2495C", 379 | "show": true 380 | }, 381 | "tableColumn": "", 382 | "targets": [ 383 | { 384 | "expr": "sum(changes(process_start_time_seconds{instance=~\"$instance\"}[$__range]))", 385 | "format": "time_series", 386 | "intervalFactor": 1, 387 | "legendFormat": "{{instance}}", 388 | "refId": "A" 389 | } 390 | ], 391 | "thresholds": "", 392 | "timeFrom": null, 393 | "timeShift": null, 394 | "title": "Process Restart Times", 395 | "type": "singlestat", 396 | "valueFontSize": "80%", 397 | "valueMaps": [ 398 | { 399 | "op": "=", 400 | "text": "N/A", 401 | "value": "null" 402 | } 403 | ], 404 | "valueName": "current" 405 | }, 406 | { 407 | "aliasColors": {}, 408 | "bars": false, 409 | "dashLength": 10, 410 | "dashes": false, 411 | "datasource": "Prometheus", 412 | "fill": 1, 413 | "gridPos": { 414 | "h": 7, 415 | "w": 16, 416 | "x": 0, 417 | "y": 7 418 | }, 419 | "id": 7, 420 | "legend": { 421 | "alignAsTable": true, 422 | "avg": true, 423 | "current": true, 424 | "max": true, 425 | "min": true, 426 | "rightSide": true, 427 | "show": true, 428 | "total": false, 429 | "values": true 430 | }, 431 | "lines": true, 432 | "linewidth": 1, 433 | "links": [], 434 | "nullPointMode": "null", 435 | "paceLength": 10, 436 | "percentage": false, 437 | "pointradius": 2, 438 | "points": false, 439 | "renderer": "flot", 440 | "seriesOverrides": [], 441 | "stack": false, 442 | "steppedLine": false, 443 | "targets": [ 444 | { 445 | "expr": "process_resident_memory_bytes{instance=~\"$instance\"}", 446 | "format": "time_series", 447 | "intervalFactor": 1, 448 | "legendFormat": "Process Memory - {{instance}}", 449 | "refId": "A" 450 | }, 451 | { 452 | "expr": "nodejs_heap_size_total_bytes{instance=~\"$instance\"}", 453 | "format": "time_series", 454 | "intervalFactor": 1, 455 | "legendFormat": "Heap Total - {{instance}}", 456 | "refId": "B" 457 | }, 458 | { 459 | "expr": "nodejs_heap_size_used_bytes{instance=~\"$instance\"}", 460 | "format": "time_series", 461 | "intervalFactor": 1, 462 | "legendFormat": "Heap Used - {{instance}}", 463 | "refId": "C" 464 | }, 465 | { 466 | "expr": "nodejs_external_memory_bytes{instance=~\"$instance\"}", 467 | "format": "time_series", 468 | "intervalFactor": 1, 469 | "legendFormat": "External Memory - {{instance}}", 470 | "refId": "D" 471 | } 472 | ], 473 | "thresholds": [], 474 | "timeFrom": null, 475 | "timeRegions": [], 476 | "timeShift": null, 477 | "title": "Process Memory Usage", 478 | "tooltip": { 479 | "shared": true, 480 | "sort": 0, 481 | "value_type": "individual" 482 | }, 483 | "type": "graph", 484 | "xaxis": { 485 | "buckets": null, 486 | "mode": "time", 487 | "name": null, 488 | "show": true, 489 | "values": [] 490 | }, 491 | "yaxes": [ 492 | { 493 | "format": "bytes", 494 | "label": null, 495 | "logBase": 1, 496 | "max": null, 497 | "min": null, 498 | "show": true 499 | }, 500 | { 501 | "format": "short", 502 | "label": null, 503 | "logBase": 1, 504 | "max": null, 505 | "min": null, 506 | "show": true 507 | } 508 | ], 509 | "yaxis": { 510 | "align": false, 511 | "alignLevel": null 512 | } 513 | }, 514 | { 515 | "aliasColors": {}, 516 | "bars": false, 517 | "dashLength": 10, 518 | "dashes": false, 519 | "datasource": "Prometheus", 520 | "fill": 1, 521 | "gridPos": { 522 | "h": 7, 523 | "w": 8, 524 | "x": 16, 525 | "y": 7 526 | }, 527 | "id": 9, 528 | "legend": { 529 | "alignAsTable": true, 530 | "avg": true, 531 | "current": true, 532 | "max": true, 533 | "min": true, 534 | "show": true, 535 | "total": false, 536 | "values": true 537 | }, 538 | "lines": true, 539 | "linewidth": 1, 540 | "links": [], 541 | "nullPointMode": "null", 542 | "paceLength": 10, 543 | "percentage": false, 544 | "pointradius": 2, 545 | "points": false, 546 | "renderer": "flot", 547 | "seriesOverrides": [], 548 | "stack": false, 549 | "steppedLine": false, 550 | "targets": [ 551 | { 552 | "expr": "nodejs_active_handles_total{instance=~\"$instance\"}", 553 | "format": "time_series", 554 | "intervalFactor": 1, 555 | "legendFormat": "Active Handler - {{instance}}", 556 | "refId": "A" 557 | }, 558 | { 559 | "expr": "nodejs_active_requests_total{instance=~\"$instance\"}", 560 | "format": "time_series", 561 | "intervalFactor": 1, 562 | "legendFormat": "Active Request - {{instance}}", 563 | "refId": "B" 564 | } 565 | ], 566 | "thresholds": [], 567 | "timeFrom": null, 568 | "timeRegions": [], 569 | "timeShift": null, 570 | "title": "Active Handlers/Requests Total", 571 | "tooltip": { 572 | "shared": true, 573 | "sort": 0, 574 | "value_type": "individual" 575 | }, 576 | "type": "graph", 577 | "xaxis": { 578 | "buckets": null, 579 | "mode": "time", 580 | "name": null, 581 | "show": true, 582 | "values": [] 583 | }, 584 | "yaxes": [ 585 | { 586 | "format": "short", 587 | "label": null, 588 | "logBase": 1, 589 | "max": null, 590 | "min": null, 591 | "show": true 592 | }, 593 | { 594 | "format": "short", 595 | "label": null, 596 | "logBase": 1, 597 | "max": null, 598 | "min": null, 599 | "show": true 600 | } 601 | ], 602 | "yaxis": { 603 | "align": false, 604 | "alignLevel": null 605 | } 606 | }, 607 | { 608 | "aliasColors": {}, 609 | "bars": false, 610 | "dashLength": 10, 611 | "dashes": false, 612 | "datasource": "Prometheus", 613 | "fill": 1, 614 | "gridPos": { 615 | "h": 8, 616 | "w": 8, 617 | "x": 0, 618 | "y": 14 619 | }, 620 | "id": 10, 621 | "legend": { 622 | "alignAsTable": true, 623 | "avg": true, 624 | "current": true, 625 | "max": true, 626 | "min": true, 627 | "rightSide": false, 628 | "show": true, 629 | "total": false, 630 | "values": true 631 | }, 632 | "lines": true, 633 | "linewidth": 1, 634 | "links": [], 635 | "nullPointMode": "null", 636 | "paceLength": 10, 637 | "percentage": false, 638 | "pointradius": 2, 639 | "points": false, 640 | "renderer": "flot", 641 | "seriesOverrides": [], 642 | "stack": false, 643 | "steppedLine": false, 644 | "targets": [ 645 | { 646 | "expr": "nodejs_heap_space_size_total_bytes{instance=~\"$instance\"}", 647 | "format": "time_series", 648 | "intervalFactor": 1, 649 | "legendFormat": "Heap Total - {{instance}} - {{space}}", 650 | "refId": "A" 651 | } 652 | ], 653 | "thresholds": [], 654 | "timeFrom": null, 655 | "timeRegions": [], 656 | "timeShift": null, 657 | "title": "Heap Total Detail", 658 | "tooltip": { 659 | "shared": true, 660 | "sort": 0, 661 | "value_type": "individual" 662 | }, 663 | "type": "graph", 664 | "xaxis": { 665 | "buckets": null, 666 | "mode": "time", 667 | "name": null, 668 | "show": true, 669 | "values": [] 670 | }, 671 | "yaxes": [ 672 | { 673 | "format": "bytes", 674 | "label": null, 675 | "logBase": 1, 676 | "max": null, 677 | "min": null, 678 | "show": true 679 | }, 680 | { 681 | "format": "short", 682 | "label": null, 683 | "logBase": 1, 684 | "max": null, 685 | "min": null, 686 | "show": true 687 | } 688 | ], 689 | "yaxis": { 690 | "align": false, 691 | "alignLevel": null 692 | } 693 | }, 694 | { 695 | "aliasColors": {}, 696 | "bars": false, 697 | "dashLength": 10, 698 | "dashes": false, 699 | "datasource": "Prometheus", 700 | "fill": 1, 701 | "gridPos": { 702 | "h": 8, 703 | "w": 8, 704 | "x": 8, 705 | "y": 14 706 | }, 707 | "id": 11, 708 | "legend": { 709 | "alignAsTable": true, 710 | "avg": true, 711 | "current": true, 712 | "max": true, 713 | "min": true, 714 | "rightSide": false, 715 | "show": true, 716 | "total": false, 717 | "values": true 718 | }, 719 | "lines": true, 720 | "linewidth": 1, 721 | "links": [], 722 | "nullPointMode": "null", 723 | "paceLength": 10, 724 | "percentage": false, 725 | "pointradius": 2, 726 | "points": false, 727 | "renderer": "flot", 728 | "seriesOverrides": [], 729 | "stack": false, 730 | "steppedLine": false, 731 | "targets": [ 732 | { 733 | "expr": "nodejs_heap_space_size_used_bytes{instance=~\"$instance\"}", 734 | "format": "time_series", 735 | "intervalFactor": 1, 736 | "legendFormat": "Heap Used - {{instance}} - {{space}}", 737 | "refId": "A" 738 | } 739 | ], 740 | "thresholds": [], 741 | "timeFrom": null, 742 | "timeRegions": [], 743 | "timeShift": null, 744 | "title": "Heap Used Detail", 745 | "tooltip": { 746 | "shared": true, 747 | "sort": 0, 748 | "value_type": "individual" 749 | }, 750 | "type": "graph", 751 | "xaxis": { 752 | "buckets": null, 753 | "mode": "time", 754 | "name": null, 755 | "show": true, 756 | "values": [] 757 | }, 758 | "yaxes": [ 759 | { 760 | "format": "bytes", 761 | "label": null, 762 | "logBase": 1, 763 | "max": null, 764 | "min": null, 765 | "show": true 766 | }, 767 | { 768 | "format": "short", 769 | "label": null, 770 | "logBase": 1, 771 | "max": null, 772 | "min": null, 773 | "show": true 774 | } 775 | ], 776 | "yaxis": { 777 | "align": false, 778 | "alignLevel": null 779 | } 780 | }, 781 | { 782 | "aliasColors": {}, 783 | "bars": false, 784 | "dashLength": 10, 785 | "dashes": false, 786 | "datasource": "Prometheus", 787 | "fill": 1, 788 | "gridPos": { 789 | "h": 8, 790 | "w": 8, 791 | "x": 16, 792 | "y": 14 793 | }, 794 | "id": 12, 795 | "legend": { 796 | "alignAsTable": true, 797 | "avg": true, 798 | "current": true, 799 | "max": true, 800 | "min": true, 801 | "rightSide": false, 802 | "show": true, 803 | "total": false, 804 | "values": true 805 | }, 806 | "lines": true, 807 | "linewidth": 1, 808 | "links": [], 809 | "nullPointMode": "null", 810 | "paceLength": 10, 811 | "percentage": false, 812 | "pointradius": 2, 813 | "points": false, 814 | "renderer": "flot", 815 | "seriesOverrides": [], 816 | "stack": false, 817 | "steppedLine": false, 818 | "targets": [ 819 | { 820 | "expr": "nodejs_heap_space_size_available_bytes{instance=~\"$instance\"}", 821 | "format": "time_series", 822 | "intervalFactor": 1, 823 | "legendFormat": "Heap Used - {{instance}} - {{space}}", 824 | "refId": "A" 825 | } 826 | ], 827 | "thresholds": [], 828 | "timeFrom": null, 829 | "timeRegions": [], 830 | "timeShift": null, 831 | "title": "Heap Available Detail", 832 | "tooltip": { 833 | "shared": true, 834 | "sort": 0, 835 | "value_type": "individual" 836 | }, 837 | "type": "graph", 838 | "xaxis": { 839 | "buckets": null, 840 | "mode": "time", 841 | "name": null, 842 | "show": true, 843 | "values": [] 844 | }, 845 | "yaxes": [ 846 | { 847 | "format": "bytes", 848 | "label": null, 849 | "logBase": 1, 850 | "max": null, 851 | "min": null, 852 | "show": true 853 | }, 854 | { 855 | "format": "short", 856 | "label": null, 857 | "logBase": 1, 858 | "max": null, 859 | "min": null, 860 | "show": true 861 | } 862 | ], 863 | "yaxis": { 864 | "align": false, 865 | "alignLevel": null 866 | } 867 | } 868 | ], 869 | "schemaVersion": 18, 870 | "style": "dark", 871 | "tags": [ 872 | "nodejs" 873 | ], 874 | "templating": { 875 | "list": [ 876 | { 877 | "allValue": null, 878 | "current": {}, 879 | "datasource": "Prometheus", 880 | "definition": "label_values(nodejs_version_info, instance)", 881 | "hide": 0, 882 | "includeAll": true, 883 | "label": "instance", 884 | "multi": true, 885 | "name": "instance", 886 | "options": [], 887 | "query": "label_values(nodejs_version_info, instance)", 888 | "refresh": 1, 889 | "regex": "", 890 | "skipUrlSync": false, 891 | "sort": 1, 892 | "tagValuesQuery": "", 893 | "tags": [], 894 | "tagsQuery": "", 895 | "type": "query", 896 | "useTags": false 897 | } 898 | ] 899 | }, 900 | "time": { 901 | "from": "now-1h", 902 | "to": "now" 903 | }, 904 | "timepicker": { 905 | "refresh_intervals": [ 906 | "5s", 907 | "10s", 908 | "30s", 909 | "1m", 910 | "5m", 911 | "15m", 912 | "30m", 913 | "1h", 914 | "2h", 915 | "1d" 916 | ], 917 | "time_options": [ 918 | "5m", 919 | "15m", 920 | "1h", 921 | "6h", 922 | "12h", 923 | "24h", 924 | "2d", 925 | "7d", 926 | "30d" 927 | ] 928 | }, 929 | "timezone": "", 930 | "title": "NodeJS Application Dashboard", 931 | "uid": "PTSqcpJWk", 932 | "version": 4 933 | } 934 | -------------------------------------------------------------------------------- /monitoring-stack/datasources/prometheus.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | datasources: 3 | - name: Prometheus 4 | type: prometheus 5 | url: http://monitoring-stack-prometheus-server 6 | access: proxy 7 | isDefault: true 8 | 9 | -------------------------------------------------------------------------------- /monitoring-stack/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Please refer to the repository README for next steps 2 | -------------------------------------------------------------------------------- /monitoring-stack/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "monitoring-stack.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "monitoring-stack.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "monitoring-stack.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "monitoring-stack.labels" -}} 37 | helm.sh/chart: {{ include "monitoring-stack.chart" . }} 38 | {{ include "monitoring-stack.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "monitoring-stack.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "monitoring-stack.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | -------------------------------------------------------------------------------- /monitoring-stack/templates/dashboard-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{ $root := . }} 2 | {{ range $path, $bytes := .Files.Glob "dashboards/*.json" }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ include "monitoring-stack.fullname" $root }}-dashboard-{{ regexFind "[^/]+$" $path }} 8 | labels: 9 | grafana_dashboard: "1" 10 | app: {{ template "monitoring-stack.name" $root }} 11 | chart: {{ template "monitoring-stack.chart" $root }} 12 | release: {{ $root.Release.Name }} 13 | heritage: {{ $root.Release.Service }} 14 | annotations: 15 | k8s-sidecar-target-directory: "/var/lib/grafana/dashboards/default" 16 | data: 17 | {{- regexFind "[^/]+$" $path | nindent 2 }}: |- 18 | {{- $root.Files.Get $path | nindent 4}} 19 | {{ end -}} 20 | -------------------------------------------------------------------------------- /monitoring-stack/templates/datasources-configmaps.yaml: -------------------------------------------------------------------------------- 1 | {{ $root := . }} 2 | {{ range $path, $bytes := .Files.Glob "datasources/*.yaml" }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ include "monitoring-stack.fullname" $root }}-datasource-{{ regexFind "[^/]+$" $path }} 8 | labels: 9 | grafana_datasource: "1" 10 | app: {{ template "monitoring-stack.name" $root }} 11 | chart: {{ template "monitoring-stack.chart" $root }} 12 | release: {{ $root.Release.Name }} 13 | heritage: {{ $root.Release.Service }} 14 | data: 15 | {{- regexFind "[^/]+$" $path | nindent 2 }}: |- 16 | {{- $root.Files.Get $path | nindent 4}} 17 | {{ end -}} 18 | -------------------------------------------------------------------------------- /monitoring-stack/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for monitoring-stack. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | nameOverride: "" 5 | fullnameOverride: "" 6 | grafana: 7 | enabled: true 8 | service: 9 | type: NodePort 10 | port: 3000 11 | ingress: 12 | enabled: true 13 | # Values can be templated 14 | annotations: 15 | kubernetes.io/ingress.class: nginx 16 | # kubernetes.io/tls-acme: "true" 17 | labels: {} 18 | path: / 19 | hosts: 20 | - grafana.localhost 21 | sidecar: 22 | dashboards: 23 | enabled: true 24 | folder: /var/lib/grafana/dashboards 25 | datasources: 26 | enabled: true 27 | dashboardProviders: 28 | dashboardproviders.yaml: 29 | apiVersion: 1 30 | providers: 31 | - name: 'default' 32 | orgId: 1 33 | folder: '' 34 | type: file 35 | disableDeletion: true 36 | editable: false 37 | options: 38 | path: /var/lib/grafana/dashboards/default 39 | 40 | 41 | prometheus: 42 | enabled: true 43 | 44 | -------------------------------------------------------------------------------- /proxy/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /proxy/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: ingress-nginx 3 | repository: https://kubernetes.github.io/ingress-nginx 4 | version: 3.7.1 5 | digest: sha256:a5fb9583cbe463eee726afaa03b54cd40530327d6e4482abfe6b58788e1f0a38 6 | generated: "2020-11-03T03:18:38.415818+01:00" 7 | -------------------------------------------------------------------------------- /proxy/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: proxy 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | appVersion: 1.16.0 24 | 25 | dependencies: 26 | - name: ingress-nginx 27 | version: "3.7.1" 28 | repository: "https://kubernetes.github.io/ingress-nginx" 29 | -------------------------------------------------------------------------------- /proxy/dashboards/ingress-controller.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "type": "dashboard" 12 | }, 13 | { 14 | "datasource": "Prometheus", 15 | "enable": true, 16 | "expr": "sum(changes(nginx_ingress_controller_config_last_reload_successful_timestamp_seconds{instance!=\"unknown\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[30s])) by (controller_class)", 17 | "hide": false, 18 | "iconColor": "rgba(255, 96, 96, 1)", 19 | "limit": 100, 20 | "name": "Config Reloads", 21 | "showIn": 0, 22 | "step": "30s", 23 | "tagKeys": "controller_class", 24 | "tags": [], 25 | "titleFormat": "Config Reloaded", 26 | "type": "tags" 27 | } 28 | ] 29 | }, 30 | "editable": true, 31 | "gnetId": null, 32 | "graphTooltip": 0, 33 | "id": 8, 34 | "iteration": 1604370957290, 35 | "links": [], 36 | "panels": [ 37 | { 38 | "cacheTimeout": null, 39 | "colorBackground": false, 40 | "colorValue": false, 41 | "colors": [ 42 | "rgba(245, 54, 54, 0.9)", 43 | "rgba(237, 129, 40, 0.89)", 44 | "rgba(50, 172, 45, 0.97)" 45 | ], 46 | "datasource": "Prometheus", 47 | "fieldConfig": { 48 | "defaults": { 49 | "custom": {} 50 | }, 51 | "overrides": [] 52 | }, 53 | "format": "ops", 54 | "gauge": { 55 | "maxValue": 100, 56 | "minValue": 0, 57 | "show": false, 58 | "thresholdLabels": false, 59 | "thresholdMarkers": true 60 | }, 61 | "id": 20, 62 | "interval": null, 63 | "links": [], 64 | "mappingType": 1, 65 | "mappingTypes": [ 66 | { 67 | "name": "value to text", 68 | "value": 1 69 | }, 70 | { 71 | "name": "range to text", 72 | "value": 2 73 | } 74 | ], 75 | "maxDataPoints": 100, 76 | "nullPointMode": "connected", 77 | "nullText": null, 78 | "postfix": "", 79 | "postfixFontSize": "50%", 80 | "prefix": "", 81 | "prefixFontSize": "50%", 82 | "rangeMaps": [ 83 | { 84 | "from": "null", 85 | "text": "N/A", 86 | "to": "null" 87 | } 88 | ], 89 | "sparkline": { 90 | "fillColor": "rgba(31, 118, 189, 0.18)", 91 | "full": true, 92 | "lineColor": "rgb(31, 120, 193)", 93 | "show": true 94 | }, 95 | "tableColumn": "", 96 | "targets": [ 97 | { 98 | "expr": "round(sum(irate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[2m])), 0.001)", 99 | "format": "time_series", 100 | "intervalFactor": 1, 101 | "refId": "A", 102 | "step": 4 103 | } 104 | ], 105 | "thresholds": "", 106 | "title": "Controller Request Volume", 107 | "type": "singlestat", 108 | "valueFontSize": "80%", 109 | "valueMaps": [ 110 | { 111 | "op": "=", 112 | "text": "N/A", 113 | "value": "null" 114 | } 115 | ], 116 | "valueName": "avg" 117 | }, 118 | { 119 | "cacheTimeout": null, 120 | "colorBackground": false, 121 | "colorValue": false, 122 | "colors": [ 123 | "rgba(245, 54, 54, 0.9)", 124 | "rgba(237, 129, 40, 0.89)", 125 | "rgba(50, 172, 45, 0.97)" 126 | ], 127 | "datasource": "Prometheus", 128 | "fieldConfig": { 129 | "defaults": { 130 | "custom": {} 131 | }, 132 | "overrides": [] 133 | }, 134 | "format": "none", 135 | "gauge": { 136 | "maxValue": 100, 137 | "minValue": 0, 138 | "show": false, 139 | "thresholdLabels": false, 140 | "thresholdMarkers": true 141 | }, 142 | "gridPos": { 143 | "h": 3, 144 | "w": 6, 145 | "x": 6, 146 | "y": 0 147 | }, 148 | "id": 82, 149 | "interval": null, 150 | "links": [], 151 | "mappingType": 1, 152 | "mappingTypes": [ 153 | { 154 | "name": "value to text", 155 | "value": 1 156 | }, 157 | { 158 | "name": "range to text", 159 | "value": 2 160 | } 161 | ], 162 | "maxDataPoints": 100, 163 | "nullPointMode": "connected", 164 | "nullText": null, 165 | "postfix": "", 166 | "postfixFontSize": "50%", 167 | "prefix": "", 168 | "prefixFontSize": "50%", 169 | "rangeMaps": [ 170 | { 171 | "from": "null", 172 | "text": "N/A", 173 | "to": "null" 174 | } 175 | ], 176 | "sparkline": { 177 | "fillColor": "rgba(31, 118, 189, 0.18)", 178 | "full": true, 179 | "lineColor": "rgb(31, 120, 193)", 180 | "show": true 181 | }, 182 | "tableColumn": "", 183 | "targets": [ 184 | { 185 | "expr": "sum(avg_over_time(nginx_ingress_controller_nginx_process_connections{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m]))", 186 | "format": "time_series", 187 | "instant": false, 188 | "intervalFactor": 1, 189 | "refId": "A", 190 | "step": 4 191 | } 192 | ], 193 | "thresholds": "", 194 | "title": "Controller Connections", 195 | "type": "singlestat", 196 | "valueFontSize": "80%", 197 | "valueMaps": [ 198 | { 199 | "op": "=", 200 | "text": "N/A", 201 | "value": "null" 202 | } 203 | ], 204 | "valueName": "avg" 205 | }, 206 | { 207 | "cacheTimeout": null, 208 | "colorBackground": false, 209 | "colorValue": false, 210 | "colors": [ 211 | "rgba(245, 54, 54, 0.9)", 212 | "rgba(237, 129, 40, 0.89)", 213 | "rgba(50, 172, 45, 0.97)" 214 | ], 215 | "datasource": "Prometheus", 216 | "fieldConfig": { 217 | "defaults": { 218 | "custom": {} 219 | }, 220 | "overrides": [] 221 | }, 222 | "format": "percentunit", 223 | "gauge": { 224 | "maxValue": 100, 225 | "minValue": 80, 226 | "show": false, 227 | "thresholdLabels": false, 228 | "thresholdMarkers": false 229 | }, 230 | "gridPos": { 231 | "h": 3, 232 | "w": 6, 233 | "x": 12, 234 | "y": 0 235 | }, 236 | "id": 21, 237 | "interval": null, 238 | "links": [], 239 | "mappingType": 1, 240 | "mappingTypes": [ 241 | { 242 | "name": "value to text", 243 | "value": 1 244 | }, 245 | { 246 | "name": "range to text", 247 | "value": 2 248 | } 249 | ], 250 | "maxDataPoints": 100, 251 | "nullPointMode": "connected", 252 | "nullText": null, 253 | "postfix": "", 254 | "postfixFontSize": "50%", 255 | "prefix": "", 256 | "prefixFontSize": "50%", 257 | "rangeMaps": [ 258 | { 259 | "from": "null", 260 | "text": "N/A", 261 | "to": "null" 262 | } 263 | ], 264 | "sparkline": { 265 | "fillColor": "rgba(31, 118, 189, 0.18)", 266 | "full": true, 267 | "lineColor": "rgb(31, 120, 193)", 268 | "show": true 269 | }, 270 | "tableColumn": "", 271 | "targets": [ 272 | { 273 | "expr": "sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",status!~\"[4-5].*\"}[2m])) / sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[2m]))", 274 | "format": "time_series", 275 | "intervalFactor": 1, 276 | "refId": "A", 277 | "step": 4 278 | } 279 | ], 280 | "thresholds": "95, 99, 99.5", 281 | "title": "Controller Success Rate (non-4|5xx responses)", 282 | "type": "singlestat", 283 | "valueFontSize": "80%", 284 | "valueMaps": [ 285 | { 286 | "op": "=", 287 | "text": "N/A", 288 | "value": "null" 289 | } 290 | ], 291 | "valueName": "avg" 292 | }, 293 | { 294 | "cacheTimeout": null, 295 | "colorBackground": false, 296 | "colorValue": false, 297 | "colors": [ 298 | "rgba(245, 54, 54, 0.9)", 299 | "rgba(237, 129, 40, 0.89)", 300 | "rgba(50, 172, 45, 0.97)" 301 | ], 302 | "datasource": "Prometheus", 303 | "decimals": 0, 304 | "fieldConfig": { 305 | "defaults": { 306 | "custom": {} 307 | }, 308 | "overrides": [] 309 | }, 310 | "format": "none", 311 | "gauge": { 312 | "maxValue": 100, 313 | "minValue": 0, 314 | "show": false, 315 | "thresholdLabels": false, 316 | "thresholdMarkers": true 317 | }, 318 | "gridPos": { 319 | "h": 3, 320 | "w": 3, 321 | "x": 18, 322 | "y": 0 323 | }, 324 | "id": 81, 325 | "interval": null, 326 | "links": [], 327 | "mappingType": 1, 328 | "mappingTypes": [ 329 | { 330 | "name": "value to text", 331 | "value": 1 332 | }, 333 | { 334 | "name": "range to text", 335 | "value": 2 336 | } 337 | ], 338 | "maxDataPoints": 100, 339 | "nullPointMode": "connected", 340 | "nullText": null, 341 | "postfix": "", 342 | "postfixFontSize": "50%", 343 | "prefix": "", 344 | "prefixFontSize": "50%", 345 | "rangeMaps": [ 346 | { 347 | "from": "null", 348 | "text": "N/A", 349 | "to": "null" 350 | } 351 | ], 352 | "sparkline": { 353 | "fillColor": "rgba(31, 118, 189, 0.18)", 354 | "full": true, 355 | "lineColor": "rgb(31, 120, 193)", 356 | "show": true 357 | }, 358 | "tableColumn": "", 359 | "targets": [ 360 | { 361 | "expr": "avg(irate(nginx_ingress_controller_success{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[1m])) * 60", 362 | "format": "time_series", 363 | "instant": false, 364 | "intervalFactor": 1, 365 | "refId": "A", 366 | "step": 4 367 | } 368 | ], 369 | "thresholds": "", 370 | "title": "Config Reloads", 371 | "type": "singlestat", 372 | "valueFontSize": "80%", 373 | "valueMaps": [ 374 | { 375 | "op": "=", 376 | "text": "N/A", 377 | "value": "null" 378 | } 379 | ], 380 | "valueName": "total" 381 | }, 382 | { 383 | "cacheTimeout": null, 384 | "colorBackground": false, 385 | "colorValue": false, 386 | "colors": [ 387 | "rgba(245, 54, 54, 0.9)", 388 | "rgba(237, 129, 40, 0.89)", 389 | "rgba(50, 172, 45, 0.97)" 390 | ], 391 | "datasource": "Prometheus", 392 | "decimals": 0, 393 | "fieldConfig": { 394 | "defaults": { 395 | "custom": {} 396 | }, 397 | "overrides": [] 398 | }, 399 | "format": "none", 400 | "gauge": { 401 | "maxValue": 100, 402 | "minValue": 0, 403 | "show": false, 404 | "thresholdLabels": false, 405 | "thresholdMarkers": true 406 | }, 407 | "gridPos": { 408 | "h": 3, 409 | "w": 3, 410 | "x": 21, 411 | "y": 0 412 | }, 413 | "id": 83, 414 | "interval": null, 415 | "links": [], 416 | "mappingType": 1, 417 | "mappingTypes": [ 418 | { 419 | "name": "value to text", 420 | "value": 1 421 | }, 422 | { 423 | "name": "range to text", 424 | "value": 2 425 | } 426 | ], 427 | "maxDataPoints": 100, 428 | "nullPointMode": "connected", 429 | "nullText": null, 430 | "postfix": "", 431 | "postfixFontSize": "50%", 432 | "prefix": "", 433 | "prefixFontSize": "50%", 434 | "rangeMaps": [ 435 | { 436 | "from": "null", 437 | "text": "N/A", 438 | "to": "null" 439 | } 440 | ], 441 | "sparkline": { 442 | "fillColor": "rgba(31, 118, 189, 0.18)", 443 | "full": true, 444 | "lineColor": "rgb(31, 120, 193)", 445 | "show": true 446 | }, 447 | "tableColumn": "", 448 | "targets": [ 449 | { 450 | "expr": "count(nginx_ingress_controller_config_last_reload_successful{controller_pod=~\"$controller\",controller_namespace=~\"$namespace\"} == 0)", 451 | "format": "time_series", 452 | "instant": true, 453 | "intervalFactor": 1, 454 | "refId": "A", 455 | "step": 4 456 | } 457 | ], 458 | "thresholds": "", 459 | "title": "Last Config Failed", 460 | "type": "singlestat", 461 | "valueFontSize": "80%", 462 | "valueMaps": [ 463 | { 464 | "op": "=", 465 | "text": "N/A", 466 | "value": "null" 467 | } 468 | ], 469 | "valueName": "avg" 470 | }, 471 | { 472 | "aliasColors": {}, 473 | "bars": false, 474 | "dashLength": 10, 475 | "dashes": false, 476 | "datasource": "Prometheus", 477 | "decimals": 2, 478 | "editable": true, 479 | "error": false, 480 | "fieldConfig": { 481 | "defaults": { 482 | "custom": {} 483 | }, 484 | "overrides": [] 485 | }, 486 | "fill": 1, 487 | "fillGradient": 0, 488 | "grid": {}, 489 | "gridPos": { 490 | "h": 7, 491 | "w": 12, 492 | "x": 0, 493 | "y": 3 494 | }, 495 | "height": "200px", 496 | "hiddenSeries": false, 497 | "id": 86, 498 | "isNew": true, 499 | "legend": { 500 | "alignAsTable": true, 501 | "avg": true, 502 | "current": false, 503 | "hideEmpty": false, 504 | "hideZero": true, 505 | "max": false, 506 | "min": false, 507 | "rightSide": true, 508 | "show": true, 509 | "sideWidth": 300, 510 | "sort": "current", 511 | "sortDesc": true, 512 | "total": false, 513 | "values": true 514 | }, 515 | "lines": true, 516 | "linewidth": 2, 517 | "links": [], 518 | "nullPointMode": "connected", 519 | "options": { 520 | "alertThreshold": true 521 | }, 522 | "percentage": false, 523 | "pluginVersion": "7.2.1", 524 | "pointradius": 5, 525 | "points": false, 526 | "renderer": "flot", 527 | "repeat": null, 528 | "repeatDirection": "h", 529 | "seriesOverrides": [], 530 | "spaceLength": 10, 531 | "stack": false, 532 | "steppedLine": false, 533 | "targets": [ 534 | { 535 | "expr": "round(sum(irate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress), 0.001)", 536 | "format": "time_series", 537 | "hide": false, 538 | "instant": false, 539 | "interval": "", 540 | "intervalFactor": 1, 541 | "legendFormat": "{{ ingress }}", 542 | "metric": "network", 543 | "refId": "A", 544 | "step": 10 545 | } 546 | ], 547 | "thresholds": [], 548 | "timeFrom": null, 549 | "timeRegions": [], 550 | "timeShift": null, 551 | "title": "Ingress Request Volume", 552 | "tooltip": { 553 | "msResolution": false, 554 | "shared": true, 555 | "sort": 2, 556 | "value_type": "cumulative" 557 | }, 558 | "type": "graph", 559 | "xaxis": { 560 | "buckets": null, 561 | "mode": "time", 562 | "name": null, 563 | "show": true, 564 | "values": [] 565 | }, 566 | "yaxes": [ 567 | { 568 | "format": "reqps", 569 | "label": null, 570 | "logBase": 1, 571 | "max": null, 572 | "min": null, 573 | "show": true 574 | }, 575 | { 576 | "format": "Bps", 577 | "label": null, 578 | "logBase": 1, 579 | "max": null, 580 | "min": null, 581 | "show": false 582 | } 583 | ], 584 | "yaxis": { 585 | "align": false, 586 | "alignLevel": null 587 | } 588 | }, 589 | { 590 | "aliasColors": { 591 | "max - istio-proxy": "#890f02", 592 | "max - master": "#bf1b00", 593 | "max - prometheus": "#bf1b00" 594 | }, 595 | "bars": false, 596 | "dashLength": 10, 597 | "dashes": false, 598 | "datasource": "Prometheus", 599 | "decimals": 2, 600 | "editable": false, 601 | "error": false, 602 | "fieldConfig": { 603 | "defaults": { 604 | "custom": {} 605 | }, 606 | "overrides": [] 607 | }, 608 | "fill": 0, 609 | "fillGradient": 0, 610 | "grid": {}, 611 | "gridPos": { 612 | "h": 7, 613 | "w": 12, 614 | "x": 12, 615 | "y": 3 616 | }, 617 | "hiddenSeries": false, 618 | "id": 87, 619 | "isNew": true, 620 | "legend": { 621 | "alignAsTable": true, 622 | "avg": true, 623 | "current": false, 624 | "hideEmpty": true, 625 | "hideZero": false, 626 | "max": false, 627 | "min": false, 628 | "rightSide": true, 629 | "show": true, 630 | "sideWidth": 300, 631 | "sort": "avg", 632 | "sortDesc": true, 633 | "total": false, 634 | "values": true 635 | }, 636 | "lines": true, 637 | "linewidth": 2, 638 | "links": [], 639 | "nullPointMode": "connected", 640 | "options": { 641 | "alertThreshold": true 642 | }, 643 | "percentage": false, 644 | "pluginVersion": "7.2.1", 645 | "pointradius": 5, 646 | "points": false, 647 | "renderer": "flot", 648 | "seriesOverrides": [], 649 | "spaceLength": 10, 650 | "stack": false, 651 | "steppedLine": false, 652 | "targets": [ 653 | { 654 | "expr": "sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",ingress=~\"$ingress\",status!~\"[4-5].*\"}[2m])) by (ingress) / sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", 655 | "format": "time_series", 656 | "instant": false, 657 | "interval": "10s", 658 | "intervalFactor": 1, 659 | "legendFormat": "{{ ingress }}", 660 | "metric": "container_memory_usage:sort_desc", 661 | "refId": "A", 662 | "step": 10 663 | } 664 | ], 665 | "thresholds": [], 666 | "timeFrom": null, 667 | "timeRegions": [], 668 | "timeShift": null, 669 | "title": "Ingress Success Rate (non-4|5xx responses)", 670 | "tooltip": { 671 | "msResolution": false, 672 | "shared": true, 673 | "sort": 1, 674 | "value_type": "cumulative" 675 | }, 676 | "type": "graph", 677 | "xaxis": { 678 | "buckets": null, 679 | "mode": "time", 680 | "name": null, 681 | "show": true, 682 | "values": [] 683 | }, 684 | "yaxes": [ 685 | { 686 | "format": "percentunit", 687 | "label": null, 688 | "logBase": 1, 689 | "max": null, 690 | "min": null, 691 | "show": true 692 | }, 693 | { 694 | "format": "short", 695 | "label": null, 696 | "logBase": 1, 697 | "max": null, 698 | "min": null, 699 | "show": false 700 | } 701 | ], 702 | "yaxis": { 703 | "align": false, 704 | "alignLevel": null 705 | } 706 | }, 707 | { 708 | "aliasColors": {}, 709 | "bars": false, 710 | "dashLength": 10, 711 | "dashes": false, 712 | "datasource": "Prometheus", 713 | "decimals": 2, 714 | "editable": true, 715 | "error": false, 716 | "fieldConfig": { 717 | "defaults": { 718 | "custom": {} 719 | }, 720 | "overrides": [] 721 | }, 722 | "fill": 1, 723 | "fillGradient": 0, 724 | "grid": {}, 725 | "gridPos": { 726 | "h": 6, 727 | "w": 8, 728 | "x": 0, 729 | "y": 10 730 | }, 731 | "height": "200px", 732 | "hiddenSeries": false, 733 | "id": 32, 734 | "isNew": true, 735 | "legend": { 736 | "alignAsTable": false, 737 | "avg": true, 738 | "current": true, 739 | "max": false, 740 | "min": false, 741 | "rightSide": false, 742 | "show": false, 743 | "sideWidth": 200, 744 | "sort": "current", 745 | "sortDesc": true, 746 | "total": false, 747 | "values": true 748 | }, 749 | "lines": true, 750 | "linewidth": 2, 751 | "links": [], 752 | "nullPointMode": "connected", 753 | "options": { 754 | "alertThreshold": true 755 | }, 756 | "percentage": false, 757 | "pluginVersion": "7.2.1", 758 | "pointradius": 5, 759 | "points": false, 760 | "renderer": "flot", 761 | "seriesOverrides": [], 762 | "spaceLength": 10, 763 | "stack": false, 764 | "steppedLine": false, 765 | "targets": [ 766 | { 767 | "expr": "sum (irate (nginx_ingress_controller_request_size_sum{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m]))", 768 | "format": "time_series", 769 | "instant": false, 770 | "interval": "10s", 771 | "intervalFactor": 1, 772 | "legendFormat": "Received", 773 | "metric": "network", 774 | "refId": "A", 775 | "step": 10 776 | }, 777 | { 778 | "expr": "- sum (irate (nginx_ingress_controller_response_size_sum{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m]))", 779 | "format": "time_series", 780 | "hide": false, 781 | "interval": "10s", 782 | "intervalFactor": 1, 783 | "legendFormat": "Sent", 784 | "metric": "network", 785 | "refId": "B", 786 | "step": 10 787 | } 788 | ], 789 | "thresholds": [], 790 | "timeFrom": null, 791 | "timeRegions": [], 792 | "timeShift": null, 793 | "title": "Network I/O pressure", 794 | "tooltip": { 795 | "msResolution": false, 796 | "shared": true, 797 | "sort": 0, 798 | "value_type": "cumulative" 799 | }, 800 | "type": "graph", 801 | "xaxis": { 802 | "buckets": null, 803 | "mode": "time", 804 | "name": null, 805 | "show": true, 806 | "values": [] 807 | }, 808 | "yaxes": [ 809 | { 810 | "format": "Bps", 811 | "label": null, 812 | "logBase": 1, 813 | "max": null, 814 | "min": null, 815 | "show": true 816 | }, 817 | { 818 | "format": "Bps", 819 | "label": null, 820 | "logBase": 1, 821 | "max": null, 822 | "min": null, 823 | "show": false 824 | } 825 | ], 826 | "yaxis": { 827 | "align": false, 828 | "alignLevel": null 829 | } 830 | }, 831 | { 832 | "aliasColors": { 833 | "max - istio-proxy": "#890f02", 834 | "max - master": "#bf1b00", 835 | "max - prometheus": "#bf1b00" 836 | }, 837 | "bars": false, 838 | "dashLength": 10, 839 | "dashes": false, 840 | "datasource": "Prometheus", 841 | "decimals": 2, 842 | "editable": false, 843 | "error": false, 844 | "fieldConfig": { 845 | "defaults": { 846 | "custom": {} 847 | }, 848 | "overrides": [] 849 | }, 850 | "fill": 0, 851 | "fillGradient": 0, 852 | "grid": {}, 853 | "gridPos": { 854 | "h": 6, 855 | "w": 8, 856 | "x": 8, 857 | "y": 10 858 | }, 859 | "hiddenSeries": false, 860 | "id": 77, 861 | "isNew": true, 862 | "legend": { 863 | "alignAsTable": true, 864 | "avg": true, 865 | "current": true, 866 | "max": false, 867 | "min": false, 868 | "rightSide": false, 869 | "show": false, 870 | "sideWidth": 200, 871 | "sort": "current", 872 | "sortDesc": true, 873 | "total": false, 874 | "values": true 875 | }, 876 | "lines": true, 877 | "linewidth": 2, 878 | "links": [], 879 | "nullPointMode": "connected", 880 | "options": { 881 | "alertThreshold": true 882 | }, 883 | "percentage": false, 884 | "pluginVersion": "7.2.1", 885 | "pointradius": 5, 886 | "points": false, 887 | "renderer": "flot", 888 | "seriesOverrides": [], 889 | "spaceLength": 10, 890 | "stack": false, 891 | "steppedLine": false, 892 | "targets": [ 893 | { 894 | "expr": "avg(nginx_ingress_controller_nginx_process_resident_memory_bytes{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}) ", 895 | "format": "time_series", 896 | "instant": false, 897 | "interval": "10s", 898 | "intervalFactor": 1, 899 | "legendFormat": "nginx", 900 | "metric": "container_memory_usage:sort_desc", 901 | "refId": "A", 902 | "step": 10 903 | } 904 | ], 905 | "thresholds": [], 906 | "timeFrom": null, 907 | "timeRegions": [], 908 | "timeShift": null, 909 | "title": "Average Memory Usage", 910 | "tooltip": { 911 | "msResolution": false, 912 | "shared": true, 913 | "sort": 2, 914 | "value_type": "cumulative" 915 | }, 916 | "type": "graph", 917 | "xaxis": { 918 | "buckets": null, 919 | "mode": "time", 920 | "name": null, 921 | "show": true, 922 | "values": [] 923 | }, 924 | "yaxes": [ 925 | { 926 | "format": "bytes", 927 | "label": null, 928 | "logBase": 1, 929 | "max": null, 930 | "min": null, 931 | "show": true 932 | }, 933 | { 934 | "format": "short", 935 | "label": null, 936 | "logBase": 1, 937 | "max": null, 938 | "min": null, 939 | "show": false 940 | } 941 | ], 942 | "yaxis": { 943 | "align": false, 944 | "alignLevel": null 945 | } 946 | }, 947 | { 948 | "aliasColors": { 949 | "max - istio-proxy": "#890f02", 950 | "max - master": "#bf1b00" 951 | }, 952 | "bars": false, 953 | "dashLength": 10, 954 | "dashes": false, 955 | "datasource": "Prometheus", 956 | "decimals": 3, 957 | "editable": false, 958 | "error": false, 959 | "fieldConfig": { 960 | "defaults": { 961 | "custom": {} 962 | }, 963 | "overrides": [] 964 | }, 965 | "fill": 0, 966 | "fillGradient": 0, 967 | "grid": {}, 968 | "gridPos": { 969 | "h": 6, 970 | "w": 8, 971 | "x": 16, 972 | "y": 10 973 | }, 974 | "height": "", 975 | "hiddenSeries": false, 976 | "id": 79, 977 | "isNew": true, 978 | "legend": { 979 | "alignAsTable": true, 980 | "avg": true, 981 | "current": true, 982 | "max": false, 983 | "min": false, 984 | "rightSide": false, 985 | "show": false, 986 | "sort": null, 987 | "sortDesc": null, 988 | "total": false, 989 | "values": true 990 | }, 991 | "lines": true, 992 | "linewidth": 2, 993 | "links": [], 994 | "nullPointMode": "connected", 995 | "options": { 996 | "alertThreshold": true 997 | }, 998 | "percentage": false, 999 | "pluginVersion": "7.2.1", 1000 | "pointradius": 5, 1001 | "points": false, 1002 | "renderer": "flot", 1003 | "seriesOverrides": [], 1004 | "spaceLength": 10, 1005 | "stack": false, 1006 | "steppedLine": false, 1007 | "targets": [ 1008 | { 1009 | "expr": "sum (rate (nginx_ingress_controller_nginx_process_cpu_seconds_total{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m])) ", 1010 | "format": "time_series", 1011 | "interval": "10s", 1012 | "intervalFactor": 1, 1013 | "legendFormat": "nginx", 1014 | "metric": "container_cpu", 1015 | "refId": "A", 1016 | "step": 10 1017 | } 1018 | ], 1019 | "thresholds": [ 1020 | { 1021 | "colorMode": "critical", 1022 | "fill": true, 1023 | "line": true, 1024 | "op": "gt" 1025 | } 1026 | ], 1027 | "timeFrom": null, 1028 | "timeRegions": [], 1029 | "timeShift": null, 1030 | "title": "Average CPU Usage", 1031 | "tooltip": { 1032 | "msResolution": true, 1033 | "shared": true, 1034 | "sort": 2, 1035 | "value_type": "cumulative" 1036 | }, 1037 | "type": "graph", 1038 | "xaxis": { 1039 | "buckets": null, 1040 | "mode": "time", 1041 | "name": null, 1042 | "show": true, 1043 | "values": [] 1044 | }, 1045 | "yaxes": [ 1046 | { 1047 | "format": "none", 1048 | "label": "cores", 1049 | "logBase": 1, 1050 | "max": null, 1051 | "min": null, 1052 | "show": true 1053 | }, 1054 | { 1055 | "format": "short", 1056 | "label": null, 1057 | "logBase": 1, 1058 | "max": null, 1059 | "min": null, 1060 | "show": true 1061 | } 1062 | ], 1063 | "yaxis": { 1064 | "align": false, 1065 | "alignLevel": null 1066 | } 1067 | }, 1068 | { 1069 | "columns": [], 1070 | "datasource": "Prometheus", 1071 | "fieldConfig": { 1072 | "defaults": { 1073 | "custom": {} 1074 | }, 1075 | "overrides": [] 1076 | }, 1077 | "fontSize": "100%", 1078 | "gridPos": { 1079 | "h": 8, 1080 | "w": 24, 1081 | "x": 0, 1082 | "y": 16 1083 | }, 1084 | "hideTimeOverride": false, 1085 | "id": 75, 1086 | "links": [], 1087 | "pageSize": 7, 1088 | "repeat": null, 1089 | "repeatDirection": "h", 1090 | "scroll": true, 1091 | "showHeader": true, 1092 | "sort": { 1093 | "col": 1, 1094 | "desc": true 1095 | }, 1096 | "styles": [ 1097 | { 1098 | "alias": "Ingress", 1099 | "align": "auto", 1100 | "colorMode": null, 1101 | "colors": [ 1102 | "rgba(245, 54, 54, 0.9)", 1103 | "rgba(237, 129, 40, 0.89)", 1104 | "rgba(50, 172, 45, 0.97)" 1105 | ], 1106 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1107 | "decimals": 2, 1108 | "pattern": "ingress", 1109 | "preserveFormat": false, 1110 | "sanitize": false, 1111 | "thresholds": [], 1112 | "type": "string", 1113 | "unit": "short" 1114 | }, 1115 | { 1116 | "alias": "Requests", 1117 | "align": "auto", 1118 | "colorMode": null, 1119 | "colors": [ 1120 | "rgba(245, 54, 54, 0.9)", 1121 | "rgba(237, 129, 40, 0.89)", 1122 | "rgba(50, 172, 45, 0.97)" 1123 | ], 1124 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1125 | "decimals": 2, 1126 | "pattern": "Value #A", 1127 | "thresholds": [ 1128 | "" 1129 | ], 1130 | "type": "number", 1131 | "unit": "ops" 1132 | }, 1133 | { 1134 | "alias": "Errors", 1135 | "align": "auto", 1136 | "colorMode": null, 1137 | "colors": [ 1138 | "rgba(245, 54, 54, 0.9)", 1139 | "rgba(237, 129, 40, 0.89)", 1140 | "rgba(50, 172, 45, 0.97)" 1141 | ], 1142 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1143 | "decimals": 2, 1144 | "pattern": "Value #B", 1145 | "thresholds": [], 1146 | "type": "number", 1147 | "unit": "ops" 1148 | }, 1149 | { 1150 | "alias": "P50 Latency", 1151 | "align": "auto", 1152 | "colorMode": null, 1153 | "colors": [ 1154 | "rgba(245, 54, 54, 0.9)", 1155 | "rgba(237, 129, 40, 0.89)", 1156 | "rgba(50, 172, 45, 0.97)" 1157 | ], 1158 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1159 | "decimals": 0, 1160 | "link": false, 1161 | "pattern": "Value #C", 1162 | "thresholds": [], 1163 | "type": "number", 1164 | "unit": "dtdurations" 1165 | }, 1166 | { 1167 | "alias": "P90 Latency", 1168 | "align": "auto", 1169 | "colorMode": null, 1170 | "colors": [ 1171 | "rgba(245, 54, 54, 0.9)", 1172 | "rgba(237, 129, 40, 0.89)", 1173 | "rgba(50, 172, 45, 0.97)" 1174 | ], 1175 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1176 | "decimals": 0, 1177 | "pattern": "Value #D", 1178 | "thresholds": [], 1179 | "type": "number", 1180 | "unit": "dtdurations" 1181 | }, 1182 | { 1183 | "alias": "P99 Latency", 1184 | "align": "auto", 1185 | "colorMode": null, 1186 | "colors": [ 1187 | "rgba(245, 54, 54, 0.9)", 1188 | "rgba(237, 129, 40, 0.89)", 1189 | "rgba(50, 172, 45, 0.97)" 1190 | ], 1191 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1192 | "decimals": 0, 1193 | "pattern": "Value #E", 1194 | "thresholds": [], 1195 | "type": "number", 1196 | "unit": "dtdurations" 1197 | }, 1198 | { 1199 | "alias": "IN", 1200 | "align": "auto", 1201 | "colorMode": null, 1202 | "colors": [ 1203 | "rgba(245, 54, 54, 0.9)", 1204 | "rgba(237, 129, 40, 0.89)", 1205 | "rgba(50, 172, 45, 0.97)" 1206 | ], 1207 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1208 | "decimals": 2, 1209 | "pattern": "Value #F", 1210 | "thresholds": [ 1211 | "" 1212 | ], 1213 | "type": "number", 1214 | "unit": "Bps" 1215 | }, 1216 | { 1217 | "alias": "", 1218 | "align": "auto", 1219 | "colorMode": null, 1220 | "colors": [ 1221 | "rgba(245, 54, 54, 0.9)", 1222 | "rgba(237, 129, 40, 0.89)", 1223 | "rgba(50, 172, 45, 0.97)" 1224 | ], 1225 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1226 | "decimals": 2, 1227 | "pattern": "Time", 1228 | "thresholds": [], 1229 | "type": "hidden", 1230 | "unit": "short" 1231 | }, 1232 | { 1233 | "alias": "OUT", 1234 | "align": "auto", 1235 | "colorMode": null, 1236 | "colors": [ 1237 | "rgba(245, 54, 54, 0.9)", 1238 | "rgba(237, 129, 40, 0.89)", 1239 | "rgba(50, 172, 45, 0.97)" 1240 | ], 1241 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1242 | "decimals": 2, 1243 | "mappingType": 1, 1244 | "pattern": "Value #G", 1245 | "thresholds": [], 1246 | "type": "number", 1247 | "unit": "Bps" 1248 | } 1249 | ], 1250 | "targets": [ 1251 | { 1252 | "expr": "histogram_quantile(0.50, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", 1253 | "format": "table", 1254 | "hide": false, 1255 | "instant": true, 1256 | "intervalFactor": 1, 1257 | "legendFormat": "{{ ingress }}", 1258 | "refId": "C" 1259 | }, 1260 | { 1261 | "expr": "histogram_quantile(0.90, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", 1262 | "format": "table", 1263 | "hide": false, 1264 | "instant": true, 1265 | "intervalFactor": 1, 1266 | "legendFormat": "{{ ingress }}", 1267 | "refId": "D" 1268 | }, 1269 | { 1270 | "expr": "histogram_quantile(0.99, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", 1271 | "format": "table", 1272 | "hide": false, 1273 | "instant": true, 1274 | "intervalFactor": 1, 1275 | "legendFormat": "{{ destination_service }}", 1276 | "refId": "E" 1277 | }, 1278 | { 1279 | "expr": "sum(irate(nginx_ingress_controller_request_size_sum{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", 1280 | "format": "table", 1281 | "hide": false, 1282 | "instant": true, 1283 | "interval": "", 1284 | "intervalFactor": 1, 1285 | "legendFormat": "{{ ingress }}", 1286 | "refId": "F" 1287 | }, 1288 | { 1289 | "expr": "sum(irate(nginx_ingress_controller_response_size_sum{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", 1290 | "format": "table", 1291 | "instant": true, 1292 | "intervalFactor": 1, 1293 | "legendFormat": "{{ ingress }}", 1294 | "refId": "G" 1295 | } 1296 | ], 1297 | "timeFrom": null, 1298 | "title": "Ingress Percentile Response Times and Transfer Rates", 1299 | "transform": "table", 1300 | "type": "table-old" 1301 | }, 1302 | { 1303 | "columns": [ 1304 | { 1305 | "text": "Current", 1306 | "value": "current" 1307 | } 1308 | ], 1309 | "datasource": "Prometheus", 1310 | "fieldConfig": { 1311 | "defaults": { 1312 | "custom": {} 1313 | }, 1314 | "overrides": [] 1315 | }, 1316 | "fontSize": "100%", 1317 | "gridPos": { 1318 | "h": 8, 1319 | "w": 24, 1320 | "x": 0, 1321 | "y": 24 1322 | }, 1323 | "height": "1024", 1324 | "id": 85, 1325 | "links": [], 1326 | "pageSize": 7, 1327 | "scroll": true, 1328 | "showHeader": true, 1329 | "sort": { 1330 | "col": 1, 1331 | "desc": false 1332 | }, 1333 | "styles": [ 1334 | { 1335 | "alias": "Time", 1336 | "align": "auto", 1337 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1338 | "pattern": "Time", 1339 | "type": "date" 1340 | }, 1341 | { 1342 | "alias": "TTL", 1343 | "align": "auto", 1344 | "colorMode": "cell", 1345 | "colors": [ 1346 | "rgba(245, 54, 54, 0.9)", 1347 | "rgba(237, 129, 40, 0.89)", 1348 | "rgba(50, 172, 45, 0.97)" 1349 | ], 1350 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1351 | "decimals": 0, 1352 | "pattern": "Current", 1353 | "thresholds": [ 1354 | "0", 1355 | "691200" 1356 | ], 1357 | "type": "number", 1358 | "unit": "s" 1359 | }, 1360 | { 1361 | "alias": "", 1362 | "align": "auto", 1363 | "colorMode": null, 1364 | "colors": [ 1365 | "rgba(245, 54, 54, 0.9)", 1366 | "rgba(237, 129, 40, 0.89)", 1367 | "rgba(50, 172, 45, 0.97)" 1368 | ], 1369 | "decimals": 2, 1370 | "pattern": "/.*/", 1371 | "thresholds": [], 1372 | "type": "number", 1373 | "unit": "short" 1374 | } 1375 | ], 1376 | "targets": [ 1377 | { 1378 | "expr": "avg(nginx_ingress_controller_ssl_expire_time_seconds{kubernetes_pod_name=~\"$controller\",namespace=~\"$namespace\",ingress=~\"$ingress\"}) by (host) - time()", 1379 | "format": "time_series", 1380 | "intervalFactor": 1, 1381 | "legendFormat": "{{ host }}", 1382 | "metric": "gke_letsencrypt_cert_expiration", 1383 | "refId": "A", 1384 | "step": 1 1385 | } 1386 | ], 1387 | "title": "Ingress Certificate Expiry", 1388 | "transform": "timeseries_aggregations", 1389 | "type": "table-old" 1390 | } 1391 | ], 1392 | "refresh": "5s", 1393 | "schemaVersion": 26, 1394 | "style": "dark", 1395 | "tags": [ 1396 | "nginx" 1397 | ], 1398 | "templating": { 1399 | "list": [ 1400 | { 1401 | "current": { 1402 | "selected": true, 1403 | "text": "Prometheus", 1404 | "value": "Prometheus" 1405 | }, 1406 | "hide": 0, 1407 | "includeAll": false, 1408 | "label": "datasource", 1409 | "multi": false, 1410 | "name": "DS_PROMETHEUS", 1411 | "options": [], 1412 | "query": "prometheus", 1413 | "queryValue": "", 1414 | "refresh": 1, 1415 | "regex": "", 1416 | "skipUrlSync": false, 1417 | "type": "datasource" 1418 | }, 1419 | { 1420 | "allValue": ".*", 1421 | "current": { 1422 | "selected": true, 1423 | "text": "All", 1424 | "value": "$__all" 1425 | }, 1426 | "datasource": "Prometheus", 1427 | "definition": "", 1428 | "hide": 0, 1429 | "includeAll": true, 1430 | "label": "Namespace", 1431 | "multi": false, 1432 | "name": "namespace", 1433 | "options": [], 1434 | "query": "label_values(nginx_ingress_controller_config_hash, controller_namespace)", 1435 | "refresh": 1, 1436 | "regex": "", 1437 | "skipUrlSync": false, 1438 | "sort": 0, 1439 | "tagValuesQuery": "", 1440 | "tags": [], 1441 | "tagsQuery": "", 1442 | "type": "query", 1443 | "useTags": false 1444 | }, 1445 | { 1446 | "allValue": ".*", 1447 | "current": { 1448 | "selected": false, 1449 | "text": "All", 1450 | "value": "$__all" 1451 | }, 1452 | "datasource": "Prometheus", 1453 | "definition": "", 1454 | "hide": 0, 1455 | "includeAll": true, 1456 | "label": "Controller Class", 1457 | "multi": false, 1458 | "name": "controller_class", 1459 | "options": [], 1460 | "query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\"}, controller_class) ", 1461 | "refresh": 1, 1462 | "regex": "", 1463 | "skipUrlSync": false, 1464 | "sort": 0, 1465 | "tagValuesQuery": "", 1466 | "tags": [], 1467 | "tagsQuery": "", 1468 | "type": "query", 1469 | "useTags": false 1470 | }, 1471 | { 1472 | "allValue": ".*", 1473 | "current": { 1474 | "selected": false, 1475 | "text": "All", 1476 | "value": "$__all" 1477 | }, 1478 | "datasource": "Prometheus", 1479 | "definition": "", 1480 | "hide": 0, 1481 | "includeAll": true, 1482 | "label": "Controller", 1483 | "multi": false, 1484 | "name": "controller", 1485 | "options": [], 1486 | "query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\",controller_class=~\"$controller_class\"}, controller_pod) ", 1487 | "refresh": 1, 1488 | "regex": "", 1489 | "skipUrlSync": false, 1490 | "sort": 0, 1491 | "tagValuesQuery": "", 1492 | "tags": [], 1493 | "tagsQuery": "", 1494 | "type": "query", 1495 | "useTags": false 1496 | }, 1497 | { 1498 | "allValue": ".*", 1499 | "current": { 1500 | "selected": false, 1501 | "text": "All", 1502 | "value": "$__all" 1503 | }, 1504 | "datasource": "Prometheus", 1505 | "definition": "", 1506 | "hide": 0, 1507 | "includeAll": true, 1508 | "label": "Ingress", 1509 | "multi": false, 1510 | "name": "ingress", 1511 | "options": [], 1512 | "query": "label_values(nginx_ingress_controller_requests{namespace=~\"$namespace\",controller_class=~\"$controller_class\",controller=~\"$controller\"}, ingress) ", 1513 | "refresh": 1, 1514 | "regex": "", 1515 | "skipUrlSync": false, 1516 | "sort": 2, 1517 | "tagValuesQuery": "", 1518 | "tags": [], 1519 | "tagsQuery": "", 1520 | "type": "query", 1521 | "useTags": false 1522 | } 1523 | ] 1524 | }, 1525 | "time": { 1526 | "from": "now-5m", 1527 | "to": "now" 1528 | }, 1529 | "timepicker": { 1530 | "refresh_intervals": [ 1531 | "5s", 1532 | "10s", 1533 | "30s", 1534 | "2m", 1535 | "5m", 1536 | "15m", 1537 | "30m", 1538 | "1h", 1539 | "2h", 1540 | "1d" 1541 | ], 1542 | "time_options": [ 1543 | "5m", 1544 | "15m", 1545 | "1h", 1546 | "6h", 1547 | "12h", 1548 | "24h", 1549 | "2d", 1550 | "7d", 1551 | "30d" 1552 | ] 1553 | }, 1554 | "timezone": "browser", 1555 | "title": "NGINX Ingress controller", 1556 | "uid": "nginx", 1557 | "version": 1 1558 | } 1559 | -------------------------------------------------------------------------------- /proxy/templates/NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wolmi/monitoring-the-easy-way/29ec3819dc8e34832fbe247a67ec2b88ae79dc72/proxy/templates/NOTES.txt -------------------------------------------------------------------------------- /proxy/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "proxy.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "proxy.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "proxy.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "proxy.labels" -}} 37 | helm.sh/chart: {{ include "proxy.chart" . }} 38 | {{ include "proxy.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "proxy.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "proxy.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | -------------------------------------------------------------------------------- /proxy/templates/dashboard-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{ $root := . }} 2 | {{ range $path, $bytes := .Files.Glob "dashboards/*.json" }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ include "proxy.fullname" $root }}-dashboard-{{ regexFind "[^/]+$" $path }} 8 | labels: 9 | grafana_dashboard: "1" 10 | app: {{ template "proxy.name" $root }} 11 | chart: {{ template "proxy.chart" $root }} 12 | release: {{ $root.Release.Name }} 13 | heritage: {{ $root.Release.Service }} 14 | annotations: 15 | k8s-sidecar-target-directory: "/var/lib/grafana/dashboards/default" 16 | data: 17 | {{- regexFind "[^/]+$" $path | nindent 2 }}: |- 18 | {{- $root.Files.Get $path | nindent 4}} 19 | {{ end -}} 20 | -------------------------------------------------------------------------------- /proxy/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for proxy. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | ingress-nginx: 5 | enabled: true 6 | controller: 7 | metrics: 8 | enabled: true 9 | podAnnotations: 10 | prometheus.io/scrape: true 11 | prometheus.io/port: "10254" 12 | -------------------------------------------------------------------------------- /service-example/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /service-example/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /service-example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json . 6 | COPY server.js . 7 | 8 | RUN npm i 9 | 10 | EXPOSE 3001 11 | 12 | CMD ["npm", "start"] 13 | -------------------------------------------------------------------------------- /service-example/chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: service-example 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | appVersion: 1.16.0 24 | -------------------------------------------------------------------------------- /service-example/chart/dashboards/service-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "Prometheus", 5 | "label": "Prometheus", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "4.3.2" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "prometheus", 28 | "name": "Prometheus", 29 | "version": "1.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "singlestat", 34 | "name": "Singlestat", 35 | "version": "" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "datasource": "Prometheus", 42 | "enable": true, 43 | "expr": "ALERTS", 44 | "hide": false, 45 | "iconColor": "rgba(255, 96, 96, 1)", 46 | "limit": 100, 47 | "name": "Alerts", 48 | "showIn": 0, 49 | "step": "10s", 50 | "type": "alert" 51 | } 52 | ] 53 | }, 54 | "description": "Application metrics", 55 | "editable": true, 56 | "gnetId": null, 57 | "graphTooltip": 0, 58 | "hideControls": false, 59 | "id": null, 60 | "links": [], 61 | "refresh": "10s", 62 | "rows": [ 63 | { 64 | "collapse": false, 65 | "height": 250, 66 | "panels": [ 67 | { 68 | "cacheTimeout": null, 69 | "colorBackground": false, 70 | "colorValue": true, 71 | "colors": [ 72 | "rgba(50, 172, 45, 0.97)", 73 | "rgba(237, 129, 40, 0.89)", 74 | "rgba(245, 54, 54, 0.9)" 75 | ], 76 | "datasource": "Prometheus", 77 | "decimals": null, 78 | "format": "none", 79 | "gauge": { 80 | "maxValue": 1, 81 | "minValue": 0, 82 | "show": true, 83 | "thresholdLabels": true, 84 | "thresholdMarkers": true 85 | }, 86 | "hideTimeOverride": false, 87 | "id": 6, 88 | "interval": null, 89 | "links": [], 90 | "mappingType": 1, 91 | "mappingTypes": [ 92 | { 93 | "name": "value to text", 94 | "value": 1 95 | }, 96 | { 97 | "name": "range to text", 98 | "value": 2 99 | } 100 | ], 101 | "maxDataPoints": 100, 102 | "nullPointMode": "connected", 103 | "nullText": null, 104 | "postfix": "", 105 | "postfixFontSize": "50%", 106 | "prefix": "", 107 | "prefixFontSize": "50%", 108 | "rangeMaps": [ 109 | { 110 | "from": "null", 111 | "text": "N/A", 112 | "to": "null" 113 | } 114 | ], 115 | "span": 3, 116 | "sparkline": { 117 | "fillColor": "rgba(31, 118, 189, 0.18)", 118 | "full": false, 119 | "lineColor": "rgb(31, 120, 193)", 120 | "show": false 121 | }, 122 | "tableColumn": "Value", 123 | "targets": [ 124 | { 125 | "expr": "sum(increase(http_request_duration_ms_count{code=~\"^5..$\"}[$__range])) / sum(increase(http_request_duration_ms_count[$__range]))", 126 | "format": "time_series", 127 | "interval": "", 128 | "intervalFactor": 2, 129 | "legendFormat": "", 130 | "refId": "A", 131 | "step": 20 132 | } 133 | ], 134 | "thresholds": "0.1", 135 | "title": "Error rate", 136 | "type": "singlestat", 137 | "valueFontSize": "80%", 138 | "valueMaps": [ 139 | { 140 | "op": "=", 141 | "text": "N/A", 142 | "value": "null" 143 | } 144 | ], 145 | "valueName": "avg" 146 | }, 147 | { 148 | "aliasColors": {}, 149 | "bars": false, 150 | "dashLength": 10, 151 | "dashes": false, 152 | "datasource": "Prometheus", 153 | "fill": 1, 154 | "id": 1, 155 | "legend": { 156 | "avg": false, 157 | "current": false, 158 | "max": false, 159 | "min": false, 160 | "show": true, 161 | "total": false, 162 | "values": false 163 | }, 164 | "lines": true, 165 | "linewidth": 1, 166 | "links": [ 167 | { 168 | "type": "dashboard" 169 | } 170 | ], 171 | "nullPointMode": "null", 172 | "percentage": false, 173 | "pointradius": 5, 174 | "points": false, 175 | "renderer": "flot", 176 | "seriesOverrides": [], 177 | "spaceLength": 10, 178 | "span": 9, 179 | "stack": false, 180 | "steppedLine": false, 181 | "targets": [ 182 | { 183 | "expr": "sum(rate(http_request_duration_ms_count[$__range])) by (service, route, method, code) * 60", 184 | "format": "time_series", 185 | "hide": false, 186 | "intervalFactor": 2, 187 | "legendFormat": "{{service}} - {{method}} {{route}} {{code}}", 188 | "metric": "", 189 | "refId": "A", 190 | "step": 2 191 | } 192 | ], 193 | "thresholds": [], 194 | "timeFrom": null, 195 | "timeShift": null, 196 | "title": "Throughput", 197 | "tooltip": { 198 | "shared": true, 199 | "sort": 0, 200 | "value_type": "individual" 201 | }, 202 | "type": "graph", 203 | "xaxis": { 204 | "buckets": null, 205 | "mode": "time", 206 | "name": null, 207 | "show": true, 208 | "values": [] 209 | }, 210 | "yaxes": [ 211 | { 212 | "format": "rpm", 213 | "label": null, 214 | "logBase": 1, 215 | "max": null, 216 | "min": null, 217 | "show": true 218 | }, 219 | { 220 | "format": "short", 221 | "label": null, 222 | "logBase": 1, 223 | "max": null, 224 | "min": null, 225 | "show": true 226 | } 227 | ] 228 | } 229 | ], 230 | "repeat": null, 231 | "repeatIteration": null, 232 | "repeatRowId": null, 233 | "showTitle": true, 234 | "title": "Throughput", 235 | "titleSize": "h6" 236 | }, 237 | { 238 | "collapse": false, 239 | "height": 250, 240 | "panels": [ 241 | { 242 | "aliasColors": {}, 243 | "bars": false, 244 | "dashLength": 10, 245 | "dashes": false, 246 | "datasource": "Prometheus", 247 | "fill": 1, 248 | "id": 4, 249 | "legend": { 250 | "avg": false, 251 | "current": false, 252 | "max": false, 253 | "min": false, 254 | "show": true, 255 | "total": false, 256 | "values": false 257 | }, 258 | "lines": true, 259 | "linewidth": 1, 260 | "links": [], 261 | "nullPointMode": "null", 262 | "percentage": false, 263 | "pointradius": 5, 264 | "points": false, 265 | "renderer": "flot", 266 | "seriesOverrides": [], 267 | "spaceLength": 10, 268 | "span": 12, 269 | "stack": false, 270 | "steppedLine": false, 271 | "targets": [ 272 | { 273 | "expr": "histogram_quantile(0.5, sum(rate(http_request_duration_ms_bucket[$__range])) by (le, service, route, method))", 274 | "format": "time_series", 275 | "intervalFactor": 2, 276 | "legendFormat": "{{service}} - {{method}} {{route}}", 277 | "refId": "A", 278 | "step": 2 279 | } 280 | ], 281 | "thresholds": [], 282 | "timeFrom": null, 283 | "timeShift": null, 284 | "title": "Median Response Time", 285 | "tooltip": { 286 | "shared": true, 287 | "sort": 0, 288 | "value_type": "individual" 289 | }, 290 | "type": "graph", 291 | "xaxis": { 292 | "buckets": null, 293 | "mode": "time", 294 | "name": null, 295 | "show": true, 296 | "values": [] 297 | }, 298 | "yaxes": [ 299 | { 300 | "format": "ms", 301 | "label": null, 302 | "logBase": 1, 303 | "max": null, 304 | "min": null, 305 | "show": true 306 | }, 307 | { 308 | "format": "short", 309 | "label": null, 310 | "logBase": 1, 311 | "max": null, 312 | "min": null, 313 | "show": true 314 | } 315 | ] 316 | }, 317 | { 318 | "aliasColors": {}, 319 | "bars": false, 320 | "dashLength": 10, 321 | "dashes": false, 322 | "datasource": "Prometheus", 323 | "fill": 1, 324 | "id": 2, 325 | "legend": { 326 | "avg": false, 327 | "current": false, 328 | "max": false, 329 | "min": false, 330 | "show": true, 331 | "total": false, 332 | "values": false 333 | }, 334 | "lines": true, 335 | "linewidth": 1, 336 | "links": [], 337 | "nullPointMode": "null", 338 | "percentage": false, 339 | "pointradius": 5, 340 | "points": false, 341 | "renderer": "flot", 342 | "seriesOverrides": [], 343 | "spaceLength": 10, 344 | "span": 12, 345 | "stack": false, 346 | "steppedLine": false, 347 | "targets": [ 348 | { 349 | "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_ms_bucket[$__range])) by (le, service, route, method))", 350 | "format": "time_series", 351 | "interval": "", 352 | "intervalFactor": 2, 353 | "legendFormat": "{{service}} - {{method}} {{route}}", 354 | "refId": "A", 355 | "step": 2 356 | } 357 | ], 358 | "thresholds": [], 359 | "timeFrom": null, 360 | "timeShift": null, 361 | "title": "95th Response Time", 362 | "tooltip": { 363 | "shared": true, 364 | "sort": 0, 365 | "value_type": "individual" 366 | }, 367 | "transparent": false, 368 | "type": "graph", 369 | "xaxis": { 370 | "buckets": null, 371 | "mode": "time", 372 | "name": null, 373 | "show": true, 374 | "values": [] 375 | }, 376 | "yaxes": [ 377 | { 378 | "format": "ms", 379 | "label": null, 380 | "logBase": 1, 381 | "max": null, 382 | "min": null, 383 | "show": true 384 | }, 385 | { 386 | "format": "short", 387 | "label": null, 388 | "logBase": 1, 389 | "max": null, 390 | "min": null, 391 | "show": true 392 | } 393 | ] 394 | } 395 | ], 396 | "repeat": null, 397 | "repeatIteration": null, 398 | "repeatRowId": null, 399 | "showTitle": true, 400 | "title": "Response time", 401 | "titleSize": "h6" 402 | }, 403 | { 404 | "collapse": false, 405 | "height": 250, 406 | "panels": [ 407 | { 408 | "aliasColors": {}, 409 | "bars": false, 410 | "dashLength": 10, 411 | "dashes": false, 412 | "datasource": "Prometheus", 413 | "fill": 1, 414 | "id": 3, 415 | "legend": { 416 | "avg": false, 417 | "current": false, 418 | "max": false, 419 | "min": false, 420 | "show": true, 421 | "total": false, 422 | "values": false 423 | }, 424 | "lines": true, 425 | "linewidth": 1, 426 | "links": [], 427 | "nullPointMode": "null", 428 | "percentage": false, 429 | "pointradius": 5, 430 | "points": false, 431 | "renderer": "flot", 432 | "seriesOverrides": [], 433 | "spaceLength": 10, 434 | "span": 12, 435 | "stack": false, 436 | "steppedLine": false, 437 | "targets": [ 438 | { 439 | "expr": "avg(nodejs_external_memory_bytes / 1024) by (service)", 440 | "format": "time_series", 441 | "intervalFactor": 2, 442 | "legendFormat": "{{service}}", 443 | "refId": "A", 444 | "step": 2 445 | } 446 | ], 447 | "thresholds": [], 448 | "timeFrom": null, 449 | "timeShift": null, 450 | "title": "Memory usage", 451 | "tooltip": { 452 | "shared": true, 453 | "sort": 0, 454 | "value_type": "individual" 455 | }, 456 | "type": "graph", 457 | "xaxis": { 458 | "buckets": null, 459 | "mode": "time", 460 | "name": null, 461 | "show": true, 462 | "values": [] 463 | }, 464 | "yaxes": [ 465 | { 466 | "format": "decmbytes", 467 | "label": null, 468 | "logBase": 1, 469 | "max": null, 470 | "min": null, 471 | "show": true 472 | }, 473 | { 474 | "format": "short", 475 | "label": null, 476 | "logBase": 1, 477 | "max": null, 478 | "min": null, 479 | "show": true 480 | } 481 | ] 482 | } 483 | ], 484 | "repeat": null, 485 | "repeatIteration": null, 486 | "repeatRowId": null, 487 | "showTitle": true, 488 | "title": "Memory", 489 | "titleSize": "h6" 490 | }, 491 | { 492 | "collapse": false, 493 | "height": 250, 494 | "panels": [ 495 | { 496 | "aliasColors": {}, 497 | "bars": false, 498 | "dashLength": 10, 499 | "dashes": false, 500 | "datasource": "Prometheus", 501 | "fill": 1, 502 | "id": 5, 503 | "legend": { 504 | "avg": false, 505 | "current": false, 506 | "max": false, 507 | "min": false, 508 | "show": true, 509 | "total": false, 510 | "values": false 511 | }, 512 | "lines": true, 513 | "linewidth": 1, 514 | "links": [], 515 | "nullPointMode": "null", 516 | "percentage": false, 517 | "pointradius": 5, 518 | "points": false, 519 | "renderer": "flot", 520 | "seriesOverrides": [], 521 | "spaceLength": 10, 522 | "span": 12, 523 | "stack": false, 524 | "steppedLine": false, 525 | "targets": [ 526 | { 527 | "expr": "sum(rate(checkouts_total[$__range])) by (payment_method) * 60", 528 | "format": "time_series", 529 | "interval": "", 530 | "intervalFactor": 2, 531 | "legendFormat": "{{payment_method}}", 532 | "refId": "A", 533 | "step": 2 534 | } 535 | ], 536 | "thresholds": [], 537 | "timeFrom": null, 538 | "timeShift": null, 539 | "title": "Checkouts", 540 | "tooltip": { 541 | "shared": true, 542 | "sort": 0, 543 | "value_type": "individual" 544 | }, 545 | "type": "graph", 546 | "xaxis": { 547 | "buckets": null, 548 | "mode": "time", 549 | "name": null, 550 | "show": true, 551 | "values": [] 552 | }, 553 | "yaxes": [ 554 | { 555 | "format": "none", 556 | "label": null, 557 | "logBase": 1, 558 | "max": null, 559 | "min": null, 560 | "show": true 561 | }, 562 | { 563 | "format": "short", 564 | "label": null, 565 | "logBase": 1, 566 | "max": null, 567 | "min": null, 568 | "show": true 569 | } 570 | ] 571 | } 572 | ], 573 | "repeat": null, 574 | "repeatIteration": null, 575 | "repeatRowId": null, 576 | "showTitle": true, 577 | "title": "Business", 578 | "titleSize": "h6" 579 | } 580 | ], 581 | "schemaVersion": 14, 582 | "style": "dark", 583 | "tags": [], 584 | "templating": { 585 | "list": [] 586 | }, 587 | "time": { 588 | "from": "now-15m", 589 | "to": "now" 590 | }, 591 | "timepicker": { 592 | "refresh_intervals": [ 593 | "5s", 594 | "10s", 595 | "30s", 596 | "1m", 597 | "5m", 598 | "15m", 599 | "30m", 600 | "1h", 601 | "2h", 602 | "1d" 603 | ], 604 | "time_options": [ 605 | "5m", 606 | "15m", 607 | "1h", 608 | "6h", 609 | "12h", 610 | "24h", 611 | "2d", 612 | "7d", 613 | "30d" 614 | ] 615 | }, 616 | "timezone": "browser", 617 | "title": "Application metrics", 618 | "version": 3 619 | } 620 | -------------------------------------------------------------------------------- /service-example/chart/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "service-example.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "service-example.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "service-example.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "service-example.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | echo "Visit http://127.0.0.1:8080 to use your application" 20 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /service-example/chart/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "service-example.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "service-example.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "service-example.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "service-example.labels" -}} 37 | helm.sh/chart: {{ include "service-example.chart" . }} 38 | {{ include "service-example.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "service-example.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "service-example.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "service-example.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "service-example.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /service-example/chart/templates/dashboard-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{ $root := . }} 2 | {{ range $path, $bytes := .Files.Glob "dashboards/*.json" }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ include "service-example.fullname" $root }}-dashboard-{{ regexFind "[^/]+$" $path }} 8 | labels: 9 | grafana_dashboard: "1" 10 | app: {{ template "service-example.name" $root }} 11 | chart: {{ template "service-example.chart" $root }} 12 | release: {{ $root.Release.Name }} 13 | heritage: {{ $root.Release.Service }} 14 | annotations: 15 | k8s-sidecar-target-directory: "/var/lib/grafana/dashboards/default" 16 | data: 17 | {{- regexFind "[^/]+$" $path | nindent 2 }}: |- 18 | {{- $root.Files.Get $path | nindent 4}} 19 | {{ end -}} 20 | -------------------------------------------------------------------------------- /service-example/chart/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "service-example.fullname" . }} 5 | labels: 6 | {{- include "service-example.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "service-example.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | annotations: 17 | prometheus.io/scrape: 'true' 18 | prometheus.io/port: '{{ .Values.service.port }}' 19 | {{- with .Values.podAnnotations }} 20 | {{- toYaml . | nindent 8 }} 21 | {{- end }} 22 | labels: 23 | {{- include "service-example.selectorLabels" . | nindent 8 }} 24 | spec: 25 | {{- with .Values.imagePullSecrets }} 26 | imagePullSecrets: 27 | {{- toYaml . | nindent 8 }} 28 | {{- end }} 29 | serviceAccountName: {{ include "service-example.serviceAccountName" . }} 30 | securityContext: 31 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 32 | containers: 33 | - name: {{ .Chart.Name }} 34 | securityContext: 35 | {{- toYaml .Values.securityContext | nindent 12 }} 36 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 37 | imagePullPolicy: {{ .Values.image.pullPolicy }} 38 | env: 39 | - name: PORT 40 | value: '{{ .Values.service.port }}' 41 | ports: 42 | - name: http 43 | containerPort: {{ .Values.service.port }} 44 | protocol: TCP 45 | livenessProbe: 46 | httpGet: 47 | path: / 48 | port: http 49 | readinessProbe: 50 | httpGet: 51 | path: / 52 | port: http 53 | resources: 54 | {{- toYaml .Values.resources | nindent 12 }} 55 | {{- with .Values.nodeSelector }} 56 | nodeSelector: 57 | {{- toYaml . | nindent 8 }} 58 | {{- end }} 59 | {{- with .Values.affinity }} 60 | affinity: 61 | {{- toYaml . | nindent 8 }} 62 | {{- end }} 63 | {{- with .Values.tolerations }} 64 | tolerations: 65 | {{- toYaml . | nindent 8 }} 66 | {{- end }} 67 | -------------------------------------------------------------------------------- /service-example/chart/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "service-example.fullname" . }} 6 | labels: 7 | {{- include "service-example.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "service-example.fullname" . }} 13 | minReplicas: {{ .Values.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 15 | metrics: 16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 17 | - type: Resource 18 | resource: 19 | name: cpu 20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | {{- end }} 22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 23 | - type: Resource 24 | resource: 25 | name: memory 26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /service-example/chart/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "service-example.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 5 | apiVersion: networking.k8s.io/v1beta1 6 | {{- else -}} 7 | apiVersion: extensions/v1beta1 8 | {{- end }} 9 | kind: Ingress 10 | metadata: 11 | name: {{ $fullName }} 12 | labels: 13 | {{- include "service-example.labels" . | nindent 4 }} 14 | {{- with .Values.ingress.annotations }} 15 | annotations: 16 | {{- toYaml . | nindent 4 }} 17 | {{- end }} 18 | spec: 19 | {{- if .Values.ingress.tls }} 20 | tls: 21 | {{- range .Values.ingress.tls }} 22 | - hosts: 23 | {{- range .hosts }} 24 | - {{ . | quote }} 25 | {{- end }} 26 | secretName: {{ .secretName }} 27 | {{- end }} 28 | {{- end }} 29 | rules: 30 | {{- range .Values.ingress.hosts }} 31 | - host: {{ .host | quote }} 32 | http: 33 | paths: 34 | {{- range .paths }} 35 | - path: {{ . }} 36 | backend: 37 | serviceName: {{ $fullName }} 38 | servicePort: {{ $svcPort }} 39 | {{- end }} 40 | {{- end }} 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /service-example/chart/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "service-example.fullname" . }} 5 | labels: 6 | {{- include "service-example.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "service-example.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /service-example/chart/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "service-example.serviceAccountName" . }} 6 | labels: 7 | {{- include "service-example.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /service-example/chart/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "service-example.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "service-example.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test-success 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "service-example.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /service-example/chart/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for service-example. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: wolmi/service-example 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "1.0.0" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 3000 42 | 43 | ingress: 44 | enabled: true 45 | annotations: 46 | kubernetes.io/ingress.class: nginx 47 | # kubernetes.io/tls-acme: "true" 48 | hosts: 49 | - host: service-example.localhost 50 | paths: 51 | - "/" 52 | tls: [] 53 | # - secretName: chart-example-tls 54 | # hosts: 55 | # - chart-example.local 56 | 57 | resources: {} 58 | # We usually recommend not to specify default resources and to leave this as a conscious 59 | # choice for the user. This also increases chances charts run on environments with little 60 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 61 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 62 | # limits: 63 | # cpu: 100m 64 | # memory: 128Mi 65 | # requests: 66 | # cpu: 100m 67 | # memory: 128Mi 68 | 69 | autoscaling: 70 | enabled: false 71 | minReplicas: 1 72 | maxReplicas: 100 73 | targetCPUUtilizationPercentage: 80 74 | # targetMemoryUtilizationPercentage: 80 75 | 76 | nodeSelector: {} 77 | 78 | tolerations: [] 79 | 80 | affinity: {} 81 | -------------------------------------------------------------------------------- /service-example/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "service-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "bintrees": { 22 | "version": "1.0.1", 23 | "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", 24 | "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" 25 | }, 26 | "content-disposition": { 27 | "version": "0.5.2", 28 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 29 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 30 | }, 31 | "content-type": { 32 | "version": "1.0.4", 33 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 34 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 35 | }, 36 | "cookie": { 37 | "version": "0.3.1", 38 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 39 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 40 | }, 41 | "cookie-signature": { 42 | "version": "1.0.6", 43 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 44 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 45 | }, 46 | "debug": { 47 | "version": "2.6.7", 48 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", 49 | "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", 50 | "requires": { 51 | "ms": "2.0.0" 52 | } 53 | }, 54 | "depd": { 55 | "version": "1.1.2", 56 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 57 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 58 | }, 59 | "destroy": { 60 | "version": "1.0.4", 61 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 62 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 63 | }, 64 | "ee-first": { 65 | "version": "1.1.1", 66 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 67 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 68 | }, 69 | "encodeurl": { 70 | "version": "1.0.2", 71 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 72 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 73 | }, 74 | "escape-html": { 75 | "version": "1.0.3", 76 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 77 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 78 | }, 79 | "etag": { 80 | "version": "1.8.1", 81 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 82 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 83 | }, 84 | "express": { 85 | "version": "4.15.3", 86 | "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", 87 | "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=", 88 | "requires": { 89 | "accepts": "~1.3.3", 90 | "array-flatten": "1.1.1", 91 | "content-disposition": "0.5.2", 92 | "content-type": "~1.0.2", 93 | "cookie": "0.3.1", 94 | "cookie-signature": "1.0.6", 95 | "debug": "2.6.7", 96 | "depd": "~1.1.0", 97 | "encodeurl": "~1.0.1", 98 | "escape-html": "~1.0.3", 99 | "etag": "~1.8.0", 100 | "finalhandler": "~1.0.3", 101 | "fresh": "0.5.0", 102 | "merge-descriptors": "1.0.1", 103 | "methods": "~1.1.2", 104 | "on-finished": "~2.3.0", 105 | "parseurl": "~1.3.1", 106 | "path-to-regexp": "0.1.7", 107 | "proxy-addr": "~1.1.4", 108 | "qs": "6.4.0", 109 | "range-parser": "~1.2.0", 110 | "send": "0.15.3", 111 | "serve-static": "1.12.3", 112 | "setprototypeof": "1.0.3", 113 | "statuses": "~1.3.1", 114 | "type-is": "~1.6.15", 115 | "utils-merge": "1.0.0", 116 | "vary": "~1.1.1" 117 | } 118 | }, 119 | "finalhandler": { 120 | "version": "1.0.6", 121 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", 122 | "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", 123 | "requires": { 124 | "debug": "2.6.9", 125 | "encodeurl": "~1.0.1", 126 | "escape-html": "~1.0.3", 127 | "on-finished": "~2.3.0", 128 | "parseurl": "~1.3.2", 129 | "statuses": "~1.3.1", 130 | "unpipe": "~1.0.0" 131 | }, 132 | "dependencies": { 133 | "debug": { 134 | "version": "2.6.9", 135 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 136 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 137 | "requires": { 138 | "ms": "2.0.0" 139 | } 140 | } 141 | } 142 | }, 143 | "forwarded": { 144 | "version": "0.1.2", 145 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 146 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 147 | }, 148 | "fresh": { 149 | "version": "0.5.0", 150 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", 151 | "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" 152 | }, 153 | "http-errors": { 154 | "version": "1.6.3", 155 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 156 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 157 | "requires": { 158 | "depd": "~1.1.2", 159 | "inherits": "2.0.3", 160 | "setprototypeof": "1.1.0", 161 | "statuses": ">= 1.4.0 < 2" 162 | }, 163 | "dependencies": { 164 | "setprototypeof": { 165 | "version": "1.1.0", 166 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 167 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 168 | }, 169 | "statuses": { 170 | "version": "1.5.0", 171 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 172 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 173 | } 174 | } 175 | }, 176 | "inherits": { 177 | "version": "2.0.3", 178 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 179 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 180 | }, 181 | "ipaddr.js": { 182 | "version": "1.4.0", 183 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", 184 | "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" 185 | }, 186 | "media-typer": { 187 | "version": "0.3.0", 188 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 189 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 190 | }, 191 | "merge-descriptors": { 192 | "version": "1.0.1", 193 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 194 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 195 | }, 196 | "methods": { 197 | "version": "1.1.2", 198 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 199 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 200 | }, 201 | "mime": { 202 | "version": "1.3.4", 203 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", 204 | "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" 205 | }, 206 | "mime-db": { 207 | "version": "1.44.0", 208 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 209 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 210 | }, 211 | "mime-types": { 212 | "version": "2.1.27", 213 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 214 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 215 | "requires": { 216 | "mime-db": "1.44.0" 217 | } 218 | }, 219 | "ms": { 220 | "version": "2.0.0", 221 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 222 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 223 | }, 224 | "negotiator": { 225 | "version": "0.6.2", 226 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 227 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 228 | }, 229 | "on-finished": { 230 | "version": "2.3.0", 231 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 232 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 233 | "requires": { 234 | "ee-first": "1.1.1" 235 | } 236 | }, 237 | "parseurl": { 238 | "version": "1.3.3", 239 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 240 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 241 | }, 242 | "path-to-regexp": { 243 | "version": "0.1.7", 244 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 245 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 246 | }, 247 | "prom-client": { 248 | "version": "9.1.1", 249 | "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-9.1.1.tgz", 250 | "integrity": "sha512-D0u3QmHpha85wT+p8UTcRkSMC70WKR1bd1mf6lZqZBhOxP2jUpnDRlec0VuHZA0Qmw9C63pSiPr9UqsiCgnf+w==", 251 | "requires": { 252 | "tdigest": "^0.1.1", 253 | "util-extend": "^1.0.1" 254 | } 255 | }, 256 | "proxy-addr": { 257 | "version": "1.1.5", 258 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", 259 | "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", 260 | "requires": { 261 | "forwarded": "~0.1.0", 262 | "ipaddr.js": "1.4.0" 263 | } 264 | }, 265 | "qs": { 266 | "version": "6.4.0", 267 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", 268 | "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" 269 | }, 270 | "range-parser": { 271 | "version": "1.2.1", 272 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 273 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 274 | }, 275 | "send": { 276 | "version": "0.15.3", 277 | "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", 278 | "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", 279 | "requires": { 280 | "debug": "2.6.7", 281 | "depd": "~1.1.0", 282 | "destroy": "~1.0.4", 283 | "encodeurl": "~1.0.1", 284 | "escape-html": "~1.0.3", 285 | "etag": "~1.8.0", 286 | "fresh": "0.5.0", 287 | "http-errors": "~1.6.1", 288 | "mime": "1.3.4", 289 | "ms": "2.0.0", 290 | "on-finished": "~2.3.0", 291 | "range-parser": "~1.2.0", 292 | "statuses": "~1.3.1" 293 | } 294 | }, 295 | "serve-static": { 296 | "version": "1.12.3", 297 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz", 298 | "integrity": "sha1-n0uhni8wMMVH+K+ZEHg47DjVseI=", 299 | "requires": { 300 | "encodeurl": "~1.0.1", 301 | "escape-html": "~1.0.3", 302 | "parseurl": "~1.3.1", 303 | "send": "0.15.3" 304 | } 305 | }, 306 | "setprototypeof": { 307 | "version": "1.0.3", 308 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 309 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 310 | }, 311 | "statuses": { 312 | "version": "1.3.1", 313 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 314 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 315 | }, 316 | "tdigest": { 317 | "version": "0.1.1", 318 | "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", 319 | "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", 320 | "requires": { 321 | "bintrees": "1.0.1" 322 | } 323 | }, 324 | "type-is": { 325 | "version": "1.6.18", 326 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 327 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 328 | "requires": { 329 | "media-typer": "0.3.0", 330 | "mime-types": "~2.1.24" 331 | } 332 | }, 333 | "unpipe": { 334 | "version": "1.0.0", 335 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 336 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 337 | }, 338 | "util-extend": { 339 | "version": "1.0.3", 340 | "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", 341 | "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" 342 | }, 343 | "utils-merge": { 344 | "version": "1.0.0", 345 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", 346 | "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" 347 | }, 348 | "vary": { 349 | "version": "1.1.2", 350 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 351 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /service-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "service-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "dependencies": { 11 | "express": "4.15.3", 12 | "prom-client": "9.1.1" 13 | }, 14 | "author": "", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /service-example/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const express = require('express') 4 | const Prometheus = require('prom-client') 5 | 6 | const app = express() 7 | const port = process.env.PORT || 3001 8 | const metricsInterval = Prometheus.collectDefaultMetrics() 9 | const checkoutsTotal = new Prometheus.Counter({ 10 | name: 'checkouts_total', 11 | help: 'Total number of checkouts', 12 | labelNames: ['payment_method'] 13 | }) 14 | const httpRequestDurationMicroseconds = new Prometheus.Histogram({ 15 | name: 'http_request_duration_ms', 16 | help: 'Duration of HTTP requests in ms', 17 | labelNames: ['method', 'route', 'code'], 18 | buckets: [0.10, 5, 15, 50, 100, 200, 300, 400, 500] // buckets for response time from 0.1ms to 500ms 19 | }) 20 | 21 | // Runs before each requests 22 | app.use((req, res, next) => { 23 | res.locals.startEpoch = Date.now() 24 | next() 25 | }) 26 | 27 | app.get('/', (req, res, next) => { 28 | setTimeout(() => { 29 | res.json({ message: 'Hello World!' }) 30 | next() 31 | }, Math.round(Math.random() * 200)) 32 | }) 33 | 34 | app.get('/bad', (req, res, next) => { 35 | next(new Error('My Error')) 36 | }) 37 | 38 | app.get('/checkout', (req, res, next) => { 39 | const paymentMethod = Math.round(Math.random()) === 0 ? 'stripe' : 'paypal' 40 | 41 | checkoutsTotal.inc({ 42 | payment_method: paymentMethod 43 | }) 44 | 45 | res.json({ status: 'ok' }) 46 | next() 47 | }) 48 | 49 | app.get('/metrics', (req, res) => { 50 | res.set('Content-Type', Prometheus.register.contentType) 51 | res.end(Prometheus.register.metrics()) 52 | }) 53 | 54 | // Error handler 55 | app.use((err, req, res, next) => { 56 | res.statusCode = 500 57 | // Do not expose your error in production 58 | res.json({ error: err.message }) 59 | next() 60 | }) 61 | 62 | // Runs after each requests 63 | app.use((req, res, next) => { 64 | const responseTimeInMs = Date.now() - res.locals.startEpoch 65 | 66 | httpRequestDurationMicroseconds 67 | .labels(req.method, req.route.path, res.statusCode) 68 | .observe(responseTimeInMs) 69 | 70 | next() 71 | }) 72 | 73 | const server = app.listen(port, () => { 74 | console.log(`Example app listening on port ${port}!`) 75 | }) 76 | 77 | // Graceful shutdown 78 | process.on('SIGTERM', () => { 79 | clearInterval(metricsInterval) 80 | 81 | server.close((err) => { 82 | if (err) { 83 | console.error(err) 84 | process.exit(1) 85 | } 86 | 87 | process.exit(0) 88 | }) 89 | }) 90 | --------------------------------------------------------------------------------