From 19eca3d0c0214e974a3013a21cb285fb3f6ed3f6 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Fri, 25 Feb 2022 18:38:11 +0100 Subject: [PATCH 01/45] Adding linkerd installation role --- docs/_docs/service-mesh.md | 43 +++++++++++++++++++++ k3s_deploy.yml | 2 + roles/linkerd/defaults/main.yml | 15 +++++++ roles/linkerd/tasks/deploy_linkerd.yml | 9 +++++ roles/linkerd/tasks/install_linkerd_cli.yml | 11 ++++++ roles/linkerd/tasks/main.yml | 17 ++++++++ 6 files changed, 97 insertions(+) create mode 100644 docs/_docs/service-mesh.md create mode 100644 roles/linkerd/defaults/main.yml create mode 100644 roles/linkerd/tasks/deploy_linkerd.yml create mode 100644 roles/linkerd/tasks/install_linkerd_cli.yml create mode 100644 roles/linkerd/tasks/main.yml diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md new file mode 100644 index 00000000..a93a64f6 --- /dev/null +++ b/docs/_docs/service-mesh.md @@ -0,0 +1,43 @@ +--- +title: Service Mesh (Linkerd) +permalink: /docs/service-mesh/ +--- + + +## Why a Service Mesh + +Introduce Service Mesh architecture to add observability, traffic management, and security capabilities to internal communications within the cluster. + +[Linkerd](https://linkerd.io/) will be deployed in the cluster as a Service Mesh implementation. + + +## Why Linkerd and not Istio + +Most known Service Mesh implementation, [Istio](https://istio.io), is not currently supporting ARM64 architecture. + +[Linkerd](https://linkerd.io/), which is a CNCF graduated project, does support ARM64 architectures since release 2.9 (see [linkerd 2.9 announcement](https://linkerd.io/2020/11/09/announcing-linkerd-2.9/). + +Moreover,instead of using [Envoy proxy](https://www.envoyproxy.io/), sidecar container to be deployed with any Pod as communication proxy, Linkerd uses its own ulta-light proxy which reduces the required resource footprint (cpu, memory) and makes it more suitable for Raspberry Pis. + + +## Linkerd installation + +Linkerd installation using `linkerd` CLI. + + +- Step 1: Download `linkerd` CLI command + + ```shell + + curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh + + ``` + + This command will install latest `linkerd` stable release. + + {{site.data.alerts.note}} + + The command above downloads the latest stable release of Linkerd available at [github linkerd repo](https://github.com/linkerd/linkerd/releases/download/) + + {{site.data.alerts.end}} + diff --git a/k3s_deploy.yml b/k3s_deploy.yml index e3393b7c..dd0c5866 100644 --- a/k3s_deploy.yml +++ b/k3s_deploy.yml @@ -51,6 +51,8 @@ tags: ['logging'] - role: backup/velero tags: ['backup'] + - role: linkerd + tags: ['linkerd'] - name: Deploy fluentbit on control nodes (gateway and pimaster) hosts: control diff --git a/roles/linkerd/defaults/main.yml b/roles/linkerd/defaults/main.yml new file mode 100644 index 00000000..402fcd1a --- /dev/null +++ b/roles/linkerd/defaults/main.yml @@ -0,0 +1,15 @@ +--- + +# Version +linkerd_version: "stable-2.11.1" +# Architecture +linkerd_arch: "arm64" + +# Package download url and checksum +linkerd_package_name: "linkerd2-cli-{{ linkerd_version }}-linux-{{ linkerd_arch }}" +linkerd_package_url: "https://github.com/linkerd/linkerd2/releases/download/{{ linkerd_version }}/{{ linkerd_package_name }}" +linkerd_checksum: "sha256:{{ linkerd_package_url }}.sha256" + +# linkerd install location +linkerd_install_dir: "/usr/local/bin" +linkerd_bin: "{{ linkerd_install_dir }}/linkerd" diff --git a/roles/linkerd/tasks/deploy_linkerd.yml b/roles/linkerd/tasks/deploy_linkerd.yml new file mode 100644 index 00000000..7f654e52 --- /dev/null +++ b/roles/linkerd/tasks/deploy_linkerd.yml @@ -0,0 +1,9 @@ +--- + +- name: Check linkerd istallation + command: + cmd: linkerd version + register: linkerd_version_out + +- debug: + var: linkerd_version_out diff --git a/roles/linkerd/tasks/install_linkerd_cli.yml b/roles/linkerd/tasks/install_linkerd_cli.yml new file mode 100644 index 00000000..efb61d60 --- /dev/null +++ b/roles/linkerd/tasks/install_linkerd_cli.yml @@ -0,0 +1,11 @@ +--- + +- name: Install linkerd cli + get_url: + url: "{{ linkerd_package_url }}" + dest: "{{ linkerd_bin }}" + owner: root + group: root + mode: '0755' + # checksum: "{{ linkerd_checksum }}" + diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml new file mode 100644 index 00000000..11030bbf --- /dev/null +++ b/roles/linkerd/tasks/main.yml @@ -0,0 +1,17 @@ +--- + +- name: Check Linkerd installation status + stat: + path: "{{ linkerd_bin }}" + register: _linkerd_bin + +- name: linkerd cli installation + include_tasks: install_linkerd_cli.yml + args: + apply: + become: true + when: + - not _linkerd_bin.stat.exists + +- name: Linkerd deployment + include_tasks: deploy_linkerd.yml From eb8347fc5079c1eb9ff0ca45a552749b6f77c8c9 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sat, 26 Feb 2022 12:14:05 +0100 Subject: [PATCH 02/45] Updating linkerd installation document --- docs/_docs/service-mesh.md | 163 +++++++++++++++++++++++++ roles/linkerd/tasks/deploy_linkerd.yml | 9 ++ 2 files changed, 172 insertions(+) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index a93a64f6..cb392b40 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -39,5 +39,168 @@ Linkerd installation using `linkerd` CLI. The command above downloads the latest stable release of Linkerd available at [github linkerd repo](https://github.com/linkerd/linkerd/releases/download/) + The `linkerd` binary is installed under `${HOME}/.linkerd2` folder. + {{site.data.alerts.end}} + +- Step 2: Update $PATH variable + + ```shell + export PATH=$PATH:${HOME}/.linkerd2/bin" + + ``` + +- Step 3: Validate `linkerd` cli installation + + ```shell + linkerd version + + ``` + + The command shows the CLI version and also **Server version: unavailable** indicates that linkerd can be installed. + + Output of the commad should be like: + + ```shell + Client version: stable-2.11.1 + Server version: unavailable + ``` + +- Step 4: Validate that Linkerd can be installed + + ```shell + linkerd check --pre + ``` + + This command validate kuberentes cluster installation + + Output of the command is like: + + ```shell + Linkerd core checks + =================== + + kubernetes-api + -------------- + √ can initialize the client + √ can query the Kubernetes API + + kubernetes-version + ------------------ + √ is running the minimum Kubernetes API version + √ is running the minimum kubectl version + + pre-kubernetes-setup + -------------------- + √ control plane namespace does not already exist + √ can create non-namespaced resources + √ can create ServiceAccounts + √ can create Services + √ can create Deployments + √ can create CronJobs + √ can create ConfigMaps + √ can create Secrets + √ can read Secrets + √ can read extension-apiserver-authentication configmap + √ no clock skew detected + + linkerd-version + --------------- + √ can determine the latest version + √ cli is up-to-date + + Status check results are √ + ``` + +- Step 5: Install linkerd + + ```shell + linkerd install | kubectl apply -f - + + ``` + +- Step 6: Check installation + + ```shell + linkerd check + + ``` + + This command checks linkerd installation + + Output of the command is like: + + ```shell + Linkerd core checks + =================== + + kubernetes-api + -------------- + √ can initialize the client + √ can query the Kubernetes API + + kubernetes-version + ------------------ + √ is running the minimum Kubernetes API version + √ is running the minimum kubectl version + + linkerd-existence + ----------------- + √ 'linkerd-config' config map exists + √ heartbeat ServiceAccount exist + √ control plane replica sets are ready + √ no unschedulable pods + √ control plane pods are ready + √ cluster networks contains all node podCIDRs + + linkerd-config + -------------- + √ control plane Namespace exists + √ control plane ClusterRoles exist + √ control plane ClusterRoleBindings exist + √ control plane ServiceAccounts exist + √ control plane CustomResourceDefinitions exist + √ control plane MutatingWebhookConfigurations exist + √ control plane ValidatingWebhookConfigurations exist + + linkerd-identity + ---------------- + √ certificate config is valid + √ trust anchors are using supported crypto algorithm + √ trust anchors are within their validity period + √ trust anchors are valid for at least 60 days + √ issuer cert is using supported crypto algorithm + √ issuer cert is within its validity period + √ issuer cert is valid for at least 60 days + √ issuer cert is issued by the trust anchor + + linkerd-webhooks-and-apisvc-tls + ------------------------------- + √ proxy-injector webhook has valid cert + √ proxy-injector cert is valid for at least 60 days + √ sp-validator webhook has valid cert + √ sp-validator cert is valid for at least 60 days + √ policy-validator webhook has valid cert + √ policy-validator cert is valid for at least 60 days + + linkerd-version + --------------- + √ can determine the latest version + √ cli is up-to-date + + control-plane-version + --------------------- + √ can retrieve the control plane version + √ control plane is up-to-date + √ control plane and cli versions match + + linkerd-control-plane-proxy + --------------------------- + √ control plane proxies are healthy + √ control plane proxies are up-to-date + √ control plane proxies and cli versions match + + Status check results are √ + + ``` \ No newline at end of file diff --git a/roles/linkerd/tasks/deploy_linkerd.yml b/roles/linkerd/tasks/deploy_linkerd.yml index 7f654e52..3b4ad697 100644 --- a/roles/linkerd/tasks/deploy_linkerd.yml +++ b/roles/linkerd/tasks/deploy_linkerd.yml @@ -7,3 +7,12 @@ - debug: var: linkerd_version_out + + +- name: Linkerd pre-installation checks + command: + cmd: linkerd check --pre + register: linkerd_check_out + +- debug: + var: linkerd_check_out From 63ef7ea0056248f3fa1c08723bc8de32f304e320 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sat, 5 Mar 2022 10:16:21 +0100 Subject: [PATCH 03/45] Adding firewall rule to enable kubernetes port forwarding to node1 using 8080 port --- host_vars/gateway.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host_vars/gateway.yml b/host_vars/gateway.yml index 6493f9c7..a68b7917 100644 --- a/host_vars/gateway.yml +++ b/host_vars/gateway.yml @@ -104,6 +104,8 @@ nft_forward_host_rules: - iifname $wan_interface oifname $lan_interface ip daddr $lan_network tcp dport {http, https} ct state new accept 240 s3 from wan: - iifname $wan_interface oifname $lan_interface ip daddr 10.0.0.11 tcp dport {9091, 9092} ct state new accept + 250 port-forwarding from wan: + - iifname $wan_interface oifname $lan_interface ip daddr 10.0.0.11 tcp dport 8080 ct state new accept # NAT Post-routing nft_nat_host_postrouting_rules: 005 masquerade lan to wan: From 54f0f827615834fa299fb56b5957ea7e7f665d7f Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 7 Mar 2022 19:00:51 +0100 Subject: [PATCH 04/45] Adding linkerd namespaces --- group_vars/k3s_cluster.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group_vars/k3s_cluster.yml b/group_vars/k3s_cluster.yml index ba1c494b..c9946c14 100644 --- a/group_vars/k3s_cluster.yml +++ b/group_vars/k3s_cluster.yml @@ -42,6 +42,8 @@ k3s_certmanager_namespace: certmanager-system k3s_logging_namespace: k3s-logging k3s_monitoring_namespace: k3s-monitoring k3s_velero_namespace: velero-system +k3s_linkerd_namespace: linkerd +k3s_linkerd_viz_namespace: linkerd-viz # MetalLB configuration # k3s external ip range: Metal LB pool configuration From 132c0862654293b02ddc5fbc8c1c81bf9e9c0be2 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 13:25:56 +0100 Subject: [PATCH 05/45] Configure cert-manager CA issuer and update documentation --- docs/_docs/certmanager.md | 180 +++++++++++++++---- roles/certmanager/tasks/main.yml | 3 +- roles/certmanager/templates/ca_issuer.yml.j2 | 26 +++ 3 files changed, 170 insertions(+), 39 deletions(-) create mode 100644 roles/certmanager/templates/ca_issuer.yml.j2 diff --git a/docs/_docs/certmanager.md b/docs/_docs/certmanager.md index 0063190f..708a81c1 100644 --- a/docs/_docs/certmanager.md +++ b/docs/_docs/certmanager.md @@ -2,19 +2,111 @@ title: SSL Certificates (Cert-Manager) permalink: /docs/certmanager/ description: How to deploy a centralized SSL certification management solution based on Cert-manager in our Raspberry Pi Kuberentes cluster. -last_modified_at: "25-02-2022" +last_modified_at: "08-03-2022" --- In the Kubernetes cluster, [Cert-Manager](https://cert-manager.io/docs/) can be used to automate the certificate management tasks (issue certificate request, renewals, etc.). Cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters, and simplifies the process of obtaining, renewing and using those certificates. It can issue certificates from a variety of supported sources, including support for auto-signed certificates or use [Let's Encrypt](https://letsencrypt.org/) service to obtain validated SSL certificates. It will ensure certificates are valid and up to date, and attempt to renew certificates at a configured time before expiry. -{{site.data.alerts.note}} -CertManager integration with Let's Encryp has not been configured since my DNS provider does not suppport yet the API for automating DNS challenges. See open issue [#16](https://github.com/ricsanfre/pi-cluster/issues/16). -CertManager has been configured to issue selfsigned certificates. +## Cert-Manager certificates issuers + +In cert-manager different kind of certificate issuer can be configured to generate signed SSL certificates + +### Self-signed Issuer + +The SelfSigned issuer doesn’t represent a certificate authority as such, but instead denotes that certificates will “sign themselves” using a given private key. In other words, the private key of the certificate will be used to sign the certificate itself. + +This Issuer type is useful for bootstrapping a root certificate (CA) for a custom PKI (Public Key Infrastructure). + +We will use this Issuer for bootstrapping our custom CA. + +### CA Issuer + +The CA issuer represents a Certificate Authority whereby its certificate and private key are stored inside the cluster as a Kubernetes Secret, and will be used to sign incoming certificate requests. This internal CA certificate can then be used to trust resulting signed certificates. + +This issuer type is typically used in a Public Key Infrastructure (PKI) setup to secure your infrastructure components to establish mTLS or otherwise provide a means to issue certificates where you also own the private key. Signed certificates with this custom CA will not be trusted by clients, such a web browser, by default. + +### ACME issuers (Lets Encrypt) + +The ACME Issuer type represents a single account registered with the Automated Certificate Management Environment (ACME) Certificate Authority server. See section [Let's Encrypt certificates](#lets-encrypt-certificates). + + +{{site.data.alerts.important}} + +CertManager has been configured to have in the cluster a custom PKI (Public Key Infrastructure) using a self-signed CA to issue auto-signed certificates. + +CertManager integration with Let's Encrypt has not been configured since my DNS provider does not suppport yet the API for automating DNS challenges. See open issue [#16](https://github.com/ricsanfre/pi-cluster/issues/16). + {{site.data.alerts.end}} + +## Cert Manager Usage + +Cert-manager add a set of Kubernetes custom resource (CRD): + +- `Issuer` and `ClusterIssuer`: resources that represent certificate authorities (CA) able to genertate signed certificates in response to certificate signed request (CSR). `Issuer` is a namespaced resource, able to issue certificates only for the namespace where the issuer is located. `ClusterIssuer` is able to issue certificates across all namespaces. + +- `Certificate`, resources that represent a human readable definition of a certificate request that need to be generated and keep up to date by an issuer. + +In order to generate new SSL certificates a `Certificate` resource can be created. + +Once the Certificate resource is created, Cert-manager signed the certificate issued by the specified issuer and stored it in a `kubernetes.io/tls Secret` resource, which is the one used to secure Ingress resource. See kuberentes [Ingress TLS documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) + +```yml +apiVersion: v1 +kind: Secret +metadata: + name: testsecret-tls + namespace: default +data: + tls.crt: base64 encoded cert + tls.key: base64 encoded key +type: kubernetes.io/tls +``` + +See further details in the [cert-manager documentation](https://cert-manager.io/docs/usage/certificate/) + + +### Securing Ingress resources + +`Ingress` resources can be configured using annotations, so cert-manager can automatically generate the needed self-signed certificates to secure the incoming communications using HTTPS/TLS + +As stated in the [documentation](https://cert-manager.io/docs/usage/ingress/), cert-manager can be used to automatically request TLS signed certificates to secure any `Ingress` resources. By means of annotations cert-manager can generate automatically the needed certificates and store them in corresponding secrets used by Ingress resource + +Ingress annotation `cert-manager.io/cluster-issuer` indicates the `ClusterIssuer` to be used. + +Ingress rule example: + +```yml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + # add an annotation indicating the issuer to use. + cert-manager.io/cluster-issuer: nameOfClusterIssuer + name: myIngress + namespace: myIngress +spec: + rules: + - host: example.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: myservice + port: + number: 80 + tls: # < placing a host in the TLS config will determine what ends up in the cert's subjectAltNames + - hosts: + - example.com + secretName: myingress-cert # < cert-manager will store the created certificate in this secret. +``` + + ## Cert Manager Installation Installation using `Helm` (Release 3): @@ -37,7 +129,7 @@ Installation using `Helm` (Release 3): - Step 3: Install Cert-Manager ```shell - helm install cert-manager jetstack/cert-manager --namespace certmanager-system --version v1.5.3 --set installCRDs=true + helm install cert-manager jetstack/cert-manager --namespace certmanager-system --set installCRDs=true ``` - Step 4: Confirm that the deployment succeeded, run: @@ -45,10 +137,16 @@ Installation using `Helm` (Release 3): kubectl -n certmanager-system get pod ``` -## Self-signed Certificates +## Cert-Manager Configuration + +A PKI (Public Key Infrastructure) with a custom CA, will be created within the cluster and all certificates withing the cluster will be auto-signed by this CA. For doing so, A CA `ClusterIssuer` need be created to be created. +Root CA certificate is needed for generated this CA Issuer, selfsigned `ClusterIssuer` will be used to generate that root CA certificated (self-signed root CA). -- Step 1: Create `ClusterIssuer` -In order to obtain certificates from cert-manager, we need to create an issuer to act as a certificate authority. We have the option of creating an `Issuer` which is a namespaced resource, or a `ClusterIssuer` which is a global resource. We’ll create a self-signed `ClusterIssuer` using the following definition: +- Step 1: Create selfsigned `ClusterIssuer` + + First step is to create the self-signed issuer for being able to selfsign a custom root certificate of the PKI (CA certificate). + + In order to obtain certificates from cert-manager, we need to create an issuer to act as a certificate authority. We have the option of creating an `Issuer` which is a namespaced resource, or a `ClusterIssuer` which is a global resource. We’ll create a self-signed `ClusterIssuer` using the following definition: ```yml apiVersion: cert-manager.io/v1 @@ -59,44 +157,50 @@ In order to obtain certificates from cert-manager, we need to create an issuer t selfSigned: {} ``` -- Step 2: Configure Ingress rule to automatically use cert-manager to issue self-signed certificates - - As stated in the [documentation](https://cert-manager.io/docs/usage/ingress/), cert-manager can be used to automatically request TLS signed certificates to secure any `Ingress` resources. By means of annotations cert-manager can generate automatically the needed certificates +- Step 2: Bootstrapping CA Issuers - Ingress annotation `cert-manager.io/cluster-issuer` indicates the `ClusterIssuer` to be used - - Ingress rule example: + Bootstrap a custom root certificate for a private PKI (custom CA) and create the corresponding cert-manager CA issuer ```yml - apiVersion: networking.k8s.io/v1 - kind: Ingress + --- + apiVersion: cert-manager.io/v1 + kind: Certificate + metadata: + name: my-selfsigned-ca + namespace: sandbox + spec: + isCA: true + commonName: my-selfsigned-ca + secretName: root-secret + privateKey: + algorithm: ECDSA + size: 256 + issuerRef: + name: selfsigned-issuer + kind: ClusterIssuer + group: cert-manager.io + --- + apiVersion: cert-manager.io/v1 + kind: ClusterIssuer metadata: - annotations: - # add an annotation indicating the issuer to use. - cert-manager.io/cluster-issuer: nameOfClusterIssuer - name: myIngress - namespace: myIngress + name: my-ca-issuer + namespace: sandbox spec: - rules: - - host: example.com - http: - paths: - - pathType: Prefix - path: / - backend: - service: - name: myservice - port: - number: 80 - tls: # < placing a host in the TLS config will determine what ends up in the cert's subjectAltNames - - hosts: - - example.com - secretName: myingress-cert # < cert-manager will store the created certificate in this secret. + ca: + secretName: root-secret ``` +{{site.data.alerts.important}} + +Algorithm used for signing SSL certificates is ECDSA P-256, since it is the one needed as requirement for installing `linkerd` + +{{site.data.alerts.end}} + + + ## Lets Encrypt Certificates -Lets Encrypt provide publicly validated TLS certificates for free. Not need to generate auti-signed SSL Certificates for the websites that are not automatic validated by HTTP browsers. +Lets Encrypt provide publicly validated TLS certificates for free. Not need to generate auto-signed SSL Certificates for the websites that are not automatic validated by HTTP browsers. The process is the following, we issue a request for a certificate to Let's Encrypt for a domain name that we own. Let's Encrypt verifies that we own that domain by using an ACME DNS or HTTP validation mechanism. If the verification is successful, Let's Encrypt provides us with certificates that cert-manager installs in our website (or other TLS encrypted endpoint). These certificates are good for 90 days before the process needs to be repeated. Cert-manager, however, will automatically keep the certificates up-to-date for us. @@ -121,7 +225,7 @@ Since Dec 2020, IONOS launched an API for remotelly configure DNS, and so the in Unfortunally IONOS API is part of a beta program that it is not available yet in my location (Spain). -### Let`s Encrypt HTTP validation method +### Lets Encrypt HTTP validation method HTTP validation method requires to actually expose a "challenge URL" in the Public Internet using the DNS domain associated to the SSL certificate. diff --git a/roles/certmanager/tasks/main.yml b/roles/certmanager/tasks/main.yml index 9884e648..5eb1c18e 100644 --- a/roles/certmanager/tasks/main.yml +++ b/roles/certmanager/tasks/main.yml @@ -21,9 +21,10 @@ release_values: installCRDs: true -- name: Configura self-signed issuer +- name: Configure Cluster Issuers kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" state: present with_items: - selfsigned_issuer.yml.j2 + - ca_issuer.yml.j2 diff --git a/roles/certmanager/templates/ca_issuer.yml.j2 b/roles/certmanager/templates/ca_issuer.yml.j2 new file mode 100644 index 00000000..b596eda0 --- /dev/null +++ b/roles/certmanager/templates/ca_issuer.yml.j2 @@ -0,0 +1,26 @@ +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: picluster-ca + namespace: {{ k3s_certmanager_namespace }} +spec: + isCA: true + commonName: picluster-ca + secretName: root-secret + privateKey: + algorithm: ECDSA + size: 256 + issuerRef: + name: self-signed-issuer + kind: ClusterIssuer + group: cert-manager.io +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: ca-issuer + namespace: {{ k3s_certmanager_namespace }} +spec: + ca: + secretName: root-secret \ No newline at end of file From 09c985060f5c742e70990324a8672a62f6d23fc7 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 13:27:34 +0100 Subject: [PATCH 06/45] Updating Traefik dashboard to use CA issuer --- docs/_docs/ingress-controller.md | 16 ++++++++++------ roles/traefik/templates/traefik_dashboard.yml.j2 | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/_docs/ingress-controller.md b/docs/_docs/ingress-controller.md index 4ee21af1..95d947c4 100644 --- a/docs/_docs/ingress-controller.md +++ b/docs/_docs/ingress-controller.md @@ -2,7 +2,7 @@ title: Ingress Controller (Traefik) permalink: /docs/traefik/ description: How to configure Ingress Contoller based on Traefik in our Raspberry Pi Kuberentes cluster. -last_modified_at: "25-02-2022" +last_modified_at: "08-03-2022" --- All HTTP/HTTPS traffic comming to K3S exposed services should be handled by a Ingress Controller. @@ -61,7 +61,7 @@ spec: number: 80 ``` -SSL certificates can be created manually and stored in Kubernetes `Secrets`. This manual step can be avoided using Cert-manager. +SSL certificates can be created manually and stored in Kubernetes `Secrets`. ```yml apiVersion: v1 @@ -74,6 +74,10 @@ data: type: kubernetes.io/tls ``` +This manual step can be avoided using Cert-manager and annotating the Ingress resource: `cert-manager.io/cluster-issuer: `. See further details in [SSL certification management documentation](/docs/certmanager/). + + + ### Redirecting HTTP traffic to HTTPS Middlewares are a means of tweaking the requests before they are sent to the service (or before the answer from the services are sent to the clients) @@ -314,7 +318,7 @@ A Kuberentes Service must be created for enabling the access to UI Dashboard app.kubernetes.io/name: traefik ``` -- Create Ingress rules for accesing through HTTPS dashboard UI, using certifcates automatically created by certmanager and providing a basic authentication mechanism. +- Create Ingress rules for accesing through HTTPS dashboard UI, using certificates automatically created by certmanager and providing a basic authentication mechanism. ```yml --- @@ -332,13 +336,13 @@ A Kuberentes Service must be created for enabling the access to UI Dashboard # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: traefik-system-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: traefik + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: traefik.picluster.ricsanfre.com spec: tls: - hosts: - traefik.picluster.ricsanfre.com - secretName: prometheus-tls + secretName: traefik-tls rules: - host: traefik.picluster.ricsanfre.com http: diff --git a/roles/traefik/templates/traefik_dashboard.yml.j2 b/roles/traefik/templates/traefik_dashboard.yml.j2 index 42c423e9..df89f70d 100644 --- a/roles/traefik/templates/traefik_dashboard.yml.j2 +++ b/roles/traefik/templates/traefik_dashboard.yml.j2 @@ -33,13 +33,13 @@ metadata: # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: traefik + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: "{{ traefik_dashboard_dns }}" spec: tls: - hosts: - {{ traefik_dashboard_dns }} - secretName: prometheus-tls + secretName: traefik-tls rules: - host: {{ traefik_dashboard_dns }} http: From d73cdeec19a94e95675cd3a08338a1eb12ea56ca Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 16:02:46 +0100 Subject: [PATCH 07/45] Use helm installation procedure for linkerd integrated with certmanager instead of CLI --- roles/linkerd/tasks/deploy_linkerd.yml | 18 ------- roles/linkerd/tasks/install_linkerd_cli.yml | 11 ---- roles/linkerd/tasks/main.yml | 54 ++++++++++++++----- roles/linkerd/templates/linkerd_issuer.yml.j2 | 25 +++++++++ 4 files changed, 66 insertions(+), 42 deletions(-) delete mode 100644 roles/linkerd/tasks/deploy_linkerd.yml delete mode 100644 roles/linkerd/tasks/install_linkerd_cli.yml create mode 100644 roles/linkerd/templates/linkerd_issuer.yml.j2 diff --git a/roles/linkerd/tasks/deploy_linkerd.yml b/roles/linkerd/tasks/deploy_linkerd.yml deleted file mode 100644 index 3b4ad697..00000000 --- a/roles/linkerd/tasks/deploy_linkerd.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- - -- name: Check linkerd istallation - command: - cmd: linkerd version - register: linkerd_version_out - -- debug: - var: linkerd_version_out - - -- name: Linkerd pre-installation checks - command: - cmd: linkerd check --pre - register: linkerd_check_out - -- debug: - var: linkerd_check_out diff --git a/roles/linkerd/tasks/install_linkerd_cli.yml b/roles/linkerd/tasks/install_linkerd_cli.yml deleted file mode 100644 index efb61d60..00000000 --- a/roles/linkerd/tasks/install_linkerd_cli.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- - -- name: Install linkerd cli - get_url: - url: "{{ linkerd_package_url }}" - dest: "{{ linkerd_bin }}" - owner: root - group: root - mode: '0755' - # checksum: "{{ linkerd_checksum }}" - diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index 11030bbf..c2bdf574 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -1,17 +1,45 @@ --- -- name: Check Linkerd installation status - stat: - path: "{{ linkerd_bin }}" - register: _linkerd_bin +- name: Create linkerd namespace. + kubernetes.core.k8s: + name: "{{ k3s_linkerd_namespace }}" + api_version: v1 + kind: Namespace + state: present -- name: linkerd cli installation - include_tasks: install_linkerd_cli.yml - args: - apply: - become: true - when: - - not _linkerd_bin.stat.exists +- name: Create linkerd issuer + kubernetes.core.k8s: + definition: "{{ lookup('template', 'templates/' + item ) }}" + state: present + with_items: + - linkerd_issuer.yml.j2 -- name: Linkerd deployment - include_tasks: deploy_linkerd.yml +- name: Get ca.crt from linkerd-identity + shell: | + kubectl get secret \ + -n "{{ k3s_linkerd_namespace }}" linkerd-identity-issuer \ + -o jsonpath="{.data.ca\.crt}" | base64 -d + register: output_ca_crt + +- name: debugging + debug: + var: output_ca_crt + +- name: Add Linkerd stable repo. + kubernetes.core.helm_repository: + name: linkerd + repo_url: "https://helm.linkerd.io/stable" + +- name: Deploy Linkerd Helm chart. + kubernetes.core.helm: + name: linkerd2 + chart_ref: linkerd/linkerd2 + release_namespace: "{{ k3s_linkerd_namespace }}" + update_repo_cache: true + state: present + release_values: + installNamespace: false + identityTrustAnchorsPEM: "{{ output_ca_crt.stdout }}" + identity: + issuer: + scheme: kubernetes.io/tls diff --git a/roles/linkerd/templates/linkerd_issuer.yml.j2 b/roles/linkerd/templates/linkerd_issuer.yml.j2 new file mode 100644 index 00000000..8258b07f --- /dev/null +++ b/roles/linkerd/templates/linkerd_issuer.yml.j2 @@ -0,0 +1,25 @@ +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: linkerd-identity-issuer + namespace: {{ k3s_linkerd_namespace }} +spec: + secretName: linkerd-identity-issuer + duration: 48h + renewBefore: 25h + issuerRef: + name: ca-issuer + kind: ClusterIssuer + group: cert-manager.io + commonName: identity.linkerd.cluster.local + dnsNames: + - identity.linkerd.cluster.local + isCA: true + privateKey: + algorithm: ECDSA + usages: + - cert sign + - crl sign + - server auth + - client auth From 16799d6141e7600d8ab4014449f1e5149f6812e4 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 16:18:14 +0100 Subject: [PATCH 08/45] Updating longhorn ingress rule to use ca-issuer --- docs/_docs/longhorn.md | 4 ++-- roles/longhorn/templates/longhorn_ingress.yml.j2 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/_docs/longhorn.md b/docs/_docs/longhorn.md index 6c6a75f1..a50f66c0 100644 --- a/docs/_docs/longhorn.md +++ b/docs/_docs/longhorn.md @@ -115,8 +115,8 @@ There is a known issue with accessing Longhorn UI from Traefik 2.x that makes Lo traefik-system-basic-auth@kubernetescrd, longhorn-system-svc-longhorn-headers@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: longhorn + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: storage.picluster.ricsanfre.com spec: tls: - hosts: diff --git a/roles/longhorn/templates/longhorn_ingress.yml.j2 b/roles/longhorn/templates/longhorn_ingress.yml.j2 index ec7b8633..3a6a140b 100644 --- a/roles/longhorn/templates/longhorn_ingress.yml.j2 +++ b/roles/longhorn/templates/longhorn_ingress.yml.j2 @@ -27,8 +27,8 @@ metadata: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd, {{ k3s_longhorn_namespace }}-svc-longhorn-headers@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: longhorn + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ longhorn_dashboard_dns }} spec: tls: - hosts: From b69ba9140fd074d1b90dbd11bbfbc5bc5891b233 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 16:26:42 +0100 Subject: [PATCH 09/45] Updating prometheus ingress resources to use ca-issuer --- docs/_docs/monitoring.md | 12 ++++++------ .../prometheus/templates/alertmanager_ingress.yml.j2 | 4 ++-- roles/prometheus/templates/grafana_ingress.yml.j2 | 4 ++-- roles/prometheus/templates/prometheus_ingress.yml.j2 | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/_docs/monitoring.md b/docs/_docs/monitoring.md index a3202a7d..6db12018 100644 --- a/docs/_docs/monitoring.md +++ b/docs/_docs/monitoring.md @@ -115,8 +115,8 @@ Since prometheus frontend does not provide any authentication mechanism, Traefik # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: traefik-system-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: prometheus + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: prometheus.picluster.ricsanfre.com spec: tls: - hosts: @@ -176,8 +176,8 @@ Since prometheus frontend does not provide any authentication mechanism, Traefik # Enable TLS traefik.ingress.kubernetes.io/router.tls: "true" # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: grafana + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: grafana.picluster.ricsanfre.com spec: tls: - hosts: @@ -237,8 +237,8 @@ Since prometheus frontend does not provide any authentication mechanism, Traefik # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: traefik-system-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: alertmanager + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: alertmanager.picluster.ricsanfre.com spec: tls: - hosts: diff --git a/roles/prometheus/templates/alertmanager_ingress.yml.j2 b/roles/prometheus/templates/alertmanager_ingress.yml.j2 index bbd77068..f29ee21f 100644 --- a/roles/prometheus/templates/alertmanager_ingress.yml.j2 +++ b/roles/prometheus/templates/alertmanager_ingress.yml.j2 @@ -13,8 +13,8 @@ metadata: # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: alertmanager + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ alertmanager_dashboard_dns }} spec: tls: - hosts: diff --git a/roles/prometheus/templates/grafana_ingress.yml.j2 b/roles/prometheus/templates/grafana_ingress.yml.j2 index e23d4641..7b6aa056 100644 --- a/roles/prometheus/templates/grafana_ingress.yml.j2 +++ b/roles/prometheus/templates/grafana_ingress.yml.j2 @@ -11,8 +11,8 @@ metadata: # Enable TLS traefik.ingress.kubernetes.io/router.tls: "true" # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: grafana + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ grafana_dashboard_dns }} spec: tls: - hosts: diff --git a/roles/prometheus/templates/prometheus_ingress.yml.j2 b/roles/prometheus/templates/prometheus_ingress.yml.j2 index 83cfcfda..9caf046c 100644 --- a/roles/prometheus/templates/prometheus_ingress.yml.j2 +++ b/roles/prometheus/templates/prometheus_ingress.yml.j2 @@ -13,8 +13,8 @@ metadata: # Use Basic Auth Midleware configured traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd # Enable cert-manager to create automatically the SSL certificate and store in Secret - cert-manager.io/cluster-issuer: self-signed-issuer - cert-manager.io/common-name: prometheus + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ prometheus_dashboard_dns }} spec: tls: - hosts: From 6a2f56e172bf9425cb215e9a6b705aa36373c1c7 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 19:10:17 +0100 Subject: [PATCH 10/45] Installing linkerd-viz extension and annotating and labeling linkerd namespace --- roles/linkerd/tasks/linkerd_extensions.yml | 23 +++++++++++++++++++ roles/linkerd/tasks/main.yml | 9 +++++--- .../templates/linkerd_namespace.yml.j2 | 11 +++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 roles/linkerd/tasks/linkerd_extensions.yml create mode 100644 roles/linkerd/templates/linkerd_namespace.yml.j2 diff --git a/roles/linkerd/tasks/linkerd_extensions.yml b/roles/linkerd/tasks/linkerd_extensions.yml new file mode 100644 index 00000000..1bc46d62 --- /dev/null +++ b/roles/linkerd/tasks/linkerd_extensions.yml @@ -0,0 +1,23 @@ +--- + +# - name: Create linkerd-viz namespace. +# kubernetes.core.k8s: +# name: "{{ k3s_linkerd_namespace }}-viz" +# api_version: v1 +# kind: Namespace +# state: present + +- name: Deploy Linkerd-viz Helm chart. + kubernetes.core.helm: + name: linkerd-viz + chart_ref: linkerd/linkerd-viz + release_namespace: "{{ k3s_linkerd_namespace }}" + update_repo_cache: true + state: present + release_values: + prometheusUrl: http://kube-prometheus-stack-prometheus.k3s-monitoring.svc.cluster.local:9090 + prometheus: + enabled: false + grafana: + enabled: false + grafanaUrl: http://kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index c2bdf574..e6043818 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -2,10 +2,10 @@ - name: Create linkerd namespace. kubernetes.core.k8s: - name: "{{ k3s_linkerd_namespace }}" - api_version: v1 - kind: Namespace + definition: "{{ lookup('template', 'templates/' + item ) }}" state: present + with_items: + - linkerd_namespace.yml.j2 - name: Create linkerd issuer kubernetes.core.k8s: @@ -43,3 +43,6 @@ identity: issuer: scheme: kubernetes.io/tls + +- name: Install linkerd extensions + include_tasks: linkerd_extensions.yml diff --git a/roles/linkerd/templates/linkerd_namespace.yml.j2 b/roles/linkerd/templates/linkerd_namespace.yml.j2 new file mode 100644 index 00000000..3a948744 --- /dev/null +++ b/roles/linkerd/templates/linkerd_namespace.yml.j2 @@ -0,0 +1,11 @@ +--- +kind: Namespace +apiVersion: v1 +metadata: + name: {{ k3s_linkerd_namespace }} + annotations: + linkerd.io/inject: disabled + labels: + linkerd.io/is-control-plane: "true" + config.linkerd.io/admission-webhooks: disabled + linkerd.io/control-plane-ns: {{ k3s_linkerd_namespace }} From f7972de41fe4c6aea452fba762bd99a4653b8e1f Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 8 Mar 2022 19:17:26 +0100 Subject: [PATCH 11/45] Updating linkerd installation doc --- docs/_docs/service-mesh.md | 297 +++++++++++++++++++------------------ 1 file changed, 156 insertions(+), 141 deletions(-) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index cb392b40..54fda628 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -1,6 +1,8 @@ --- title: Service Mesh (Linkerd) permalink: /docs/service-mesh/ +description: How to deploy service-mesh architecture based on Linkerd. + --- @@ -20,187 +22,200 @@ Most known Service Mesh implementation, [Istio](https://istio.io), is not curren Moreover,instead of using [Envoy proxy](https://www.envoyproxy.io/), sidecar container to be deployed with any Pod as communication proxy, Linkerd uses its own ulta-light proxy which reduces the required resource footprint (cpu, memory) and makes it more suitable for Raspberry Pis. -## Linkerd installation +## Automatic mTLS -Linkerd installation using `linkerd` CLI. +By default, Linkerd automatically enables mutually-authenticated Transport Layer Security (mTLS) for all TCP traffic between meshed pods. This means that Linkerd adds authenticated, encrypted communication to your application with no extra work on your part. (And because the Linkerd control plane also runs on the data plane, this means that communication between Linkerd’s control plane components are also automatically secured via mTLS.) +The Linkerd control plane contains a certificate authority (CA) called `identity`. This CA issues TLS certificates to each Linkerd data plane proxy. These TLS certificates expire after 24 hours and are automatically rotated. The proxies use these certificates to encrypt and authenticate TCP traffic to other proxies. -- Step 1: Download `linkerd` CLI command +On the control plane side, Linkerd maintains a set of credentials in the cluster: a **trust anchor**, and an **issuer certificate and private key**. While Linkerd automatically rotates the TLS certificates for data plane proxies every 24 hours, it does not rotate the TLS credentials and private key associated with the issuer. `cert-manager` can be used to initially generate this issuer certificate and private key and automatically rotate them. - ```shell - - curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh - ``` - This command will install latest `linkerd` stable release. +## Linkerd Installation - {{site.data.alerts.note}} +Installation procedure to use cert-manager and bein able to automatically rotate control-plane tls credentiasl is described in [linkerd documentation](https://linkerd.io/2.11/tasks/automatically-rotating-control-plane-tls-credentials/). - The command above downloads the latest stable release of Linkerd available at [github linkerd repo](https://github.com/linkerd/linkerd/releases/download/) +The following instalation procedure is a slightly different from the one proposed in that documentation since we will use as linkerd trust-anchor the root CA and CA ClusterIssuer already created during Cert-manager installation and configuration for the cluster. - The `linkerd` binary is installed under `${HOME}/.linkerd2` folder. +### Installation pre-requisite: Configure Cert-Manager - {{site.data.alerts.end}} +Cert-manager need to be configured to act as an on-cluster CA and to re-issue Linkerd’s issuer certificate and private key on a periodic basis. +Cert-manager CA root certificate (trust-anchor) and CA Cluster issuer is already configured as part of [Cert-Manager installation and configuration](/docs/certmanager/). -- Step 2: Update $PATH variable +That trust-anchor anc ClusterIssuer will be used to generate linkerd certificate used as CA for signing linkerd's mTLS certificates. - ```shell - export PATH=$PATH:${HOME}/.linkerd2/bin" +### Linkerd Installation using Helm - ``` +Installation using `Helm` (Release 3): -- Step 3: Validate `linkerd` cli installation +- Step 1: Add the Linkerd Helm stable repository: - ```shell - linkerd version + ```shell + helm repo add linkerd https://helm.linkerd.io/stable + ``` +- Step2: Fetch the latest charts from the repository: - ``` + ```shell + helm repo update + ``` +- Step 3: Create namespace - The command shows the CLI version and also **Server version: unavailable** indicates that linkerd can be installed. + By default, the helm chart creates the control plane namespace with the `config.linkerd.io/admission-webhooks: disabled` label. It is required for the control plane to work correctly.creates the namespace annotated and labeled. - Output of the commad should be like: + Since we are creating the namespace we need to provide the same labels and annotations. - ```shell - Client version: stable-2.11.1 - Server version: unavailable + Create namespace manifest file `linkerd_namespace.yml` + + ```yml + kind: Namespace + apiVersion: v1 + metadata: + name: linkerd + annotations: + linkerd.io/inject: disabled + labels: + linkerd.io/is-control-plane: "true" + config.linkerd.io/admission-webhooks: disabled + linkerd.io/control-plane-ns: linkerd ``` -- Step 4: Validate that Linkerd can be installed + And apply the manifest with the following command: + ```shell - linkerd check --pre + kubectl apply -f linkerd_namespace.yml + ``` - This command validate kuberentes cluster installation +- Step 4: Create `linkerd-identity-issuer` certificate resource + + Create file `linkerd-identity-issuer.yml` + + ```yml + apiVersion: cert-manager.io/v1 + kind: Certificate + metadata: + name: linkerd-identity-issuer + namespace: linkerd + spec: + secretName: linkerd-identity-issuer + duration: 48h + renewBefore: 25h + issuerRef: + name: ca-issuer + kind: ClusterIssuer + group: cert-manager.io + commonName: identity.linkerd.cluster.local + dnsNames: + - identity.linkerd.cluster.local + isCA: true + privateKey: + algorithm: ECDSA + usages: + - cert sign + - crl sign + - server auth + - client auth + ``` + + ClusterIssuer `ca-issuer`, created as part of cert-manager configuration, is used to sign this certificate. + + `duration` instructs cert-manager to consider certificates as valid for 48 hours and `renewBefore` indicates that cert-manager will attempt to issue a new certificate 25 hours before expiration of the current one. - Output of the command is like: + Certificate is creates as CA (isCA:true) because it will be use by linkerd to issue mTLS certificates. + +- Step 2: Command certmanger to create the `Certificate` and the associated `Secret`. ```shell - Linkerd core checks - =================== - - kubernetes-api - -------------- - √ can initialize the client - √ can query the Kubernetes API - - kubernetes-version - ------------------ - √ is running the minimum Kubernetes API version - √ is running the minimum kubectl version - - pre-kubernetes-setup - -------------------- - √ control plane namespace does not already exist - √ can create non-namespaced resources - √ can create ServiceAccounts - √ can create Services - √ can create Deployments - √ can create CronJobs - √ can create ConfigMaps - √ can create Secrets - √ can read Secrets - √ can read extension-apiserver-authentication configmap - √ no clock skew detected - - linkerd-version - --------------- - √ can determine the latest version - √ cli is up-to-date - - Status check results are √ + kubectl apply -f linkerd-identity-issuer.yml ``` -- Step 5: Install linkerd +- Step 3: Get CA certificate used to sign the linkerd-identy-issuer certificate + + Linkerd installation procedure (using Helm chart of `linkerd` CLI), requires to pass as parameter the trust-anchor (root certiticate) used to sign the linkerd-identy-issuer. It can be obtained from the associated Secret with the following commad. ```shell - linkerd install | kubectl apply -f - + kubectl get secret linkerd-identity-issuer -o jsonpath="{.data.ca\.crt}" -n linkerd | base64 -d > ca.crt ``` -- Step 6: Check installation +- Step 4: Install Linkerd + + ```shell + helm install linkerd2 \ + --set-file identityTrustAnchorsPEM=ca.crt \ + --set identity.issuer.scheme=kubernetes.io/tls \ + --set installNamespace=false \ + linkerd/linkerd2 \ + -n linkerd + ``` + +- Step 5: Confirm that the deployment succeeded, run: + + ```shell + kubectl -n linkerd get pod + ``` + +- Step 6: Check linkerd control plane configmap + + Check that the ca.crt is properly included in linkerd configmap ```shell - linkerd check + kubectl get configmap linkerd-config -o yaml -n linkerd - ``` + ``` - This command checks linkerd installation + The `identiyTrustAnchorPEM` key included in the Configmap should show th ca.crt extracted in Step 3 + + ```yml + identityTrustAnchorsPEM: |- + -----BEGIN CERTIFICATE----- + MIIBbzCCARWgAwIBAgIRAKTg35A0zYXdNKIfOfzmvBswCgYIKoZIzj0EAwIwFzEV + MBMGA1UEAxMMcGljbHVzdGVyLWNhMB4XDTIyMDMwODEyMTYxM1oXDTIyMDYwNjEy + MTYxM1owFzEVMBMGA1UEAxMMcGljbHVzdGVyLWNhMFkwEwYHKoZIzj0CAQYIKoZI + zj0DAQcDQgAEYcZquh74RiIWje8/PHC8haksDdjvQroRrZQnsKP9j/LL+C0qLx9n + 7Fs3nLMQ6ipRZ1KV9k/sP0nFHzI4G4W3wKNCMEAwDgYDVR0PAQH/BAQDAgKkMA8G + A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFM+IzMMYOlVcCe0BEBvmVKGO7RF9MAoG + CCqGSM49BAMCA0gAMEUCIBRop9dU9iDuZRVlxFLjwwxnQxL601atw/298/wQWdzn + AiEAwlZ6RTYjoN4XHxQnz2yZhu7ACsjX5p3oSNnL2nOs+7k= + -----END CERTIFICATE----- + ``` + +### Linkerd Viz extension installation + +Linkerd provides a full on-cluster metrics stack, a web dashboard, and pre-configured Grafana dashboards. This is the linkerd viz extension. + +This extension installs the following components into a new namespace linkerd-viz: + +- A Prometheus instance +- A Grafana instance +- metrics-api, tap, tap-injector, and web components - Output of the command is like: +Since we have already our monitoring deployment, we will configure Viz extension to use the existing Prometheus and Grafana instance. See linkerd documentation ["Bringing your own Prometheus"](https://linkerd.io/2.11/tasks/external-prometheus/) + + +- Step 1: Prepare values.yml for Viz helm chart installation + + + ```yml + prometheusUrl: http://kube-prometheus-stack-prometheus.k3s-monitoring.svc.cluster.local:9090 + prometheus: + enabled: false + grafana + enabled: false + grafanaUrl: http://kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local + ``` +- Step 2: Install linkerd viz extension helm ```shell - Linkerd core checks - =================== - - kubernetes-api - -------------- - √ can initialize the client - √ can query the Kubernetes API - - kubernetes-version - ------------------ - √ is running the minimum Kubernetes API version - √ is running the minimum kubectl version - - linkerd-existence - ----------------- - √ 'linkerd-config' config map exists - √ heartbeat ServiceAccount exist - √ control plane replica sets are ready - √ no unschedulable pods - √ control plane pods are ready - √ cluster networks contains all node podCIDRs - - linkerd-config - -------------- - √ control plane Namespace exists - √ control plane ClusterRoles exist - √ control plane ClusterRoleBindings exist - √ control plane ServiceAccounts exist - √ control plane CustomResourceDefinitions exist - √ control plane MutatingWebhookConfigurations exist - √ control plane ValidatingWebhookConfigurations exist - - linkerd-identity - ---------------- - √ certificate config is valid - √ trust anchors are using supported crypto algorithm - √ trust anchors are within their validity period - √ trust anchors are valid for at least 60 days - √ issuer cert is using supported crypto algorithm - √ issuer cert is within its validity period - √ issuer cert is valid for at least 60 days - √ issuer cert is issued by the trust anchor - - linkerd-webhooks-and-apisvc-tls - ------------------------------- - √ proxy-injector webhook has valid cert - √ proxy-injector cert is valid for at least 60 days - √ sp-validator webhook has valid cert - √ sp-validator cert is valid for at least 60 days - √ policy-validator webhook has valid cert - √ policy-validator cert is valid for at least 60 days - - linkerd-version - --------------- - √ can determine the latest version - √ cli is up-to-date - - control-plane-version - --------------------- - √ can retrieve the control plane version - √ control plane is up-to-date - √ control plane and cli versions match - - linkerd-control-plane-proxy - --------------------------- - √ control plane proxies are healthy - √ control plane proxies are up-to-date - √ control plane proxies and cli versions match - - Status check results are √ - - ``` \ No newline at end of file + helm install linkerd-viz -n linkerd-viz + + ``` + By default, helm chart creates `linkerd-viz` namespace where all components are deployed. + +- Step 3: Exposing Linkerd Viz dashboard + + Ingress controller rule can be defined to grant access to Viz dashboard. Linkerd documentation contains information about how to do it using [Traefik as Ingress Controller](https://linkerd.io/2.11/tasks/exposing-dashboard/#traefik) + From 5a66245892b8b1875692ad075aadac84dcf607d7 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Thu, 10 Mar 2022 18:51:13 +0100 Subject: [PATCH 12/45] Including installation of linkerd cli --- roles/linkerd/tasks/install_linkerd_cli.yml | 10 ++++++++++ roles/linkerd/tasks/main.yml | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 roles/linkerd/tasks/install_linkerd_cli.yml diff --git a/roles/linkerd/tasks/install_linkerd_cli.yml b/roles/linkerd/tasks/install_linkerd_cli.yml new file mode 100644 index 00000000..212ccc7e --- /dev/null +++ b/roles/linkerd/tasks/install_linkerd_cli.yml @@ -0,0 +1,10 @@ +--- + +- name: Install linkerd cli + get_url: + url: "{{ linkerd_package_url }}" + dest: "{{ linkerd_bin }}" + owner: root + group: root + mode: '0755' + # checksum: "{{ linkerd_checksum }}" diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index e6043818..16688f9a 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -1,5 +1,8 @@ --- +- name: Install linkerd CLI + include_tasks: install_linkerd_cli.yml + - name: Create linkerd namespace. kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" From 4d4b9dffcc568cc1c7d9c9d48edb0b842580bbd5 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Thu, 10 Mar 2022 18:52:11 +0100 Subject: [PATCH 13/45] Adding linkerd-viz ingress rule --- group_vars/all.yml | 1 + roles/linkerd/tasks/linkerd_extensions.yml | 11 +++- .../templates/linkerd_viz_ingress.yml.j2 | 59 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 roles/linkerd/templates/linkerd_viz_ingress.yml.j2 diff --git a/group_vars/all.yml b/group_vars/all.yml index 5c1619b5..8dbf6706 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -23,6 +23,7 @@ grafana_dashboard_dns: "grafana.{{ dns_domain }}" prometheus_dashboard_dns: "prometheus.{{ dns_domain }}" alertmanager_dashboard_dns: "alertmanager.{{ dns_domain }}" elasticsearch_dns: "elasticsearch.{{ dns_domain }}" +linkerd_dashboard_dns: "linkerd.{{ dns_domain }}" ####################### # backup configuration diff --git a/roles/linkerd/tasks/linkerd_extensions.yml b/roles/linkerd/tasks/linkerd_extensions.yml index 1bc46d62..f728b669 100644 --- a/roles/linkerd/tasks/linkerd_extensions.yml +++ b/roles/linkerd/tasks/linkerd_extensions.yml @@ -11,7 +11,8 @@ kubernetes.core.helm: name: linkerd-viz chart_ref: linkerd/linkerd-viz - release_namespace: "{{ k3s_linkerd_namespace }}" + release_namespace: "{{ k3s_linkerd_namespace }}-viz" + create_namespace: true update_repo_cache: true state: present release_values: @@ -21,3 +22,11 @@ grafana: enabled: false grafanaUrl: http://kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local + + +- name: Create Ingress for linkerd-viz dashboard + kubernetes.core.k8s: + definition: "{{ lookup('template', 'templates/' + item ) }}" + state: present + with_items: + - linkerd_viz_ingress.yml.j2 diff --git a/roles/linkerd/templates/linkerd_viz_ingress.yml.j2 b/roles/linkerd/templates/linkerd_viz_ingress.yml.j2 new file mode 100644 index 00000000..4f16ebf3 --- /dev/null +++ b/roles/linkerd/templates/linkerd_viz_ingress.yml.j2 @@ -0,0 +1,59 @@ +--- +# HTTPS Ingress +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: linkerd-viz-ingress + namespace: {{ k3s_linkerd_viz_namespace }} + annotations: + # HTTPS as entry point + traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Enable TLS + traefik.ingress.kubernetes.io/router.tls: "true" + # Use Basic Auth Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd + # Enable cert-manager to create automatically the SSL certificate and store in Secret + cert-manager.io/cluster-issuer: self-signed-issuer + cert-manager.io/common-name: linkerd +spec: + tls: + - hosts: + - {{ linkerd_dashboard_dns }} + secretName: linkerd-viz-tls + rules: + - host: {{ linkerd_dashboard_dns }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: web + port: + number: 8084 + +--- +# http ingress for http->https redirection +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: linkerd-viz-redirect + namespace: {{ k3s_linkerd_viz_namespace }} + annotations: + # Use redirect Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-redirect@kubernetescrd + # HTTP as entrypoint + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + rules: + - host: {{ linkerd_dashboard_dns }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: web + port: + number: 8084 From 10ed18dfbeb0109d921d8468758c59f87ff629b1 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Thu, 10 Mar 2022 18:53:31 +0100 Subject: [PATCH 14/45] Adding Prometheus PodMonitoring resources for linkerd --- .../templates/linkerd_viz_prometheus.yml.j2 | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 diff --git a/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 b/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 new file mode 100644 index 00000000..9b2f9ad1 --- /dev/null +++ b/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 @@ -0,0 +1,100 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-controller + namespace: {{ k3s_monitoring_namespace }} +spec: + namespaceSelector: + matchNames: + - linkerd-viz + - linkerd + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_container_port_name + action: keep + regex: admin-http + - sourceLabels: + - __meta_kubernetes_pod_container_name + action: replace + targetLabel: component +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-service-mirror + namespace: {{ k3s_monitoring_namespace }} +spec: + namespaceSelector: + any: true + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_label_linkerd_io_control_plane_component + - __meta_kubernetes_pod_container_port_name + action: keep + regex: linkerd-service-mirror;admin-http$ + - sourceLabels: + - __meta_kubernetes_pod_container_name + action: replace + targetLabel: component +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-proxy + namespace: {{ k3s_monitoring_namespace }} +spec: + namespaceSelector: + any: true + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_container_name + - __meta_kubernetes_pod_container_port_name + - __meta_kubernetes_pod_label_linkerd_io_control_plane_ns + action: keep + regex: ^linkerd-proxy;linkerd-admin;linkerd$ + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod + - sourceLabels: [__meta_kubernetes_pod_label_linkerd_io_proxy_job] + action: replace + targetLabel: k8s_job + - action: labeldrop + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_job + - action: labelmap + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_(.+) + - action: labeldrop + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_linkerd_io_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + replacement: __tmp_pod_label_$1 + - action: labelmap + regex: __tmp_pod_label_linkerd_io_(.+) + replacement: __tmp_pod_label_$1 + - action: labeldrop + regex: __tmp_pod_label_linkerd_io_(.+) + - action: labelmap + regex: __tmp_pod_label_(.+) \ No newline at end of file From f5c50462569d7235ce4f562a352a2be5bd14c67c Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Fri, 11 Mar 2022 16:16:54 +0100 Subject: [PATCH 15/45] Checking previous linkerd cli installation and becoming root --- roles/linkerd/tasks/main.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index 16688f9a..50819d5f 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -1,7 +1,17 @@ --- +- name: Check Linkerd CLI installation status + stat: + path: "{{ linkerd_bin }}" + register: _linkerd_bin + - name: Install linkerd CLI include_tasks: install_linkerd_cli.yml + args: + apply: + become: true + when: + - not _linkerd_bin.stat.exists - name: Create linkerd namespace. kubernetes.core.k8s: From 6a86b570ec010c3b18cf504de0a366db3292df76 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Fri, 11 Mar 2022 18:50:10 +0100 Subject: [PATCH 16/45] Updating linkerd-viz deployment to solve dns re-binding issue and enable Prometheus integration --- roles/linkerd/tasks/linkerd_extensions.yml | 29 ++++++++++++++----- .../templates/linkerd_viz_namespace.yml.j2 | 10 +++++++ 2 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 roles/linkerd/templates/linkerd_viz_namespace.yml.j2 diff --git a/roles/linkerd/tasks/linkerd_extensions.yml b/roles/linkerd/tasks/linkerd_extensions.yml index f728b669..511b11bf 100644 --- a/roles/linkerd/tasks/linkerd_extensions.yml +++ b/roles/linkerd/tasks/linkerd_extensions.yml @@ -1,27 +1,33 @@ --- -# - name: Create linkerd-viz namespace. -# kubernetes.core.k8s: -# name: "{{ k3s_linkerd_namespace }}-viz" -# api_version: v1 -# kind: Namespace -# state: present +- name: Create linkerd-viz namespace. + kubernetes.core.k8s: + definition: "{{ lookup('template', 'templates/' + item ) }}" + state: present + with_items: + - linkerd_viz_namespace.yml.j2 - name: Deploy Linkerd-viz Helm chart. kubernetes.core.helm: name: linkerd-viz chart_ref: linkerd/linkerd-viz release_namespace: "{{ k3s_linkerd_namespace }}-viz" - create_namespace: true update_repo_cache: true state: present release_values: + # Skip namespace creation + installNamespace: false + # External Prometheus prometheusUrl: http://kube-prometheus-stack-prometheus.k3s-monitoring.svc.cluster.local:9090 prometheus: enabled: false + # External Grafana grafana: enabled: false - grafanaUrl: http://kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local + grafanaUrl: kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local:80 + # Disabling DNS rebinding protection + dashboard: + enforcedHostRegexp: .* - name: Create Ingress for linkerd-viz dashboard @@ -30,3 +36,10 @@ state: present with_items: - linkerd_viz_ingress.yml.j2 + +- name: Create Prometheus configuration + kubernetes.core.k8s: + definition: "{{ lookup('template', 'templates/' + item ) }}" + state: present + with_items: + - linkerd_viz_prometheus.yml.j2 diff --git a/roles/linkerd/templates/linkerd_viz_namespace.yml.j2 b/roles/linkerd/templates/linkerd_viz_namespace.yml.j2 new file mode 100644 index 00000000..7581be44 --- /dev/null +++ b/roles/linkerd/templates/linkerd_viz_namespace.yml.j2 @@ -0,0 +1,10 @@ +--- +kind: Namespace +apiVersion: v1 +metadata: + name: {{ k3s_linkerd_namespace }}-viz + annotations: + linkerd.io/inject: enabled + config.linkerd.io/proxy-await: "enabled" + labels: + linkerd.io/extension: viz From fdf41a01eafab24c775c92f3be40b738b47315db Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Fri, 11 Mar 2022 18:56:42 +0100 Subject: [PATCH 17/45] Updating linkerd-viz installation documentation --- docs/_docs/service-mesh.md | 213 +++++++++++++++++++++++++++++++++++-- 1 file changed, 204 insertions(+), 9 deletions(-) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index 54fda628..955063d8 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -193,29 +193,224 @@ This extension installs the following components into a new namespace linkerd-vi - A Grafana instance - metrics-api, tap, tap-injector, and web components -Since we have already our monitoring deployment, we will configure Viz extension to use the existing Prometheus and Grafana instance. See linkerd documentation ["Bringing your own Prometheus"](https://linkerd.io/2.11/tasks/external-prometheus/) +Since we have already our monitoring deployment, we will configure Viz extension to use the existing Prometheus and Grafana instance. See linkerd documentation ["Bringing your own Prometheus"](https://linkerd.io/2.11/tasks/external-prometheus/). -- Step 1: Prepare values.yml for Viz helm chart installation +linkerd-viz dashboard (web component) will be exposed configuring a Ingress resource. By default linkerd-viz dashboard has a DNS rebinding protection. Since Traefik does not support a mechanism for ovewritting Host header, the Host validation regexp that the dashboard server uses need to be tweaked using Helm chart paramenter `enforcedHostRegexp`. See document ["Exposing dashboard - DNS Rebinding Protection"](https://linkerd.io/2.11/tasks/exposing-dashboard/#dns-rebinding-protection) for more details. +- Step 1: Create namespace + + By default, the helm chart creates a namespace `linkerd-viz` with annotations `linkerd.io/inject: enabled` and `config.linkerd.io/proxy-await: "enabled"` + + Since we are creating the namespace we need to provide the same labels and annotations. + + Create namespace manifest file `linkerd_viz_namespace.yml` + + ```yml + kind: Namespace + apiVersion: v1 + metadata: + name: linkerd-viz + annotations: + linkerd.io/inject: enabled + config.linkerd.io/proxy-await: "enabled" + labels: + linkerd.io/extension: viz + ``` + + And apply the manifest with the following command: + + + ```shell + kubectl apply -f linkerd_viz_namespace.yml + + ``` + + +- Step 2: Prepare values.yml for Viz helm chart installation + ```yml + # Skip namespace creation + installNamespace: false + # Disable Prometheus installation and configure external Prometheus URL prometheusUrl: http://kube-prometheus-stack-prometheus.k3s-monitoring.svc.cluster.local:9090 prometheus: enabled: false - grafana + # Disable Grafana installation and configure external Grafana URL + grafana: enabled: false - grafanaUrl: http://kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local - ``` -- Step 2: Install linkerd viz extension helm + grafanaUrl: kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local:80 + # Disabling DNS rebinding protection + dahsboard: + enforcedHostRegexp: ".*" + ``` + +- Step 3: Install linkerd viz extension helm ```shell - helm install linkerd-viz -n linkerd-viz + helm install linkerd-viz -n linkerd-viz -f values.yml ``` By default, helm chart creates `linkerd-viz` namespace where all components are deployed. -- Step 3: Exposing Linkerd Viz dashboard - Ingress controller rule can be defined to grant access to Viz dashboard. Linkerd documentation contains information about how to do it using [Traefik as Ingress Controller](https://linkerd.io/2.11/tasks/exposing-dashboard/#traefik) +- Step 4: Exposing Linkerd Viz dashboard + + Ingress controller rule can be defined to grant access to Viz dashboard. + + In case of Traefik, it is not needed to mesh Traefik deployment to grant access + + Linkerd documentation contains information about how to configure [Traefik as Ingress Controller](https://linkerd.io/2.11/tasks/exposing-dashboard/#traefik). To enable mTLS in the communication from Ingress Controller, Traefik deployment need to be meshed using "ingress" proxy injection. + +- Step 5: Configure Prometheus to scrape metrics from linkerd + + Create `linkerd-prometheus.yml` + + + ```yml + --- + apiVersion: monitoring.coreos.com/v1 + kind: PodMonitor + metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-controller + namespace: k3s-monitoring + spec: + namespaceSelector: + matchNames: + - linkerd-viz + - linkerd + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_container_port_name + action: keep + regex: admin-http + - sourceLabels: + - __meta_kubernetes_pod_container_name + action: replace + targetLabel: component + --- + apiVersion: monitoring.coreos.com/v1 + kind: PodMonitor + metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-service-mirror + namespace: k3s-monitoring + spec: + namespaceSelector: + any: true + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_label_linkerd_io_control_plane_component + - __meta_kubernetes_pod_container_port_name + action: keep + regex: linkerd-service-mirror;admin-http$ + - sourceLabels: + - __meta_kubernetes_pod_container_name + action: replace + targetLabel: component + --- + apiVersion: monitoring.coreos.com/v1 + kind: PodMonitor + metadata: + labels: + app: linkerd + release: kube-prometheus-stack + name: linkerd-proxy + namespace: k3s-monitoring + spec: + namespaceSelector: + any: true + selector: + matchLabels: {} + podMetricsEndpoints: + - relabelings: + - sourceLabels: + - __meta_kubernetes_pod_container_name + - __meta_kubernetes_pod_container_port_name + - __meta_kubernetes_pod_label_linkerd_io_control_plane_ns + action: keep + regex: ^linkerd-proxy;linkerd-admin;linkerd$ + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod + - sourceLabels: [__meta_kubernetes_pod_label_linkerd_io_proxy_job] + action: replace + targetLabel: k8s_job + - action: labeldrop + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_job + - action: labelmap + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_(.+) + - action: labeldrop + regex: __meta_kubernetes_pod_label_linkerd_io_proxy_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_linkerd_io_(.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + replacement: __tmp_pod_label_$1 + - action: labelmap + regex: __tmp_pod_label_linkerd_io_(.+) + replacement: __tmp_pod_label_$1 + - action: labeldrop + regex: __tmp_pod_label_linkerd_io_(.+) + - action: labelmap + regex: __tmp_pod_label_(.+) + ``` + + Apply manifest file + + ```shell + kubectl apply -f linkerd-prometheus.yml + + ``` + + {{site.data.alerts.note}} + + This is a direct translation of the [Prometheus' scrape configuration defined in linkerd documentation](https://linkerd.io/2.11/tasks/external-prometheus/#prometheus-scrape-configuration) to Prometheus Operator based configuration (ServiceMonitor and PodMonitor CRDs). + + {{site.data.alerts.end}} + +- Step 6: Load linkerd dashboards into Grafana + + Linkerd available Grafana dashboards are located in linkerd2 repository: [linkerd grafana dashboards](https://github.com/linkerd/linkerd2/tree/main/grafana/dashboards) + + +## Configure Ingress Controller + +Linkerd does not come with a Ingress Controller. Existing ingress controller can be integrated with Linkerd doing the following: + - Configuring Ingress Controller to support Linkerd. + - Meshing Ingress Controller pods so that they have the Linkerd proxy installed. + +In general, Linkerd can be used with any ingress controller. In order for Linkerd to properly apply features such as route-based metrics and traffic splitting, Linkerd needs the IP/port of the Kubernetes Service. However, by default, many ingresses do their own endpoint selection and pass the IP/port of the destination Pod, rather than the Service as a whole. + +More details in linkerd documentation ["Ingress Traffic"](https://linkerd.io/2.11/tasks/using-ingress/). + + +### Meshing Traefik + +In order to integrate Traefik with Linkerd the following must be done: + +- Traefik should be meshed with ingress mode enabled, i.e. with the `linkerd.io/inject: ingress` annotation rather than the default enabled. + +- Configure Ingress rules to use a Traefik's Middleware inserting a specific header, `l5d-dst-override` pointing to the Service IP/Port (using internal DNS name: `..svc.cluster.local` + +Linkerd-proxy configured in ingress mode will take `ld5-dst-override` HTTP header for routing the traffic to the service. + +{{site.data.alerts.important}} +Since for the routing linkerd is using a HTTP header, only HTTP protocol is supported and not HTTPS. +{{site.data.alerts.end}} From f730cac440f184b38718e80c12a0640a36105194 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sat, 12 Mar 2022 13:26:26 +0100 Subject: [PATCH 18/45] Factoring grafana dashboard task to create all json dashboards from directory --- .../tasks/configure_grafana_dashboards.yml | 2 +- roles/prometheus/tasks/main.yml | 23 ++++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/roles/prometheus/tasks/configure_grafana_dashboards.yml b/roles/prometheus/tasks/configure_grafana_dashboards.yml index 3d116741..21e145fa 100644 --- a/roles/prometheus/tasks/configure_grafana_dashboards.yml +++ b/roles/prometheus/tasks/configure_grafana_dashboards.yml @@ -1,5 +1,5 @@ --- -- name: Configure Dashboard +- name: "Configure Dashboard {{ dashboard_name }}" kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/grafana_dashboard.yml.j2' ) }}" state: present diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index af29b309..7feda228 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -92,22 +92,9 @@ - name: Configure Grafana Dashboards include_tasks: configure_grafana_dashboards.yml vars: - dashboard_name: "{{ item.name }}" + dashboard_name: "{{ item | basename | splitext | first }}" dashboard_file: - name: "{{ item.file }}" - content: "{{ lookup('file', 'files/' + item.file ) | string }}" - with_items: - - name: dashboard-traefik - file: traefik-dashboard.json - - name: dashboard-longhorn - file: longhorn-dashboard.json - - name: k3s-controller-manager - file: k3s-controllermanager-dashboard.json - - name: k3s-scheduler - file: k3s-scheduler-dashboard.json - - name: k3s-proxy - file: k3s-proxy-dashboard.json - - name: velero - file: velero-dashboard.json - - name: minio - file: minio-dashboard.json + name: "{{ item | basename }}" + content: "{{ lookup('file', item ) | string }}" + with_fileglob: + - "files/*" From 0591e4240be77e7f4bdf860efe6d963b5c7a31ea Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 14 Mar 2022 19:16:10 +0100 Subject: [PATCH 19/45] Adding waiting for pods to start tasks to enable one-go deploymentt --- k3s_deploy.yml | 8 ++++---- roles/backup/velero/tasks/main.yml | 5 +++++ roles/certmanager/tasks/main.yml | 6 ++++++ roles/linkerd/tasks/linkerd_extensions.yml | 5 +++++ roles/linkerd/tasks/main.yml | 10 ++++++---- roles/logging/k3s/tasks/install_fluentbit.yml | 6 ++++++ roles/logging/k3s/tasks/main.yml | 16 ++++++++++++++++ roles/longhorn/tasks/main.yml | 12 ++++++++++++ roles/metallb/tasks/main.yml | 6 ++++++ roles/prometheus/tasks/main.yml | 8 +++++++- 10 files changed, 73 insertions(+), 9 deletions(-) diff --git a/k3s_deploy.yml b/k3s_deploy.yml index dd0c5866..da3bd423 100644 --- a/k3s_deploy.yml +++ b/k3s_deploy.yml @@ -39,18 +39,18 @@ roles: - role: metallb tags: ['metallb'] - - role: traefik - tags: ['traefik'] - role: certmanager tags: ['certmanager'] + - role: traefik + tags: ['traefik'] + - role: backup/velero + tags: ['backup'] - role: longhorn tags: ['longhorn'] - role: prometheus tags: ['monitoring'] - role: logging/k3s tags: ['logging'] - - role: backup/velero - tags: ['backup'] - role: linkerd tags: ['linkerd'] diff --git a/roles/backup/velero/tasks/main.yml b/roles/backup/velero/tasks/main.yml index 936f2c7a..40d33677 100644 --- a/roles/backup/velero/tasks/main.yml +++ b/roles/backup/velero/tasks/main.yml @@ -70,6 +70,11 @@ aws_access_key_id: "{{ minio_velero_user }}" aws_secret_access_key: "{{ minio_velero_key }}" +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_velero_namespace }} --all --timeout=600s" + register: velero_pods_ready + changed_when: false - name: Create Full backup Schedule policy kubernetes.core.k8s: diff --git a/roles/certmanager/tasks/main.yml b/roles/certmanager/tasks/main.yml index 5eb1c18e..e5811dd9 100644 --- a/roles/certmanager/tasks/main.yml +++ b/roles/certmanager/tasks/main.yml @@ -21,6 +21,12 @@ release_values: installCRDs: true +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_certmanager_namespace }} --all --timeout=600s" + register: certmanager_pods_ready + changed_when: false + - name: Configure Cluster Issuers kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" diff --git a/roles/linkerd/tasks/linkerd_extensions.yml b/roles/linkerd/tasks/linkerd_extensions.yml index 511b11bf..882b17ba 100644 --- a/roles/linkerd/tasks/linkerd_extensions.yml +++ b/roles/linkerd/tasks/linkerd_extensions.yml @@ -29,6 +29,11 @@ dashboard: enforcedHostRegexp: .* +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_linkerd_namespace }}-viz --all --timeout=600s" + register: linkerd_viz_pods_ready + changed_when: false - name: Create Ingress for linkerd-viz dashboard kubernetes.core.k8s: diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index 50819d5f..b074b34e 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -34,10 +34,6 @@ -o jsonpath="{.data.ca\.crt}" | base64 -d register: output_ca_crt -- name: debugging - debug: - var: output_ca_crt - - name: Add Linkerd stable repo. kubernetes.core.helm_repository: name: linkerd @@ -57,5 +53,11 @@ issuer: scheme: kubernetes.io/tls +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_linkerd_namespace }} --all --timeout=600s" + register: linkerd_pods_ready + changed_when: false + - name: Install linkerd extensions include_tasks: linkerd_extensions.yml diff --git a/roles/logging/k3s/tasks/install_fluentbit.yml b/roles/logging/k3s/tasks/install_fluentbit.yml index 287b431c..738cb703 100644 --- a/roles/logging/k3s/tasks/install_fluentbit.yml +++ b/roles/logging/k3s/tasks/install_fluentbit.yml @@ -13,3 +13,9 @@ update_repo_cache: true state: present values: "{{ lookup('template', 'templates/fluentbit_helm_values.yml.j2') | from_yaml }}" + +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_logging_namespace }} --all --timeout=600s" + register: fluentbit_pods_ready + changed_when: false diff --git a/roles/logging/k3s/tasks/main.yml b/roles/logging/k3s/tasks/main.yml index 341cc2f9..e1eb40c5 100644 --- a/roles/logging/k3s/tasks/main.yml +++ b/roles/logging/k3s/tasks/main.yml @@ -28,6 +28,12 @@ update_repo_cache: true state: present +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace=elastic-system --all --timeout=600s" + register: eck_pods_ready + changed_when: false + - name: Deploy elasticsearch and kibana kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" @@ -38,6 +44,16 @@ - kibana.yml.j2 - kibana_ingress.yml.j2 +- name: Wait for Elastic search to be deployed + command: + cmd: "kubectl get elastic -o jsonpath='{.items[*].status.phase}' -n {{ k3s_logging_namespace }}" + register: elastic + changed_when: false + until: + - '"Ready" in elastic.stdout' + retries: 10 + delay: 60 + - name: Deploy fluentd kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" diff --git a/roles/longhorn/tasks/main.yml b/roles/longhorn/tasks/main.yml index 80546bd2..ff5df557 100644 --- a/roles/longhorn/tasks/main.yml +++ b/roles/longhorn/tasks/main.yml @@ -42,6 +42,18 @@ when: not longhorn_s3_backup +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_longhorn_namespace }} --all --timeout=600s" + register: longhorn_pods_ready + changed_when: false + +- name: Repeat task since more pods are created + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_longhorn_namespace }} --all --timeout=600s" + register: longhorn_pods_ready + changed_when: false + - name: Create Ingress rule for Longhorn UI and Recurring backup job kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" diff --git a/roles/metallb/tasks/main.yml b/roles/metallb/tasks/main.yml index 29f34ae8..546c6d7c 100644 --- a/roles/metallb/tasks/main.yml +++ b/roles/metallb/tasks/main.yml @@ -25,3 +25,9 @@ protocol: layer2 addresses: - "{{ k3s_external_ip_range }}" + +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_metallb_namespace }} --all --timeout=600s" + register: metallb_pods_ready + changed_when: false diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index 7feda228..54da9db4 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -54,6 +54,12 @@ kubeEtcd: enabled: false +- name: Wait for pods to be ready + command: + cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_monitoring_namespace }} --all --timeout=600s" + register: prometheus_pods_ready + changed_when: false + - name: Create metrics services (K3s and Minio) kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" @@ -97,4 +103,4 @@ name: "{{ item | basename }}" content: "{{ lookup('file', item ) | string }}" with_fileglob: - - "files/*" + - "files/*" From e987ec57410315a380d311ac863823cbe5f26816 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 14 Mar 2022 19:17:41 +0100 Subject: [PATCH 20/45] Changing linkerd prometheus configuration to match linkerd-viz grafana dashboards configuration --- .../templates/linkerd_viz_prometheus.yml.j2 | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 b/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 index 9b2f9ad1..06200c07 100644 --- a/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 +++ b/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 @@ -15,7 +15,9 @@ spec: selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_container_port_name action: keep @@ -24,6 +26,13 @@ spec: - __meta_kubernetes_pod_container_name action: replace targetLabel: component + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-controller + --- apiVersion: monitoring.coreos.com/v1 kind: PodMonitor @@ -39,7 +48,9 @@ spec: selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_label_linkerd_io_control_plane_component - __meta_kubernetes_pod_container_port_name @@ -49,6 +60,12 @@ spec: - __meta_kubernetes_pod_container_name action: replace targetLabel: component + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-service-mirror --- apiVersion: monitoring.coreos.com/v1 kind: PodMonitor @@ -64,7 +81,9 @@ spec: selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_container_name - __meta_kubernetes_pod_container_port_name @@ -97,4 +116,10 @@ spec: - action: labeldrop regex: __tmp_pod_label_linkerd_io_(.+) - action: labelmap - regex: __tmp_pod_label_(.+) \ No newline at end of file + regex: __tmp_pod_label_(.+) + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-proxy From d94a31c8d2042727be09baa5ef4d768982b64b9b Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 16 Mar 2022 16:43:37 +0100 Subject: [PATCH 21/45] Adding cert-manager picture --- docs/_docs/certmanager.md | 7 ++++--- docs/assets/img/cert-manager.png | Bin 0 -> 103732 bytes 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 docs/assets/img/cert-manager.png diff --git a/docs/_docs/certmanager.md b/docs/_docs/certmanager.md index 708a81c1..3a0eae00 100644 --- a/docs/_docs/certmanager.md +++ b/docs/_docs/certmanager.md @@ -7,8 +7,9 @@ last_modified_at: "08-03-2022" In the Kubernetes cluster, [Cert-Manager](https://cert-manager.io/docs/) can be used to automate the certificate management tasks (issue certificate request, renewals, etc.). Cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters, and simplifies the process of obtaining, renewing and using those certificates. -It can issue certificates from a variety of supported sources, including support for auto-signed certificates or use [Let's Encrypt](https://letsencrypt.org/) service to obtain validated SSL certificates. It will ensure certificates are valid and up to date, and attempt to renew certificates at a configured time before expiry. +It can issue certificates from a variety of supported sources, including support for auto-signed certificates or use [Let's Encrypt](https://letsencrypt.org/) service to obtain validated SSL certificates. It will ensure certificates are valid and up to date, and attempt to renew certificates at a configured time before expiry. It also keep up to date the associated Kuberentes Secrets storing key pairs used by Ingress resources when securing the incoming communications. +![picluster-certmanager](/assets/img/cert-manager.png) ## Cert-Manager certificates issuers @@ -26,7 +27,7 @@ We will use this Issuer for bootstrapping our custom CA. The CA issuer represents a Certificate Authority whereby its certificate and private key are stored inside the cluster as a Kubernetes Secret, and will be used to sign incoming certificate requests. This internal CA certificate can then be used to trust resulting signed certificates. -This issuer type is typically used in a Public Key Infrastructure (PKI) setup to secure your infrastructure components to establish mTLS or otherwise provide a means to issue certificates where you also own the private key. Signed certificates with this custom CA will not be trusted by clients, such a web browser, by default. +This issuer type is typically used in a private Public Key Infrastructure (PKI) setup to secure your infrastructure components to establish mTLS or otherwise provide a means to issue certificates where you also own the private key. Signed certificates with this custom CA will not be trusted by clients, such a web browser, by default. ### ACME issuers (Lets Encrypt) @@ -35,7 +36,7 @@ The ACME Issuer type represents a single account registered with the Automated C {{site.data.alerts.important}} -CertManager has been configured to have in the cluster a custom PKI (Public Key Infrastructure) using a self-signed CA to issue auto-signed certificates. +CertManager has been configured to have in the cluster a private PKI (Public Key Infrastructure) using a self-signed CA to issue auto-signed certificates. CertManager integration with Let's Encrypt has not been configured since my DNS provider does not suppport yet the API for automating DNS challenges. See open issue [#16](https://github.com/ricsanfre/pi-cluster/issues/16). diff --git a/docs/assets/img/cert-manager.png b/docs/assets/img/cert-manager.png new file mode 100644 index 0000000000000000000000000000000000000000..317aa6a7236082fb3f9f573da2a5628d6cbbe9f9 GIT binary patch literal 103732 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%0A* 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�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 Date: Wed, 16 Mar 2022 18:43:19 +0100 Subject: [PATCH 22/45] Adding service-mesh doc to navigation --- docs/_data/docs.yml | 3 ++ docs/_docs/service-mesh.md | 58 +++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/docs/_data/docs.yml b/docs/_data/docs.yml index 223b4dbd..4e42779a 100644 --- a/docs/_data/docs.yml +++ b/docs/_data/docs.yml @@ -29,6 +29,9 @@ - title: Cluster Backup docs: - backup +- title: Service Mesh + docs: + - service-mesh - title: Reference Docs docs: - k8s-networking diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index 955063d8..3d3c860b 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -5,14 +5,12 @@ description: How to deploy service-mesh architecture based on Linkerd. --- - ## Why a Service Mesh Introduce Service Mesh architecture to add observability, traffic management, and security capabilities to internal communications within the cluster. [Linkerd](https://linkerd.io/) will be deployed in the cluster as a Service Mesh implementation. - ## Why Linkerd and not Istio Most known Service Mesh implementation, [Istio](https://istio.io), is not currently supporting ARM64 architecture. @@ -21,7 +19,6 @@ Most known Service Mesh implementation, [Istio](https://istio.io), is not curren Moreover,instead of using [Envoy proxy](https://www.envoyproxy.io/), sidecar container to be deployed with any Pod as communication proxy, Linkerd uses its own ulta-light proxy which reduces the required resource footprint (cpu, memory) and makes it more suitable for Raspberry Pis. - ## Automatic mTLS By default, Linkerd automatically enables mutually-authenticated Transport Layer Security (mTLS) for all TCP traffic between meshed pods. This means that Linkerd adds authenticated, encrypted communication to your application with no extra work on your part. (And because the Linkerd control plane also runs on the data plane, this means that communication between Linkerd’s control plane components are also automatically secured via mTLS.) @@ -30,8 +27,6 @@ The Linkerd control plane contains a certificate authority (CA) called `identity On the control plane side, Linkerd maintains a set of credentials in the cluster: a **trust anchor**, and an **issuer certificate and private key**. While Linkerd automatically rotates the TLS certificates for data plane proxies every 24 hours, it does not rotate the TLS credentials and private key associated with the issuer. `cert-manager` can be used to initially generate this issuer certificate and private key and automatically rotate them. - - ## Linkerd Installation Installation procedure to use cert-manager and bein able to automatically rotate control-plane tls credentiasl is described in [linkerd documentation](https://linkerd.io/2.11/tasks/automatically-rotating-control-plane-tls-credentials/). @@ -86,7 +81,6 @@ Installation using `Helm` (Release 3): ```shell kubectl apply -f linkerd_namespace.yml - ``` - Step 4: Create `linkerd-identity-issuer` certificate resource @@ -138,7 +132,6 @@ Installation using `Helm` (Release 3): ```shell kubectl get secret linkerd-identity-issuer -o jsonpath="{.data.ca\.crt}" -n linkerd | base64 -d > ca.crt - ``` - Step 4: Install Linkerd @@ -164,7 +157,6 @@ Installation using `Helm` (Release 3): ```shell kubectl get configmap linkerd-config -o yaml -n linkerd - ``` The `identiyTrustAnchorPEM` key included in the Configmap should show th ca.crt extracted in Step 3 @@ -224,7 +216,6 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso ```shell kubectl apply -f linkerd_viz_namespace.yml - ``` @@ -250,7 +241,6 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso ```shell helm install linkerd-viz -n linkerd-viz -f values.yml - ``` By default, helm chart creates `linkerd-viz` namespace where all components are deployed. @@ -264,10 +254,9 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso Linkerd documentation contains information about how to configure [Traefik as Ingress Controller](https://linkerd.io/2.11/tasks/exposing-dashboard/#traefik). To enable mTLS in the communication from Ingress Controller, Traefik deployment need to be meshed using "ingress" proxy injection. - Step 5: Configure Prometheus to scrape metrics from linkerd - + Create `linkerd-prometheus.yml` - - + ```yml --- apiVersion: monitoring.coreos.com/v1 @@ -286,7 +275,9 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_container_port_name action: keep @@ -295,6 +286,12 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso - __meta_kubernetes_pod_container_name action: replace targetLabel: component + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-controller --- apiVersion: monitoring.coreos.com/v1 kind: PodMonitor @@ -310,7 +307,9 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_label_linkerd_io_control_plane_component - __meta_kubernetes_pod_container_port_name @@ -320,6 +319,12 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso - __meta_kubernetes_pod_container_name action: replace targetLabel: component + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-service-mirror --- apiVersion: monitoring.coreos.com/v1 kind: PodMonitor @@ -335,7 +340,9 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso selector: matchLabels: {} podMetricsEndpoints: - - relabelings: + - interval: 10s + scrapeTimeout: 10s + relabelings: - sourceLabels: - __meta_kubernetes_pod_container_name - __meta_kubernetes_pod_container_port_name @@ -369,25 +376,38 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso regex: __tmp_pod_label_linkerd_io_(.+) - action: labelmap regex: __tmp_pod_label_(.+) + # Replace job value + - source_labels: + - __address__ + action: replace + targetLabel: job + replacement: linkerd-proxy ``` - + Apply manifest file ```shell kubectl apply -f linkerd-prometheus.yml - ``` {{site.data.alerts.note}} This is a direct translation of the [Prometheus' scrape configuration defined in linkerd documentation](https://linkerd.io/2.11/tasks/external-prometheus/#prometheus-scrape-configuration) to Prometheus Operator based configuration (ServiceMonitor and PodMonitor CRDs). + Only two additional changes have been added to match linkerd's Grafana dashboards configuration: + + - Changing `job` label: Prometheus operator by default creates job names and job labels with `/`. Additional relabel rule has been added to remove namespace from job label matching Grafana dashboard's filters + + - Changing scraping `interval` and `timeout` to 10 seconds, instead default prometheus configuration (30 seconds). Linkerd's Grafana dashboards are configured to calculate rates from metrics in the last 30 seconds. + {{site.data.alerts.end}} - Step 6: Load linkerd dashboards into Grafana Linkerd available Grafana dashboards are located in linkerd2 repository: [linkerd grafana dashboards](https://github.com/linkerd/linkerd2/tree/main/grafana/dashboards) + Follow ["Provision dashboards automatically"](/docs/prometheus/#provisioning-dashboards-automatically) procedure to load Grafana dashboards automatically. + ## Configure Ingress Controller @@ -411,6 +431,6 @@ In order to integrate Traefik with Linkerd the following must be done: Linkerd-proxy configured in ingress mode will take `ld5-dst-override` HTTP header for routing the traffic to the service. {{site.data.alerts.important}} -Since for the routing linkerd is using a HTTP header, only HTTP protocol is supported and not HTTPS. +Since Traefik terminates TLS, this TLS traffic (e.g. HTTPS calls from outside the cluster) will pass through Linkerd as an opaque TCP stream and Linkerd will only be able to provide byte-level metrics for this side of the connection. The resulting HTTP or gRPC traffic to internal services, of course, will have the full set of metrics and mTLS support. {{site.data.alerts.end}} From 69ec0bcbe52d3952305bb9ef9857b00f3bff2c69 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Fri, 18 Mar 2022 16:27:56 +0100 Subject: [PATCH 23/45] Reviewing Grafana dashboard provisioning doc --- docs/_docs/monitoring.md | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/docs/_docs/monitoring.md b/docs/_docs/monitoring.md index 6db12018..c781ffa6 100644 --- a/docs/_docs/monitoring.md +++ b/docs/_docs/monitoring.md @@ -2,7 +2,7 @@ title: Monitoring (Prometheus) permalink: /docs/prometheus/ description: How to deploy kuberentes cluster monitoring solution based on Prometheus. Installation based on Prometheus Operator using kube-prometheus-stack project. -last_modified_at: "25-02-2022" +last_modified_at: "18-03-2022" --- Prometheus stack installation for kubernetes using Prometheus Operator can be streamlined using [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) project maintaned by the community. @@ -682,9 +682,13 @@ Minio dashboard sample can be donwloaded from [grafana.com](https://grafana.com) ## Provisioning Dashboards automatically -Custom Grafana dashboards can be added creating CongigMap resources, containing dashboard definition in json format, because kube-prometheus-stack configure by default grafana provisioning sidecar to check for new ConfigMaps containing label `grafana_dashboard` +Grafana dashboards can be provisioned automatically creating ConfigMap resources containing the dashboard json definition. For doing so, a provisioning sidecar container must be enabled. -The default chart values are: +Check grafana chart [documentation](https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards) explaining how to enable/use dashboard provisioning side-car. + +`kube-prometheus-stack` configure by default grafana provisioning sidecar to check for new ConfigMaps containing label `grafana_dashboard` + +This are the default helm chart values configuring the sidecar: ```yml grafana: @@ -700,9 +704,7 @@ grafana: labelValue: null ``` -Check grafana chart [documentation](https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards) explaining how to enable/use dashboard provisioning side-car. - -Config Map resouce containing the json dashboard definition as data +For provision automatically a new dashboard, a new `ConfigMap` resource must be created, labeled with `grafana_dashboard: 1` and containing as `data` the json file content. ```yml apiVersion: v1 @@ -713,12 +715,25 @@ metadata: grafana_dashboard: "1" data: dashboard.json: |- - [...] + [json_file_content] ``` -Due to Grafana´s [issue](https://github.com/grafana/grafana/issues/10786), json files need to be modified before inserting them into ConfigMap yaml file, in order to detect DS_PROMETHEUS datasource. See issue [#18](https://github.com/ricsanfre/pi-cluster/issues/18) -Modify each json file adding the following code to `templating` section +{{site.data.alerts.important}} + +Most of [Grafana community dashboards available](https://grafana.com/grafana/dashboards/) have been exported from a running Grafana and so they include a input variable (`DS_PROMETHEUS`) which represent a datasource which is referenced in all dashboard panels (`${DS_PROMETHEUS}`). See details in [Grafana export/import documentation](https://grafana.com/docs/grafana/latest/dashboards/export-import/). + +When automatic provisioning those exported dashboards following the procedure described above, an error appear when accessing them in the UI: + +``` +Datasource named ${DS_PROMETHEUS} was not found +``` + +There is an open [Grafana´s issue](https://github.com/grafana/grafana/issues/10786), asking for support of dasboard variables in dashboard provisioning. + +As a workarround, json files can be modified before inserting them into ConfigMap yaml file, in order to detect DS_PROMETHEUS datasource. See issue [#18](https://github.com/ricsanfre/pi-cluster/issues/18) for more details + +Modify each json file, containing `DS_PROMETHEUS` input variable within `__input` json key, adding the following code to `templating.list` key ```json "templating": { @@ -732,5 +747,7 @@ Modify each json file adding the following code to `templating` section "refresh": 1, "regex": "", "type": "datasource" - } + }, + ... ``` +{{site.data.alerts.end}} From 46be2c65288c9615eb25da0dc2700568fe1d6c04 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sat, 19 Mar 2022 13:16:42 +0100 Subject: [PATCH 24/45] Automating workarround issue #18 --- .../prometheus/files/longhorn-dashboard.json | 13 +- roles/prometheus/files/minio-dashboard.json | 5082 ++++++++--------- roles/prometheus/files/traefik-dashboard.json | 10 - roles/prometheus/files/velero-dashboard.json | 2148 +++---- .../tasks/configure_grafana_dashboards.yml | 45 +- roles/prometheus/tasks/main.yml | 7 +- .../templates/grafana_dashboard.yml.j2 | 4 +- 7 files changed, 3659 insertions(+), 3650 deletions(-) diff --git a/roles/prometheus/files/longhorn-dashboard.json b/roles/prometheus/files/longhorn-dashboard.json index 129924db..fa1190f8 100644 --- a/roles/prometheus/files/longhorn-dashboard.json +++ b/roles/prometheus/files/longhorn-dashboard.json @@ -2131,18 +2131,7 @@ "style": "dark", "tags": [], "templating": { - "list": [ - { - "hide": 0, - "label": "datasource", - "name": "DS_PROMETHEUS", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" - } - ] + "list": [] }, "time": { "from": "now-1h", diff --git a/roles/prometheus/files/minio-dashboard.json b/roles/prometheus/files/minio-dashboard.json index 0dec5e77..42fa5eb3 100644 --- a/roles/prometheus/files/minio-dashboard.json +++ b/roles/prometheus/files/minio-dashboard.json @@ -1,2684 +1,2674 @@ { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "panel", - "id": "bargauge", - "name": "Bar gauge", - "version": "" - }, - { - "type": "panel", - "id": "gauge", - "name": "Gauge", - "version": "" - }, - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.0.6" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.0.6" }, - "description": "MinIO Grafana Dashboard - https://min.io/", - "editable": true, - "gnetId": 13502, - "graphTooltip": 0, - "id": null, - "iteration": 1629787190164, - "links": [ + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + } + ], + "annotations": { + "list": [ { - "icon": "external link", - "includeVars": true, - "keepTime": true, - "tags": [ - "minio" - ], - "type": "dashboards" + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" } - ], - "panels": [ - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + ] + }, + "description": "MinIO Grafana Dashboard - https://min.io/", + "editable": true, + "gnetId": 13502, + "graphTooltip": 0, + "id": null, + "iteration": 1629787190164, + "links": [ + { + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "minio" + ], + "type": "dashboards" + } + ], + "panels": [ + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "percentage", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null } - ], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "dtdurations" + ] }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 3, - "x": 0, - "y": 0 + "unit": "dtdurations" }, - "id": 1, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 0, + "y": 0 + }, + "id": 1, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "time() - max(minio_node_process_starttime_seconds{job=\"$scrape_jobs\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{instance}}", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Uptime", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "time() - max(minio_node_process_starttime_seconds{job=\"$scrape_jobs\"})", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{instance}}", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Uptime", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "bytes" + ] }, - "overrides": [] + "unit": "bytes" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 3, - "y": 0 - }, - "id": 65, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 0 + }, + "id": 65, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "sum by (instance) (minio_s3_traffic_received_bytes{job=\"$scrape_jobs\"})", - "format": "table", - "hide": false, - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{instance}}", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total S3 Traffic Inbound", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "sum by (instance) (minio_s3_traffic_received_bytes{job=\"$scrape_jobs\"})", + "format": "table", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{instance}}", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total S3 Traffic Inbound", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "rgba(255, 255, 255, 0.97)", + "value": null } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(255, 255, 255, 0.97)", - "value": null - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 3, - "x": 6, - "y": 0 - }, - "id": 50, - "interval": "1m", - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + ] }, - "showThresholdLabels": false, - "showThresholdMarkers": true, - "text": {} + "unit": "bytes" }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "topk(1, sum(minio_cluster_capacity_usable_free_bytes{job=\"$scrape_jobs\"}) by (instance))", - "format": "time_series", - "instant": false, - "interval": "1m", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A", - "step": 300 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Current Usable Capacity", - "type": "gauge" + "overrides": [] }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 7, - "x": 9, - "y": 0 - }, - "hiddenSeries": false, - "id": 68, - "legend": { - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true + "gridPos": { + "h": 6, + "w": 3, + "x": 6, + "y": 0 + }, + "id": 50, + "interval": "1m", + "links": [], + "maxDataPoints": 100, + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "topk(1, sum(minio_cluster_capacity_usable_free_bytes{job=\"$scrape_jobs\"}) by (instance))", + "format": "time_series", + "instant": false, + "interval": "1m", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A", + "step": 300 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Usable Capacity", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 9, + "y": 0 + }, + "hiddenSeries": false, + "id": 68, + "legend": { + "avg": false, + "current": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(minio_bucket_usage_total_bytes{job=\"$scrape_jobs\"}) by (instance)", + "interval": "", + "legendFormat": "Used Capacity", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Data Usage Growth", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:419", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum(minio_bucket_usage_total_bytes{job=\"$scrape_jobs\"}) by (instance)", - "interval": "", - "legendFormat": "Used Capacity", - "refId": "A" + { + "$$hashKey": "object:420", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "semi-dark-red", + "value": 80 + } + ] } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Data Usage Growth", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 16, + "y": 0 + }, + "id": 52, + "links": [], + "options": { + "displayMode": "basic", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false }, - "yaxes": [ - { - "$$hashKey": "object:419", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:420", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "showUnfilled": false, + "text": {} }, - { - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "semi-dark-red", - "value": 80 + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "max by (range) (minio_bucket_objects_size_distribution{job=\"$scrape_jobs\"})", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{range}}", + "refId": "A", + "step": 300 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Object size distribution", + "type": "bargauge" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" } - ] + }, + "type": "special" } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 5, - "x": 16, - "y": 0 + "unit": "short" }, - "id": 52, - "links": [], - "options": { - "displayMode": "basic", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "showUnfilled": false, - "text": {} + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 61, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "max by (range) (minio_bucket_objects_size_distribution{job=\"$scrape_jobs\"})", - "format": "time_series", - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{range}}", - "refId": "A", - "step": 300 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Object size distribution", - "type": "bargauge" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "sum (minio_node_file_descriptor_open_total{job=\"$scrape_jobs\"})", + "format": "table", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Open FDs", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "bytes" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 21, - "y": 0 - }, - "id": 61, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 3 + }, + "id": 64, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "sum (minio_node_file_descriptor_open_total{job=\"$scrape_jobs\"})", - "format": "table", - "hide": false, - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Open FDs", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "sum by (instance) (minio_s3_traffic_sent_bytes{job=\"$scrape_jobs\"})", + "format": "table", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total S3 Traffic Outbound", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "bytes" + ] }, - "overrides": [] + "unit": "short" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 3, - "y": 3 - }, - "id": 64, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 3 + }, + "id": 62, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "sum by (instance) (minio_s3_traffic_sent_bytes{job=\"$scrape_jobs\"})", - "format": "table", - "hide": false, - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total S3 Traffic Outbound", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "sum without (server,instance) (minio_node_go_routine_total{job=\"$scrape_jobs\"})", + "format": "table", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Goroutines", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "short" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 21, - "y": 3 - }, - "id": 62, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 3, + "x": 0, + "y": 6 + }, + "id": 53, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "sum without (server,instance) (minio_node_go_routine_total{job=\"$scrape_jobs\"})", - "format": "table", - "hide": false, - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Goroutines", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_cluster_nodes_online_total{job=\"$scrape_jobs\"}", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Online Servers", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "short" }, - "gridPos": { - "h": 2, - "w": 3, - "x": 0, - "y": 6 - }, - "id": 53, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 3, + "x": 3, + "y": 6 + }, + "id": 9, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_cluster_nodes_online_total{job=\"$scrape_jobs\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Online Servers", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_cluster_disk_online_total{job=\"$scrape_jobs\"}", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Total online disks in MinIO Cluster", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Online Disks", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null + }, + { + "color": "dark-yellow", + "value": 75000000 + }, + { + "color": "dark-red", + "value": 100000000 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "short" }, - "gridPos": { - "h": 2, - "w": 3, - "x": 3, - "y": 6 + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 6 + }, + "id": 66, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "id": 9, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "count(count by (bucket) (minio_bucket_usage_total_bytes{job=\"$scrape_jobs\"}))", + "format": "time_series", + "instant": false, + "interval": "1m", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Number of Buckets", + "type": "stat" + }, + { + "aliasColors": { + "S3 Errors": "light-red", + "S3 Requests": "light-green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 9, + "y": 6 + }, + "hiddenSeries": false, + "id": 63, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum by (server) (rate(minio_s3_traffic_received_bytes{job=\"$scrape_jobs\"}[$__rate_interval]))", + "interval": "1m", + "intervalFactor": 2, + "legendFormat": "Data Received [{{server}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "S3 API Data Received Rate ", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:331", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_cluster_disk_online_total{job=\"$scrape_jobs\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "Total online disks in MinIO Cluster", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Online Disks", - "type": "stat" + { + "$$hashKey": "object:332", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "S3 Errors": "light-red", + "S3 Requests": "light-green" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "mappings": [ + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 6 + }, + "hiddenSeries": false, + "id": 70, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum by (server) (rate(minio_s3_traffic_sent_bytes{job=\"$scrape_jobs\"}[$__rate_interval]))", + "interval": "1m", + "intervalFactor": 2, + "legendFormat": "Data Sent [{{server}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "S3 API Data Sent Rate ", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:331", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:332", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "red", + "value": 80 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "dark-yellow", - "value": 75000000 - }, - { - "color": "dark-red", - "value": 100000000 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "short" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 6, - "y": 6 + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 3, + "x": 0, + "y": 8 + }, + "id": 69, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false }, - "id": 66, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_cluster_nodes_offline_total{job=\"$scrape_jobs\"}", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Offline Servers", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, - "text": {}, - "textMode": "auto" + "unit": "short" }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "count(count by (bucket) (minio_bucket_usage_total_bytes{job=\"$scrape_jobs\"}))", - "format": "time_series", - "instant": false, - "interval": "1m", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "Number of Buckets", - "type": "stat" + "overrides": [] }, - { - "aliasColors": { - "S3 Errors": "light-red", - "S3 Requests": "light-green" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 7, - "x": 9, - "y": 6 - }, - "hiddenSeries": false, - "id": 63, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, + "gridPos": { + "h": 2, + "w": 3, + "x": 3, + "y": 8 + }, + "id": 78, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", "values": false }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum by (server) (rate(minio_s3_traffic_received_bytes{job=\"$scrape_jobs\"}[$__rate_interval]))", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "Data Received [{{server}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "S3 API Data Received Rate ", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:331", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:332", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "text": {}, + "textMode": "auto" }, - { - "aliasColors": { - "S3 Errors": "light-red", - "S3 Requests": "light-green" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 6 - }, - "hiddenSeries": false, - "id": 70, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum by (server) (rate(minio_s3_traffic_sent_bytes{job=\"$scrape_jobs\"}[$__rate_interval]))", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "Data Sent [{{server}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "S3 API Data Sent Rate ", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:331", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:332", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_cluster_disk_offline_total{job=\"$scrape_jobs\"}", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 } - }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Offline Disks", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 2, - "w": 3, - "x": 0, - "y": 8 - }, - "id": 69, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_cluster_nodes_offline_total{job=\"$scrape_jobs\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Offline Servers", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "mappings": [ + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "dark-yellow", + "value": 75000000 + }, { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "dark-red", + "value": 100000000 } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] - }, - "gridPos": { - "h": 2, - "w": 3, - "x": 3, - "y": 8 + "unit": "short" }, - "id": 78, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 9 + }, + "id": 44, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_cluster_disk_offline_total{job=\"$scrape_jobs\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Total Offline Disks", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "mappings": [ + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "topk(1, sum(minio_bucket_usage_object_total{job=\"$scrape_jobs\"}) by (instance))", + "format": "time_series", + "instant": false, + "interval": "1m", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Number of Objects", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" + "color": "green", + "value": null } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "dark-yellow", - "value": 75000000 - }, - { - "color": "dark-red", - "value": 100000000 - } - ] - }, - "unit": "short" + ] }, - "overrides": [] + "unit": "ns" }, - "gridPos": { - "h": 3, - "w": 3, - "x": 6, - "y": 9 - }, - "id": 44, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "topk(1, sum(minio_bucket_usage_object_total{job=\"$scrape_jobs\"}) by (instance))", - "format": "time_series", - "instant": false, - "interval": "1m", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "Number of Objects", - "type": "stat" + "overrides": [] }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "ns" - }, - "overrides": [] - }, - "gridPos": { - "h": 2, - "w": 3, - "x": 0, - "y": 10 - }, - "id": 80, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" + "gridPos": { + "h": 2, + "w": 3, + "x": 0, + "y": 10 + }, + "id": 80, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_heal_time_last_activity_nano_seconds{job=\"$scrape_jobs\"}", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{server}}", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Time Since Last Heal Activity", - "type": "stat" + "text": {}, + "textMode": "auto" }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "ns" + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_heal_time_last_activity_nano_seconds{job=\"$scrape_jobs\"}", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{server}}", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Time Since Last Heal Activity", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" }, - "overrides": [] - }, - "gridPos": { - "h": 2, - "w": 3, - "x": 3, - "y": 10 - }, - "id": 81, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "last" - ], - "fields": "", - "values": false + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] }, - "text": {}, - "textMode": "auto" + "unit": "ns" }, - "pluginVersion": "8.0.6", - "targets": [ - { - "exemplar": true, - "expr": "minio_usage_last_activity_nano_seconds{job=\"$scrape_jobs\"}", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{server}}", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Time Since Last Scan Activity", - "type": "stat" + "overrides": [] }, - { - "aliasColors": { - "S3 Errors": "light-red", - "S3 Requests": "light-green" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 12 - }, - "hiddenSeries": false, - "id": 60, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, + "gridPos": { + "h": 2, + "w": 3, + "x": 3, + "y": 10 + }, + "id": 81, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", "values": false }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum by (server,api) (increase(minio_s3_requests_total{job=\"$scrape_jobs\"}[$__rate_interval]))", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "{{server,api}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "S3 API Request Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:331", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:332", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "exemplar": true, + "expr": "minio_usage_last_activity_nano_seconds{job=\"$scrape_jobs\"}", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{server}}", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 } + ], + "timeFrom": null, + "timeShift": null, + "title": "Time Since Last Scan Activity", + "type": "stat" + }, + { + "aliasColors": { + "S3 Errors": "light-red", + "S3 Requests": "light-green" }, - { - "aliasColors": { - "S3 Errors": "light-red", - "S3 Requests": "light-green" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 12, - "x": 12, - "y": 12 - }, - "hiddenSeries": false, - "id": 71, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum by (server,api) (increase(minio_s3_requests_errors_total{job=\"$scrape_jobs\"}[$__rate_interval]))", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "{{server,api}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "S3 API Request Error Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:331", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:332", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum by (server,api) (increase(minio_s3_requests_total{job=\"$scrape_jobs\"}[$__rate_interval]))", + "interval": "1m", + "intervalFactor": 2, + "legendFormat": "{{server,api}}", + "refId": "A" } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "S3 API Request Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": { - "10.13.1.25:9000 DELETE": "red", - "10.13.1.25:9000 GET": "green", - "10.13.1.25:9000 POST": "blue" - }, - "bars": true, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "description": "Total number of bytes received and sent among all MinIO server instances", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 10, - "fillGradient": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 22 - }, - "hiddenSeries": false, - "id": 17, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "rate(minio_inter_node_traffic_sent_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "Internode Bytes Received [{{server}}]", - "metric": "minio_http_requests_duration_seconds_count", - "refId": "A", - "step": 4 - }, - { - "exemplar": true, - "expr": "rate(minio_inter_node_traffic_received_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", - "interval": "", - "legendFormat": "Internode Bytes Sent [{{server}}]", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Internode Data Transfer", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:331", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:211", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:212", - "format": "s", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:332", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "S3 Errors": "light-red", + "S3 Requests": "light-green" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 22 - }, - "hiddenSeries": false, - "id": 84, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "sum by (instance) (minio_heal_objects_heal_total{job=\"$scrape_jobs\"})", - "interval": "", - "legendFormat": "Objects healed in current self heal run", - "refId": "A" - }, - { - "exemplar": true, - "expr": "sum by (instance) (minio_heal_objects_error_total{job=\"$scrape_jobs\"})", - "hide": false, - "interval": "", - "legendFormat": "Heal errors in current self heal run", - "refId": "B" - }, - { - "exemplar": true, - "expr": "sum by (instance) (minio_heal_objects_total{job=\"$scrape_jobs\"}) ", - "hide": false, - "interval": "", - "legendFormat": "Objects scanned in current self heal run", - "refId": "C" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Healing", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:846", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:847", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 12 + }, + "hiddenSeries": false, + "id": 71, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum by (server,api) (increase(minio_s3_requests_errors_total{job=\"$scrape_jobs\"}[$__rate_interval]))", + "interval": "1m", + "intervalFactor": 2, + "legendFormat": "{{server,api}}", + "refId": "A" } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "S3 API Request Error Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": {}, - "bars": true, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 31 - }, - "hiddenSeries": false, - "id": 77, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "rate(minio_node_process_cpu_total_seconds{job=\"$scrape_jobs\"}[$__rate_interval])", - "interval": "", - "legendFormat": "CPU Usage Rate [{{server}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Node CPU Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:331", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:1043", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:1044", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:332", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "10.13.1.25:9000 DELETE": "red", + "10.13.1.25:9000 GET": "green", + "10.13.1.25:9000 POST": "blue" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 31 - }, - "hiddenSeries": false, - "id": 76, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "minio_node_process_resident_memory_bytes{job=\"$scrape_jobs\"}", - "interval": "", - "legendFormat": "Memory Used [{{server}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Node Memory Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "Total number of bytes received and sent among all MinIO server instances", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 10, + "fillGradient": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "rate(minio_inter_node_traffic_sent_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Internode Bytes Received [{{server}}]", + "metric": "minio_http_requests_duration_seconds_count", + "refId": "A", + "step": 4 }, - "yaxes": [ - { - "$$hashKey": "object:1043", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:1044", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "exemplar": true, + "expr": "rate(minio_inter_node_traffic_received_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", + "interval": "", + "legendFormat": "Internode Bytes Sent [{{server}}]", + "refId": "B" } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Internode Data Transfer", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 40 - }, - "hiddenSeries": false, - "id": 74, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "minio_node_disk_used_bytes{job=\"$scrape_jobs\"}", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Used Capacity [{{server}}:{{disk}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Drive Used Capacity", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:211", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:381", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:382", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:212", + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 22 }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 40 - }, - "hiddenSeries": false, - "id": 82, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "minio_cluster_disk_free_inodes{job=\"$scrape_jobs\"}", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Free Inodes [{{server}}:{{disk}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Drives Free Inodes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + "hiddenSeries": false, + "id": 84, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum by (instance) (minio_heal_objects_heal_total{job=\"$scrape_jobs\"})", + "interval": "", + "legendFormat": "Objects healed in current self heal run", + "refId": "A" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "exemplar": true, + "expr": "sum by (instance) (minio_heal_objects_error_total{job=\"$scrape_jobs\"})", + "hide": false, + "interval": "", + "legendFormat": "Heal errors in current self heal run", + "refId": "B" }, - "yaxes": [ - { - "$$hashKey": "object:381", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:382", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "exemplar": true, + "expr": "sum by (instance) (minio_heal_objects_total{job=\"$scrape_jobs\"}) ", + "hide": false, + "interval": "", + "legendFormat": "Objects scanned in current self heal run", + "refId": "C" } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Healing", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": { - "Offline 10.13.1.25:9000": "dark-red", - "Total 10.13.1.25:9000": "blue" - }, - "bars": true, - "cacheTimeout": null, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "description": "Number of online disks per MinIO Server", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 48 - }, - "hiddenSeries": false, - "id": 11, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": false - }, - "lines": false, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "rate(minio_node_syscall_read_total{job=\"$scrape_jobs\"}[$__rate_interval])", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "Read Syscalls [{{server}}]", - "metric": "process_start_time_seconds", - "refId": "A", - "step": 60 - }, - { - "exemplar": true, - "expr": "rate(minio_node_syscall_write_total{job=\"$scrape_jobs\"}[$__rate_interval])", - "interval": "", - "legendFormat": "Write Syscalls [{{server}}]", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Node Syscalls", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:846", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:185", - "decimals": 0, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:186", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:847", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 31 }, - { - "aliasColors": { - "available 10.13.1.25:9000": "green", - "used 10.13.1.25:9000": "blue" - }, - "bars": false, - "cacheTimeout": null, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 48 - }, - "hiddenSeries": false, - "id": 8, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "minio_node_file_descriptor_open_total{job=\"$scrape_jobs\"}", - "interval": "", - "legendFormat": "Open FDs [{{server}}]", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Node File Descriptors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "hiddenSeries": false, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "rate(minio_node_process_cpu_total_seconds{job=\"$scrape_jobs\"}[$__rate_interval])", + "interval": "", + "legendFormat": "CPU Usage Rate [{{server}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Node CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1043", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:212", - "decimals": null, - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:213", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:1044", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 31 }, - { - "aliasColors": {}, - "bars": true, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_PROMETHEUS}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 57 + "hiddenSeries": false, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "minio_node_process_resident_memory_bytes{job=\"$scrape_jobs\"}", + "interval": "", + "legendFormat": "Memory Used [{{server}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Node Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1043", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "hiddenSeries": false, - "id": 73, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false + { + "$$hashKey": "object:1044", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "minio_node_disk_used_bytes{job=\"$scrape_jobs\"}", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Used Capacity [{{server}}:{{disk}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Drive Used Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:381", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true + { + "$$hashKey": "object:382", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 40 + }, + "hiddenSeries": false, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "minio_cluster_disk_free_inodes{job=\"$scrape_jobs\"}", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Free Inodes [{{server}}:{{disk}}]", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Drives Free Inodes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:381", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "percentage": false, - "pluginVersion": "8.0.6", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "exemplar": true, - "expr": "rate(minio_node_io_rchar_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Node RChar [{{server}}]", - "refId": "A" - }, - { - "exemplar": true, - "expr": "rate(minio_node_io_wchar_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", - "interval": "", - "legendFormat": "Node WChar [{{server}}]", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Node IO", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + { + "$$hashKey": "object:382", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Offline 10.13.1.25:9000": "dark-red", + "Total 10.13.1.25:9000": "blue" + }, + "bars": true, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "Number of online disks per MinIO Server", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 48 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "rate(minio_node_syscall_read_total{job=\"$scrape_jobs\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Read Syscalls [{{server}}]", + "metric": "process_start_time_seconds", + "refId": "A", + "step": 60 }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "exemplar": true, + "expr": "rate(minio_node_syscall_write_total{job=\"$scrape_jobs\"}[$__rate_interval])", + "interval": "", + "legendFormat": "Write Syscalls [{{server}}]", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Node Syscalls", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:185", + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true }, - "yaxes": [ - { - "$$hashKey": "object:381", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:382", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "$$hashKey": "object:186", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true } + ], + "yaxis": { + "align": false, + "alignLevel": null } - ], - "refresh": "10s", - "schemaVersion": 30, - "style": "dark", - "tags": [ - "minio" - ], - "templating": { - "list": [ + }, + { + "aliasColors": { + "available 10.13.1.25:9000": "green", + "used 10.13.1.25:9000": "blue" + }, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 48 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "minio_node_file_descriptor_open_total{job=\"$scrape_jobs\"}", + "interval": "", + "legendFormat": "Open FDs [{{server}}]", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Node File Descriptors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ { - "hide": 0, - "label": "datasource", - "name": "DS_PROMETHEUS", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" + "$$hashKey": "object:212", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true }, { - "allValue": null, - "current": {}, - "datasource": "${DS_PROMETHEUS}", - "definition": "label_values(job)", - "description": null, - "error": null, - "hide": 0, - "includeAll": true, + "$$hashKey": "object:213", + "format": "none", "label": null, - "multi": true, - "name": "scrape_jobs", - "options": [], - "query": { - "query": "label_values(job)", - "refId": "StandardVariableQuery" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" + "logBase": 1, + "max": null, + "min": "0", + "show": true } - ] - }, - "time": { - "from": "now-3h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "yaxis": { + "align": false, + "alignLevel": null + } }, - "timezone": "", - "title": "MinIO Dashboard", - "uid": "TgmJnqnnk", - "version": 18 - } \ No newline at end of file + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 57 + }, + "hiddenSeries": false, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "rate(minio_node_io_rchar_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Node RChar [{{server}}]", + "refId": "A" + }, + { + "exemplar": true, + "expr": "rate(minio_node_io_wchar_bytes{job=\"$scrape_jobs\"}[$__rate_interval])", + "interval": "", + "legendFormat": "Node WChar [{{server}}]", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Node IO", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:381", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:382", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 30, + "style": "dark", + "tags": [ + "minio" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(job)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "scrape_jobs", + "options": [], + "query": { + "query": "label_values(job)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "MinIO Dashboard", + "uid": "TgmJnqnnk", + "version": 18 +} \ No newline at end of file diff --git a/roles/prometheus/files/traefik-dashboard.json b/roles/prometheus/files/traefik-dashboard.json index 150715ec..3a2bd739 100644 --- a/roles/prometheus/files/traefik-dashboard.json +++ b/roles/prometheus/files/traefik-dashboard.json @@ -1202,16 +1202,6 @@ ], "templating": { "list": [ - { - "hide": 0, - "label": "datasource", - "name": "DS_PROMETHEUS", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" - }, { "allValue": null, "current": {}, diff --git a/roles/prometheus/files/velero-dashboard.json b/roles/prometheus/files/velero-dashboard.json index 6d399b45..de8fd8f1 100644 --- a/roles/prometheus/files/velero-dashboard.json +++ b/roles/prometheus/files/velero-dashboard.json @@ -1,1126 +1,1126 @@ { - "__requires": [ + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.1" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "5.2.1" + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Stats for Velero backups", + "editable": true, + "gnetId": 11055, + "graphTooltip": 1, + "id": 40, + "iteration": 1572366481432, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "5.0.0" + "id": 15, + "panels": [], + "title": "Backup", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "format": "short", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": false }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "5.0.0" - } - ], - "annotations": { - "list": [ + "gridPos": { + "h": 9, + "w": 5, + "x": 0, + "y": 1 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "pluginVersion": "6.3.2", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" + "from": "null", + "text": "N/A", + "to": "null" } - ] + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(velero_backup_active_total{schedule=~\"$schedule\"})", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Active Backup", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current", + "datasource": "$datasource" }, - "description": "Stats for Velero backups", - "editable": true, - "gnetId": 11055, - "graphTooltip": 1, - "id": 40, - "iteration": 1572366481432, - "links": [], - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 15, - "panels": [], - "title": "Backup", - "type": "row" + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "#d44a3a", - "rgba(237, 129, 40, 0.89)", - "#299c46" - ], - "format": "short", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": false - }, - "gridPos": { - "h": 9, - "w": 5, - "x": 0, - "y": 1 - }, - "id": 4, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "pluginVersion": "6.3.2", - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false, - "ymax": null, - "ymin": null - }, - "tableColumn": "", - "targets": [ - { - "expr": "sum(velero_backup_active_total{schedule=~\"$schedule\"})", - "instant": false, - "interval": "", - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "Active Backup", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "0", - "value": "null" - } - ], - "valueName": "current", - "datasource": "$datasource" + "gridPos": { + "h": 9, + "w": 4, + "x": 5, + "y": 1 }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": true, - "colors": [ - "#d44a3a", - "rgba(237, 129, 40, 0.89)", - "#299c46" - ], - "format": "percentunit", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { - "h": 9, - "w": 4, - "x": 5, - "y": 1 - }, - "id": 22, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 }, - "tableColumn": "", - "targets": [ - { - "expr": "sum(velero_backup_success_total{schedule=~\"$schedule\"}) / sum(velero_backup_attempt_total{schedule=~\"$schedule\"})", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": ".95,.99", - "timeFrom": null, - "timeShift": null, - "title": "Backup Success Rate", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "current", - "datasource": "$datasource" + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false }, - { - "aliasColors": {}, - "bars": false, - "cacheTimeout": null, - "dashLength": 10, - "dashes": false, - "decimals": 0, - "fill": 10, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 15, - "x": 9, - "y": 1 - }, - "id": 8, - "legend": { - "alignAsTable": false, - "avg": true, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "sort": "avg", - "sortDesc": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pluginVersion": "6.3.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": true, - "targets": [ - { - "expr": "sum(increase(velero_backup_success_total{schedule=~\"$schedule\"}[1h]))", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Backup success", - "refId": "A" - }, - { - "expr": "sum(increase(velero_backup_failure_total{schedule=~\"$schedule\"}[1h]))", - "hide": false, - "legendFormat": "Backup failure", - "refId": "B" - }, - { - "expr": "sum(increase(velero_backup_partial_failure_total{schedule=~\"$schedule\"}[1h]))", - "legendFormat": "Backup partial failure", - "refId": "C" - }, - { - "expr": "sum(increase(velero_backup_deletion_success_total{schedule=~\"$schedule\"}[1h]))", - "legendFormat": "Backup deletion success", - "refId": "D" - }, - { - "expr": "sum(increase(velero_backup_deletion_failure_total{schedule=~\"$schedule\"}[1h]))", - "legendFormat": "Backup deletion failure", - "refId": "E" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Backup per hour", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - }, - "datasource": "$datasource" + "tableColumn": "", + "targets": [ + { + "expr": "sum(velero_backup_success_total{schedule=~\"$schedule\"}) / sum(velero_backup_attempt_total{schedule=~\"$schedule\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": ".95,.99", + "timeFrom": null, + "timeShift": null, + "title": "Backup Success Rate", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current", + "datasource": "$datasource" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "decimals": 0, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 15, + "x": 9, + "y": 1 }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "decimals": 0, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 10 - }, - "id": 2, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": true, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true + "id": 8, + "legend": { + "alignAsTable": false, + "avg": true, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": false, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.3.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": true, + "targets": [ + { + "expr": "sum(increase(velero_backup_success_total{schedule=~\"$schedule\"}[1h]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Backup success", + "refId": "A" }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] + { + "expr": "sum(increase(velero_backup_failure_total{schedule=~\"$schedule\"}[1h]))", + "hide": false, + "legendFormat": "Backup failure", + "refId": "B" }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "velero_backup_total", - "legendFormat": "Backup Total", - "refId": "A" - }, - { - "expr": "velero_backup_active_total{schedule=~\"$schedule\"}", - "legendFormat": "Backup {{schedule}}", - "refId": "D" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Backup Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + { + "expr": "sum(increase(velero_backup_partial_failure_total{schedule=~\"$schedule\"}[1h]))", + "legendFormat": "Backup partial failure", + "refId": "C" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "expr": "sum(increase(velero_backup_deletion_success_total{schedule=~\"$schedule\"}[1h]))", + "legendFormat": "Backup deletion success", + "refId": "D" }, - "yaxes": [ - { - "decimals": null, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "expr": "sum(increase(velero_backup_deletion_failure_total{schedule=~\"$schedule\"}[1h]))", + "legendFormat": "Backup deletion failure", + "refId": "E" } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Backup per hour", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 17 - }, - "id": 11, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null as zero", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "histogram_quantile(0.99, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", - "legendFormat": "Scheduled: 0.99", - "refId": "A" - }, - { - "expr": "histogram_quantile(0.99, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", - "legendFormat": "Non Scheduled: 0.99", - "refId": "F" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", - "legendFormat": "Scheduled: 0.95", - "refId": "B" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", - "legendFormat": "Non Scheduled: 0.95", - "refId": "E" - }, - { - "expr": "histogram_quantile(0.50, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", - "legendFormat": "Scheduled: 0.50", - "refId": "C" - }, - { - "expr": "histogram_quantile(0.50, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", - "legendFormat": "Non Scheduled: 0.50", - "refId": "D" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Backup Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "yaxes": [ - { - "decimals": 0, - "format": "s", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "datasource": "$datasource" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 0, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "velero_backup_total", + "legendFormat": "Backup Total", + "refId": "A" }, - "datasource": "$datasource" + { + "expr": "velero_backup_active_total{schedule=~\"$schedule\"}", + "legendFormat": "Backup {{schedule}}", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Backup Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 23 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "id": 18, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", + "legendFormat": "Scheduled: 0.99", + "refId": "A" }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null as zero", - "options": { - "dataLinks": [] + { + "expr": "histogram_quantile(0.99, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", + "legendFormat": "Non Scheduled: 0.99", + "refId": "F" }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "avg_over_time(velero_backup_tarball_size_bytes{schedule=~\"$schedule\"}[15m])", - "legendFormat": "{{schedule}}", - "refId": "A" - }, - { - "expr": "avg_over_time(velero_backup_tarball_size_bytes{schedule!~\".*\"}[15m])", - "hide": false, - "legendFormat": "Non Scheduled", - "refId": "F" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Backup Size", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + { + "expr": "histogram_quantile(0.95, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", + "legendFormat": "Scheduled: 0.95", + "refId": "B" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "expr": "histogram_quantile(0.95, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", + "legendFormat": "Non Scheduled: 0.95", + "refId": "E" }, - "yaxes": [ - { - "decimals": 0, - "format": "decbytes", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "expr": "histogram_quantile(0.50, sum(rate(velero_backup_duration_seconds_bucket{schedule=~\"$schedule\"}[15m])) by (le))", + "legendFormat": "Scheduled: 0.50", + "refId": "C" }, - "datasource": "$datasource" + { + "expr": "histogram_quantile(0.50, sum(rate(velero_backup_duration_seconds_bucket{schedule!~\".*\"}[15m])) by (le))", + "legendFormat": "Non Scheduled: 0.50", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Backup Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "columns": [ - { - "text": "Current", - "value": "current" - } - ], - "datasource": "$datasource", - "fontSize": "100%", - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 29 - }, - "id": 13, - "options": {}, - "pageSize": null, - "scroll": true, - "showHeader": true, - "sort": { - "col": 0, - "desc": false + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "s", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "styles": [ - { - "alias": "Time", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "pattern": "Time", - "type": "date" - }, - { - "alias": "Hours since last backup", - "colorMode": "row", - "colors": [ - "rgba(50, 172, 45, 0.97)", - "rgba(237, 129, 40, 0.89)", - "rgba(245, 54, 54, 0.9)" - ], - "decimals": 2, - "pattern": "Current", - "thresholds": [ - "24", - "48" - ], - "type": "number", - "unit": "short" - } - ], - "targets": [ - { - "expr": "(time() - velero_backup_last_successful_timestamp{schedule!=\"\"}) / 60 / 60", - "legendFormat": "{{schedule}}", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Hours since last Backup", - "transform": "timeseries_aggregations", - "type": "table" + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 37 + "datasource": "$datasource" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg_over_time(velero_backup_tarball_size_bytes{schedule=~\"$schedule\"}[15m])", + "legendFormat": "{{schedule}}", + "refId": "A" }, - "id": 17, - "panels": [], - "title": "Restore", - "type": "row" + { + "expr": "avg_over_time(velero_backup_tarball_size_bytes{schedule!~\".*\"}[15m])", + "hide": false, + "legendFormat": "Non Scheduled", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Backup Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "#d44a3a", - "rgba(237, 129, 40, 0.89)", - "#299c46" - ], - "datasource": "$datasource", - "format": "short", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": false + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "decbytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "gridPos": { - "h": 9, - "w": 5, - "x": 0, - "y": 38 + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "datasource": "$datasource" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$datasource", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 13, + "options": {}, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" }, - "id": 5, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "pluginVersion": "6.3.2", - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false, - "ymax": null, - "ymin": null + { + "alias": "Hours since last backup", + "colorMode": "row", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "decimals": 2, + "pattern": "Current", + "thresholds": [ + "24", + "48" + ], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "(time() - velero_backup_last_successful_timestamp{schedule!=\"\"}) / 60 / 60", + "legendFormat": "{{schedule}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Hours since last Backup", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 17, + "panels": [], + "title": "Restore", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "$datasource", + "format": "short", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 9, + "w": 5, + "x": 0, + "y": 38 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 }, - "tableColumn": "", - "targets": [ - { - "expr": "sum(rate(velero_restore_attempt_total[$__interval])) / sum(rate(velero_restore_success_total[$__interval]))", - "instant": false, - "interval": "", - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "Active Restore", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "0", - "value": "null" - } - ], - "valueName": "current" + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "pluginVersion": "6.3.2", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null }, - { - "aliasColors": {}, - "bars": true, - "cacheTimeout": null, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "decimals": 0, - "fill": 10, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 19, - "x": 5, - "y": 38 + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(velero_restore_attempt_total[$__interval])) / sum(rate(velero_restore_success_total[$__interval]))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Active Restore", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": true, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 0, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 19, + "x": 5, + "y": 38 + }, + "id": 19, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "sort": "avg", + "sortDesc": false, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.3.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(velero_restore_success_total{schedule!~\".*\"}[15m])) / sum(rate(velero_restore_attempt_total{schedule!~\".*\"}[15m]))", + "interval": "", + "legendFormat": "Backup success rate", + "refId": "A" }, - "id": 19, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": false, - "show": true, - "sort": "avg", - "sortDesc": false, - "total": false, - "values": true + { + "expr": "sum(rate(velero_restore_success_total{schedule=~\"$schedule\"}[15m])) / sum(rate(velero_restore_attempt_total{schedule=~\"$schedule\"}[15m]))", + "legendFormat": "Backup success rate {{schedule}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Restore Success", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "options": { - "dataLinks": [] + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 0, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg_over_time(velero_restore_total[15m]) ", + "legendFormat": "Restore Total", + "refId": "A" }, - "percentage": false, - "pluginVersion": "6.3.2", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(velero_restore_success_total{schedule!~\".*\"}[15m])) / sum(rate(velero_restore_attempt_total{schedule!~\".*\"}[15m]))", - "interval": "", - "legendFormat": "Backup success rate", - "refId": "A" - }, - { - "expr": "sum(rate(velero_restore_success_total{schedule=~\"$schedule\"}[15m])) / sum(rate(velero_restore_attempt_total{schedule=~\"$schedule\"}[15m]))", - "legendFormat": "Backup success rate {{schedule}}", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Restore Success", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + { + "expr": "avg_over_time(velero_restore_success_total{schedule=~\"$schedule\"}[15m])", + "legendFormat": "Restore Success Total {{schedule}}", + "refId": "D" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "expr": "avg_over_time(velero_restore_success_total{schedule!~\".*\"}[15m])", + "legendFormat": "Restore Success Total", + "refId": "G" }, - "yaxes": [ - { - "decimals": 0, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "decimals": 0, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 47 + { + "expr": "avg_over_time(velero_restore_partial_failure_total{schedule=~\"$schedule\"}[15m])", + "legendFormat": " Restore Partial Failure Total {{schedule}}", + "refId": "C" }, - "id": 20, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "hideZero": true, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true + { + "expr": "avg_over_time(velero_restore_partial_failure_total{schedule!~\".*\"}[15m])", + "legendFormat": "Restore Partial Failure Total", + "refId": "F" }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] + { + "expr": "avg_over_time(velero_restore_failed_total{schedule=~\"$schedule\"}[15m])", + "legendFormat": "Restore Failure Total {{schedule}}", + "refId": "B" }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "avg_over_time(velero_restore_total[15m]) ", - "legendFormat": "Restore Total", - "refId": "A" - }, - { - "expr": "avg_over_time(velero_restore_success_total{schedule=~\"$schedule\"}[15m])", - "legendFormat": "Restore Success Total {{schedule}}", - "refId": "D" - }, - { - "expr": "avg_over_time(velero_restore_success_total{schedule!~\".*\"}[15m])", - "legendFormat": "Restore Success Total", - "refId": "G" - }, - { - "expr": "avg_over_time(velero_restore_partial_failure_total{schedule=~\"$schedule\"}[15m])", - "legendFormat": " Restore Partial Failure Total {{schedule}}", - "refId": "C" - }, - { - "expr": "avg_over_time(velero_restore_partial_failure_total{schedule!~\".*\"}[15m])", - "legendFormat": "Restore Partial Failure Total", - "refId": "F" - }, - { - "expr": "avg_over_time(velero_restore_failed_total{schedule=~\"$schedule\"}[15m])", - "legendFormat": "Restore Failure Total {{schedule}}", - "refId": "B" - }, - { - "expr": "avg_over_time(velero_restore_failed_total{schedule!~\".*\"}[15m])", - "legendFormat": "Restore Failure Total", - "refId": "E" - }, - { - "expr": "avg_over_time(velero_restore_validation_failed_total{schedule=~\"$schedule\"}[15m])", - "legendFormat": "Restore Validation Failed {{schedule}}", - "refId": "I" - }, - { - "expr": "avg_over_time(velero_restore_validation_failed_total{schedule!~\".*\"}[15m])", - "legendFormat": "Restore Validation Failed", - "refId": "H" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Total Restore Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + { + "expr": "avg_over_time(velero_restore_failed_total{schedule!~\".*\"}[15m])", + "legendFormat": "Restore Failure Total", + "refId": "E" }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "expr": "avg_over_time(velero_restore_validation_failed_total{schedule=~\"$schedule\"}[15m])", + "legendFormat": "Restore Validation Failed {{schedule}}", + "refId": "I" }, - "yaxes": [ - { - "decimals": null, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null + { + "expr": "avg_over_time(velero_restore_validation_failed_total{schedule!~\".*\"}[15m])", + "legendFormat": "Restore Validation Failed", + "refId": "H" } - } - ], - "refresh": false, - "schemaVersion": 19, - "style": "dark", - "tags": [ - "velero" - ], - "templating": { - "list": [ + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total Restore Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ { - "current": { - "selected": false, - "tags": [], - "text": "Prometheus", - "value": "Prometheus" - }, - "hide": 0, - "includeAll": false, - "label": "Datasource", - "multi": false, - "name": "datasource", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "type": "datasource" + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true }, { - "allValue": null, - "current": { - "text": "All", - "value": [ - "$__all" - ] - }, - "datasource": "$datasource", - "definition": "label_values(velero_backup_attempt_total, schedule)", - "hide": 0, - "includeAll": true, + "format": "short", "label": null, - "multi": true, - "name": "schedule", - "options": [], - "query": "label_values(velero_backup_attempt_total, schedule)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false + "logBase": 1, + "max": null, + "min": null, + "show": true } - ] - }, - "time": { - "from": "now-2d", - "to": "now" - }, - "timepicker": { - "hidden": false, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Kubernetes / Addons / Velero Stats", - "uid": "YAniUGC", - "version": 2 - } \ No newline at end of file + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 19, + "style": "dark", + "tags": [ + "velero" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "tags": [], + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": "$datasource", + "definition": "label_values(velero_backup_attempt_total, schedule)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "schedule", + "options": [], + "query": "label_values(velero_backup_attempt_total, schedule)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Kubernetes / Addons / Velero Stats", + "uid": "YAniUGC", + "version": 2 +} \ No newline at end of file diff --git a/roles/prometheus/tasks/configure_grafana_dashboards.yml b/roles/prometheus/tasks/configure_grafana_dashboards.yml index 21e145fa..4aeab8c0 100644 --- a/roles/prometheus/tasks/configure_grafana_dashboards.yml +++ b/roles/prometheus/tasks/configure_grafana_dashboards.yml @@ -1,5 +1,48 @@ --- -- name: "Configure Dashboard {{ dashboard_name }}" + +# Patch Dashboard json if needed. +# Check if json file contains DS_PROMETHEUS variable defined and patch json file +# See issue #18 + +- name: Provisioninig dashboard {{ dashboard_name }} | Initialize loop variables + set_fact: + dashboard_name: "{{ dashboard_file | basename | splitext | first }}" + dashboard_file_name: "{{ dashboard_file | basename }}" + dashboard_content: "{{ lookup('file', dashboard_file) | from_json }}" + input_detected: false + input_variable: false + +- name: Provisioninig dashboard {{ dashboard_name }} | Check if __inputs key exits within json dashboard + set_fact: + input_detected: true + when: dashboard_content.__inputs is defined + +- name: Provisioninig dashboard {{ dashboard_name }} | Detect if variable DS_PROMETHEUS exits + set_fact: + input_variable: "{{ dashboard_content.__inputs | selectattr('name','==', 'DS_PROMETHEUS') | length > 0 }}" + when: input_detected + +- name: Provisioninig dashboard {{ dashboard_name }} | Generating patch templating.list code block to add DS_PROMETHEUS variable + set_fact: + patch: "{{ [{ 'hide': 0, + 'label': 'datasource', + 'name': 'DS_PROMETHEUS', + 'options': [], + 'query': 'prometheus', + 'refresh': 1, + 'regex': '', + 'type': 'datasource' }] + dashboard_content.templating.list }}" + when: input_variable + +- name: Provisioninig dashboard {{ dashboard_name }} | Patch json dashboard file + set_fact: + dashboard_content: "{{ dashboard_content | combine(new_item, recursive=true) }}" + vars: + new_item: "{{ { 'templating': { 'list': patch } } }}" + when: input_variable + +# Create ConfigMap +- name: "Provisioninig dashboard {{ dashboard_name }} | Kubernetes apply" kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/grafana_dashboard.yml.j2' ) }}" state: present diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index 54da9db4..9a3f7ac6 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -97,10 +97,7 @@ - name: Configure Grafana Dashboards include_tasks: configure_grafana_dashboards.yml - vars: - dashboard_name: "{{ item | basename | splitext | first }}" - dashboard_file: - name: "{{ item | basename }}" - content: "{{ lookup('file', item ) | string }}" + loop_control: + loop_var: dashboard_file with_fileglob: - "files/*" diff --git a/roles/prometheus/templates/grafana_dashboard.yml.j2 b/roles/prometheus/templates/grafana_dashboard.yml.j2 index 88e19f8a..c076e3c5 100644 --- a/roles/prometheus/templates/grafana_dashboard.yml.j2 +++ b/roles/prometheus/templates/grafana_dashboard.yml.j2 @@ -7,5 +7,5 @@ metadata: labels: grafana_dashboard: "1" data: - {{ dashboard_file.name }}: |- -{{ dashboard_file.content | string | indent(4, true) }} + {{ dashboard_file_name }}: |- +{{ dashboard_content | to_nice_json | indent(4, true) }} From 9a9aa88a3ff53ac57d986fe6b75e43f8f6f9ac5b Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sat, 19 Mar 2022 13:22:46 +0100 Subject: [PATCH 25/45] ansible-lint fix --- roles/linkerd/tasks/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/tasks/main.yml index b074b34e..12e8c779 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/tasks/main.yml @@ -29,10 +29,14 @@ - name: Get ca.crt from linkerd-identity shell: | + set -o pipefail kubectl get secret \ -n "{{ k3s_linkerd_namespace }}" linkerd-identity-issuer \ -o jsonpath="{.data.ca\.crt}" | base64 -d + args: + executable: /bin/bash register: output_ca_crt + changed_when: false - name: Add Linkerd stable repo. kubernetes.core.helm_repository: From 218c9cd5fd5cb3afff91511898089ab64d92e483 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Sun, 20 Mar 2022 13:04:54 +0100 Subject: [PATCH 26/45] Splitting linkerd role into two: control-plane and linkerd-viz --- k3s_deploy.yml | 6 ++++-- roles/linkerd/{ => control-plane}/defaults/main.yml | 0 .../{ => control-plane}/tasks/install_linkerd_cli.yml | 0 roles/linkerd/{ => control-plane}/tasks/main.yml | 3 --- .../{ => control-plane}/templates/linkerd_issuer.yml.j2 | 0 .../{ => control-plane}/templates/linkerd_namespace.yml.j2 | 0 .../linkerd_extensions.yml => linkerd-viz/tasks/main.yml} | 0 .../{ => linkerd-viz}/templates/linkerd_viz_ingress.yml.j2 | 0 .../templates/linkerd_viz_namespace.yml.j2 | 0 .../templates/linkerd_viz_prometheus.yml.j2 | 0 10 files changed, 4 insertions(+), 5 deletions(-) rename roles/linkerd/{ => control-plane}/defaults/main.yml (100%) rename roles/linkerd/{ => control-plane}/tasks/install_linkerd_cli.yml (100%) rename roles/linkerd/{ => control-plane}/tasks/main.yml (95%) rename roles/linkerd/{ => control-plane}/templates/linkerd_issuer.yml.j2 (100%) rename roles/linkerd/{ => control-plane}/templates/linkerd_namespace.yml.j2 (100%) rename roles/linkerd/{tasks/linkerd_extensions.yml => linkerd-viz/tasks/main.yml} (100%) rename roles/linkerd/{ => linkerd-viz}/templates/linkerd_viz_ingress.yml.j2 (100%) rename roles/linkerd/{ => linkerd-viz}/templates/linkerd_viz_namespace.yml.j2 (100%) rename roles/linkerd/{ => linkerd-viz}/templates/linkerd_viz_prometheus.yml.j2 (100%) diff --git a/k3s_deploy.yml b/k3s_deploy.yml index da3bd423..8be405e0 100644 --- a/k3s_deploy.yml +++ b/k3s_deploy.yml @@ -41,6 +41,8 @@ tags: ['metallb'] - role: certmanager tags: ['certmanager'] + - role: linkerd/control-plane + tags: ['linkerd'] - role: traefik tags: ['traefik'] - role: backup/velero @@ -49,10 +51,10 @@ tags: ['longhorn'] - role: prometheus tags: ['monitoring'] + - role: linkerd/linkerd-viz + tags: ['linkerd-viz'] - role: logging/k3s tags: ['logging'] - - role: linkerd - tags: ['linkerd'] - name: Deploy fluentbit on control nodes (gateway and pimaster) hosts: control diff --git a/roles/linkerd/defaults/main.yml b/roles/linkerd/control-plane/defaults/main.yml similarity index 100% rename from roles/linkerd/defaults/main.yml rename to roles/linkerd/control-plane/defaults/main.yml diff --git a/roles/linkerd/tasks/install_linkerd_cli.yml b/roles/linkerd/control-plane/tasks/install_linkerd_cli.yml similarity index 100% rename from roles/linkerd/tasks/install_linkerd_cli.yml rename to roles/linkerd/control-plane/tasks/install_linkerd_cli.yml diff --git a/roles/linkerd/tasks/main.yml b/roles/linkerd/control-plane/tasks/main.yml similarity index 95% rename from roles/linkerd/tasks/main.yml rename to roles/linkerd/control-plane/tasks/main.yml index 12e8c779..fe8b9c8b 100644 --- a/roles/linkerd/tasks/main.yml +++ b/roles/linkerd/control-plane/tasks/main.yml @@ -62,6 +62,3 @@ cmd: "kubectl wait --for=condition=Ready pod --namespace={{ k3s_linkerd_namespace }} --all --timeout=600s" register: linkerd_pods_ready changed_when: false - -- name: Install linkerd extensions - include_tasks: linkerd_extensions.yml diff --git a/roles/linkerd/templates/linkerd_issuer.yml.j2 b/roles/linkerd/control-plane/templates/linkerd_issuer.yml.j2 similarity index 100% rename from roles/linkerd/templates/linkerd_issuer.yml.j2 rename to roles/linkerd/control-plane/templates/linkerd_issuer.yml.j2 diff --git a/roles/linkerd/templates/linkerd_namespace.yml.j2 b/roles/linkerd/control-plane/templates/linkerd_namespace.yml.j2 similarity index 100% rename from roles/linkerd/templates/linkerd_namespace.yml.j2 rename to roles/linkerd/control-plane/templates/linkerd_namespace.yml.j2 diff --git a/roles/linkerd/tasks/linkerd_extensions.yml b/roles/linkerd/linkerd-viz/tasks/main.yml similarity index 100% rename from roles/linkerd/tasks/linkerd_extensions.yml rename to roles/linkerd/linkerd-viz/tasks/main.yml diff --git a/roles/linkerd/templates/linkerd_viz_ingress.yml.j2 b/roles/linkerd/linkerd-viz/templates/linkerd_viz_ingress.yml.j2 similarity index 100% rename from roles/linkerd/templates/linkerd_viz_ingress.yml.j2 rename to roles/linkerd/linkerd-viz/templates/linkerd_viz_ingress.yml.j2 diff --git a/roles/linkerd/templates/linkerd_viz_namespace.yml.j2 b/roles/linkerd/linkerd-viz/templates/linkerd_viz_namespace.yml.j2 similarity index 100% rename from roles/linkerd/templates/linkerd_viz_namespace.yml.j2 rename to roles/linkerd/linkerd-viz/templates/linkerd_viz_namespace.yml.j2 diff --git a/roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 b/roles/linkerd/linkerd-viz/templates/linkerd_viz_prometheus.yml.j2 similarity index 100% rename from roles/linkerd/templates/linkerd_viz_prometheus.yml.j2 rename to roles/linkerd/linkerd-viz/templates/linkerd_viz_prometheus.yml.j2 From 86fec13aa211648c76cd2f584633f53a773cfa4b Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 21 Mar 2022 17:55:20 +0100 Subject: [PATCH 27/45] Enabling grafana connection from linkerd-viz --- host_vars/gateway.yml | 4 ++++ roles/linkerd/linkerd-viz/tasks/main.yml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/host_vars/gateway.yml b/host_vars/gateway.yml index a68b7917..80828cd3 100644 --- a/host_vars/gateway.yml +++ b/host_vars/gateway.yml @@ -33,6 +33,10 @@ dnsmasq_additional_dns_hosts: desc: "Elasticsearch server" hostname: elasticsearch ip: 10.0.0.101 + grafana: + desc: "Grafana server" + hostname: grafana + ip: 10.0.0.100 #################### # ntp role variables diff --git a/roles/linkerd/linkerd-viz/tasks/main.yml b/roles/linkerd/linkerd-viz/tasks/main.yml index 882b17ba..cb6bb2c1 100644 --- a/roles/linkerd/linkerd-viz/tasks/main.yml +++ b/roles/linkerd/linkerd-viz/tasks/main.yml @@ -24,7 +24,7 @@ # External Grafana grafana: enabled: false - grafanaUrl: kube-prometheus-stack-grafana.k3s-monitoring.svc.cluster.local:80 + grafanaUrl: grafana.picluster.ricsanfre.com:80 # Disabling DNS rebinding protection dashboard: enforcedHostRegexp: .* From 5938b96131b2fc015f068d095b4fcba415053d97 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 21 Mar 2022 17:57:38 +0100 Subject: [PATCH 28/45] Adding linkerd service mesh to prometheus --- roles/prometheus/defaults/main.yml | 3 +++ roles/prometheus/tasks/main.yml | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/roles/prometheus/defaults/main.yml b/roles/prometheus/defaults/main.yml index c9cbdfa8..9ae184a1 100644 --- a/roles/prometheus/defaults/main.yml +++ b/roles/prometheus/defaults/main.yml @@ -13,3 +13,6 @@ prometheus_storage_class: "longhorn" # Grafana Settings prometheus_grafana_password: "s1cret0" + +# Enable service mesh +enable_linkerd: true diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index 9a3f7ac6..77c4e1db 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -6,6 +6,17 @@ kind: Namespace state: present +- name: Annotate namespace to enable linkerd + kubernetes.core.k8s: + definition: + kind: Namespace + apiVersion: v1 + metadata: + name: "{{ k3s_monitoring_namespace }}" + annotations: + linkerd.io/inject: enabled + when: enable_linkerd + - name: Add prometheus community chart repo. kubernetes.core.helm_repository: name: prometheus-community @@ -19,6 +30,12 @@ update_repo_cache: true state: present release_values: + # Disable linkerd injection for admission webhooks jobs + prometheusOperator: + admissionWebhooks: + patch: + podAnnotations: + linkerd.io/inject: disabled alertmanager: alertmanagerSpec: storage: From 01d6acfe720fc68d56f095292fb9dda669b38279 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 21 Mar 2022 17:58:32 +0100 Subject: [PATCH 29/45] Adding linkerd service mesh to longhorn --- roles/longhorn/defaults/main.yml | 3 +++ roles/longhorn/tasks/main.yml | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/roles/longhorn/defaults/main.yml b/roles/longhorn/defaults/main.yml index c1370215..e9cb7acc 100644 --- a/roles/longhorn/defaults/main.yml +++ b/roles/longhorn/defaults/main.yml @@ -7,3 +7,6 @@ longhorn_dashboard_dns: storage.picluster.ricsanfre.com # Enable S3 backup longhorn_s3_backup: true + +# Enable service mesh +enable_linkerd: false diff --git a/roles/longhorn/tasks/main.yml b/roles/longhorn/tasks/main.yml index ff5df557..aeba8de0 100644 --- a/roles/longhorn/tasks/main.yml +++ b/roles/longhorn/tasks/main.yml @@ -6,6 +6,17 @@ kind: Namespace state: present +- name: Annotate namespace to enable linkerd + kubernetes.core.k8s: + definition: + kind: Namespace + apiVersion: v1 + metadata: + name: "{{ k3s_longhorn_namespace }}" + annotations: + linkerd.io/inject: enabled + when: enable_linkerd + - name: Add rancher chart repo. kubernetes.core.helm_repository: name: longhorn From 05071ab9de13c6cea3e65e85eae99d7d8c6fd406 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 21 Mar 2022 18:58:48 +0100 Subject: [PATCH 30/45] Adding linkerd service mesh to EFK --- roles/logging/k3s/defaults/main.yml | 3 +++ roles/logging/k3s/tasks/main.yml | 28 +++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/roles/logging/k3s/defaults/main.yml b/roles/logging/k3s/defaults/main.yml index dd7ea0ad..3d7c3eae 100644 --- a/roles/logging/k3s/defaults/main.yml +++ b/roles/logging/k3s/defaults/main.yml @@ -98,3 +98,6 @@ fluentbit_filters: call: local_timestamp_to_UTC fluent_bit_log_level: info + +# Enable service mesh +enable_linkerd: true diff --git a/roles/logging/k3s/tasks/main.yml b/roles/logging/k3s/tasks/main.yml index e1eb40c5..b25c013e 100644 --- a/roles/logging/k3s/tasks/main.yml +++ b/roles/logging/k3s/tasks/main.yml @@ -7,20 +7,42 @@ kind: Namespace state: present -# namespace for hosting ELK operator -- name: Create elk namespace. +- name: Annotate namespace to enable linkerd + kubernetes.core.k8s: + definition: + kind: Namespace + apiVersion: v1 + metadata: + name: "{{ k3s_logging_namespace }}" + annotations: + linkerd.io/inject: enabled + when: enable_linkerd + +# namespace for hosting ECK operator +- name: Create eck namespace. kubernetes.core.k8s: name: elastic-system api_version: v1 kind: Namespace state: present +- name: Annotate namespace to enable linkerd + kubernetes.core.k8s: + definition: + kind: Namespace + apiVersion: v1 + metadata: + name: elastic-system + annotations: + linkerd.io/inject: enabled + when: enable_linkerd + - name: Add elastic chart repo. kubernetes.core.helm_repository: name: elastic repo_url: "https://helm.elastic.co" -- name: Deploy ELK Operator Helm chart. +- name: Deploy ECK Operator Helm chart. kubernetes.core.helm: name: elastic-operator chart_ref: elastic/eck-operator From faa4592b44d2051203022ed745bddb7ab541a59d Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Mon, 21 Mar 2022 18:59:27 +0100 Subject: [PATCH 31/45] Updating linkerd doc --- docs/_docs/service-mesh.md | 146 +++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index 3d3c860b..7ee99082 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -409,6 +409,143 @@ linkerd-viz dashboard (web component) will be exposed configuring a Ingress reso Follow ["Provision dashboards automatically"](/docs/prometheus/#provisioning-dashboards-automatically) procedure to load Grafana dashboards automatically. +## Meshing a service with linkerd + +There are two common ways to define a resource as meshed with Linkerd: + +- **Explicit**: add `linkerd.io/inject: enabled` annotation per resource. Annotated pod deployment is injected with linkerd-proxy. + + Annotation can be added automatically using `linkerd` command to inject the annotation + + ```shell + kubectl get -n NAMESPACE deploy -o yaml | linkerd inject - | kubectl apply -f - + ``` + + This command takes all deployments resoureces from NAMESPACE and inject the annotation, so linkerd can inject linkerd-proxy automatically + + +- **Implicit**: add `linkerd.io/inject: enabled` annotation for a namespace. Any new pod created within the namespace is automatically injected with linkerd-proxy. + + Using kubectl: + ```shell + kubectl annotate ns linkerd.io/inject=enabled + ``` + + Through manifest file during namespace creation or patching the resource. + ```yml + kind: Namespace + apiVersion: v1 + metadata: + name: test + annotations: + linkerd.io/inject: enabled + ``` + +### Problems with Kuberentes Jobs and implicit annotation + + +With `linkerd.io/inject: enabled` annotation at namespace level, [Kubernetes Jobs](https://kubernetes.io/docs/concepts/workloads/controllers/job/) do not terminate after completion since the Pods created are injected with linkerd-proxy and it continues to run after the job container completes its work. + +That behaviour might cause errors during helm chart installation that deploy Jobs or during executions of scheduled CronJobs. + +As stated in this [blog post](https://itnext.io/three-ways-to-use-linkerd-with-kubernetes-jobs-c12ccc6d4c7c) there are different ways to handle this issue, both of them requires to modify Job template definition: + +1) Do not mesh the Jobs resources + +Adding `linkerd.io/inject: disabled` annotation to job template definition. + +```yml +jobTemplate: + spec: + template: + metadata: + annotations: + linkerd.io/inject: disabled +``` + +2) Shuting down linkerd-proxy as part of the Job execution. + +This can be done using [`linkerd-await`](https://github.com/linkerd/linkerd-await) as wrapper of the main job command. +`linkerd-await` waits till linkerd-proxy is ready then executes the main job command and, when it finishes, it calls the linkerd-proxy `/shutdown` endpoint. + ```shell + linked-await --shutdown option + ``` + +See details of implementation of this second workarround [here](https://itnext.io/three-ways-to-use-linkerd-with-kubernetes-jobs-c12ccc6d4c7c) + + +## Meshing cluster services + +### Longhorn distributed Storate + +#### Error installing Longhorn with namespace implicit annotation + +When installing longhorn installation hangs when deploying CSI plugin. + +`longhorn-driver-deployer` pod crashes showing an error "Got an error when checking MountProgapgation with node status, Node XX is not support mount propagation" + + +```sh +oss@node1:~$ kubectl get pods -n longhorn-system +NAME READY STATUS RESTARTS AGE +longhorn-ui-84f97cf569-c6fcq 2/2 Running 0 15m +longhorn-manager-cc7tt 2/2 Running 0 15m +longhorn-manager-khrx6 2/2 Running 0 15m +longhorn-manager-84zwx 2/2 Running 0 15m +instance-manager-e-86ec5db9 2/2 Running 0 14m +instance-manager-r-cdcb538b 2/2 Running 0 14m +engine-image-ei-4dbdb778-bc9q2 2/2 Running 0 14m +instance-manager-r-0d602480 2/2 Running 0 14m +instance-manager-e-429cc6bf 2/2 Running 0 14m +instance-manager-e-af266d5e 2/2 Running 0 14m +instance-manager-r-02fad614 2/2 Running 0 14m +engine-image-ei-4dbdb778-2785c 2/2 Running 0 14m +engine-image-ei-4dbdb778-xrj4k 2/2 Running 0 14m +longhorn-driver-deployer-6bc898bc7b-nmzkc 1/2 CrashLoopBackOff 6 (2m46s ago) 15m +oss@node1:~$ kubectl logs longhorn-driver-deployer-6bc898bc7b-nmzkc longhorn-driver-deployer -n longhorn-system +2022/03/20 12:42:58 proto: duplicate proto type registered: VersionResponse +W0320 12:42:58.148324 1 client_config.go:552] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work. +time="2022-03-20T12:43:48Z" level=warning msg="Got an error when checking MountPropagation with node status, Node node2 is not support mount propagation" +time="2022-03-20T12:43:48Z" level=fatal msg="Error deploying driver: CSI cannot be deployed because MountPropagation is not set: Node node2 is not support mount propagation" +``` + +### Prometheus Stack + +#### Error installing Prometheus Operator with namespace implicit annotation + +When deploying `kube-prometheus-stack` helm using an annotated namespace (`linkerd.io/inject: enabled`), causes the Prometheus Operartor to hung. + +Job pod `pod/kube-prometheus-stack-admission-create-` is created and its status is always `NotReady` since the linkerd-proxy continues to run after the job container ends so the Job Pod never ends. + +See [linkerd Prometheus Operator issue](https://github.com/prometheus-community/helm-charts/issues/479). + +To solve this issue linkerd injection must be disabled in the associated jobs created by Prometheus Operator. This can be achieved adding the following parameters to `values.yml` file of kube-prometheus-stack helm chart. + +```yml +prometheusOperator: + admissionWebhooks: + patch: + podAnnotations: + linkerd.io/inject: disabled +``` + +### EFK + +To mesh with linkerd all EFK services, it is enough to use the implicit annotation at namespace level before deploying ECK Operator and create Kibana and Elasticsearch service and before deploying fluentbit chart. + +Modify [ECK installation procedure](/docs/logging/#eck-perator-installation) to annotate the corresponding namespace before deploying the helm charts. + +```shell +kubectl annotate ns elastic-system linkerd.io/inject=enabled + +kubectl annotaet ns k3s-logging linkerd.io/inject=enabled +``` + +Deployment using ECK can be integrated with linkerd. See [ECK-linkerd document](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html) + + + + ## Configure Ingress Controller Linkerd does not come with a Ingress Controller. Existing ingress controller can be integrated with Linkerd doing the following: @@ -434,3 +571,12 @@ Linkerd-proxy configured in ingress mode will take `ld5-dst-override` HTTP heade Since Traefik terminates TLS, this TLS traffic (e.g. HTTPS calls from outside the cluster) will pass through Linkerd as an opaque TCP stream and Linkerd will only be able to provide byte-level metrics for this side of the connection. The resulting HTTP or gRPC traffic to internal services, of course, will have the full set of metrics and mTLS support. {{site.data.alerts.end}} + + +## References + +- How Linkerd uses iptables to transparently route Kubernetes traffic [[1]](https://linkerd.io/2021/09/23/how-linkerd-uses-iptables-to-transparently-route-kubernetes-traffic/) +- Protocol Detection and Opaque Ports in Linkerd [[2]](https://linkerd.io/2021/02/23/protocol-detection-and-opaque-ports-in-linkerd/) +- x [[3]]() +- x [[4]]() +- x [[5]]() \ No newline at end of file From 80b9a8b116a47720478774130c82c1ce265725c1 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 22 Mar 2022 13:17:55 +0100 Subject: [PATCH 32/45] New jinja2 template for kube-prometheus-stack helm chart values. Adding likerd specific configuration only when linkerd meshing is enabled --- roles/prometheus/tasks/main.yml | 42 +--------------- .../prometheus_stack_helm_values.yml.j2 | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 41 deletions(-) create mode 100644 roles/prometheus/templates/prometheus_stack_helm_values.yml.j2 diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index 77c4e1db..cc26d029 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -29,47 +29,7 @@ release_namespace: "{{ k3s_monitoring_namespace }}" update_repo_cache: true state: present - release_values: - # Disable linkerd injection for admission webhooks jobs - prometheusOperator: - admissionWebhooks: - patch: - podAnnotations: - linkerd.io/inject: disabled - alertmanager: - alertmanagerSpec: - storage: - volumeClaimTemplate: - spec: - storageClassName: "{{ prometheus_storage_class }}" - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: "{{ prometheus_storage_size }}" - prometheus: - prometheusSpec: - storageSpec: - volumeClaimTemplate: - spec: - storageClassName: "{{ prometheus_storage_class }}" - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: "{{ prometheus_storage_size }}" - grafana: - adminPassword: "{{ prometheus_grafana_password }}" - plugins: - - grafana-piechart-panel - kubeApiServer: - enabled: true - kubeControllerManager: - enabled: false - kubeScheduler: - enabled: false - kubeProxy: - enabled: false - kubeEtcd: - enabled: false + values: "{{ lookup('template', 'templates/prometheus_stack_helm_values.yml.j2') | from_yaml }}" - name: Wait for pods to be ready command: diff --git a/roles/prometheus/templates/prometheus_stack_helm_values.yml.j2 b/roles/prometheus/templates/prometheus_stack_helm_values.yml.j2 new file mode 100644 index 00000000..dc3a2f15 --- /dev/null +++ b/roles/prometheus/templates/prometheus_stack_helm_values.yml.j2 @@ -0,0 +1,49 @@ +--- +# kube-prometheus-stack helm chart values + +{% if enable_linkerd is sameas true %} +# Disable linkerd injection for admission webhooks jobs +prometheusOperator: + admissionWebhooks: + patch: + podAnnotations: + linkerd.io/inject: disabled +# Enable serviceaccount automount +prometheus-node-exporter: + serviceAccount: + automountServiceAccountToken: true +{% endif %} +alertmanager: + alertmanagerSpec: + storage: + volumeClaimTemplate: + spec: + storageClassName: "{{ prometheus_storage_class }}" + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: "{{ prometheus_storage_size }}" +prometheus: + prometheusSpec: + storageSpec: + volumeClaimTemplate: + spec: + storageClassName: "{{ prometheus_storage_class }}" + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: "{{ prometheus_storage_size }}" +grafana: + adminPassword: "{{ prometheus_grafana_password }}" + plugins: + - grafana-piechart-panel +kubeApiServer: + enabled: true +kubeControllerManager: + enabled: false +kubeScheduler: + enabled: false +kubeProxy: + enabled: false +kubeEtcd: + enabled: false \ No newline at end of file From 5ac7c0c5ddedfe43a94b7b81dc4c8e63f08fc189 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 22 Mar 2022 13:34:59 +0100 Subject: [PATCH 33/45] Fix #42. Making elasticsearch version configurable --- roles/logging/k3s/defaults/main.yml | 3 +++ roles/logging/k3s/templates/elasticsearch.yml.j2 | 2 +- roles/logging/k3s/templates/kibana.yml.j2 | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/roles/logging/k3s/defaults/main.yml b/roles/logging/k3s/defaults/main.yml index 3d7c3eae..3de2a1e7 100644 --- a/roles/logging/k3s/defaults/main.yml +++ b/roles/logging/k3s/defaults/main.yml @@ -5,6 +5,9 @@ k3s_logging_namespace: k3s-logging # EFK cluster name efk_cluster_name: "efk" +# Elastic search version +efk_elasticsearch_version: 7.15.0 + # Number of Elastic Search nodes efk_elasticsearch_nodes: 1 # Enable/Disable memory map diff --git a/roles/logging/k3s/templates/elasticsearch.yml.j2 b/roles/logging/k3s/templates/elasticsearch.yml.j2 index d9f1047b..c00ad232 100644 --- a/roles/logging/k3s/templates/elasticsearch.yml.j2 +++ b/roles/logging/k3s/templates/elasticsearch.yml.j2 @@ -5,7 +5,7 @@ metadata: name: "{{ efk_cluster_name }}" namespace: "{{ k3s_logging_namespace }}" spec: - version: 7.15.0 + version: {{ efk_elasticsearch_version }} nodeSets: - name: default count: {{ efk_elasticsearch_nodes }} diff --git a/roles/logging/k3s/templates/kibana.yml.j2 b/roles/logging/k3s/templates/kibana.yml.j2 index 21670d59..d6d7d3b8 100644 --- a/roles/logging/k3s/templates/kibana.yml.j2 +++ b/roles/logging/k3s/templates/kibana.yml.j2 @@ -5,7 +5,7 @@ metadata: name: "{{ efk_cluster_name }}" namespace: "{{ k3s_logging_namespace }}" spec: - version: 7.15.0 + version: {{ efk_elasticsearch_version }} count: 1 elasticsearchRef: name: "{{ efk_cluster_name }}" From 2014c59a94d3c3af2fb03b125d570c89df6cf9ee Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 22 Mar 2022 18:42:15 +0100 Subject: [PATCH 34/45] Fix #45: Disable Elasticsearch TLS configuratin --- docs/_docs/logging.md | 171 ++++++++++++++---- group_vars/control.yml | 2 +- host_vars/gateway.yml | 2 +- roles/logging/k3s/defaults/main.yml | 2 +- roles/logging/k3s/tasks/main.yml | 1 + .../k3s/templates/elasticsearch.yml.j2 | 8 +- .../templates/elasticsearch_ingress.yml.j2 | 56 ++++++ 7 files changed, 198 insertions(+), 44 deletions(-) create mode 100644 roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 diff --git a/docs/_docs/logging.md b/docs/_docs/logging.md index 52e0f43c..8df1fa97 100644 --- a/docs/_docs/logging.md +++ b/docs/_docs/logging.md @@ -2,7 +2,7 @@ title: Log Management (EFK) permalink: /docs/logging/ description: How to deploy centralized logging solution based on EFK stack (Elasticsearch- Fluentd/Fluentbit - Kibana) in our Raspberry Pi Kuberentes cluster. -last_modified_at: "25-02-2022" +last_modified_at: "22-03-2022" --- @@ -96,16 +96,10 @@ Basic instructions [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k requests: storage: 5Gi storageClassName: longhorn - http: # Making elasticsearch service available from outisde the cluster: Note(3) - service: - spec: - type: LoadBalancer - loadBalancerIP: 10.0.0.101 - tls: # Configuring self-signed certificate with DNS and static IP address: Note(4) + http: + tls: # Disabling TLS automatic configuration. Note(3) selfSignedCertificate: - subjectAltNames: - - ip: 10.0.0.101 - - dns: elasticsearch.picluster.ricsanfre.com + disabled: true ``` {{site.data.alerts.note}} **(1) About Memory mapping configuration** @@ -126,17 +120,13 @@ Basic instructions [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k See how to configure PersistenVolumeTemplates for Elasticsearh using this operator [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-volume-claim-templates.html) {{site.data.alerts.end}} - {{site.data.alerts.note}} **(3): About accesing ELK services from outside the cluster** - By default ELK services (elasticsearch, kibana, etc) are accesible through Kubernetes `ClusterIP` service types (only available within the cluster). To make them available outside the cluster they can be configured as `LoadBalancer` service type and specifying a static IP address (`loadBalancerIP`) for the service from the Metal LB pool. - This can be useful for example if elasticsearh database have to be used to monitoring logs from servers outside the cluster(i.e: `gateway` service can be configured to send logs to the elasticsearch running in the cluster). - - More details [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-services.html) - {{site.data.alerts.end}} + {{site.data.alerts.note}} **(3): Disable TLS automatic configuration** - {{site.data.alerts.note}} **(4): TLS self-signed certificate** - - Self-signed certificate will be created for elasticsearch, SANS (Service Alternative Names) can be added to the TLS certificate. More details [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-transport-settings.html) + Disabling TLS automatic configuration in Elasticsearch HTTP server enables Linkerd (Cluster Service Mesh) to gather more statistics about connections. Linkerd is parsing plain text traffic (HTTP) and not encrypted (HTTPS). + + Linkerd service mesh will enforce secure communications between all PODs. + {{site.data.alerts.end}} - Step 2: Apply manifest @@ -144,17 +134,22 @@ Basic instructions [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k ```shell kubectl apply -f manifest.yml ``` -- Step 3: Check Services and Pods +- Step 3: Check Elasticsearch status ```shell - kubectl get services -n k3s-logging - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - efk-es-transport ClusterIP None 9300/TCP 3h2m - efk-es-default ClusterIP None 9200/TCP 3h2m - efk-es-http LoadBalancer 10.43.186.20 10.0.0.102 9200:30079/TCP 147m + kubectl get elasticsearch -n k3s-logging + NAME HEALTH NODES VERSION PHASE AGE + efk yellow 1 7.15.0 Ready 139m ``` + + {{site.data.alerts.note}} -### Elasticsearch authentication + Elasticsearch status `HEALTH=yellow` indicates that only one node of the Elasticsearch is running (no HA mechanism), `PHASE=Ready` indicates that the server is up and running + + {{site.data.alerts.end}} + + +#### Elasticsearch authentication By default ECK configures secured communications with auto-signed SSL certificates. Access to its API on port 9200 is only available through https and user authentication is required to allow the connection. ECK defines a `elastic` user and stores its credentials within a kubernetes Secret. @@ -178,6 +173,108 @@ data: elastic: "{{ efk_elasticsearch_passwd | b64encode }}" ``` +#### Accesing Elasticsearch from outside the cluster + +By default Elasticsearh HTTP service is accesible through Kubernetes `ClusterIP` service types (only available within the cluster). To make them available outside the cluster Traefik reverse-proxy can be configured to enable external communication with Elasicsearh server. + +This can be useful for example if elasticsearh database have to be used to monitoring logs from servers outside the cluster(i.e: `gateway` service can be configured to send logs to the elasticsearch running in the cluster). + +- Step 1. Create the ingress rule manifest + + + ```yml + --- + # HTTPS Ingress + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: elasticsearch-ingress + namespace: k3s-logging + annotations: + # HTTPS as entry point + traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Enable TLS + traefik.ingress.kubernetes.io/router.tls: "true" + # Enable cert-manager to create automatically the SSL certificate and store in Secret + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: elasticsearch.picluster.ricsanfre.com + spec: + tls: + - hosts: + - elasticsearch.picluster.ricsanfre.com + secretName: elasticsearch-tls + rules: + - host: elasticsearch.picluster.ricsanfre.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: efk-es-http + port: + number: 9200 + --- + # http ingress for http->https redirection + kind: Ingress + apiVersion: networking.k8s.io/v1 + metadata: + name: elasticsearch-redirect + namespace: k3s-logging + annotations: + # Use redirect Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: traefik-system-redirect@kubernetescrd + # HTTP as entrypoint + traefik.ingress.kubernetes.io/router.entrypoints: web + spec: + rules: + - host: elasticsearch.picluster.ricsanfre.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: efk-es-http + port: + number: 9200 + ``` + + Traefik ingress rule exposes elasticsearch server as `elasticsearch.picluster.ricsanfre.com` virtual host, routing rules are configured for redirecting all incoming HTTP traffic to HTTPS and TLS is enabled using a certificate generated by Cert-manager. + + See [Traefik configuration document](/docs/traefik/) for furher details. + +- Step 2: Apply manifest + + ```shell + kubectl apply -f manifest.yml + ``` +- Step 3. Access to Elastic HTTP service + + UI can be access through http://elasticsearch.picluster.ricsanfre.com using loging `elastic` and the password stored in `-es-elastic-user`. + + It should shows the following output (json message) + + ```json + { + "name" : "efk-es-default-0", + "cluster_name" : "efk", + "cluster_uuid" : "EQK8niEnSzqZFHmpRSDpgg", + "version" : { + "number" : "7.15.0", + "build_flavor" : "default", + "build_type" : "docker", + "build_hash" : "79d65f6e357953a5b3cbcc5e2c7c21073d89aa29", + "build_date" : "2021-09-16T03:05:29.143308416Z", + "build_snapshot" : false, + "lucene_version" : "8.9.0", + "minimum_wire_compatibility_version" : "6.8.0", + "minimum_index_compatibility_version" : "6.0.0-beta1" + }, + "tagline" : "You Know, for Search" + } + ``` + ### Kibana installation - Step 1. Create a manifest file @@ -193,7 +290,7 @@ data: count: 2 # Elastic Search statefulset deployment with two replicas elasticsearchRef: name: "elasticsearch" - http: # NOTE disabling selfSigned certificate + http: # NOTE disabling kibana automatic TLS configuration tls: selfSignedCertificate: disabled: true @@ -202,13 +299,19 @@ data: ```shell kubectl apply -f manifest.yml ``` -- Step 3: Check kibana POD and services +- Step 3: Check kibana status ```shell - kubectl get services -n k3s-logging - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - efk-kb-http LoadBalancer 10.43.242.252 10.0.0.101 5601:31779/TCP 3h2m + kubectl get kibana -n k3s-logging + NAME HEALTH NODES VERSION AGE + efk green 1 7.15.0 171m ``` + {{site.data.alerts.note}} + + Kibana status `HEALTH=green` indicates that Kibana is up and running. + + {{site.data.alerts.end}} + #### Ingress rule for Traefik Make accesible Kibana UI from outside the cluster through Ingress Controller @@ -401,7 +504,7 @@ For speed-up the installation there is available a [helm chart](https://github.c Tag_Key tag HTTP_User ${FLUENT_ELASTICSEARCH_USER} HTTP_Passwd ${FLUENT_ELASTICSEARCH_PASSWORD} - tls True + tls False tls.verify False Retry_Limit False # fluent-bit.config PARSERS **NOTE 5** @@ -509,7 +612,7 @@ For speed-up the installation there is available a [helm chart](https://github.c {{site.data.alerts.note}} **(4): Fluentbit OUTPUT configuration** - [OUTPUT] configuration by default uses elasticsearch, but it needs to be modified for specifying the access credentials and https protocol specific parameters (use tls and skip SSL certification validation) + [OUTPUT] configuration by default uses elasticsearch, but it needs to be modified for specifying the access credentials and https protocol specific parameters (do not use tls). {{site.data.alerts.end}} {{site.data.alerts.note}} **(5): Fluentbit PARSER configuration** @@ -799,7 +902,7 @@ fluentbit_outputs: Tag_Key: tag HTTP_User: elastic HTTP_Passwd: s1cret0 - tls: On + tls: Off tls.verify: Off Retry_Limit: False # Fluentbit custom parsers diff --git a/group_vars/control.yml b/group_vars/control.yml index f367a047..57a1d8df 100644 --- a/group_vars/control.yml +++ b/group_vars/control.yml @@ -31,7 +31,7 @@ fluentbit_outputs: - Name: es match: "*" Host: "{{ elasticsearch_dns }}" - Port: 9200 + Port: 443 Logstash_Format: true Logstash_Prefix: logstash Include_Tag_Key: true diff --git a/host_vars/gateway.yml b/host_vars/gateway.yml index 80828cd3..c14545fd 100644 --- a/host_vars/gateway.yml +++ b/host_vars/gateway.yml @@ -32,7 +32,7 @@ dnsmasq_additional_dns_hosts: elasticsearch: desc: "Elasticsearch server" hostname: elasticsearch - ip: 10.0.0.101 + ip: 10.0.0.100 grafana: desc: "Grafana server" hostname: grafana diff --git a/roles/logging/k3s/defaults/main.yml b/roles/logging/k3s/defaults/main.yml index 3de2a1e7..64ae9243 100644 --- a/roles/logging/k3s/defaults/main.yml +++ b/roles/logging/k3s/defaults/main.yml @@ -66,7 +66,7 @@ fluentbit_outputs: Tag_Key: tag HTTP_User: ${FLUENT_ELASTICSEARCH_USER} HTTP_Passwd: ${FLUENT_ELASTICSEARCH_PASSWORD} - tls: true + tls: false tls.verify: false Retry_Limit: false # Fluentbit custom parsers diff --git a/roles/logging/k3s/tasks/main.yml b/roles/logging/k3s/tasks/main.yml index b25c013e..1894c265 100644 --- a/roles/logging/k3s/tasks/main.yml +++ b/roles/logging/k3s/tasks/main.yml @@ -65,6 +65,7 @@ - elasticsearch.yml.j2 - kibana.yml.j2 - kibana_ingress.yml.j2 + - elasticsearch_ingress.yml.j2 - name: Wait for Elastic search to be deployed command: diff --git a/roles/logging/k3s/templates/elasticsearch.yml.j2 b/roles/logging/k3s/templates/elasticsearch.yml.j2 index c00ad232..f0aaa190 100644 --- a/roles/logging/k3s/templates/elasticsearch.yml.j2 +++ b/roles/logging/k3s/templates/elasticsearch.yml.j2 @@ -22,12 +22,6 @@ spec: storage: "{{ efk_elasticsearch_storage_size }}" storageClassName: "{{ efk_elasticsearch_storage_class }}" http: # Making elasticsearch service available from outisde the cluster - service: - spec: - type: LoadBalancer - loadBalancerIP: {{ k3s_elasticsearch_external_ip }} tls: selfSignedCertificate: - subjectAltNames: - - ip: {{ k3s_elasticsearch_external_ip }} - - dns: {{ elasticsearch_dns }} + disabled: true diff --git a/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 b/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 new file mode 100644 index 00000000..d804ae11 --- /dev/null +++ b/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 @@ -0,0 +1,56 @@ +--- +# HTTPS Ingress +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: elasticsearch-ingress + namespace: {{ k3s_logging_namespace }} + annotations: + # HTTPS as entry point + traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Enable TLS + traefik.ingress.kubernetes.io/router.tls: "true" + # Enable cert-manager to create automatically the SSL certificate and store in Secret + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ elasticsearch_dns }} +spec: + tls: + - hosts: + - {{ elasticsearch_dns }} + secretName: elasticsearch-tls + rules: + - host: {{ elasticsearch_dns }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ efk_cluster_name }}-es-http + port: + number: 9200 + +--- +# http ingress for http->https redirection +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: elasticsearch-redirect + namespace: {{ k3s_logging_namespace }} + annotations: + # Use redirect Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-redirect@kubernetescrd + # HTTP as entrypoint + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + rules: + - host: {{ elasticsearch_dns }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ efk_cluster_name }}-es-http + port: + number: 9200 From 760c9edbfc07f4b0a12862e0110c99e9bb9e4e10 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 22 Mar 2022 19:59:56 +0100 Subject: [PATCH 35/45] Fix #44: Securing access to Kibana --- docs/_docs/logging.md | 60 +++++++++++++++---- .../k3s/templates/kibana_ingress.yml.j2 | 44 ++++++++++++-- 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/docs/_docs/logging.md b/docs/_docs/logging.md index 8df1fa97..c11b726e 100644 --- a/docs/_docs/logging.md +++ b/docs/_docs/logging.md @@ -181,7 +181,6 @@ This can be useful for example if elasticsearh database have to be used to monit - Step 1. Create the ingress rule manifest - ```yml --- # HTTPS Ingress @@ -319,26 +318,63 @@ Make accesible Kibana UI from outside the cluster through Ingress Controller - Step 1. Create the ingress rule manifest ```yml + --- + # HTTPS Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kibana-ingress namespace: k3s-logging annotations: - kubernetes.io/ingress.class: traefik + # HTTPS as entry point + traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Enable TLS + traefik.ingress.kubernetes.io/router.tls: "true" + # Enable cert-manager to create automatically the SSL certificate and store in Secret + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: kibana.picluster.ricsanfre.com spec: + tls: + - hosts: + - kibana.picluster.ricsanfre.com + secretName: kibana-tls rules: - - host: kibana.picluster.ricsanfre.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: "efk-kb-http" - port: - number: 5601 + - host: kibana.picluster.ricsanfre.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: efk-kb-http + port: + number: 5601 + --- + # http ingress for http->https redirection + kind: Ingress + apiVersion: networking.k8s.io/v1 + metadata: + name: kibana-redirect + namespace: k3s-logging + annotations: + # Use redirect Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: traefik-system-redirect@kubernetescrd + # HTTP as entrypoint + traefik.ingress.kubernetes.io/router.entrypoints: web + spec: + rules: + - host: kibana.picluster.ricsanfre.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: efk-kb-http + port: + number: 5601 ``` + - Step 2: Apply manifest ```shell kubectl apply -f manifest.yml diff --git a/roles/logging/k3s/templates/kibana_ingress.yml.j2 b/roles/logging/k3s/templates/kibana_ingress.yml.j2 index 6bbc606d..f96a7fc4 100644 --- a/roles/logging/k3s/templates/kibana_ingress.yml.j2 +++ b/roles/logging/k3s/templates/kibana_ingress.yml.j2 @@ -1,20 +1,56 @@ --- +# HTTPS Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kibana-ingress - namespace: k3s-logging + namespace: {{ k3s_logging_namespace }} annotations: - kubernetes.io/ingress.class: traefik + # HTTPS as entry point + traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Enable TLS + traefik.ingress.kubernetes.io/router.tls: "true" + # Enable cert-manager to create automatically the SSL certificate and store in Secret + cert-manager.io/cluster-issuer: ca-issuer + cert-manager.io/common-name: {{ kibana_dashboard_dns }} spec: + tls: + - hosts: + - {{ kibana_dashboard_dns }} + secretName: kibana-tls rules: - - host: {{ kibana_dashboard_dns }} + - host: {{ kibana_dashboard_dns }} http: paths: - path: / pathType: Prefix backend: service: - name: "{{ efk_cluster_name }}-kb-http" + name: {{ efk_cluster_name }}-kb-http + port: + number: 5601 + +--- +# http ingress for http->https redirection +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: kibana-redirect + namespace: {{ k3s_logging_namespace }} + annotations: + # Use redirect Midleware configured + traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-redirect@kubernetescrd + # HTTP as entrypoint + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + rules: + - host: {{ kibana_dashboard_dns }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ efk_cluster_name }}-kb-http port: number: 5601 From bbb434f59a0bdda622601e9f80d940e0289cb73a Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 23 Mar 2022 15:12:54 +0100 Subject: [PATCH 36/45] Enabling serviceAccountAutoMount for Elastic and Kibana to make linkerd-proxy being injected --- roles/logging/k3s/templates/elasticsearch.yml.j2 | 14 ++++++++++---- roles/logging/k3s/templates/kibana.yml.j2 | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/roles/logging/k3s/templates/elasticsearch.yml.j2 b/roles/logging/k3s/templates/elasticsearch.yml.j2 index f0aaa190..35d713a6 100644 --- a/roles/logging/k3s/templates/elasticsearch.yml.j2 +++ b/roles/logging/k3s/templates/elasticsearch.yml.j2 @@ -6,6 +6,10 @@ metadata: namespace: "{{ k3s_logging_namespace }}" spec: version: {{ efk_elasticsearch_version }} + http: # Making elasticsearch service available from outisde the cluster + tls: + selfSignedCertificate: + disabled: true nodeSets: - name: default count: {{ efk_elasticsearch_nodes }} @@ -21,7 +25,9 @@ spec: requests: storage: "{{ efk_elasticsearch_storage_size }}" storageClassName: "{{ efk_elasticsearch_storage_class }}" - http: # Making elasticsearch service available from outisde the cluster - tls: - selfSignedCertificate: - disabled: true + {% if enable_linkerd is sameas true %} + # Enabling service account token. linkerd requirement + podTemplate: + spec: + automountServiceAccountToken: true + {% endif %} diff --git a/roles/logging/k3s/templates/kibana.yml.j2 b/roles/logging/k3s/templates/kibana.yml.j2 index d6d7d3b8..6de08ffc 100644 --- a/roles/logging/k3s/templates/kibana.yml.j2 +++ b/roles/logging/k3s/templates/kibana.yml.j2 @@ -13,3 +13,9 @@ spec: tls: selfSignedCertificate: disabled: true + {% if enable_linkerd is sameas true %} + # Enabling service account token. linkerd requirement + podTemplate: + spec: + automountServiceAccountToken: true + {% endif %} From 3b903810660652a3b79eb9456c8644535bcaaa13 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 23 Mar 2022 17:40:33 +0100 Subject: [PATCH 37/45] Playbook typos fixing --- k3s_reset.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k3s_reset.yml b/k3s_reset.yml index b13c766a..09a77c70 100644 --- a/k3s_reset.yml +++ b/k3s_reset.yml @@ -3,7 +3,7 @@ become: true gather_facts: false tasks: - - name: Unisntall k3s + - name: Uninstall k3s command: /usr/local/bin/k3s-uninstall.sh changed_when: true - import_tasks: tasks/cleaning.yml @@ -13,7 +13,7 @@ become: true gather_facts: false tasks: - - name: Unisntall k3s + - name: Uninstall k3s command: /usr/local/bin/k3s-agent-uninstall.sh changed_when: true - import_tasks: tasks/cleaning.yml From 5030e889d8898c5ba6aa0241fe2665ba35a1a604 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 23 Mar 2022 18:05:28 +0100 Subject: [PATCH 38/45] Linkerd: Meshing Traefik Ingress --- roles/traefik/defaults/main.yml | 3 +++ roles/traefik/templates/traefik-config.yml.j2 | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/roles/traefik/defaults/main.yml b/roles/traefik/defaults/main.yml index e44322b8..d97327b7 100644 --- a/roles/traefik/defaults/main.yml +++ b/roles/traefik/defaults/main.yml @@ -11,3 +11,6 @@ traefik_basic_auth_user: admin traefik_basic_auth_passwd: s1cret0 traefik_auth_htpasswd_pair: KKYWRtaW46JGFwcjEkWkRkMWIvNC4kUG9RR244RW5Gc0lWUUFDS3p3VHJrLgoK + +# Enable service mesh +enable_linkerd: true diff --git a/roles/traefik/templates/traefik-config.yml.j2 b/roles/traefik/templates/traefik-config.yml.j2 index d515fa46..e847c7ec 100644 --- a/roles/traefik/templates/traefik-config.yml.j2 +++ b/roles/traefik/templates/traefik-config.yml.j2 @@ -12,6 +12,11 @@ spec: - "--accesslog.format=json" - "--accesslog.filepath=/data/access.log" deployment: +{% if enable_linkerd is sameas true %} + podAnnotations: + linkerd.io/inject: ingress + config.linkerd.io/skip-outbound-ports: "443" +{% endif %} additionalContainers: - name: stream-accesslog image: busybox From 91caae7397c6458161f448262587ae2101f71ee4 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 23 Mar 2022 18:47:27 +0100 Subject: [PATCH 39/45] Updating Traefik Ingress resources to work with Linkerd --- docs/_docs/service-mesh.md | 146 ++++++++++++++++-- .../k3s/templates/elasticsearch.yml.j2 | 4 +- .../templates/elasticsearch_ingress.yml.j2 | 18 +++ roles/logging/k3s/templates/kibana.yml.j2 | 4 +- .../k3s/templates/kibana_ingress.yml.j2 | 18 +++ .../templates/alertmanager_ingress.yml.j2 | 18 ++- .../templates/grafana_ingress.yml.j2 | 18 +++ .../templates/prometheus_ingress.yml.j2 | 18 ++- 8 files changed, 225 insertions(+), 19 deletions(-) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index 7ee99082..ee4a8e9b 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -511,7 +511,8 @@ time="2022-03-20T12:43:48Z" level=fatal msg="Error deploying driver: CSI cannot ### Prometheus Stack -#### Error installing Prometheus Operator with namespace implicit annotation +To mesh with linkerd all Prometheus-stack services, implicit annotation at namespace level can be used before deploying kube-prometheys-stack chart. + When deploying `kube-prometheus-stack` helm using an annotated namespace (`linkerd.io/inject: enabled`), causes the Prometheus Operartor to hung. @@ -529,30 +530,71 @@ prometheusOperator: linkerd.io/inject: disabled ``` +Modify [Prometheus installation procedure](/docs/monitoring/) to annotate the corresponding namespace before deploying the helm chart and use the modified values.yml file. + +```shell +kubectl annotate ns k3s-monitoring linkerd.io/inject=enabled +``` + +{{site.data.alerts.note}} + +`node-exporter` daemonset, which are part of kube-prometheus-stack, are not injected with linkerd-proxy becasue its PODs use hosts network namespace `spec.hostNework=true`. Linkerd injection is disabled for pods with hostNetwork=true. + +If you try to inject manually: + +```shell +kubectl get daemonset -n k3s-monitoring -o yaml | linkerd inject - + +Error transforming resources: +failed to inject daemonset/kube-prometheus-stack-prometheus-node-exporter: hostNetwork is enabled +``` + +{{site.data.alerts.end}} + + ### EFK To mesh with linkerd all EFK services, it is enough to use the implicit annotation at namespace level before deploying ECK Operator and create Kibana and Elasticsearch service and before deploying fluentbit chart. -Modify [ECK installation procedure](/docs/logging/#eck-perator-installation) to annotate the corresponding namespace before deploying the helm charts. +Modify [EFK installation procedure](/docs/logging/) to annotate the corresponding namespace before deploying the helm charts. ```shell kubectl annotate ns elastic-system linkerd.io/inject=enabled -kubectl annotaet ns k3s-logging linkerd.io/inject=enabled +kubectl annotate ns k3s-logging linkerd.io/inject=enabled ``` -Deployment using ECK can be integrated with linkerd. See [ECK-linkerd document](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html) +When deploying Elasticsearch and Kibana using the ECK operator, it is needed to specify the parameter `automountServiceAccountToken: true`, otherwise the linkerd-proxy is not injected. +The following configuration need to be added to Elastic and Kibana resources +```yml +podTemplate: + spec: + automountServiceAccountToken: true + +``` + +For details about how to integrate with linkerd Elastic stack components using ECK operator, see [ECK-linkerd document](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html). + + +{{site.data.alerts.important}} + +Elasticsearch automatic TLS configuration that was itinitially configured has been disabled, so Linkerd can gather more metrics about the connections. See [issue #45](https://github.com/ricsanfre/pi-cluster/issues/45) + +{{site.data.alerts.end}} ## Configure Ingress Controller Linkerd does not come with a Ingress Controller. Existing ingress controller can be integrated with Linkerd doing the following: + - Configuring Ingress Controller to support Linkerd. - Meshing Ingress Controller pods so that they have the Linkerd proxy installed. -In general, Linkerd can be used with any ingress controller. In order for Linkerd to properly apply features such as route-based metrics and traffic splitting, Linkerd needs the IP/port of the Kubernetes Service. However, by default, many ingresses do their own endpoint selection and pass the IP/port of the destination Pod, rather than the Service as a whole. +Linkerd can be used with any ingress controller. In order for Linkerd to properly apply features such as route-based metrics and traffic splitting, Linkerd needs the IP/port of the Kubernetes Service as the traffic destination. However, by default, many ingresses, like Traefik, do their own load balance and endpoint selection when forwarding HTTP traffic pass the IP/port of the destination Pod, rather than the Service as a whole. + +In order to enable linkerd implementation of load balancing at HTTP request level, Traefik load balancing mechanism must be skipped. More details in linkerd documentation ["Ingress Traffic"](https://linkerd.io/2.11/tasks/using-ingress/). @@ -561,22 +603,100 @@ More details in linkerd documentation ["Ingress Traffic"](https://linkerd.io/2.1 In order to integrate Traefik with Linkerd the following must be done: -- Traefik should be meshed with ingress mode enabled, i.e. with the `linkerd.io/inject: ingress` annotation rather than the default enabled. +1. Traefik must be meshed with `ingress mode` enabled, i.e. with the `linkerd.io/inject: ingress` annotation rather than the default enabled. + + Executing the following command Traefik deployment is injected with linkerd-proxy in ingress mode: -- Configure Ingress rules to use a Traefik's Middleware inserting a specific header, `l5d-dst-override` pointing to the Service IP/Port (using internal DNS name: `..svc.cluster.local` + ```shell + kubectl get deployment traefik -o yaml -n kube-system | linkerd inject --ingress - | kubectl apply -f - + ``` -Linkerd-proxy configured in ingress mode will take `ld5-dst-override` HTTP header for routing the traffic to the service. + {{site.data.alerts.important}} -{{site.data.alerts.important}} -Since Traefik terminates TLS, this TLS traffic (e.g. HTTPS calls from outside the cluster) will pass through Linkerd as an opaque TCP stream and Linkerd will only be able to provide byte-level metrics for this side of the connection. The resulting HTTP or gRPC traffic to internal services, of course, will have the full set of metrics and mTLS support. -{{site.data.alerts.end}} + In ingress mode only HTTP traffic is routed by linkerd-proxy. Traefik will stop routing any HTTPS traffic. In this mode we must be sure that Traefil will end all TLS communications coming from ourside de cluster and that it communicate with the internal services only using HTTP. + + This is how we have configured all services within the cluster. Disabling TLS configurations of all internal HTTP services. + + Linkerd at platform level provides that TLS secure layer. + + HTTP communications from clients outside the cluster are secured by Traefik (closing external TLS sessions). From Traefik traffic routing to the cluster will be secured by Linkerd-proxy. + + {{site.data.alerts.end}} + + Since Traefik needs to talk to Kubernetes API using HTTPS standard port (to impliments its own routing and load balancing mechanism), this mode of execution breaks Traefik unless outbound communications using port 443 skips the linkerd-proxy. + + For making Traefik still working with its own loadbalancing/routing mechanism the following command need to be executed. + + ```shell + kubectl get deployment traefik -o yaml -n kube-system | linkerd inject --ingress --skip-outbound-ports 443 - | kubectl apply -f - + ``` + + See [Linkerd discussion #7387](https://github.com/linkerd/linkerd2/discussions/7387) for further details about this issue. + + Alternative the Traefik helm chart can be configured so the deployed pod contains the required linkerd annotations to enable the ingress mode and skip port 443. The following additional values must be provided + + ```yml + deployment: + podAnnotations: + linkerd.io/inject: ingress + config.linkerd.io/skip-outbound-ports: "443" + ``` + + Traefik is a K3S embedded components that is auto-deployed using Helm. In order to configure Helm chart configuration parameters the official [document](https://rancher.com/docs/k3s/latest/en/helm/#customizing-packaged-components-with-helmchartconfig) must be followed. See how to do it in [Traefik configuration documentation](/docs/traefik/) + + + +2. Replace Traefik routing and load-balancing mechanism by linkerd-proxy routing and load balancing mechanism. + Configure Ingress resources to use a Traefik's Middleware inserting a specific header, `l5d-dst-override` pointing to the Service IP/Port (using internal DNS name: `..svc.cluster.local` + Linkerd-proxy configured in ingress mode will take `ld5-dst-override` HTTP header for routing the traffic to the service. + + When an HTTP (not HTTPS) request is received by a Linkerd proxy, the destination service of that request is identified. + + The destination service for a request is computed by selecting the value of the first HTTP header to exist of, `l5d-dst-override`, `:authority`, and `Host`. The port component, if included and including the colon, is stripped. That value is mapped to the fully qualified DNS name. + + + Per ingress resource do the following: + + - Step 1: Create Middleware routing for providing l5d-dst-override HTTP header + + ```yml + apiVersion: traefik.containo.us/v1alpha1 + kind: Middleware + metadata: + name: l5d-header-middleware + namespace: my-namespace + spec: + headers: + customRequestHeaders: + l5d-dst-override: "my-service.my-namespace.svc.cluster.local:80" + + ``` + - Step 2: Add traefik middleware annotation to Ingress definition + + ```yml + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: my-ingress + namespace: my-namespace + annotations: + traefik.ingress.kubernetes.io/router.middlewares: + my-namespace-l5d-header-middleware@kubernetescrd + + ``` + +{{site.data.alerts.note}} + +Since Traefik terminates TLS, this TLS traffic (e.g. HTTPS calls from outside the cluster) will pass through Linkerd as an opaque TCP stream and Linkerd will only be able to provide byte-level metrics for this side of the connection. The resulting HTTP or gRPC traffic to internal services, of course, will have the full set of metrics and mTLS support. + +{{site.data.alerts.end}} ## References - How Linkerd uses iptables to transparently route Kubernetes traffic [[1]](https://linkerd.io/2021/09/23/how-linkerd-uses-iptables-to-transparently-route-kubernetes-traffic/) - Protocol Detection and Opaque Ports in Linkerd [[2]](https://linkerd.io/2021/02/23/protocol-detection-and-opaque-ports-in-linkerd/) -- x [[3]]() +- How to configure linkerd service-mesh with Elastic Cloud Operator [[3]](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html) - x [[4]]() -- x [[5]]() \ No newline at end of file +- x [[5]]() diff --git a/roles/logging/k3s/templates/elasticsearch.yml.j2 b/roles/logging/k3s/templates/elasticsearch.yml.j2 index 35d713a6..25107133 100644 --- a/roles/logging/k3s/templates/elasticsearch.yml.j2 +++ b/roles/logging/k3s/templates/elasticsearch.yml.j2 @@ -25,9 +25,9 @@ spec: requests: storage: "{{ efk_elasticsearch_storage_size }}" storageClassName: "{{ efk_elasticsearch_storage_class }}" - {% if enable_linkerd is sameas true %} +{% if enable_linkerd is sameas true %} # Enabling service account token. linkerd requirement podTemplate: spec: automountServiceAccountToken: true - {% endif %} +{% endif %} diff --git a/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 b/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 index d804ae11..dfc6ff34 100644 --- a/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 +++ b/roles/logging/k3s/templates/elasticsearch_ingress.yml.j2 @@ -1,3 +1,16 @@ +{% if enable_linkerd is sameas true %} +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: l5d-header-middleware-elasticsearch + namespace: {{ k3s_logging_namespace }} +spec: + headers: + customRequestHeaders: + l5d-dst-override: "{{ efk_cluster_name }}-es-http.{{ k3s_logging_namespace }}.svc.cluster.local:9200" +{% endif %} + --- # HTTPS Ingress apiVersion: networking.k8s.io/v1 @@ -13,6 +26,11 @@ metadata: # Enable cert-manager to create automatically the SSL certificate and store in Secret cert-manager.io/cluster-issuer: ca-issuer cert-manager.io/common-name: {{ elasticsearch_dns }} +{% if enable_linkerd is sameas true %} + # Linkerd header + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_logging_namespace }}-l5d-header-middleware-elasticsearch@kubernetescrd +{% endif %} spec: tls: - hosts: diff --git a/roles/logging/k3s/templates/kibana.yml.j2 b/roles/logging/k3s/templates/kibana.yml.j2 index 6de08ffc..1fdc0ee0 100644 --- a/roles/logging/k3s/templates/kibana.yml.j2 +++ b/roles/logging/k3s/templates/kibana.yml.j2 @@ -13,9 +13,9 @@ spec: tls: selfSignedCertificate: disabled: true - {% if enable_linkerd is sameas true %} +{% if enable_linkerd is sameas true %} # Enabling service account token. linkerd requirement podTemplate: spec: automountServiceAccountToken: true - {% endif %} +{% endif %} diff --git a/roles/logging/k3s/templates/kibana_ingress.yml.j2 b/roles/logging/k3s/templates/kibana_ingress.yml.j2 index f96a7fc4..5ced3ca0 100644 --- a/roles/logging/k3s/templates/kibana_ingress.yml.j2 +++ b/roles/logging/k3s/templates/kibana_ingress.yml.j2 @@ -1,3 +1,16 @@ +{% if enable_linkerd is sameas true %} +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: l5d-header-middleware-kibana + namespace: {{ k3s_logging_namespace }} +spec: + headers: + customRequestHeaders: + l5d-dst-override: "{{ efk_cluster_name }}-kb-http.{{ k3s_logging_namespace }}.svc.cluster.local:5601" +{% endif %} + --- # HTTPS Ingress apiVersion: networking.k8s.io/v1 @@ -13,6 +26,11 @@ metadata: # Enable cert-manager to create automatically the SSL certificate and store in Secret cert-manager.io/cluster-issuer: ca-issuer cert-manager.io/common-name: {{ kibana_dashboard_dns }} +{% if enable_linkerd is sameas true %} + # Linkerd header + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_logging_namespace }}-l5d-header-middleware-kibana@kubernetescrd +{% endif %} spec: tls: - hosts: diff --git a/roles/prometheus/templates/alertmanager_ingress.yml.j2 b/roles/prometheus/templates/alertmanager_ingress.yml.j2 index f29ee21f..adaf40e0 100644 --- a/roles/prometheus/templates/alertmanager_ingress.yml.j2 +++ b/roles/prometheus/templates/alertmanager_ingress.yml.j2 @@ -1,3 +1,15 @@ +{% if enable_linkerd is sameas true %} +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: l5d-header-middleware-alertmanager + namespace: {{ k3s_monitoring_namespace }} +spec: + headers: + customRequestHeaders: + l5d-dst-override: "kube-prometheus-stack-alertmanager.{{ k3s_monitoring_namespace }}.svc.cluster.local:9093" +{% endif %} --- # HTTPS Ingress apiVersion: networking.k8s.io/v1 @@ -11,7 +23,11 @@ metadata: # Enable TLS traefik.ingress.kubernetes.io/router.tls: "true" # Use Basic Auth Midleware configured - traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd +{% if enable_linkerd is sameas true %} + ,{{ k3s_monitoring_namespace }}-l5d-header-middleware-alertmanager@kubernetescrd +{% endif %} # Enable cert-manager to create automatically the SSL certificate and store in Secret cert-manager.io/cluster-issuer: ca-issuer cert-manager.io/common-name: {{ alertmanager_dashboard_dns }} diff --git a/roles/prometheus/templates/grafana_ingress.yml.j2 b/roles/prometheus/templates/grafana_ingress.yml.j2 index 7b6aa056..89a88006 100644 --- a/roles/prometheus/templates/grafana_ingress.yml.j2 +++ b/roles/prometheus/templates/grafana_ingress.yml.j2 @@ -1,3 +1,16 @@ +{% if enable_linkerd is sameas true %} +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: l5d-header-middleware-grafana + namespace: {{ k3s_monitoring_namespace }} +spec: + headers: + customRequestHeaders: + l5d-dst-override: "kube-prometheus-stack-grafana.{{ k3s_monitoring_namespace }}.svc.cluster.local:80" +{% endif %} + --- # HTTPS Ingress apiVersion: networking.k8s.io/v1 @@ -13,6 +26,11 @@ metadata: # Enable cert-manager to create automatically the SSL certificate and store in Secret cert-manager.io/cluster-issuer: ca-issuer cert-manager.io/common-name: {{ grafana_dashboard_dns }} +{% if enable_linkerd is sameas true %} + # Linkerd header + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_monitoring_namespace }}-l5d-header-middleware-grafana@kubernetescrd +{% endif %} spec: tls: - hosts: diff --git a/roles/prometheus/templates/prometheus_ingress.yml.j2 b/roles/prometheus/templates/prometheus_ingress.yml.j2 index 9caf046c..ca822428 100644 --- a/roles/prometheus/templates/prometheus_ingress.yml.j2 +++ b/roles/prometheus/templates/prometheus_ingress.yml.j2 @@ -1,3 +1,15 @@ +{% if enable_linkerd is sameas true %} +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: l5d-header-middleware-prometheus + namespace: {{ k3s_monitoring_namespace }} +spec: + headers: + customRequestHeaders: + l5d-dst-override: "kube-prometheus-stack-prometheus.{{ k3s_monitoring_namespace }}.svc.cluster.local:9090" +{% endif %} --- # HTTPS Ingress apiVersion: networking.k8s.io/v1 @@ -11,7 +23,11 @@ metadata: # Enable TLS traefik.ingress.kubernetes.io/router.tls: "true" # Use Basic Auth Midleware configured - traefik.ingress.kubernetes.io/router.middlewares: {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd + traefik.ingress.kubernetes.io/router.middlewares: + {{ k3s_traefik_namespace }}-basic-auth@kubernetescrd +{% if enable_linkerd is sameas true %} + ,{{ k3s_monitoring_namespace }}-l5d-header-middleware-prometheus@kubernetescrd +{% endif %} # Enable cert-manager to create automatically the SSL certificate and store in Secret cert-manager.io/cluster-issuer: ca-issuer cert-manager.io/common-name: {{ prometheus_dashboard_dns }} From 059e3065b0c866d8a95a1fa789b787d57ca5929f Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 29 Mar 2022 19:05:13 +0200 Subject: [PATCH 40/45] Linkerd: Longhorn explicit annotation longhorn-manager and longhorn-ui --- k3s_install.yml | 2 +- .../longhorn/tasks/configure_linkerd_mesh.yml | 32 +++++++++++ roles/longhorn/tasks/main.yml | 55 ++++++++----------- .../templates/longhorn_helm_values.yml.j2 | 16 ++++++ .../templates/longhorn_ingress.yml.j2 | 3 + 5 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 roles/longhorn/tasks/configure_linkerd_mesh.yml create mode 100644 roles/longhorn/templates/longhorn_helm_values.yml.j2 diff --git a/k3s_install.yml b/k3s_install.yml index ea59d0d1..d3cfdd88 100644 --- a/k3s_install.yml +++ b/k3s_install.yml @@ -23,7 +23,7 @@ - name: Label K3S worker nodes hosts: k3s_master tasks: - - name: Wait for node {{ item }} to be ready + - name: "Wait for worker nodes to be ready" command: cmd: "kubectl get nodes {{ item }}" register: nodes diff --git a/roles/longhorn/tasks/configure_linkerd_mesh.yml b/roles/longhorn/tasks/configure_linkerd_mesh.yml new file mode 100644 index 00000000..e010ee12 --- /dev/null +++ b/roles/longhorn/tasks/configure_linkerd_mesh.yml @@ -0,0 +1,32 @@ +--- +# Make longhorn-manager container listen on localhost + +- name: Change longhorn-manager POD_IP env variable + command: + cmd: "kubectl set env daemonset/longhorn-manager -n {{ k3s_longhorn_namespace }} POD_IP=0.0.0.0" + register: change_pod_env + changed_when: '"daemonset.apps/longhorn-manager env updated" in change_pod_env.stdout' + +# Daemon is injectd through anotation (helm chart value) +# - name: Inject longhorn-manager using linkerd cli +# shell: | +# set -o pipefail +# kubectl get daemonset longhorn-manager -o yaml -n longhorn-system | \ +# linkerd inject - | kubectl apply -f - +# register: longhorn_manager_injection +# args: +# executable: /bin/bash +# changed_when: '"daemonset \"longhorn-manager\" injected" in longhorn_manager_injection.stdout' +# failed_when: +# - longhorn_manager_injection.rc == 0 +# - '"Warning: resource daemonsets/longhorn-manager is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply" not in longhorn_manager_injection.stdout' + +- name: Inject longhorn-ui using linkerd cli + shell: | + set -o pipefail + kubectl get deployment longhorn-ui -o yaml -n longhorn-system | \ + linkerd inject - | kubectl apply -f - + register: longhorn_ui_injection + args: + executable: /bin/bash + changed_when: '"deployment \"longhorn-ui\" injected" in longhorn_ui_injection.stdout' diff --git a/roles/longhorn/tasks/main.yml b/roles/longhorn/tasks/main.yml index aeba8de0..be237831 100644 --- a/roles/longhorn/tasks/main.yml +++ b/roles/longhorn/tasks/main.yml @@ -6,52 +6,37 @@ kind: Namespace state: present -- name: Annotate namespace to enable linkerd - kubernetes.core.k8s: - definition: - kind: Namespace - apiVersion: v1 - metadata: - name: "{{ k3s_longhorn_namespace }}" - annotations: - linkerd.io/inject: enabled - when: enable_linkerd +# Do not use Implicit namespace annotation for Linkerd +# Skip automatic injection of linkerd jobs +# - name: Annotate namespace to enable linkerd +# kubernetes.core.k8s: +# definition: +# kind: Namespace +# apiVersion: v1 +# metadata: +# name: "{{ k3s_longhorn_namespace }}" +# annotations: +# linkerd.io/inject: enabled +# when: enable_linkerd - name: Add rancher chart repo. kubernetes.core.helm_repository: name: longhorn repo_url: "https://charts.longhorn.io" -- name: Deploy Longhorn enabling S3 backup - block: - - name: Create Minio S3 secret - include_tasks: create_minio_s3_secret.yml - - name: Deploy LongHorn Helm chart with S3 backup. - kubernetes.core.helm: - name: longhorn - chart_ref: longhorn/longhorn - update_repo_cache: true - release_namespace: "{{ k3s_longhorn_namespace }}" - state: present - release_values: - defaultSettings: - defaultDataPath: "/storage" - backupTarget: "s3://{{ minio_longhorn_bucket }}@{{ minio_site_region }}/" - backupTargetCredentialSecret: minio-secret + +- name: Create Minio S3 secret + include_tasks: create_minio_s3_secret.yml when: longhorn_s3_backup -- name: Deploy LongHorn Helm chart without S3 backup. +- name: Deploy LongHorn Helm chart. kubernetes.core.helm: name: longhorn chart_ref: longhorn/longhorn update_repo_cache: true release_namespace: "{{ k3s_longhorn_namespace }}" state: present - release_values: - defaultSettings: - defaultDataPath: "/storage" - when: not longhorn_s3_backup - + values: "{{ lookup('template', 'templates/longhorn_helm_values.yml.j2') | from_yaml }}" - name: Wait for pods to be ready command: @@ -65,6 +50,12 @@ register: longhorn_pods_ready changed_when: false + +- name: Enable linkerd integration + include_tasks: configure_linkerd_mesh.yml + when: enable_linkerd + + - name: Create Ingress rule for Longhorn UI and Recurring backup job kubernetes.core.k8s: definition: "{{ lookup('template', 'templates/' + item ) }}" diff --git a/roles/longhorn/templates/longhorn_helm_values.yml.j2 b/roles/longhorn/templates/longhorn_helm_values.yml.j2 new file mode 100644 index 00000000..95eb108a --- /dev/null +++ b/roles/longhorn/templates/longhorn_helm_values.yml.j2 @@ -0,0 +1,16 @@ +--- +# longhorn helm chart values + +defaultSettings: + defaultDataPath: "/storage" +{% if longhorn_s3_backup is sameas true %} + # Backup S3 configuration + backupTarget: "s3://{{ minio_longhorn_bucket }}@{{ minio_site_region }}/" + backupTargetCredentialSecret: minio-secret +{% endif %} +{% if enable_linkerd is sameas true %} +# Linkerd injection +# Inject linkerd-proxy +annotations: + linkerd.io/inject: enabled +{% endif %} diff --git a/roles/longhorn/templates/longhorn_ingress.yml.j2 b/roles/longhorn/templates/longhorn_ingress.yml.j2 index 3a6a140b..e143fa5e 100644 --- a/roles/longhorn/templates/longhorn_ingress.yml.j2 +++ b/roles/longhorn/templates/longhorn_ingress.yml.j2 @@ -9,6 +9,9 @@ spec: headers: customRequestHeaders: X-Forwarded-Proto: "https" +{% if enable_linkerd is sameas true %} + l5d-dst-override: "longhorn-frontend.{{ k3s_longhorn_namespace }}.svc.cluster.local:80" +{% endif %} --- # HTTPS Ingress From ecbc80165241dd058738f7128ed8fb40f5216f55 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 30 Mar 2022 15:43:24 +0200 Subject: [PATCH 41/45] Linkerd: Changing the way Longhorn is annotated. Using manifest patching capabilitiey of ansible k8s module instead of executing linkerd cli --- docs/_docs/service-mesh.md | 100 ++++++++++++------ roles/longhorn/defaults/main.yml | 2 +- .../longhorn/tasks/configure_linkerd_mesh.yml | 51 +++++---- roles/longhorn/tasks/main.yml | 2 +- .../templates/longhorn_helm_values.yml.j2 | 6 -- 5 files changed, 99 insertions(+), 62 deletions(-) diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index ee4a8e9b..a7057afc 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -2,6 +2,7 @@ title: Service Mesh (Linkerd) permalink: /docs/service-mesh/ description: How to deploy service-mesh architecture based on Linkerd. +last_modified_at: "29-03-2022" --- @@ -418,11 +419,19 @@ There are two common ways to define a resource as meshed with Linkerd: Annotation can be added automatically using `linkerd` command to inject the annotation ```shell - kubectl get -n NAMESPACE deploy -o yaml | linkerd inject - | kubectl apply -f - + kubectl get -n NAMESPACE deploy/daemonset/statefulset -o yaml | linkerd inject - | kubectl apply -f - ``` This command takes all deployments resoureces from NAMESPACE and inject the annotation, so linkerd can inject linkerd-proxy automatically + Alternative the deployment/daemonset/statefulset can be manually annotated through the `kubectl patch` command: + + ```shell + kubectl patch deployment/daemonset/stateful "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"linkerd.io/inject\":\"enabled\"}}}}}" + + ``` + + In both cases deployemnt/daemonset/stateful are redeploy after applying the command. - **Implicit**: add `linkerd.io/inject: enabled` annotation for a namespace. Any new pod created within the namespace is automatically injected with linkerd-proxy. @@ -476,39 +485,66 @@ See details of implementation of this second workarround [here](https://itnext.i ## Meshing cluster services -### Longhorn distributed Storate - -#### Error installing Longhorn with namespace implicit annotation - -When installing longhorn installation hangs when deploying CSI plugin. - -`longhorn-driver-deployer` pod crashes showing an error "Got an error when checking MountProgapgation with node status, Node XX is not support mount propagation" - - -```sh -oss@node1:~$ kubectl get pods -n longhorn-system -NAME READY STATUS RESTARTS AGE -longhorn-ui-84f97cf569-c6fcq 2/2 Running 0 15m -longhorn-manager-cc7tt 2/2 Running 0 15m -longhorn-manager-khrx6 2/2 Running 0 15m -longhorn-manager-84zwx 2/2 Running 0 15m -instance-manager-e-86ec5db9 2/2 Running 0 14m -instance-manager-r-cdcb538b 2/2 Running 0 14m -engine-image-ei-4dbdb778-bc9q2 2/2 Running 0 14m -instance-manager-r-0d602480 2/2 Running 0 14m -instance-manager-e-429cc6bf 2/2 Running 0 14m -instance-manager-e-af266d5e 2/2 Running 0 14m -instance-manager-r-02fad614 2/2 Running 0 14m -engine-image-ei-4dbdb778-2785c 2/2 Running 0 14m -engine-image-ei-4dbdb778-xrj4k 2/2 Running 0 14m -longhorn-driver-deployer-6bc898bc7b-nmzkc 1/2 CrashLoopBackOff 6 (2m46s ago) 15m -oss@node1:~$ kubectl logs longhorn-driver-deployer-6bc898bc7b-nmzkc longhorn-driver-deployer -n longhorn-system -2022/03/20 12:42:58 proto: duplicate proto type registered: VersionResponse -W0320 12:42:58.148324 1 client_config.go:552] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work. -time="2022-03-20T12:43:48Z" level=warning msg="Got an error when checking MountPropagation with node status, Node node2 is not support mount propagation" -time="2022-03-20T12:43:48Z" level=fatal msg="Error deploying driver: CSI cannot be deployed because MountPropagation is not set: Node node2 is not support mount propagation" +### Longhorn + +Implicit annotation at namespace cannot be used since Longhorn create some kubernetes jobs, and there is no way to annotate them through customization of the helm chart. + +The DaemonSet `longhorn-manager` is customizable via the Helm chart, but the workloads managed by longhorn-manager (e.g. instance managers and jobs) are not. There is an [longhorn's open feature request](https://github.com/longhorn/longhorn/issues/3286) asking for this kind of functionality. + +By the other way, trying to use explicit annotation and injecting the linkerd-proxy, Longhorn is not being able to be deployed. See [issue #47](https://github.com/ricsanfre/pi-cluster/issues/47). + +One of the problems is that `longhorn-manager`, main component of Longhorn control plane, is not accepting connections coming from localhost only connections coming to the assigned IP address. When deploying linkerd-proxy all connections to its API are rejected because linkerd-proxy is using 127.0.0.1 as destination IP-address when routing all the incoming traffic to the container. + +{{site.data.alerts.note}} + +Linkerd iptables forwarding rules makes that all received traffic by the meshed containers appears to come from localhost. + +So containers meshed with linkerd need to be listening on localhost. They should be listening on "0.0.0.0" address (any IP address including localhost: 127.0.0.1) + +There is a [linkerd open issue](https://github.com/linkerd/linkerd2/issues/4713) for changing linkerd's default behavior and keep IP addresses when forwarding the traffic using TPROXY. + +{{site.data.alerts.end}} + +There is a [longhorn open issue](https://github.com/longhorn/longhorn/issues/1315) with a similar problem when trying to mesh with Istio. As a workarround it is proposed to change `longhorn-manager` POD_IP environment variable. + +`longhorn-manager` container open the listening port on the IP get form POD_IP environment variable which points to the assigned ip to the POD. See daemonset definition: + +```yml +env: +- name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +- name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP ``` +- Meshing `longhorn-manager` daemonset + + 1) Change environment variable (POD_IP) to make the container listen to localhost connetions + + ```shell + kubectl set env daemonset/longhorn-manager -n longhorn-system POD_IP=0.0.0.0 + ``` + + 2) Annotate daemonset to deploy linkerd sidecar + + ```shell + kubectl patch daemonset longhorn-manager "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"linkerd.io/inject\":\"enabled\"}}}}}" -n longhorn-system + + ``` +- Meshing `longhorn-ui` deployment + + Annotate daemonset to deploy linkerd sidecar + + ```shell + kubectl patch deployment longhorn-ui "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"linkerd.io/inject\":\"enabled\"}}}}}" -n longhorn-system + + ``` + + ### Prometheus Stack To mesh with linkerd all Prometheus-stack services, implicit annotation at namespace level can be used before deploying kube-prometheys-stack chart. diff --git a/roles/longhorn/defaults/main.yml b/roles/longhorn/defaults/main.yml index e9cb7acc..629f8c59 100644 --- a/roles/longhorn/defaults/main.yml +++ b/roles/longhorn/defaults/main.yml @@ -9,4 +9,4 @@ longhorn_dashboard_dns: storage.picluster.ricsanfre.com longhorn_s3_backup: true # Enable service mesh -enable_linkerd: false +enable_linkerd: true diff --git a/roles/longhorn/tasks/configure_linkerd_mesh.yml b/roles/longhorn/tasks/configure_linkerd_mesh.yml index e010ee12..991c10e2 100644 --- a/roles/longhorn/tasks/configure_linkerd_mesh.yml +++ b/roles/longhorn/tasks/configure_linkerd_mesh.yml @@ -7,26 +7,33 @@ register: change_pod_env changed_when: '"daemonset.apps/longhorn-manager env updated" in change_pod_env.stdout' -# Daemon is injectd through anotation (helm chart value) -# - name: Inject longhorn-manager using linkerd cli -# shell: | -# set -o pipefail -# kubectl get daemonset longhorn-manager -o yaml -n longhorn-system | \ -# linkerd inject - | kubectl apply -f - -# register: longhorn_manager_injection -# args: -# executable: /bin/bash -# changed_when: '"daemonset \"longhorn-manager\" injected" in longhorn_manager_injection.stdout' -# failed_when: -# - longhorn_manager_injection.rc == 0 -# - '"Warning: resource daemonsets/longhorn-manager is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply" not in longhorn_manager_injection.stdout' +- name: Annotate longhorn-manager + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: DaemonSet + metadata: + name: longhorn-manager + namespace: "{{ k3s_longhorn_namespace }}" + spec: + template: + metadata: + annotations: + linkerd.io/inject: enabled + state: patched -- name: Inject longhorn-ui using linkerd cli - shell: | - set -o pipefail - kubectl get deployment longhorn-ui -o yaml -n longhorn-system | \ - linkerd inject - | kubectl apply -f - - register: longhorn_ui_injection - args: - executable: /bin/bash - changed_when: '"deployment \"longhorn-ui\" injected" in longhorn_ui_injection.stdout' + +- name: Annotate longhorn-ui + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Deployment + metadata: + name: longhorn-ui + namespace: "{{ k3s_longhorn_namespace }}" + spec: + template: + metadata: + annotations: + linkerd.io/inject: enabled + state: patched diff --git a/roles/longhorn/tasks/main.yml b/roles/longhorn/tasks/main.yml index be237831..f6f1149f 100644 --- a/roles/longhorn/tasks/main.yml +++ b/roles/longhorn/tasks/main.yml @@ -73,4 +73,4 @@ name: local-path annotations: storageclass.kubernetes.io/is-default-class: "false" - state: present + state: patched diff --git a/roles/longhorn/templates/longhorn_helm_values.yml.j2 b/roles/longhorn/templates/longhorn_helm_values.yml.j2 index 95eb108a..f57a25b6 100644 --- a/roles/longhorn/templates/longhorn_helm_values.yml.j2 +++ b/roles/longhorn/templates/longhorn_helm_values.yml.j2 @@ -8,9 +8,3 @@ defaultSettings: backupTarget: "s3://{{ minio_longhorn_bucket }}@{{ minio_site_region }}/" backupTargetCredentialSecret: minio-secret {% endif %} -{% if enable_linkerd is sameas true %} -# Linkerd injection -# Inject linkerd-proxy -annotations: - linkerd.io/inject: enabled -{% endif %} From 905f107c0da6db0d0c2c59d2db18069d44f6b3ff Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Wed, 30 Mar 2022 18:02:32 +0200 Subject: [PATCH 42/45] Linkerd: Meshing Velero services --- docs/_docs/service-mesh.md | 16 ++++++- roles/backup/velero/defaults/main.yml | 3 ++ roles/backup/velero/tasks/main.yml | 41 +--------------- .../templates/velero_helm_values.yml.j2 | 47 +++++++++++++++++++ 4 files changed, 65 insertions(+), 42 deletions(-) create mode 100644 roles/backup/velero/templates/velero_helm_values.yml.j2 diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index a7057afc..8a3ca961 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -547,7 +547,7 @@ env: ### Prometheus Stack -To mesh with linkerd all Prometheus-stack services, implicit annotation at namespace level can be used before deploying kube-prometheys-stack chart. +For applying linkerd service mesh to Prometheus-stack services, implicit annotation at namespace level can be used before deploying kube-prometheys-stack chart. When deploying `kube-prometheus-stack` helm using an annotated namespace (`linkerd.io/inject: enabled`), causes the Prometheus Operartor to hung. @@ -590,7 +590,7 @@ failed to inject daemonset/kube-prometheus-stack-prometheus-node-exporter: hostN ### EFK -To mesh with linkerd all EFK services, it is enough to use the implicit annotation at namespace level before deploying ECK Operator and create Kibana and Elasticsearch service and before deploying fluentbit chart. +For applying linkerd service mesh to EFK services, it is enough to use the implicit annotation at namespace level before deploying ECK Operator and create Kibana and Elasticsearch service and before deploying fluentbit chart. Modify [EFK installation procedure](/docs/logging/) to annotate the corresponding namespace before deploying the helm charts. @@ -621,6 +621,18 @@ Elasticsearch automatic TLS configuration that was itinitially configured has be {{site.data.alerts.end}} +### Velero + +For applying linkerd service mesh to Velero services, implicit annotation is used for `velero` deployment and `restic` daemonset. + +This annotation can be automatic applied when installing Velero's helm chart using the parameter `podAnnnotations`. This can be achieved adding the following parameters to `values.yml` file of velero helm chart. + +```yml +podAnnotations: + linkerd.io/inject: enabled +``` + + ## Configure Ingress Controller Linkerd does not come with a Ingress Controller. Existing ingress controller can be integrated with Linkerd doing the following: diff --git a/roles/backup/velero/defaults/main.yml b/roles/backup/velero/defaults/main.yml index 234a74d1..e8d73afc 100644 --- a/roles/backup/velero/defaults/main.yml +++ b/roles/backup/velero/defaults/main.yml @@ -1,3 +1,6 @@ --- velero_version: v1.7.1 velero_arch: arm64 + +# Enable service mesh +enable_linkerd: true diff --git a/roles/backup/velero/tasks/main.yml b/roles/backup/velero/tasks/main.yml index 40d33677..c4a86b7f 100644 --- a/roles/backup/velero/tasks/main.yml +++ b/roles/backup/velero/tasks/main.yml @@ -29,46 +29,7 @@ update_repo_cache: true release_namespace: "{{ k3s_velero_namespace }}" state: present - release_values: - # AWS backend plugin configuration - initContainers: - - name: velero-plugin-for-aws - image: velero/velero-plugin-for-aws:v1.3.0 - imagePullPolicy: IfNotPresent - volumeMounts: - - mountPath: /target - name: plugins - # Upgrading CRDs is causing issues - upgradeCRDs: false - # Use a kubectl image supporting ARM64 - # bitnami default is not suppporting it - # kubectl: - # image: - # repository: rancher/kubectl - # tag: v1.21.5 - # Disable volume snapshots. Longhorn deals with them - snapshotsEnabled: false - # Deploy restic - deployRestic: true - # Minio storage configuration - configuration: - # Cloud provider being used - provider: aws - backupStorageLocation: - provider: aws - bucket: "{{ minio_velero_bucket }}" - caCert: "{{ lookup('file','certificates/CA.pem') | b64encode | replace('\n', '') }}" - config: - region: "{{ minio_site_region }}" - s3ForcePathStyle: true - s3Url: "{{ minio_url }}" - insecureSkipTLSVerify: true - credentials: - secretContents: - cloud: | - [default] - aws_access_key_id: "{{ minio_velero_user }}" - aws_secret_access_key: "{{ minio_velero_key }}" + values: "{{ lookup('template', 'templates/velero_helm_values.yml.j2') | from_yaml }}" - name: Wait for pods to be ready command: diff --git a/roles/backup/velero/templates/velero_helm_values.yml.j2 b/roles/backup/velero/templates/velero_helm_values.yml.j2 new file mode 100644 index 00000000..d0f11e42 --- /dev/null +++ b/roles/backup/velero/templates/velero_helm_values.yml.j2 @@ -0,0 +1,47 @@ +--- +# velero helm chart values + +# AWS backend plugin configuration +initContainers: + - name: velero-plugin-for-aws + image: velero/velero-plugin-for-aws:v1.3.0 + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: /target + name: plugins +# Upgrading CRDs is causing issues +upgradeCRDs: false +# Use a kubectl image supporting ARM64 +# bitnami default is not suppporting it +# kubectl: +# image: +# repository: rancher/kubectl +# tag: v1.21.5 +# Disable volume snapshots. Longhorn deals with them +snapshotsEnabled: false +# Deploy restic +deployRestic: true +# Minio storage configuration +configuration: + # Cloud provider being used + provider: aws + backupStorageLocation: + provider: aws + bucket: "{{ minio_velero_bucket }}" + caCert: "{{ lookup('file','certificates/CA.pem') | b64encode | replace('\n', '') }}" + config: + region: "{{ minio_site_region }}" + s3ForcePathStyle: true + s3Url: "{{ minio_url }}" + insecureSkipTLSVerify: true +credentials: + secretContents: + cloud: | + [default] + aws_access_key_id: "{{ minio_velero_user }}" + aws_secret_access_key: "{{ minio_velero_key }}" +{% if enable_linkerd is sameas true %} +# Enable linkerd +podAnnotations: + linkerd.io/inject: enabled +{% endif %} From f0a1ba12cbb2d56826a3efbdfb3fa29d312cacb9 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 5 Apr 2022 15:33:38 +0200 Subject: [PATCH 43/45] Updating Linkerd documentation --- docs/_docs/ansible-instructions.md | 24 ++-- docs/_docs/certmanager.md | 7 +- docs/_docs/index.md | 28 +++-- docs/_docs/k8s-commands.md | 134 +++++++++++++++++++-- docs/_docs/service-mesh.md | 145 +++++++++++++++-------- docs/assets/img/linkerd-architecture.png | Bin 0 -> 92907 bytes docs/assets/img/pi-cluster-icons.png | Bin 140642 -> 145232 bytes docs/index.html | 6 +- 8 files changed, 258 insertions(+), 86 deletions(-) create mode 100644 docs/assets/img/linkerd-architecture.png diff --git a/docs/_docs/ansible-instructions.md b/docs/_docs/ansible-instructions.md index 3710c6c1..7ae95de6 100644 --- a/docs/_docs/ansible-instructions.md +++ b/docs/_docs/ansible-instructions.md @@ -2,7 +2,7 @@ title: Quick Start Instructions permalink: /docs/ansible/ description: Quick Start guide to deploy our Raspberry Pi Kuberentes Cluster using cloud-init and ansible playbooks. -last_modified_at: "25-02-2022" +last_modified_at: "05-04-2022" --- This are the instructions to quickly deploy Kuberentes Pi-cluster using cloud-init and Ansible Playbooks @@ -217,7 +217,7 @@ ansible-playbook k3s_install.yml ### K3S basic services deployment -To deploy and configure basic services (metallb, traefik, certmanager, longhorn, EFK, Prometheus, Velero) run the playbook: +To deploy and configure basic services (metallb, traefik, certmanager, linkerd, longhorn, EFK, Prometheus, Velero) run the playbook: ```shell ansible-playbook k3s_deploy.yml @@ -229,15 +229,19 @@ Different ansible tags can be used to select the componentes to deploy: ansible-playbook k3s_deploy.yml --tags ``` -| Ansible Tag | Component to configure/deploy | +The following table shows the different components and their dependencies. + +| Ansible Tag | Component to configure/deploy | Dependencies |---|---| -| `metallb` | Metal LB | -| `traefik` | Traefik | -| `certmanager` | Cert-manager | -| `longhorn` | Longhorn | -| `logging` | EFK Stack | -| `monitoring` | Prometheus Stack | -| `backup` | Velero | +| `metallb` | Metal LB | - | +| `certmanager` | Cert-manager | - | +| `linkerd` | Linkerd | Cert-manager | +| `traefik` | Traefik | Linkerd | +| `longhorn` | Longhorn | Linkerd | +| `monitoring` | Prometheus Stack | Longhorn, Linkerd | +| `linkerd-viz` | Linkerd Viz | Prometheus Stack, Linkerd | +| `logging` | EFK Stack | Longhorn, Linkerd | +| `backup` | Velero | Linkerd | {: .table } ### K3s Cluster reset diff --git a/docs/_docs/certmanager.md b/docs/_docs/certmanager.md index 3a0eae00..5f59eb6e 100644 --- a/docs/_docs/certmanager.md +++ b/docs/_docs/certmanager.md @@ -140,8 +140,9 @@ Installation using `Helm` (Release 3): ## Cert-Manager Configuration -A PKI (Public Key Infrastructure) with a custom CA, will be created within the cluster and all certificates withing the cluster will be auto-signed by this CA. For doing so, A CA `ClusterIssuer` need be created to be created. -Root CA certificate is needed for generated this CA Issuer, selfsigned `ClusterIssuer` will be used to generate that root CA certificated (self-signed root CA). +A PKI (Public Key Infrastructure) with a custom CA will be created in the cluster and all certificates will be auto-signed by this CA. For doing so, A CA `ClusterIssuer` resource need to be created. + +Root CA certificate is needed for generated this CA Issuer. A selfsigned `ClusterIssuer` resource will be used to generate that root CA certificate (self-signed root CA). - Step 1: Create selfsigned `ClusterIssuer` @@ -193,7 +194,7 @@ Root CA certificate is needed for generated this CA Issuer, selfsigned `ClusterI {{site.data.alerts.important}} -Algorithm used for signing SSL certificates is ECDSA P-256, since it is the one needed as requirement for installing `linkerd` +Algorithm used for creating private keys is ECDSA P-256. The use of this algorithm is required by the service mesh implementation I have selected for the cluster, Linkerd. RootCa and Linkerd identity issuer certificate must used ECDSA P-256 algorithm. {{site.data.alerts.end}} diff --git a/docs/_docs/index.md b/docs/_docs/index.md index 50020b7a..fbf239ba 100644 --- a/docs/_docs/index.md +++ b/docs/_docs/index.md @@ -2,8 +2,8 @@ title: What is this project about? permalink: /docs/home/ redirect_from: /docs/index.html -description: The scope of this project is to create a kubernetes cluster at home using Raspberry Pis and to use Ansible to automate the deployment and configuration. How to automatically deploy K3s baesed kubernetes cluster, Longhorn as distributed block storage for PODs' persisten volumes, Prometheus as monitoring solution, EFK stack as centralized log management solution and Velero and Restic as backup solution. -last_modified_at: "25-02-2022" +description: The scope of this project is to create a kubernetes cluster at home using Raspberry Pis and to use Ansible to automate the deployment and configuration. How to automatically deploy K3s baesed kubernetes cluster, Longhorn as distributed block storage for PODs' persisten volumes, Prometheus as monitoring solution, EFK stack as centralized log management solution, Velero and Restic as backup solution and Linkerd as service mesh architecture. +last_modified_at: "05-04-2022" --- @@ -12,7 +12,7 @@ The scope of this project is to create a kubernetes cluster at home using **Rasp This is an educational project to explore kubernetes cluster configurations using an ARM architecture and its automation using Ansible. -As part of the project the goal is to use a lightweight Kubernetes flavor based on [K3S](https://ks3.io/) and deploy cluster basic services such as: 1) distributed block storage for POD's persistent volumes, [LongHorn](https://longhorn.io/), 2) centralized monitoring tool, [Prometheus](https://prometheus.io/) 3) centralized log managemeent, EFK stack ([Elasticsearch](https://www.elastic.co/elasticsearch/)-[Fluentbit](https://fluentbit.io/)-[Kibana](https://www.elastic.co/kibana/) and 3) backup/restore solution for the cluster, [Velero](https://velero.io/) and [Restic](https://restic.net/). +As part of the project the goal is to use a lightweight Kubernetes flavor based on [K3S](https://ks3.io/) and deploy cluster basic services such as: 1) distributed block storage for POD's persistent volumes, [LongHorn](https://longhorn.io/), 2) centralized monitoring tool, [Prometheus](https://prometheus.io/) 3) centralized log managemeent, EFK stack ([Elasticsearch](https://www.elastic.co/elasticsearch/)-[Fluentbit](https://fluentbit.io/)-[Kibana](https://www.elastic.co/kibana/), 3) backup/restore solution for the cluster, [Velero](https://velero.io/) and [Restic](https://restic.net/) and 4) service mesh architecture, [Linkerd](https://linkerd.io/) The following picture shows the set of opensource solutions used for building this cluster: @@ -94,21 +94,23 @@ The software used and the latest version tested of each component | OS | Ubuntu | 20.04.3 | OS need to be tweaked for Raspberry PI when booting from external USB | | Control | Ansible | 2.12.1 | | | Control | cloud-init | 21.4 | version pre-integrated into Ubuntu 20.04 | -| Kubernetes | K3S | v1.22.6 | K3S version| +| Kubernetes | K3S | v1.22.7 | K3S version| | Kubernetes | Helm | v3.6.3 || | Computing | containerd | v1.5.9-k3s1 | version pre-integrated into K3S | -| Networking | Flannel | v0.15.1 | version pre-integrated into K3S | +| Networking | Flannel | v0.16.13 | version pre-integrated into K3S | | Networking | CoreDNS | v1.8.6 | version pre-integrated into K3S | -| Networking | Metal LB | v0.11.0 | Helm chart version: metallb-0.11.0 | -| Service Proxy | Traefik | v2.5.6 | Helm chart: traefik-10.9.100 version pre-integrated into K3S | -| Storage | Longhorn | v1.2.3 | Helm chart version: longhorn-1.2.3 | -| SSL Certificates | Certmanager | v1.7.1 | Helm chart version: cert-manager-v1.7.1 | -| Logging | ECK Operator | 2.0.0 | Helm chart version: eck-operator-2.0.0 | +| Networking | Metal LB | v0.12.1 | Helm chart version: metallb-0.12.1 | +| Service Mesh | Linkerd | v2.11.1 | Helm chart version: linkerd2-2.11.1 | +| Service Proxy | Traefik | v2.6.1 | Helm chart: traefik-10.14.100 version pre-integrated into K3S | +| Storage | Longhorn | v1.2.4 | Helm chart version: longhorn-1.2.4 | +| SSL Certificates | Certmanager | v1.7.2 | Helm chart version: cert-manager-v1.7.2 | +| Logging | ECK Operator | 2.1.0 | Helm chart version: eck-operator-2.1.0 | | Logging | Elastic Search | 7.15 | Deployed with ECK Operator | | Logging | Kibana | 7.15 | Deployed with ECK Operator | -| Logging | Fluentbit | 1.8.12 | Helm chart version: fluent-bit-0.19.19 | -| Monitoring | Kube Prometheus Stack | 0.54.0 | Helm chart version: kube-prometheus-stack-32.2.1 | +| Logging | Fluentbit | 1.8.15 | Helm chart version: fluent-bit-0.19.23 | +| Monitoring | Kube Prometheus Stack | 0.55.0 | Helm chart version: kube-prometheus-stack-34.6.0 | | Backup | Minio | 2021-12-29T06:49:06Z | | | Backup | Restic | 0.12.1 | | -| Backup | Velero |1.7.1 | Helm chart version: velero-2.27.2 | +| Backup | Velero | 1.8.1 | Helm chart version: velero-2.29.4 | + {: .table } diff --git a/docs/_docs/k8s-commands.md b/docs/_docs/k8s-commands.md index fd474b0c..f8c22f9a 100644 --- a/docs/_docs/k8s-commands.md +++ b/docs/_docs/k8s-commands.md @@ -1,23 +1,137 @@ --- title: Kubernetes commands permalink: /docs/k8s-commands/ +description: Reference of kubectl/helm commands for our Kuberentes Raspberry Pi Cluster +last_modified_at: "03-04-2022" --- +## Kubectl Commands -## List PODs running on an specific node +- List PODs running on an specific node -```shell -kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName= -``` + ```shell + kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName= + ``` + +- List Taints of all nodes + + ```shell + kubectl describe nodes | grep Taint + ``` + +- Restart pod + + ```shell + kubectl rollout restart daemonset/deployment/statefulset + ``` + +- Get logs from a pod + + ```shell + kubectl logs -n + ``` + +- Connect to a container -## List Taints of all nodes + ```shell + kubectl exec -it -c -n -- /bin/bash + ``` + +- Service port forwarding + + ```shell + kubectl port-forward svc/[service-name] -n [namespace] [external-port]:[internal-port] --addess 0.0.0.0 + ``` + + Port forwarding from binding service `service-name` listening on `internal_port` to `0.0.0.0:external_port` + + +## Patching Helm manifest files on the fly using Kustomize + +Helm provides the possibility of manipulate, configure, and/or validate rendered manifests before they are installed by Helm: [`--post-rendering` option](https://helm.sh/docs/topics/advanced/#post-rendering). This enables the use of [`kustomize`](https://kustomize.io/) to apply configuration changes without the need to fork a public chart or requiring chart maintainers to specify every last configuration option for a piece of software. + +Since v1.14, `kubectl` includes [`kustomize` support](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/): ```shell -kubectl describe nodes | grep Taint +kubectl kustomize +kubectl apply -k ``` -## Restart pod +Based on procedure described [in this post](https://alysivji.github.io/helm-post-rendering-hook.html) kustomize can be used to apply patches to manifest files generated by Helm before install them. -```shell -kubectl rollout restart daemonset/deployment/statefulset -``` \ No newline at end of file + + +- Step 1: Create directory `kustomize` + + ``` + mkdir kustomize + ``` + +- Step 2: Create `kustomize` wrapper script within `kustomize` directory + + ```shell + #!/bin/bash + + # save incoming YAML to file + cat <&0 > all.yaml + + # modify the YAML with kustomize + kubectl kustomize . && rm all.yaml + ``` + + The script simply save all incomming manifest files from helm chart to a temporal file `all.yaml` and then execute `kubectl kustomize` to the current directory, applying kustomize transformations, and finally remove the temporal file + +- Step 3: Create kutomize files. In this example, a environment variable (`POD_IP`) within DaemonSet `longhorn-manager` will be patched with a new value. + + `kustomization.yml` + ```yml + apiVersion: kustomize.config.k8s.io/v1beta1 + kind: Kustomization + + resources: + - all.yaml + patches: + - path: patch.yaml + target: + kind: DaemonSet + name: "longhorn-manager" + ``` + + This file indicates to patch DaemonSet `longhorn-manager` within `all.yml` file using `patch.yaml` + + `patch.yaml` + ```yml + apiVersion: apps/v1 + kind: DaemonSet + metadata: + name: longhorn-manager + spec: + template: + spec: + containers: + - name: longhorn-manager # (1) + env: + - name: POD_IP + value: 0.0.0.0 + valueFrom: + ``` + NOTE: It is needed to set null to key `valueFrom` in order to delete previous value. + + + - Step 3: Execute dry-run of helm install to see the changes in the manifests files + + ```shell + helm install longhorn longhorn/longhorn -f ../longhorn_values.yml --post-renderer ./kustomize --debug --dry-run + ``` + + - Step 4: Deploy the helm + + ```shell + helm install longhorn longhorn/longhorn -f ../longhorn_values.yml --post-renderer ./kustomize --namespace longhorn-system + ``` + + {{site.data.alerts.note}} + + Ansible does not support yet --post-rendering option to helm module. There is [open issue in kubernetes core asible collection](https://github.com/ansible-collections/kubernetes.core/issues/30) for providing this functionallity. + + {{site.data.alerts.end}} diff --git a/docs/_docs/service-mesh.md b/docs/_docs/service-mesh.md index 8a3ca961..5678eed6 100644 --- a/docs/_docs/service-mesh.md +++ b/docs/_docs/service-mesh.md @@ -1,8 +1,8 @@ --- title: Service Mesh (Linkerd) permalink: /docs/service-mesh/ -description: How to deploy service-mesh architecture based on Linkerd. -last_modified_at: "29-03-2022" +description: How to deploy service-mesh architecture based on Linkerd. Adding observability, traffic management and security to our Kubernetes cluster. +last_modified_at: "05-04-2022" --- @@ -10,27 +10,51 @@ last_modified_at: "29-03-2022" Introduce Service Mesh architecture to add observability, traffic management, and security capabilities to internal communications within the cluster. -[Linkerd](https://linkerd.io/) will be deployed in the cluster as a Service Mesh implementation. +[Linkerd](https://linkerd.io/) service mesh implementation has been selected to be deployed in my Raspeberry PI Kuberentes cluster. ## Why Linkerd and not Istio -Most known Service Mesh implementation, [Istio](https://istio.io), is not currently supporting ARM64 architecture. +- **ARM support** -[Linkerd](https://linkerd.io/), which is a CNCF graduated project, does support ARM64 architectures since release 2.9 (see [linkerd 2.9 announcement](https://linkerd.io/2020/11/09/announcing-linkerd-2.9/). + Most known Service Mesh implementation, [Istio](https://istio.io), is not currently supporting ARM64 architecture. + [Linkerd](https://linkerd.io/), which is a CNCF graduated project, does support ARM64 architectures since release 2.9. See [linkerd 2.9 announcement](https://linkerd.io/2020/11/09/announcing-linkerd-2.9/). -Moreover,instead of using [Envoy proxy](https://www.envoyproxy.io/), sidecar container to be deployed with any Pod as communication proxy, Linkerd uses its own ulta-light proxy which reduces the required resource footprint (cpu, memory) and makes it more suitable for Raspberry Pis. +- **Performance and reduced footprint** -## Automatic mTLS + Linkerd uses its own implementation of the communications proxy, a sidecar container that need to be deployed with any Pod as to inctercep all inbound/outbound traffic. Instead of using a generic purpose proxy ([Envoy proxy](https://www.envoyproxy.io/)) used by others service mesh implementations (Istio, Consul), a specifc proxy tailored only to cover Kubernetes communications has been developed. Covering just Kubernetes scenario, allows Linkerd proxy to be a simpler, lighter, faster and more secure proxy. -By default, Linkerd automatically enables mutually-authenticated Transport Layer Security (mTLS) for all TCP traffic between meshed pods. This means that Linkerd adds authenticated, encrypted communication to your application with no extra work on your part. (And because the Linkerd control plane also runs on the data plane, this means that communication between Linkerd’s control plane components are also automatically secured via mTLS.) + Linkerd ulta-light proxy with a reduced memory/cpu footprint and its better performance makes it more suitable for nodes with reduced computing capabilities like Raspberry Pis. + + As a reference of performance/footprint comparison this is the lastest [Istio vs Linkerd benchmarking](https://linkerd.io/2021/11/29/linkerd-vs-istio-benchmarks-2021/). + + +## Linkerd Architecture + +Linkerd service mesh archictecture is composed of three planes: control Plane, data plane and observability plane as shows the following diagram: + +![picluster-linkerd](/assets/img/linkerd-architecture.png) + + +- **Control plane**: providing the services for automatically injecting data plane components into pods(`poxy-injector`), generate certificates used in mTLS communications in the data plane and authorized data plane componentes (`identity`), and traffic flow control services (`destination`) + +- **Data Plane**, transparent proxy running as sidecar container within the pods. Proxies automatically intercept Pod's inbound/outbound TCP traffic and add transparantly encryption (mTLS), Later-7 load balancing, routing, retries, telemetry, etc. + +- **Observability Plane**: Linkerd-viz component add a Linkerd dashboard and metrics generated by linkerd control-plane and data-plane components can be scraped by Prometheus and visualized in Grafana Dashboards. Linkerd also support distributed tracing integration with Jaeger. + + +## Automatic mTLS configuration and Certmanager + +By default, Linkerd automatically enables mutually-authenticated Transport Layer Security (mTLS) for all TCP traffic between meshed pods. This means that Linkerd adds authenticated, encrypted communication to all application by default. The Linkerd control plane contains a certificate authority (CA) called `identity`. This CA issues TLS certificates to each Linkerd data plane proxy. These TLS certificates expire after 24 hours and are automatically rotated. The proxies use these certificates to encrypt and authenticate TCP traffic to other proxies. On the control plane side, Linkerd maintains a set of credentials in the cluster: a **trust anchor**, and an **issuer certificate and private key**. While Linkerd automatically rotates the TLS certificates for data plane proxies every 24 hours, it does not rotate the TLS credentials and private key associated with the issuer. `cert-manager` can be used to initially generate this issuer certificate and private key and automatically rotate them. +In our cluster we will use `certmanager` to generate the **trust anchor** (root CA) needed to sign `identity` TLS certificate and being able to validate the rest of TLS certificates issued by `identity` to `linkerd-proxy` processes. + ## Linkerd Installation -Installation procedure to use cert-manager and bein able to automatically rotate control-plane tls credentiasl is described in [linkerd documentation](https://linkerd.io/2.11/tasks/automatically-rotating-control-plane-tls-credentials/). +Installation procedure to use cert-manager and being able to automatically rotate control-plane tls credentials is described in [linkerd documentation](https://linkerd.io/2.11/tasks/automatically-rotating-control-plane-tls-credentials/). The following instalation procedure is a slightly different from the one proposed in that documentation since we will use as linkerd trust-anchor the root CA and CA ClusterIssuer already created during Cert-manager installation and configuration for the cluster. @@ -40,7 +64,7 @@ Cert-manager need to be configured to act as an on-cluster CA and to re-issue Li Cert-manager CA root certificate (trust-anchor) and CA Cluster issuer is already configured as part of [Cert-Manager installation and configuration](/docs/certmanager/). -That trust-anchor anc ClusterIssuer will be used to generate linkerd certificate used as CA for signing linkerd's mTLS certificates. +That trust-anchor anc ClusterIssuer will be used to generate linkerd certificate used as intermediate CA for signing linkerd's mTLS certificates. ### Linkerd Installation using Helm @@ -58,7 +82,7 @@ Installation using `Helm` (Release 3): ``` - Step 3: Create namespace - By default, the helm chart creates the control plane namespace with the `config.linkerd.io/admission-webhooks: disabled` label. It is required for the control plane to work correctly.creates the namespace annotated and labeled. + By default, the helm chart creates the control plane namespace with the `config.linkerd.io/admission-webhooks: disabled` label. It is required for the control plane to work correctly. Since we are creating the namespace we need to provide the same labels and annotations. @@ -137,20 +161,20 @@ Installation using `Helm` (Release 3): - Step 4: Install Linkerd - ```shell - helm install linkerd2 \ - --set-file identityTrustAnchorsPEM=ca.crt \ - --set identity.issuer.scheme=kubernetes.io/tls \ - --set installNamespace=false \ - linkerd/linkerd2 \ - -n linkerd - ``` + ```shell + helm install linkerd2 \ + --set-file identityTrustAnchorsPEM=ca.crt \ + --set identity.issuer.scheme=kubernetes.io/tls \ + --set installNamespace=false \ + linkerd/linkerd2 \ + -n linkerd + ``` - Step 5: Confirm that the deployment succeeded, run: - ```shell - kubectl -n linkerd get pod - ``` + ```shell + kubectl -n linkerd get pod + ``` - Step 6: Check linkerd control plane configmap @@ -161,19 +185,19 @@ Installation using `Helm` (Release 3): ``` The `identiyTrustAnchorPEM` key included in the Configmap should show th ca.crt extracted in Step 3 - + ```yml - identityTrustAnchorsPEM: |- - -----BEGIN CERTIFICATE----- - MIIBbzCCARWgAwIBAgIRAKTg35A0zYXdNKIfOfzmvBswCgYIKoZIzj0EAwIwFzEV - MBMGA1UEAxMMcGljbHVzdGVyLWNhMB4XDTIyMDMwODEyMTYxM1oXDTIyMDYwNjEy - MTYxM1owFzEVMBMGA1UEAxMMcGljbHVzdGVyLWNhMFkwEwYHKoZIzj0CAQYIKoZI - zj0DAQcDQgAEYcZquh74RiIWje8/PHC8haksDdjvQroRrZQnsKP9j/LL+C0qLx9n - 7Fs3nLMQ6ipRZ1KV9k/sP0nFHzI4G4W3wKNCMEAwDgYDVR0PAQH/BAQDAgKkMA8G - A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFM+IzMMYOlVcCe0BEBvmVKGO7RF9MAoG - CCqGSM49BAMCA0gAMEUCIBRop9dU9iDuZRVlxFLjwwxnQxL601atw/298/wQWdzn - AiEAwlZ6RTYjoN4XHxQnz2yZhu7ACsjX5p3oSNnL2nOs+7k= - -----END CERTIFICATE----- + identityTrustAnchorsPEM: |- + -----BEGIN CERTIFICATE----- + MIIBbzCCARWgAwIBAgIRAKTg35A0zYXdNKIfOfzmvBswCgYIKoZIzj0EAwIwFzEV + MBMGA1UEAxMMcGljbHVzdGVyLWNhMB4XDTIyMDMwODEyMTYxM1oXDTIyMDYwNjEy + MTYxM1owFzEVMBMGA1UEAxMMcGljbHVzdGVyLWNhMFkwEwYHKoZIzj0CAQYIKoZI + zj0DAQcDQgAEYcZquh74RiIWje8/PHC8haksDdjvQroRrZQnsKP9j/LL+C0qLx9n + 7Fs3nLMQ6ipRZ1KV9k/sP0nFHzI4G4W3wKNCMEAwDgYDVR0PAQH/BAQDAgKkMA8G + A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFM+IzMMYOlVcCe0BEBvmVKGO7RF9MAoG + CCqGSM49BAMCA0gAMEUCIBRop9dU9iDuZRVlxFLjwwxnQxL601atw/298/wQWdzn + AiEAwlZ6RTYjoN4XHxQnz2yZhu7ACsjX5p3oSNnL2nOs+7k= + -----END CERTIFICATE----- ``` ### Linkerd Viz extension installation @@ -487,13 +511,24 @@ See details of implementation of this second workarround [here](https://itnext.i ### Longhorn -Implicit annotation at namespace cannot be used since Longhorn create some kubernetes jobs, and there is no way to annotate them through customization of the helm chart. +Implicit annotation at namespace cannot be used since Longhorn create several kubernetes workloads (daemonsets, deployments and jobs) that cannot be annotated through customization of the helm chart. -The DaemonSet `longhorn-manager` is customizable via the Helm chart, but the workloads managed by longhorn-manager (e.g. instance managers and jobs) are not. There is an [longhorn's open feature request](https://github.com/longhorn/longhorn/issues/3286) asking for this kind of functionality. +Only the DaemonSet `longhorn-manager` is customizable via the Helm chart, but the workloads managed by longhorn-manager (e.g. instance managers and jobs) are not. There is an [longhorn's open feature request](https://github.com/longhorn/longhorn/issues/3286) asking for this kind of functionality. -By the other way, trying to use explicit annotation and injecting the linkerd-proxy, Longhorn is not being able to be deployed. See [issue #47](https://github.com/ricsanfre/pi-cluster/issues/47). +In order to not impact on the performance of Longhorn data plane, implicit annotation at namespace level should be avoided. `lonhorn-enine` and `longhorn-replica`, data plane components shoud not be meshed with linkerd so mTLS connection does not implact on read/write operations. -One of the problems is that `longhorn-manager`, main component of Longhorn control plane, is not accepting connections coming from localhost only connections coming to the assigned IP address. When deploying linkerd-proxy all connections to its API are rejected because linkerd-proxy is using 127.0.0.1 as destination IP-address when routing all the incoming traffic to the container. +So we will try to limit the meshing to Longhorn control-plane components (`longhorn-manager` including its `csi plugin` ) and UI component (`longhorn-ui`) + +{{site.data.alerts.note}} + +One `longhorn-engine` process and a set of `longhorn-replica` processes is created per Volume created by Longhorn. These processes run inside `instance-manager-e` and `instance-manager-r` pods (one per node) whose controls their lifecycle. + +{{site.data.alerts.end}} + + +Trying to apply the explicit annotation at namespace level or only explicit annotation for longhorn-manager daemon set (only available at Helm Chart configuration) causes Longhorn deployment to fail. See [picluster-issue #47](https://github.com/ricsanfre/pi-cluster/issues/47). + +One of the main problems is that `longhorn-manager`, is not accepting connections coming from localhost, only connections coming to the assigned IP address. When deploying `linkerd-proxy` as its sidecar, all connections received to its API endpoint are rejected because linkerd-proxy is using 127.0.0.1 as destination IP-address when routing all the incoming traffic to the container. {{site.data.alerts.note}} @@ -511,16 +546,29 @@ There is a [longhorn open issue](https://github.com/longhorn/longhorn/issues/131 ```yml env: -- name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP ``` +This environment variable can be changed using on an already deployed daemon set using the command `kubectl set env` or can be patched during installation of Helm Chart using its post-rendering feature with `kustomize`: + +- `kubectl set env` procedure described in [this comment of issue #47]:(https://github.com/ricsanfre/pi-cluster/issues/47#issuecomment-1077866955) +- `helm+kustomize` procedure described in [this comment of issue #47]: (https://github.com/ricsanfre/pi-cluster/issues/47#issuecomment-1081754487) + + +Applying patching procedure on installation time (`helm+kustomize` procedure) still produces the error that Longhorn is not completely deployed (CSI driver is not deployed). See the analysis and the root cause identified in [issue #47](https://github.com/ricsanfre/pi-cluster/issues/47) and the correponding [bug submitted to longhorn project](https://github.com/longhorn/longhorn/issues/3809). + + +So the only way to meshing `longhorn-manager` component is to wait till Longhorn is completely deployed and inject linkerd-proxy using explicit annotation afterwards: + +- Deploy Lonhgorn using Helm. + + +- Wait till it is completely deployed. + + - Meshing `longhorn-manager` daemonset 1) Change environment variable (POD_IP) to make the container listen to localhost connetions @@ -743,8 +791,11 @@ Since Traefik terminates TLS, this TLS traffic (e.g. HTTPS calls from outside th ## References -- How Linkerd uses iptables to transparently route Kubernetes traffic [[1]](https://linkerd.io/2021/09/23/how-linkerd-uses-iptables-to-transparently-route-kubernetes-traffic/) -- Protocol Detection and Opaque Ports in Linkerd [[2]](https://linkerd.io/2021/02/23/protocol-detection-and-opaque-ports-in-linkerd/) -- How to configure linkerd service-mesh with Elastic Cloud Operator [[3]](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html) -- x [[4]]() -- x [[5]]() + +- Linkerd vs Istio Benchmarks ([1])(https://linkerd.io/2021/11/29/linkerd-vs-istio-benchmarks-2021/) +- Why Linkerd does not use Envoy proxy ([2])(https://linkerd.io/2020/12/03/why-linkerd-doesnt-use-envoy/) +- Linkerd architecture ([3])(https://linkerd.io/2.11/reference/architecture/) +- How Linkerd uses iptables to transparently route Kubernetes traffic [[4]](https://linkerd.io/2021/09/23/how-linkerd-uses-iptables-to-transparently-route-kubernetes-traffic/) +- Protocol Detection and Opaque Ports in Linkerd [[5]](https://linkerd.io/2021/02/23/protocol-detection-and-opaque-ports-in-linkerd/) +- Linkerd gRPC load balancing vs default Kubernetes kube-proxy([6])(https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/) +- How to configure linkerd service-mesh with Elastic Cloud Operator [[7]](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-service-mesh-linkerd.html) diff --git a/docs/assets/img/linkerd-architecture.png b/docs/assets/img/linkerd-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..8dbffe5a37e7939b1dd57d9ac0699c87f56a9cf7 GIT binary patch literal 92907 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

VvQ1_j`(EK17jZLhL2|2hGXaP86;WrzbKB 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

dup*hd- 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 HBH(`jX-qt! literal 140642 zcmce7by(HU_O61`(jgrZ($WnIf^>IEE8QI;-3`(p(%s$NE#2KnH+Qz*bI$MHbMN2R z=TSEwX3w6PwPvk%z3biAd-m*=nCM6OXU|^5KYIq{4+jOFRG9M?up^;|E12 z?Snq5isV z`R666k2;j3^}k+EMtu$v`sZ~<+zSPQe-9`BvG%XG=2Em_`v2=SJ$yDNWHvCRiP*cY zzcZ8i$Vz;tM*i1pb@cx~Q-i$)2E%1^tK`;5J2}Qr4F~OmRmq;6^)z}B3h{Pgf!E$u zoIZ(@99;rZG)#zX$UwbHjIc_5j%KH705I!e$>br*|MuawX+>_Z+~5vpn&yOoL%oYtfBui z!*(Pb+sl7G7!C4{;BVj^BL2RRBd3RpTSql{JW)jduP49?leML&z(ToQZ8ijgLj zWfI{t7jniHybLYce?0*n^a=$L;$7;m=z2&ekyaBZ{_BZukWj9dE-COBSz7N+aBBFx zbsuxRrb0y8mnEVo!wFf>>=N;3y4i!dHzCUF3f5(Tw z5G0K@KugcRK(dcb%`e zU}UW*fzyftoJ)7gWrBF@@TyFr_^6&X5e)=jLN5R9gjRYSE|2shH!WW#61=sg= zPHQw$MMqzkeIG|hE`+gZA)hfnT!( zgJa0LyI=&~k>g1h`Cxw#6#sKjf)Y$SMZuxGuh`?~vY`CS#-^ys?Wp>NmOj3I+17c=ArI_s?$?l?QUR zZr{f0sBR;|4Os2BFd{p<4ymnT6`xWRmAc11B}DLW#(q^zQazsxkd=v5G^^*rDIdsj zuh-Fx6n*@`QQCfoBA6?uOApR)e8!hkWxf6u*<{<71+|uolbZN)>r&V=#a@K-vvI9G z{H&G8#clqCp28bZ`giS_3um*Bp;Q&RO5%~IgFZ=vtk7t}st&OlMq;A$*l|7GOP>i| ziZY^j+Byx7zky}IM#zJ1Rp9Z+a(ZNhcl0Rd;8I~^Wq-cC?$NXvHDmV%OPg4wE^BK} zfXz3=#nGj(6p8U5$uku#?)k4Zlt(d}qt%Os1{fzAVghXX!ggfO8D}+Bhg)~g#Qn?H zs|ypU!C6Vem?Ol5zh%*oA)c*)2t4~@I#;DrDbF$H2waEY-#Lcy>Rpr@(mu)SywoKJ z$C(LLGK3egQDV;5X-M>wM@5kBDGrD% zDc{iS2w_A<2%nE>o{iJwik)h`xIlY<(ro&tIWY~-pk-orTF+Uta%8YT=^@4VECsgo z(kV{X0U9-<=L*j2<#gy(Dx=jR3h()H53}#4bOuoew~orWkcFO zSU;SrBAKEmaj}$o8HbYU`-j4wt4`)Rx}w5jR>DnEH#s!3*%AF%pEQ z+c=7=S~;B99zJf@Q~VgGG8^u#&fqsu9j0e%Ih*F%mKr9CvUfL8%D13;xf!>7ne$M3 z7F4>&dtKkmFW9iJ;H~m?jBnAGA^v32V=ne|-ivixs+ci-UmxDzxSVO~BGhhi#$JH9 zND3V}uYWi$cPbOtV)l_hpy(is)3YouW9W(N`Ds!q?@x)9H8tyYX2IMth&Q^J+zKW~ zw@6=tAXybC?8=~hH%?gRT?tjT^wM~57!LL)bmcI=6YGExR+8@~40%?sE3AleZeyK8 zzU1(f%FZ9vyQ7$#aS1KkIebS)3^D?^Q+fB(_ahlh&!g7_u?0|7I)p7=^)3tDZ2Y)9 zNpCli&g*i^v=~%s=5M{oYcs7nP4F5n*jmYZa1=K-#yxaXzA3hy7I~LHT5@`!loNm0 zD6h3FI`dkaLwB~0xHorL@uv5r8aU#s&PNb*cwXk=GqyhmA>Xb567o|MPlIavCv8kX z3_PpLt_t+k!?1yleAK(Z8lGIf+tySr6H|R@J;onM9O9q0ejH}ne`ar-BhJ%t$fHBT zieR#wV$*}m)YKYxg_L_O0}nO6UExY!&r#j}mLwE`h_zitGV1G%NJY_{b|IUsyGhC7 ztdgq3MVd9?_r{p^)2&Vd-482sN;Wd`ZF?QK?d27WSp|Jff+=NZIg8XVhz}FRn7UZZ zPu?AKa09(kF$sskHAZ1O8+^Zn)|>HHrmW!>X+ToW57$r)u#J-IOeQ6z#BZ>ZVITTD z{iSA~nBXf^`gr@>@({Su4%imYt8rp5}=7uwTdS=i-WsQhVIytPiK!7tg)?x*fK=qF!pFeWe6F zJ&>!(Sd#B`#?92G^NAU|c&kUwuIakp{+sKxL@$jF&h~9O)}^L*J%1I=l$F*33QsX- ziK;D;l9mqf^r7jGv(_6ZWlkioGvyDy`+sPxwBfcD&omKpFU0zpipAb0vygW}GBzGD z1ddH~s1pd<|0Y1NF7~rKNhH{Ba56Ol;3P?Q9}DNO!sRi27n-cg9;dI)k2^F(M*z6* zQp%E$rgd()g5hCo=83@*4#&>sTDfc7i%V%^AMeVWlauOp8*@bucZ;YB zd~@^K%aIo+Ybr+>LF#4R@dLjpv4=pojQJ;AW<&BQcS98jm(-N1EN}R&`i2K9f8r~` z%hHmB1VvuAUALqW^Lpy_{21MjlF|CqUD8DD-p+pSxbxFhpH{Jk#xdXSP@2p1i`^lQ zn0D`1Z7NUH)urYfSNal`!lR2iT;)XPo0^Z-T^a4HFj%$7woq2zIcv(<%ifVLzVozm znz$NhEdUt91>$H)Tgm~pLFY>C{#O9+^vEY!7#Y}^3d4ROCYam0GKL}YbUaW&xpL5c zucRA+lpZC=qk~V1|kLvgE3~@#&deZl(7PB<9EL zdTkT-L{>gu{O$l|^$7>?Z*6&%{x61n4KUSS`YiTZvH>QOrJ_?tTl3mzRbYZHu#+qZAxJm|KuJZ|p*qxU6A`!cH09gfYNTYZbT+Tbm4jL*{(}2MHsj<9 zGn^O={$-~&wVFIbhy12@#8nleDu&_w)A|y_Yy=JR^G7k?kI=M>Hw&j#QXHgx<26h? zj*o3mCc|{7Q=cT-2U=1v=aORaw27y4s?W?GLl{vwp9_)=$-cCPwb?wn z!$*b)1Wj8JYwGv8_1g#52JvrGH95mae9ETt?kf@Xkp&`gynZ zISAX~$XAWG4}2!O2S|4Zj8s0(t@)WYxJAwE9e<#=1MZ98tgE~pYi<`(Av#{VX#P$E zdt1Ug@oiN5<|uY?Pyu7QL}gJDdMa;uf1P_*(4M9duXtqmg1VMp+_!;q>Ow37n}%z- z(adwWQEpX=m%wm{!607d&aS1FEb^YolH?-~C@v?{OR@cB&8uPn);@l_c;M9rLikE+ zY>{6KnNGsoth2kKp_S3oqP{!+dgp`R1C5q(3HD?jIh^CuP2V+Ms(J&-VbIgLWp%u^i|HCAO9+KJ;haAX1937r?62_^T@JluBoa1lE9(vJ2CG7mc!~yeH z-8=nV34Tyt4aAS%>DKil&S+8*_+QHn9K}cjK;hJ=hn6~*HiF!|s`{oz`Bh2y zzJe`f(_X6jW^+t?d25x<=1t*gnu8WvT;$zMs$w}~-FcTanv_81dvi$UVtaKU7bsig zR?GgiYidB{-Y)1BBZ?^+we;t5CY__+Aj@^8UqbpR%Wpsl21Sd!IflgJx>Dt3m6&lO zK=s}OBkq$Oye2QLw5kXk8%bdoshvK3CF=ICIEAxM{%Ip@MZD@07mAR2k3MlV?qKkA zLOjXY2O3iSz=O=c)2+UMWgXl1R&O{0wJO;s`WZnjI;dH(qeImi+1@Y+@)VmQ{^%nt z`S*Ajbr;g%sSQ;DPWW#M&pAm^lOUy=imAefPVX3(TZMKFAfC0awTlx+ooW z8$lXsMe&(5+)CwpNbNbPnT4eW)&dd@Ii>0w_No_<<&;6{ValRB)a@5JP*#E`yVW5Z zZWWNyF!zQF6baUEEde?~Es5heCWbh@A|#-R(b9HuwZXT24~(P@-y)Wn3YLQGHJT4c zf+K}GRe*c&Z0`V*9`QeKP%fbB8Ftj|>xma!~vvjZ|cgpX3PN&{Et>fIs04`BRw5FMn9%*cj1ZaP6mI_@~JpkuGX zh8!dl1koW_DE-Y)!-PcDYqCpulHPwe`iElk^=cE&lGm!cs+ox}&-D~cAxr`uHpm*qZGxIFALd=! zal3zBe4Wiwh8*GO5Yy}r;e7?zsxv&?b$a$XSjd@wgE-?W>@^xwob*Hv8n@llgMWKh zGs5{fczXpb%vIQUpp*qPWZ@)W;en;7DukXX2jIFwoU2ij60*TOtGXWN1+rQCS;RSUH^$f)ocGg6HGAmpHfsuA?BbTJiLi@GjnqKPSTnqM%h5ES^#!fV&M|+;Wrh}veTBHwRkpv z$*8=diPs2>r={Vyl5(jZpQe%d+n$?P^Z3Xf0=6WcryQo{>R|b|f|;Po|6Mr6fyFug zi>IvM+59)LAve@NcnMZ|6mWJ-l#P`ni)c_&!GmI4vKZ-bt=Qbv-}_cR>*w33?mcCp5>+IXzdFMAv5mOX;3F*^E}ylIy~OyzuPQ~_rGtWCZt3TM?%cc(~C&Z zzjk%qdwP`mjlcUexWl}?^!j_NH6Chyd!8g<-hP5wz$O0|m>dDzj(Xh5c3;FUVV{MO zDEfHmUvY2)9^73#6Z%J16bRB=kT{X zS=VLW9ekBGf2vKKb~fA_V3CfnVxqF1HjjfNHetG7Mqa1kXY3!=sn+ic?y_XI+lhx* zaXce#z^S;Pekr0`C2EO34c+tYLvA&&;}rlK4A=CLx?MKs3uT0BKg%>e^Hm|rN{F5M zyU)63@)cy#qvC*DRunc)k63k*w9(nQ|EJ zYjs7F8}kRlia!2Ql?Z(04bCu)28Y9=#fB{Tud=ccGeHp_%PBKRnr3d#d*8X?7iR4| z8_E~LZD;PRL(_sHor5oc%ShA>7vE?;395yO2M%0M+D?64R>eR9^>BYS(tf(q z=50KZN>8UEtEqY4Pg^o$#;zI`65{r!3rC42)=EJOH&i6J3(8TYz|x^q>Utq0G?dT% z_8izs$MeCyOo{B~ux7d1ViBS4sA^hUfyNZC;bJg>CC%fOdZ0YQDOer&s@0J@55V`D->T=Q0Ah4gEo}w%7@AXlo-Cs=WJe{RIHD3JI&{J@4 z+cs+PcnBlntN$`a2A7~$@bR?wP5Avu2a1P>M?9m>dyXHO)NockfPa zw$nT>XN|?sTU1PNCE1NY+^vOMj6lA)zq2!TvIi8HcN%K16#cw?7w#$mKMi-E;0AUm zZ}trs!-4@ZSh=m2H{+A|sv$+|w55VSH7K6=SWU}kV33VSnl3_IEFosWfrOSyr_mq_ zDpbAtnZwUG_uDhvq);>sQ>nK~XfK|BprD}GZ1sW`Y@m%Z^mQQ=mOH^eogX@1q62?u zX=xc4u%|7hV?X^IJ6YD8+~PE3e(Z`D&q9R)8$zB%Io;z}c4KkBwF|Ivc6MfLJZYcS z@uW8kN#yEDrcHRm?X2%pK-_Egrd|`DU_Ys-Zw*~ASLDZ91P{%mh6a5c}#^M{kjE_N>jgds7R`Z69WjZ}V&IUI&)_B4Ctwv);)TLZ1 z%JS@=o!#$?p9&VUjUFE#--v{Ke!W%F@`#?KnapXuwlkKA8Z=jJj#$7kYx{90NbMLo zA@n)=L5kxNmwtDMKQL??EV0``S&zrV#dMSFmBY~jt_8%mCB!?+;$VjXXw-IVqnvMW?R!RKQH{XDAQX9yL6-lY%_ z&@pS;TlRcnOOV8%k~UjzZkkaHCFF6qKlXgmDARj+uifBKq+NnzY4w(tRzgye?(Is8 zLT_Imm+cl(;rI2PaFqZta5=S_T&iqU_NPlY@Cq1&*)c0-=@_(L%3KCgrGE33h-cW` z+Cm7;bruKw24@V1qm$|{OR4w|Kk*^p?EXF;>!@*p4Ed&g3R;17Pz_)$$HK5C#SGdbv3JRE>_3s-c+X*r+d*3NH85B zT)-l|metmN91(a5C_+Z+cppXvw-&~8gz7@0{B^$CyuOybFnIP&1f$1+B5cVaUOk_V6{?(LNvrA6$&1HiP0Afp{Q4*-(_ z9smb6g~zZ-{=!O$py#XT72IbLXT zb(}8N!eP+7u7)PB2lkarVt?iE)@Rw zluff$s09(olKHeCP&R!gE#B>VVY-C`57EffBZbWbYXqge#2DVp`>F6;YqZa{V;Bc3 z2JL6lC{t(o%WP6nVg>ETR)(K{Ge1S3y+kT}6}JA`FX5do)UP}~*UMx9&!yRBn@w@m zA8e*^;#uF#eH>K4&c1033=9|pD_;4YSG7JT8%1Pn{9LA*>iKxn$m?-^3Vh*srVM(V zkWMCr8*6;d!9Rt^5!i9Aj0N6@`^$2bDbBACx&kFlmv|dOqTZCzU&nq5pJ>dKKX03m zl$Q1@b?IAO>k5WNA#%HzQi-S6fT`iXm{brv{WvrP3KB|u9!IC#!u&vP*(L~`$lZ3P zvY`zij)adBHMV4kk3yP$-n3S!Polh0s$5Y_e#}%Hva+Rk+3YNW_q+nRZuJbuAy&?2 zkz`R^n+1za0Ym&EYA1bwRfj)H&8*qe<6X(%YI4a;NGvx@*?RLe{z-~ri*6h1t?dM3WQhuHo*mY5K%#We<;DQXqPQ&CMZQ)Gb$P7Q<=E;!6f@p zR!=*2TDR}l#?rcT-Ag5%8yFs+U-6L|BXaM3d>oFOuG)_`2jYcty?w!D!@l#S291 znz#@$P((1Y&cq*uL$fat}e`QYA=(Gs2_0O-! z4)}yF3OUs@u_jxC38-e(X0tYXlX<`kO<5CpjvEyk>(Hb7$YYB5pYG3Gf$g6AtEot( z@e_`tEvU=O%MYy0`y%3WhY`A7Ejn7xRZ>$>yj&yh9Uk^uZpX5=r(c_b`GBfLP|poF z0Iu2`ioiWd`~ZjL(*4*c;=rVz8i2n-vQ#@0@m&vrl6nS!{1kd>7n!4%Z|#=8LC6&_ zAQ0!`5==FyK5#J3=)8J*K{wsQ(soPub$7NKLrnPTKvab$m--EeF8fH7b0Wb{2AIry zHX=7mnM#;)L)ddB`a)2XYcB4K9(RWko61G%7a%38(qZ=+wY9aana93g!oWUid3war zar@&do^Jhke*+fzPHmODCI5A3cTSoI-cNlyJ67J?EQxrMmd%ZgjjgThoE#KFZpDRS zG{sa#(|-X9do3|(Nv?ht z+8f8R%ZoNiS~1|aURfHaigl$}=4`W}XSPp7ZmfL8RI`gj|88*ClRK-!67*uDy-ic3 zk!lzTxr5()Db>WVBApl^kAkdGsj#0(*TwA~@T+hlJ`(;1kh;BhC_+r-3Ad}Pz^!qA zdblEWQF<1d=62eb8P2b+l_se|C7nD|ZWt^{d3QN)N%~wwSQwxyXBU?}JMJoVEobi2 zZV@>}Sy@!NnD}@coM~eO*h$&{RL3ud-;TyWievMYKsp;l)c{jJGWS@ZjDwQck)|TG z1OF%Y?o78tQ52DQ;SaH}G-}Qy&7Uy}Fc|a{fp?VES|=YhmuFf(W!v9g4z<;U21Jx5 zk4e&EO=d(p2Z~|A=5Qseu4F}b41;}r-?&`yMnM=D8yjO&X`QRFWJGdXOU69%^EuUu zJ^Ny8XxMffM#yuyKP~gcy54HFeYV25D>l3RT?i_n?<%XW$mIFTB6ZUYv!x;@Sa#>% zWdnw$h!_}x-ZRDQai^4UTjEla4wSx`@bI!%huEdZs?ySr_6lhaRcu)ct&XV#b3E4* zFCTFD=BIJ{=7gP_?=)Lvw2x36D^(NZn-0^=r(aF|h|5}b<#m)TN&ozmbSMXZ)Oa== zujApo)aY#4bP*?#iKbDow!hEgaGQ)Q|mFCR6k%2Jgm&`#s}4&m%oOkA9D^F|PHQOa@7~^8RC4d7KydB6pL zM4NE5g=#sn94zrkeIIXCZ)AtU4D?j zVw|ke&V28e^8|{VR_PTAcTmW5Ny%X_&;9^>#Tr>9=tc;V%I$+>UVL!3)VTnP^aQL9 z3;9QSs`!J!b}w4|snO;(Z&%odlkKjF?VExk)wp@*cl*WGV=avW_tkQ8<9knE-^Pyb zM$bQ-ww2~(W?m8uVdpDQMI)%(C-MGrlwF?T9{EPsNfjVpm1j4``l^LCsM$Pq}R*_ zy}gld{85OTK}xTsW@o?jf+hOq`*hdx)NnS;vkbx$NaMEcKJd0%gSY}7Zp+Q?tCXwX zQhdDgM&AyaM5Lw?5fcO0GJO<#zB@t1!-HRqCerA0Xgrj-xlpcAV{w8XrSai|S53{8 zijMos@Zn<|whSn~hqmnVzOrV()dflIU_<(|*g7WECi_8Ek@bUM9|tGH_lzpKDCh&G zoHvQsTHf7F)Z|Y~^!``us!i^8lLO%w=a+?3T`FE4dn%~`_#EWlNyxjh;%ef^Pk55Y ze987T117$(qAIqxx0|rs2DG#Ym=U~wt(vjMVK!3=0OO){58-IDURMyulGFMWSQ&^( zo(~r)z5W1F28V=Ta@cE%UxCVQ5oDK$L_WQEiBm&LsJ(?cw@7u{!I`n%AJ z?h3%uj?^@lJ?a^AJG;u9oE&A>#S?m~ciP(8+>7>SwC{t%!%+x|ER|NMeSCc2nmA&` z4d1_i?@Pbh9Kk}W!T)%@4zLeMO%`&|VzlLSvk6?rqN0*k=69VxyCI!mCL)tnJpzLC zq8UrvtBYF0nEz?Go8+a~PEsN0PvPN3g1xZdZ7Gq_F1_CQrHgjVJFSwLKeBJeJi+L0 zXRv;BewBLcI9yWStq(OF|xj)A^Nv(a~a~x=@6;Wm`U&1Un2ozXoXZ+pmd$KdrG{Sj@cl$T~^#c4&6*EDy64l#!yBV~b zsH;{YURy?wBk(-KTkr#K>R&LVc6ru(M}_(q&88j?S|i&m1CeMwWSAVy{A<4u92UJC zrOpCg?AF5ZNd#?`-yZRGZrrUs$}iDA%Y6o7@xgH93BQ+94%Ib6RHxeaJ13Ey_uIyf zuJ`=Swv>YOi-|s<2W)@hO^3lr2^1U4*z-gse`cS}7^pWdxC98LTf9(F6bMYJ;>_yo z$f`c7`f)rsX7`Bidt4ybQ>=LDVhn-hBDeFhCUXr#M1_^($o7hFirM(C+2 zvVM~Y#K!x7FWg#&>nM$vABZdDyjyalI&`?KqFN{VF(=pfDg!&%sFwJ0Gk0?`2#bYd))6SRbdEO!O*gCt=O~($g=^ecdZDQlZ=Ju~Em5oGo81 zv*kZr?Cs$Yl9zzW|2j+|ss8qpDU zX1W|D3Bxc?#>y0yA76sV$%Lw!xbGIZilxk`l0P6;!5A9d0oIwa=hgwGz}!*K4sjJo zYD%EPv`P@50z;p&bx;DffiSF;u;jo{_p5Y9Q`3T;<3yp-d2eHh$VR|YDc)g;h`X*7 zSCC#yJ<@RYF&QAEH|~G>=i{COAo!oT+*b-sfnEr@3Y~uY0xnjJtD6np_qs?n7;t*3XrpdY0>)*bj{zjS3#jJtrQ}DU-*~$V*j7Q+*+hRZu`&JVJAi4i?s#c z0~?@_I{F&dN6%!zn%Hj@44hYU5J@JA^ZYGP6qe>X+d*6A{n)Bg zq`AZ-Q>XsN`1jVrWH&~p<+VN$4Ujy9Mb}wnVRZ!Q;5^rBcFck(09B=Co?(66Ko6qH zwCYcYLjaqrYsb)>%>PU}OgKpN`XDEkVKzaS#Yv4(a0g~3bZx>M7j$R>)geGC*AT*# z6u;}r_zjI{eWb6cvRn&y2p9w@b`hZHWr(lP>y6z`emHCt>2?a1%B6tFR?<#k!Rjb< zoprH~=6ryfFa6@K?vSShQ2=pXy5KF5fy;YDn1ulte~6-!3}#n`LbSHX)%s=vx;lZz z7Hty(5xKa?x03`Go+XeB|K!=&%m-J>2rX-CG#J7#=^{1zOQ*>9H&QkB?PJn0%V|^vV+y3!Ngp+ z!h?iFCgo)kR|e~?v2b-2pf_|pnEsy{q3AVa?2k3sV9=FJUYjHHK8NH2G>bx7Q!N7i z2OxQOQBJx5ctHAn{lwK2$O!)}wH(n=_ta8mSOG1uktmx9K>dvk1Mjx?a*7rfM*v9z zc0o6R+VBO*{e80kY(R*}hPF%)K7F0ta1 z#KH{8Ur^95XB(2pCbQg z&3Fq-6_CzV_$r4pPw8*>lyu=c=(SGD$)zC?NkAo3uLc3Jy`dp_ky_^m0gJv>Olio1 z@_#OkwOPF%sKv@X9&UYnUi9jVXMyD52ntQ}`D&z&R)08h)?UkJ*q^6Ns<;Kz$}1`u zwHx8`P^x_zsba-5fBpol7&b96quJ=aIj_;DevN-GHigCnUN$LK{lNLR1 zjGpq!KtqzDpb}`}ud%741c#QMRz7BK#Id7cc#xjva+WjDOv%)SR|a3__5aX;dS3zb zO^=VgCL8;Y@I+~U)#3cpV#x~{w)u9i;Kz?2W%@lLA|khUcflN!a=N;@+S*I29sc12 zTu`pATM5RU_=&VhDXw=l)uNQ=EGxO4E-D#eW3DMCLc?vn8cJlZ4Uv`)`hw;`uS!uIc z`#CnbhtFRzJNRy}+5L{0nfdcY!*R1IfMaH6X7cjmKbZ7gu8s)N(d7rU0QeLn$oE<& zOBj^?um|Z@rc`wN6ix(4LPv-M;Y5s)WP#Tx)(rR@up1QKlW#MV_rEsAElXHa`sClm z$%kPq8@xcGEgK`~WarTd+|Ym%{26l=IjGn0n=A_s&fW(1gVxg!`iF>^@dAw>7qMUS z*+1BnVNDJEpE8vV70{oL1{W0;0Ch>K^TFos;c7Wl*&s5ky^Z-2Xjf-ID*oNTc!#+KZN-KglwLXW%Jp4}zlKVg>OjTB6cIN9KiT!NqED6u;2jbm59$JV1KA@mUZ7& zAW=dRp&{#|nT;l)arG&20=U>x5t9l+$cNdAv|>({Id21N;yll&nM#qMiHp#qeHY#5 zvzAGDwwu4Ey&*eLbprBy3bcze$ z){uz#H5VeG8~p$W&;^J?QiOg?OmoBbyW99|JUvR^`Tj#?TEf@s_D9QhBeGJrkx&Jx zai&>?p=XoMeAg@9gxq#N_*|U!E-J$q^1r_}OVfDZ4& zQILXone9>?jdEOkfJ(EEr!Y>Ef5y zes>qY{e!oI)q(cSDtSmK8_v9{UsEN;C;W8Y6Jd0HV>Y}YaM`#(>1*wX-lrhLS7p$L zu6klx65LQ?uI9(JHT=%Knk&5`r)seHBuZ_-yfQ)Vi-GZz^c9?vt6%<=yBh;Xo==oq ztC4I{o??@* zC}RWDfc=`3I>3R>lMUL9wWAJBSac;bAx4(@bTFS)-)nQB9toxH>ha+YNFIo;5S|C< z1%G-UAHA5gGnyU**W3=UyRFfMX3UXVh~t*g4*c~w6B3ET=jBD>f9@eKvOd)SdV2P>!)5oZmBXo2H!Rf=UR zkMx(?Am#uKe3)lLV`|@UD^HrZc-|&6^d~$%cR$aE-=j*)#QTdpMW!kVQwZ~-S@M2{ z`nGaEHZ-N)~{d@H2eK2{X*bNG@>fvijQ(`j2s~i|RWf*52TK2hvg>3z;v>IG+Lt<|9zCw&%}(9NX$_i5y(8u{=5qFBU@2ElROp2ZFu(7C zeS#TTPm9&Z5=<%eiuXGh6M<2)uuGZ7y^(T)M!e)U%SWp;gj~>f75vfUR z8o?U2P_R7_RR-&)h)%!l@J;fVR6bXSp+q*umiyCDoO*{Qp7HD)+Lkyg9Ptky=q8Pm z=(8#*MKebGR#;MFB5%zU)}G{tE&CH$b;kvs?%ymup91`@Y!kc!bWhEnR>o7)h(^7x zu>_W@kk@hq*dk-Bl{1?*X%g{%#>S>1;h}C%>lRDXdMA&`<81L~k`Bsya5mU}p=T3( za}<)Q_S}l;0#6IPeI)|Kd&@1g<{G2~bB5*VF)<#lSIDbx=Drw{8&V!sJ6)VPx_rD2exPDBoS=2Y2VrMBo*9*W3Zdu9W}2@hzs(=2Lwry< zZj;NE}c|#_8am-rv9cDne{<`kQI@r zA~Z0C#^&bcvfJ4ZkT^V!7PtyB--x83zF6Jdve}HQ!U>d4^*^X;S@+&OW7^M8pc7(4+|l?6LB?@pb;D9aD3Gjq&ZcNf$m^n zY+Pkd`;jw@PyDrUJdWA)WM zxS#8$Svh{0PP!o?L_PoY>xDe=f-p7JAp248%XvTjtw#B5{U4GAWUHjzS8`utJ6F$? z8??wM4(Ln=XcUV0zObszrkel44C}E~k`J@q9Q#h?=c^a~MUjFNxAsSo4D~yN0%4c= zTB5dg=6a>qet_To^Cq0P+~r~qNNS0}mTaY}bU-V(-pxs4&}k;X$KO9Zq+eROTwv-F z%aRwh{)9qITbFx}B3c^n6t~#S5;Y zG%|C~$5p%PryAK`GgwGv-jn-_vJ8gtF}>jK)`NVZv4+ry+ks0KAmjCd~BDA zXEYl&I5=o@KJ$?{kTnN2KB9-jMoFFZ51wivP1Z+O5&QR%A4^2F#50_)y2e4UFjjfL zVV7U)B%__Wu@|4sD(s7eBa_73#lf#lh-J>6w0XKuBYc7vH-Eq-LOW!mb#Lb*=DE|0 z=9F_$`)I<^APGYqD9M?cJ*{#7;L9YvGR0^%UwzgaDYc-xC76A9W7w@FX5&{~UWta> zVX#SJ+VoU9vMAK)^mI%*(P$Zbm0TuHEm%aN`J_lv=WNm^E3gZl$!h-H0KShsW1Yf0 z{>5DcO2~LS3=E5L2G@4e=jWFw_yobig&rBNKq8&ckAlD7CH5F);lyUp$1^SEkDd`a%K zFchPP&ogUne4XX*c2+=j$;c0zA)R6Cc1L5@Wo3hspaUy&?YhP}+){w!Ia2VJi+Wnr zRwmxe?NN2DgxdVmiwoCsZ=Fvl-QDF5)-1g?rD|5mHJY@DNJt@JVc2tW=5(ObXf_^w zDgF3}n3V2~B2~2h1NT2&AG3Qmho5PcmDR!zdh?O@sCTSC65+BdzDTuq=?oQ-X zl$ZNxq|BZ8a@xoE)5y{bIPaYYVo)IyavL}z1+V>*?;kRsgS`j{<@Zee_JDZ79Tshq zy!6(?dxg%Wn+{ zaaxKzW(*$lQkTtvNB22eiC1B?1%xEk7ZxQ>dOwf)#OlMhooEeT*j8Ec_x#b_f}_ow!F`USHJDXhjq^1pIcMn^*J<7I>lInwhK8d5bWK>xb1GJZ zkrG8LbYcZ={B2$`u_1Op9~;dO0$QH>@vVk^P*6~+>rq`_G}ZRTMu3#Xpp?SGdbq$6 zSGMh5+r3X($&7gz8gdD8LL+WXP0FN#BVvgqax+AuF={ZvFmRW zq-4X&=yYQv-qTdXjJqxgRIJwN^PBTgy3I5U1(3{{v=qy4i@FHMpMPp@GN7yEJ!yqL zoUg&Le9s}DTT{&ag8}q&R`^%7eUOrEdbPX4#`XIObe+F+X>KrBe|scfk;2zkJ}<`MywZ*$2QD<^`y|w{FVI_?Ky;a_DsY-t!lWIu-`U}EG5c&? zX6eFxp!Q{3RXNAJzKsT<|A%oiHEm7*VH}yN@AlVnYY(EyC@S|myOox@mKdp#$6r=M z&!d%vX*Ta^b*rsWr^G|)J~FTRdg-w9EJsFd*2?Mx{puWfF*p3`;3pl8v14kvU2x3Z zj;L|Z^Qa9=EIs@KY=>r}7I>n!TuGixs~IiH`}>)hD`h_MM93uz`A%C&@|>SPdGn}O z3-lQ1ZzH30^%2RL^YYiH)RIRYa3(pDHfU;okb0>%U#M0A5q^}fu}hw}2^9i(*!t~x zU|^tLbc4+V%V%G~v1)UTDB?>Uve@WSk|irF#I&l-N=w(pUn92;iI~m%O%q9vNuPU} zgruXtz7@T6O5kX!Mi)n|kbMuNqF37A3+UL`>_JNjP*5Mie_MLTR0h-mj0*BOHyzFTDbkKs}Mww<=kh#KY6 zg`&E2gJW5J_&VH2SQ!bY=1-*_9;i^W1fQu`Zx{Y(=x0)7 zHa}FxuK(>D5*8((O$T(S%H>a;RL>msqM-zCh$>D;8}-G?E2ug-O*3fm@|EDPbc)U^ zgxD3wK3H^wr8yF1|0+*UCkfrEZ`1!0M_)aPFsDA=Y-@90+Io6gT49XKWjXkRNn2Zr z)nF%9(`7&mUZ37RW`g{L@|ESpvA_mjE~3D}Y98jiei{z;zMAeAjL#Le86J~*qB`p3 zwaIMro&4A2ebeV}<;UsOJpjRx%lJ}*nQnVujK(0U%QIGM@TWv*VOu+V6;E9VuUp$3 z`^V~|&{iH;6FT-k`+QF6WPFGy2q>=#yc=j%Kd(e2rxBrUu%~SlZ`7*P%^2uo7s(J# z4x1VvXUT^l^>hnS3}c^qwx8=0iTRb!hpkEy{-^>#w%b7Ezq<$yPYUx+A~GXgS9_ZrUZF zGU@3$)`=jL$u{1&ybycKYgiX(2ObM{<+2KN`6CVeS`)kT~IC9UO*Du@}`b$a_t9OYcNo1c>@%cn3N2$X%MZPiARITEt}hL-lX(Ar+Irn+ z(NkbnF}mxabk>UDQ`a~QX;&SlBNi;Q$xgChd^IT!0le?V~U1 zOVyS4j7u=i_2N^cu)UwR(h?2Ox$p0eThyxaZFfcVS@B3Yq!XCC zdU`&Y*-#xNt-S|4gX7^`tOHZQTeXsLYTouKH_8G8at5s*H1E0*$K$i|CBD!ZR*xPv z>n{aH%c6I;b4#PpkY&ACusa$FS*N|GT{9Z|@n=#&rmt8V_q&Ookit)qmpOBP%z06? z#)xGmu0sA7S8u^pRoJ#`t0*lcA>Ccl4bt5y-QArFDd~`IM7p~hM7q0Kz@oc*ebeW8 z-*1n-$KW5##hmwjUB`Kxli?Nia!e_x$15qViJ5A)t2fv9{p)Yn*i}$l*ySB)8Xl$J(|)0ZPlL0RO$^W z8otp{!7j6t@t0TaP-s$d?tI8t`yW=Sc-^sjxbP0R6a&EH-p!GewDK%~1psG1PslJ< zUCX#8*JtD(qM;~j9vgmGu!`<*_E}qjfq_&Cna$5Bkd_ogN(P*%4aLHE#5xo;Dotrs z6wLh7kt)xu74>uBb#u>Oy`sAWk<(bx=qgz1&P&Z_GcJ&&LSVr9?=nEHdjjZFI069K zhjE_Y%|&1~x;8EZwrEr{&5jl$CQl0FDM1}bp?LH8-Y<3vyJFm&y&GSLi?|~GH%Sy$ z`T;>6RUFYj;wgJaC;vH)tyai+?=JF%h=uW7#-?mwU)+Lf;pgK8{r|NV0o*#Png}Bd0&JE)!>J)>cpsXG%0}bx;eU zSRv?zy?3gnMG?_O5!cd`e_1m+CPf^^X#$U_LoIu2-COwAWw8n?7M0P~eXB5iwUj!? zCrprq*>{$n*X!mxq|a~1CxSH1w}=RGQ*kyq1p8G;jv4+;)SC`4> z0eur|qC91_2Ic5{inpkDz`&xXmyTd&SRH_jF{&25>wikVmmTiufXH{2l4n%1k_)pC9^J@*Qc0$R@XTYMVgG5IOpuE-%XjoeZs%K@TGs?yE*U*3&k}BeLoa7^2*Lo7xNs)7C`WtB_bKVhplB}9wdeem;9x!cn5zPB` z40b{O4iv(sc;!Wr$kGLWWz7n0^RPtp(xS&3zQ_dHSDDi4VV2p*ju@eurY${pk)8QL z5QE0_tqVxIdH}Ko7nz;BOM55Z^fLGDGEM9e;`d*(u1b4;QF$f;bADAv9-cFx6|;8T zUxp{<8Cgh|zt^)N06cEIz3Zo=t2NHs%B&%O*o+thxwl#TQ+UKu9&E%tz%^CLwxHYR z(MnO7!PU+hL7b)HEEtr{`xPd3kx8uaAa%(Sy!jz-N4sH^wcV$Gp>z&Nmsb4|6JlYg z-%WuBKuKragooq035{|s(#qL2J&(1UNm0~rdJKe-T6`{hOwGey`=%UTH$-=FWqbA- z3SUAdO)Rkek5KyP%)|t@}}MUigHZxxJiOmTNbgDd3vYevgE_m_(*5QR?Kq z&Y#qgrHF&^syxZBQ7M|ufB9rGYRT_bACX&hPazNv;8S$g`J_1YeYGqbxA`QeWgpJ&{WEY~9CYoFD)^X^eXGg0rCK}xjHY-&FsFouP1Yx?Y1f{E zKb9t{n!oJHOa=%4EjU;>cWiS zV-1#-X++zzl_>DZI|J+t0ztv7Hmb52nd2~$v3T&B5iW?NU~DP7nQLQ* zwCo@;bK1L;2%m-Oz7=e$6{9fzB$W1>U+gYj1dpPT^L<&gkF)gDf!qhtBiZZGIuB1l zjx=b(t5q4e!a%lz?xp}h7Sqt`)tp6&cJF?1U2JPvCocSzEGbigd0O_Nb?hIBb+I1?CiE$g6G_R$M z6ux>kKEVx)?}izWX`F9^Gvh)+v$gz&IN;xEy_~fs?l++@uO`xQ>Q$|Kl#g#%M1T|r zaWt)Sdr*HV1F0(@y$h@j+xLw91QoQgllbFV+|JL3SeKZ><$rDd=J)FONi`y!6|S^| zV3h>JCHzU;(F_@C^=_m$G$L(#L^G*rm*V{~+%4=Ad)@RU(h5cLk^VZycF!-8$SC~T zYIKyuw531v8uRwQt)#1Cuh&U^4TgU^n=fH^w4P>Bd~oDS2st8PdNS(Vh`9^ggu^!O zHJj9$5Rjp8{32vOg_CmS;C+WY*PYw@w$A-(Xe8M=?_Oci`hQJb+EI?hJ>XR*`Aq<0 z9UULX);z3q*yyZ8N3m>J_Ezla|1t_dlD3?nd2Fr#T7~O%pR+Y!=MEt6Khbw+%$`0h zqZ4~6>K^kwm~2R2$gptAE!-@kv+ntAAowMLv-4HeqxWvg#K-rb7ikWzT&)l@9)DVs5?*kj|}EGgJfFfc0RWXGvV5w`#{V zhUIj7TXLFi{%iKr(`8?m0j6f@#oyifVW(o?u`Gr1v2F6p>6R#y6MoH887Tn>mCXNS z`9rIhMLu{c7=C6dGOcK4`nkw@H^!uQDSTRny03Xxmwj$HY$c*CB}Y?`p{kB9Sz5{v~deA^10PJbvzM?O*PdgS5xFGqWz%*Gn5Y zqxfd@4dyA`Ur_q0IF##55>AdxRa$o11sU#nOQV51A(0l^5}fN907=lz`~i^O&)(Zf%8V_qD2SX#1-CS`GO%~zXAGFs$`ehtB0gi zN5r>;pAAz4h+$4O(57ih?tF7tuK3|ZM+RO$HH8R1`fU2GL3;Kk za)4L-A+RW;{?gZuu<Fc|9EOIXnIX3@iZV> z_M0pVkmDM(N})`84eBohx&H_bK-IJz$sq&Sbc;{!Au8z}4Fr-iP&UYjAg%Y)Q!kDnoj!ZlahvB+xS;elM7ah-i#+Rd#A4B_gx77-b08$c2B9xA$?qPo{qb*-%ruO@_0 zkz53xx()>Xj@NpR4@+@}>C>s)DnDfRn>}r6@CXl4VvfwYmcXncf$ri%d(WVluUAC} zQ8>q zNa|)?xI+*w#`YJ2`Hkez!TRHvJJw406Pa9a?YvaexJbesXIion_-&>J@@rf8PjAvC zppDsg*9cnmf)&3?y`Va9(PV|(8<9y_jmr-#c?cnJBVBtJ4nF0<`3NNeo1X|pmDc4R zzFhUd-IR6Gc%K~o{veA8Jv*o+_R*U71|JepC&zAYp!GPk5K`r_CYq?iIOfzYQt`#u?>#{Qq zA;*nG-OgeV)X}avhkez+d*jRNW*t&m#wsJhX96OIzTCeaYN-_j1ioqVaEfA!g%H3# z<~r~Y4?Hz~b#7V$Ygerp8w!a$r>otuEt$0;$R+S!sjVgGdw&jORSm&+8~!-j647{A z7-YAyrSy^g&O3wXP6Z7vcbHAC2h#wD&n><$ayF$gZl83nSGW_5Nw%s(xne-K+Ran@ z4Nvbf?=>|&u?&9c=Bh2?*Hn;NDmOil$>4Cg?t3WHOjF|t09%W* zt_e3Vyd6W9=K)fDsi~ihynvgVi2PYuRcEdC!bC6 zM6cP~OArg{%wO(Z0$=IM4&%o7Raz3}a~rX}A_H>ZUHMcb3hIbY*`4H{> zMt;J8TIUOkGeGVJ&Be;i{Prr{zI0JzJwXT$rlL@pi#AW&y%(cq!=NLFeCjcUV|&Oh z?~$P)*-S$)8yot#u4#t(cItid&GjjoK}*gpXT0Tonir|1-cSk)=O-ju1qIjG-JH1= zS6+_TO8eI){J^#}yUdMnI!^H+sv?vGq4N)HR_R!@ZXG2U!>l9LlT%Co6fI?)ogGt0I1aPi74s`=GQ=B`8Cqv@ND{hk8B)CzNuVrkU`0LnlRIoohJroT)!&Cn~@IRxOzeirF zApYY~Ii{6h$C!sdD}&pkl|znm7uXDD13GYA#3~9jI%u!le`bNPCphVMH%_6GX z|HBv%7~%Q?qsv|qN5^v@Uq;KYpl)w(@71F7OznQeW@4l^g93yER47y8(7>D-%nHML zjXkcyizHu5I}8@C+|HDdIwZ#~_aTy2h@ZEe{d%8!-SX(e*hE+K0A57(Z!w5a@MG?YB+` zAfK}FBibiqZ;9ldngMPE_ci3J-+{<53M$8vR&L|uaB;rVgkX)+EsP>&N@6iJgY?wR z-1&y^+Gh%6c!vPFfT*Bmmu<|VWLev_J;&v9z{CN9RQU`$w|AY*Z z0&d^To*%I)U4l>zK3T9`8jN4&6i)b{E)hO2LcL-;^=7;>Tl+o{U5q@RtrK1@V%p&} zyJfLh`JTqcUFW~YmGQcdw@xp-@fKJOru(M?qm}07!{%+%(AaHHE;sqEOmAJO5roU99ILRy|_rAK%7AxPa>P%GW*|_hw zi<4b#X*tQ^S)|j^n4CmW3})DV8VyzJNDGnsa4}>FHtZ3VzqX|(o|ZqzrGl`6CZ+Bx zlrezi*`s@$j}1az5?_uH*S8kJ@Z^t@W4)g7o3?lzPxWR{9{OWC%2RH6$LKN!IU$5W1`!h_L-W6lY-Bbdm z2K6Kx_qjopQK)eQE?%aDs~oU6zrP3psz*YL%Rd=o@k?Dc)Uw9$!d29(U&?cKv&4wwwNep2a z(Z&8%=iPh4lJ8@~-^v0Su;JcdFXi9QtLpX%qgy`WF@{ zT&yuGn^m--?WJ2c>NAu$M}d&WDiwCRda0);1h+iYgHlfk!zEkoLs5tvyoY;{h7khw9oN65jR)A8#2rKL z8iaht-WR{IV(v2eRj3H(^`x|9cTtL7GhC_c+!^Na*Lkbf&L+@oj~40q2c*NIydSpG zCf`@f19CdE`#~tl_rc*|S+sBh%82u*1G=|Zy1qj+_g8UT_#K!6qUnsc3H?)`66bUR zNq8*%;i1`x5FdS5k~yh4mlus}yb?fh6mGh5n}979lo6W&oUI7uY72Lkq`55vg`@(G zWp-6g5 zL8kFNT!Xn}M0)9XZ0sIY-Yt$wiUO&is+C13!^6gIk0_9|VXv1Tkc&z>(}t0h0zi>B z7pQX*F6Z^v=Jp%kMoQFpc{0YC%p-1Wof}_N8vQ14Wv#Qb%qgO_ktj+3_SR-4=?>+B z=M#1LcKSqd%3;|ulr1f^Vgfh&QNPG`zmrA_*Rgrl)}V9UGyPC{D1v&GiVcnVNQ zKD%+@Q4}G3vw|f{wmB}@1WfH*pG-)|)*C!GYUsCc#m$CVV8cv{W{%vA_=CH-G_pzv zCN`NJ_Lh#AC^%NSkNIqyYc4wJ4eOmRktMlb5G~m*j(~XHVc(mUyMY6`Ls|0 zLXv)lv6f66FrYjpMWQt;6C|yZ)spBH_%ii9l{k~UJ%p60Ph2l~s zuXGAs4V}svaWKjG=x9307K|v7A*8`JFKiScWrfoejXsXO9>*=9@^0s-0=H+Msm{_^ zdk6ALwdwb8jyB?tbby%FpiyW~&D`dIRpv1|i*@@LvdY|f-?@?mMW^@!$D%MBR_sjH zOy@*E53%j%)5sWYw5oe0zd2!ApPXc1?|0fF#wR7^Crohd<8cZHbR8cKA|Vv!^d6)M zh;L-DExS7fq?Ec`Yy*o!@<3>Nt>77HNI^s>j}h`(fNX8Il~4b2g!H z?7Dx#68_Jm4k)V$b||rt{nxX$MrBo>ejwq)3yoy&Q`eW7&Wa(IYWw)+!Vc~A88F_Kx0IgMt+z4Hw7f-JokQD^83?Dh)noEpJpz}J*vBZH2i32B-ML^A$x-PFPR3&#KU6f|J2R&gmZl3IOx6GBU8VdG4Y7uac85c%XaMbx-x8@N@;U zIWg{lw1PI;K;xY)d|@F8DQs1z6&oOL#LA-s zNsB&)DMy`Es0_p7GuE8LC|_z0EPbo=D?YvmC%QwKd+!> zFhMq>tyN~Nk1`$8rw)BZ+fTP}7eb~}8N2@8k ziB;0`3yMaW?Bo;B&?@}KS=KB#H?De6(3bFLc=4R+EqxB|B9jz#IjmR7D_=n!TYT08 z-G*Cbgv}0JoXSoI47r=85QEAUz5e0V(>-(5EWxs~Y7L(<^pB|BxS)x;hJe9e@KYm2Wx?KRyIwT~95fM+F z2J58iWnd@-@S#GF`+2>GKwvK9Eqo8aLI#H{2W7Qk-)XZn$vVLXfq}%m;zs53tuy4)y16+={Fy{C9#fb5$1 zSVM3mOxJbSb;Tsl)wU++u+E?9_H|QGR8``s6vJSjqr9T1Szo%zP`=lt<55DN9urA0 zd-^uziFa<&51oIOt9U0X0P9rejBh?(MdH<=kUPjC3GeBRJrB3hKhrDFVbh#F=riJnWWc9`dL4YXj}Wj&fFh*$@SW@Bf5II~s+C-REm1%JjX=IAkf(2RPKAJ6s83Z~!?ZmX5njahga6p#f86l2^ zF&$?81Vte)fOlYoUU*P0oK}z%Z$esZfz|K8|;@bXqmRe@`FOG$BvqDg;1zX;Tve( zT(_nVK>YN`AOY*MYcY$QeyO)TQ`%u+67)^Jp%*D9u&<;F+U``^^TaIvZNgnoiQ;(_ z539wLAu;Ly2FlfM-~&~LOKG;*;r>?w#zWqjmMtRw7`ZVi8smMI<5C&q^+)^(-mC!V zq$o4^;e?|9J6`$!v`b`Sbsf@~H^BAS9v$c!dD+@JrhHK}+5-$m9-Uj_!uSfNNa9l9 z#mt8>toC<&`uIE+YJ3*=wtm3GS}8E7f7#*W;qg%+n*n6uu>D5@g@mAiFm=Q^KsCIRzzn;lMUYa4oJ#$ zFzL64z0d`;jiKY5R;)g##hxg-60c0Hq}lCYveZ}X8KAoH+!&uR^{C&$r7lr_fmXaV z*q9?arQvK@ow|ShMO^4nUW@bZ6D(UPAYL}R2scUa-@t!wI78-mggj&Nl&zU`OID3+ zqW*0)`mMW%_S0*Q+r7%sxdS74XI<3uI_nnPh|~ZoLzK2TZpUaPN@G*Y8ozzPBF!qI z&LzG-oJTzh^zZx?kIzbp+#rcaX|0wWcJgn+ELi-ZW_>!D9)IRH4($x|(j%Wf<%vkd zUFN2k8t*tU_RQWpV;#HF|EO}97p=!#FcL{X;bEEoC{T7>}Qwmot__mrt*1O zsQoC(xOX27*1rZL&Cl}lJyTxAib$y;irfeISgDICu+*IdKZLaLpAnV{I!_%oN7@18 zPKwRVQEWQtrm$fUV@R82;*WDO?@bN7C?y>h4bE0(^aiI1y=II)kcW8zVXq{-**Y zQ`Nc!Oun0(o~6fLfXPxk<5qXV;}a_K)if#nyG=jPkJ>JuQxyaZ?z)zoGILu)XLLU$0VAPvK; zij)*Qg#_>`Beyr-y}=GGJP;0oB?O$3A9JRvykhCh<<4{Wh3O3Fmd~A**15$83x9=T z<*TLg|Ke2v7WZFFT>QC>z|_7vn*z^vXEpt{@*T{Z%KXw0q<(xs+O?=NMU1>OU z*Xb8Lv6s~_LQtvId0Le&&!XRN=m^7OzV~q37kjN`jPbb~Ofm|{Mr}Z%$*by&yv)mj zA9=R;NbTz;rGybrVM%U9Kj%zIAzsqweRUFTxXp6an}pF8a(19?Zd`P`;Cm0B!;<}2 z>Urgq@CAl@`?IRp{@Y<8^gtn#AC^|Nm-2KU3{dJOkC`W)?hd+hUOPK~?=)pegb-x2 zKt;5yI^lL(x!!?eV*QlsA5xbj2hOnL+lPAHkW(15w_%o0jlnR)So>-ewtt1*L#2FA zVjBBI(Vk2565;LwmEho%?2QL*Rs0_){LP?98!69jlluqU+9lIAV0L3)VyEI2^WR?; z{aYDLfNnMSw_``$bh7`ga#2TdoMw{Z^Nc^MPFc;KHkMbViTbnc9YCn4eR9he{wD33#1BsfaC6K4}`Q6pb zr;G6jGKx_Pe;!i6k_28X-SHjf*vCA4i>hhnSLKxsb$PeLW#lE6(%oN2r(Y6czYlD0 zfKkTNx5mOx=9=$?^Yin?BrY{Wv9Ym56kM{9e*wq45n#JKnHyBCt)|BAb-5#*K-FIQ}PfXLKLLCSl~J+we@We#sgpjHSElAnCY8{Dyh^ z3(7s(kq9c!F{2MeXL~&ZRQLX2)@Xes%0mUgA`(h*8(Pw7KMSOW>|WGRW9C5@!4tK6 z&qO(!=)2UXe>Q?@>oAObT96eK?osf1W59k#KsJXs2apL>G_qsos;jwheO?=?fl4#ik}T{K_4D#rQeWP zPlhDc?3LG>;U5eGlrNR-p*qKKY|-&7e1WC}n{$h7=QqcB6y2d|641F8VPXgV>o4*> zt^$g8l1T1b6u9=DOYDt<<^hilR~7KV!c-4k6?EDXBkc{~u$fm&oj3tpU>6q`0MCS_ z0cbbxPS=p6Cr@BzavPKq|)9j~&W`|;=ZkDMwwUrMO`+-6zt%h{#x z#WaUgPY7IY>T0#=L>iY|Yp$&??7ArJnjUIhd=stF>Vt>O?!BGRZE9t;az7R7^}bhb zMJoyIH;brC0U{`9j`hPyjk0A{)rJ${xyGf^lk=-M^A(uU80ezq6{MWPct$SwXBSW_SFr5c zg?QTh_LN(%#jf#rvCR~Wpio-KH(nq85MsYTbLEHB-mufnB%|_Ik*6XK1EXVl z&8b8FTG!Uh3nlO!X;3^o48!j@SexRA4u%x8OFr|Lw+;p8b-ry=rbd2ln6|JMb8QM~ zxC6JyBO&)PMc10l=@5a^&}ma}vK>eFt;379_kKIaY>KyQrbZr_;Wnw>L#ID1n-A#> zEZoGIK_TIyI0W+9sxIxH-LX-~qUX<`IY-{tvEUjB3_?-W@tj2#s_Rx8r!HWi;LAFi zC}@QL%I7-OQG-RNht;Zz7_AaPur5x3w&IpAul81-(Bq1iH;lgF9AF(0k&yfTIn8@( z%i`nX0o8)<^^{~Uo!B2BNHVb`Z3h6T+1Ya_l$(gB(_Q{1@_I9?&6*LPsNNzcT0??o zFT|-$X?sVf(%eCuxvoA|=^biJB_%rKV$B4F&wMZFPI~ViVjs$n-;6DpX)^z+l9P$+ zk2;78sp2SLrId)-^_k{=moG;)hyL7DddlC803fJk@2MO9e+#(m^TOCS>4v4Qu8O^@ z-Jc^2+tBJL11rK?EPr*KS+V&p>Z0qPUo^riqQ2mu|0M`vA@7&Ll4kEOU$v(t|M)GK zMbnrz`MgiLwwx*z;Serha^51q?2pP-@LX?$OXH~vBgoHE!M!0!q>mhasJ;g;rr`oX zO2!oP3q(TDLAY6k{$4*4r*8kEBWYqC%wm&x`?F>_bl_0GeMYr{Lhz~WIU1UD%5Bz? zC{JxR`A{$#BKL%2^Kf?jG(aQdv)bfWj9j~s-+9Qh?N&48oRG9p(KAZOZ^7r><9*+L zBbRQcH5?wERyP~OD^dgWw&hT#^@c*{`0?mnn2f+b#7K@9!xzdirv){ z8%%5$-)&i_51(XE`M@MOrnD<_|Xg*3_G1y|J6sM!ho?VWPCjGA2t6e zsEX?H&3m^eMQ5Il`?`x_@o|iYF!N~iecUP8^B)^p8}7z*Vcl~3!hoa+WLx1i+7DVW zZPLyyzJQisYdG5Vbkz&6+Vnb$i1enh%_(T#1LLiKxDC}zgHh;vfRXfAbqZ}(A&2(? zHrwc$|6VwnRNy)_vYM*}p|B$4#9$gD`69dLCyqZYLdfBW?*!?}?t^ze;cP7Y@a-@? z@>+3Au(fA1@Gf#q`H?tM>LuWoZ=CS3CEkjboKXG{;tu0>BbxfN8XLiYS)(jtd+tyk z@K_Z$1gfq8z{A8|`aIPo^jQZ@(nAVt7eV6$D|%{!>#`c@21~K+yn!; ze|^;J62Ezf*RjKVxIfmNzGdSQw_d8jHJ$v$Ns?_W~0m)7@y}L zy<7KRY*TGMHjGzy*mb3Qed$t7J#Kt09eSBXI=#_u`*MB}{;cJn;<8`0a0KM>EBI{J z;|*W;etE4o^%GYz$x1a^B~q*^d&1uXs~bfQS~(vyLYm0%%`%-L6-&0U2}wA`T)Q`G z3r=?WE`Sye^xyVXbMCyaN#*Qpw^>>0x1WPE*{buPE}!@i${KLJ^WQDxyY3q+C%JuD zu#fA}A3ls%j7vF8fb-@J(uFMlIs#d5ri*9cJgKLKk^rSnXVFt4pZRJnqg?h=G*E%h zmc!Pca76Kn^_W+ng@C)v8i4T{s+F>Uqe3hm$00Da-g;CA&dBHr+cp45#-3F6kTx>RWzJESINJz+NyJ-*T zNVK`Qd$NGOy#JKA*bBpG##7`fyv#70P$v278q>zZFEn0grl4aa2fUG}c1NI0kW$A; z`=RQIL1&PjfcCzqX^IkAy5yM>5j9+n@h2T{;;rTkthrQk~ngooF<)I39g|eNhuplV=2QyoDbd&n?fvw!# zgd|4~YD-Ppuvm?hm--~=;P*dsZ5>-ZQ_EG^mwv#G7L42O*|ZmX^^!b#6Y@-@i;@y= z<9}WE+gJdJr+T*A9E;UVBH4%%k1}^llA-clX7QqBrKV3yT#SNlW4hh5a*t}WOI*4& z>`w&!O2EZ9>+F2n%^S-JLTX7K0WD{#@D%YNncZy5$(W~mT}`kh-9h^cBgd8HGI8qE z5m>>IO#|FEK@R1-+jvNNdrVaUHmR;zp}$&r2G%|%Z`)4;B7L9RW7R#3Bf+tFEDo%+SIx8jV6$#dQK3x#4U-{<5os371 zxgJEg&b34TlIS*mq1vaR#?JJ)|4$XBeX9`k&LmlGu?V#!uPuCw0KR5%eE&xiSBUL$Ddt&EY$14KGg3BqHAt{q$ zGz7Q~ZFCn>%XyjhAkdj)Tn`IPM|O>%GJPlXK1;=_h6-On)><34;eR^`MFE*EAKEC2 z0;Q2~U^(JQh7=vtMoWr%kynNG{Dm45p=f;TbCRPA;N)(cDjgK>O7UyZaB!1D(+r4% zWTIr&i3E=@nAX$1!iHHqi^e_YeJ{%rp$l|h{Mt-2Zoh}3SKVXO*W)w%@zdk#qdxvQ z7qb5l(3?C|12R@c0(&nl0u5+Q3z^d6SY3ULG)=yp7lB`P$UkF$Qi^2?TqAGK{7|1| zab@A_)!hPJRk@lOiQ&83pq(|*+OwAI#SDHZ&T0@Q#YP$4lMQcNzQ!4cL7mFsbYmQN$!qkO@ zx8CFbTjPc}$(JVN-h5;_mhRdXq zIzF=srN_=!BpZ73v6ZnQhm_N1OL`@YX_nI4EJ%Q`iXM>Pv>aNrZ5>42*!`WuYOFdb zT3rxQ7d!F-uBO~xvdDS4-;V9iSd;$0J+S?_i|E#V@y<~|E7b%c(Y(sv0I5-W!RD)( zp$}!Ew%?+Hzq1J@$FU|xBptw~C6hgXaSJl_%(|fJS!c>38@5MLV0P7_1f#ddph=aAYRggL?h=@k#*~y@~B)9(JWuA@*?ZAjn~QR z_{Ge9{SbTa?RNGcy~c=bQ5HoYJGAr@AkByTi)t)axj~`Gu=LS{V`|g zWc5LalJu*Gk7()&_?zBUh%Rrqsi}+8j?m}L3*Sy|QQ@QM4l?E39)SL7Gfmb3VZ|0= z>4%K5`69&}AUPd=lq6L!4Y+?@Pv{f^H(FfwmK8sf0KE_MfG9WQTRWHl1VE7@K4yp^ z@9Y8TT5#%+<_0BiXS`*T*v@IhKb{ zLk9a?AVzH*L7JW$cUks-!|wUsJ$P%WRxeSmC}_hY zk31Y(Yf5pno${Zxb9fb>={+?VxfliZO7X9=~oBG)4 zOKvfWP6bpeaj9?iIAM4nLm!G`^=UEOwF-dlT97Zl;H>1c;xRDIxw=y7CIp+IFX+H? zU;Ia$gH|T`A8`(2Ny0g!q;g_T&PFQKP;=V{=AUS3&ha?B{I^x)Z$V$QaZ9P2}rk?(k|YD|p^-RJy>PMw*GBC`CbhIXA=`Xr|8UkBHb zug%dWg1}zz;c72(rR5XDAJRKD^G4?Nbe57fgR|mY&8B9~(6f5gQBc z==flGO?z{=KQuY7tu(YjyH&m}tB5SqI-->UeOH^PXSZBeH&hBtMHHESeL6jFH7(+7 zyo*>r0#e#+JoH1a8{>-Pk@4yQRTGA6rVr)DdYjEeNezku;=oL_*NSxE&D4GW zB$TC0hdD;#)Gy)P_e!rwt1rr^u&Mpk$5d=ZmgkY~$hOkDa-nC&z=gtPZ;5|z#)C*7 zQnUfw_JPIG7ts;Ktg{c(5RfL;+T zWnYe%UF(eEKrOgSEa*`fA&ORwutLkyyAC_|BU@$L;-wn+iW@o5wl%YMj=@lehnTdy zqdjRF(zkTdOIWRrU*|Qwko~c4s*U>Gj~A6|gra@^I}*;3170^jQbNJaRD<%|u%Uy; znE6Bt4J|m}4WaDX#!2gi6dtNGDy_hJS(@ao#>gb;<8$@=0avyMYH|@r~ za5Q$oZVqvWC8zQpgynO81#0s5+{w(tq;DQr#5ffn=qEzHtVl7sgQ+3S!j zJU^Zk2H)+llKbrZo-+k^E-8(B5LUd(NFbFZY90$6Algr5ESA8q6Z0Rx z+zG3uz^BOwKf85b&+&F>_XtUZ2l(CSPlW!xMDQP4zKmT+^g5!EDLlfqf3dD~fUsz$ z|ILmpKsa~=3@6(AQSadA4F97Kk4V9b`Cn76H7zwYH4_sP*WKUkLQY_o-F3eeNuA@X zqU(Ww>N!n7M0A=tuO}@fbk}k6)@~y^B5o*s+~7fe4f}H6P`w{aR%F@go&c9_9p%{F ztu0x$d>3axKj0%fCj=+w)8hh9OB(U*({XMvi-b%Eb#cFJGO%Ue&qhZHEfhPIlRyXj z#5j1zBex4)+ND&SEW@!4TJZ6K#jr#2!%In->SJkOu6~wD6}@1X@wQ^_$YBUmzM4ep zwd!)%_E+|gA(`-3dGInQ14!XEb3`V}JW#h4Kl1vlUbE-P#26!L%`-N6|E|qg0a#04 z!+h+^)TG@U>5l-Vrir!#r1eT89Yq$|ba*NvR=s=R6~kn~2n0YCh-#@EcTdupdSL@A zFTdXNmAtN~qtk=cg6s2i2^wXk2b1sDL9vaJv?jS#8heJ+!NFmw!M(L=bpPU?pALM z$3>?T`!U?u6@t4g40Rd%K$MrBlkH9~*Wt7>T3azq72c$b>0(fdTY9($U=S(UAlp*sDb zA{%2_+)w#@x#Dly5P#iQY4`Q^0=P6Kdn=$8C#Cp|yDdJiIJB>?REXzZ8!7- zC2TVBAC+FXexFe55Cquq!llh~*O&(ciuVYiYm~oBswCK!Qc*bzJP=hj(D#69+F2PR zp3_|cApbKVaF^LUt=8&((rP_NS5RBh^~siM^?H`)%NNJXouO)_|BtJ;jOyxp-oFLu zmio}$APCak(%mWDjdZ7UN_Tgsl$4Z6mvnb`|2N;?TK9wdxvb^;oU`}LTr+dMxYE1L zisI_sG0MPM`8APhJsR5uTgl`_by z%HUvNVD9l{A6S~}0d8_-N$THe%sfTLqp80lQd)%^kCGN-TLz9h&pvTk;o6^s#f@_q zxc%}Ap4L2B!ecB?tLd-;76Lr^V81CQrD{lMI^v#RviH_Xvl9b9&VRv!{8^iPR*AMJ z#)QX%|6;qZO!+Tn(Dv6h{Y*K5T;qRi<5J}t3CUuR!@$1+Ww&@utx;- zBrmAfPnEOa_Jt;p2Vt8@s>~8&Pz;83pMD1?koy0|tZmPiVBpvwfUn|r&>MOM)W-iz zq0J#{Yise@t>J*p=-hJ5Beo!LDn{r+#LbuOQNj6wH%sFEEgrW0h)u^_vgTY@s%o_i zK`DU2V3fMzDWx5;J=8OSE`8(^wVV=ss?BcK4m=8qZC%&(4v^m9RMGxF1h;ak7jc(q zNp{)Z<@ZRO!q&t%77Eqda(8&8Tw~RLLTMM(J=LQ7G4?Y3LIr7lk?~h2B-90GRU_(H zeA8Q5Q?tbEm({I_WO`kzpT{FuQtr)*RL=ut@IEeq=5eDPRLGr#D^(gsybap&QDmRC zbo4gg6QRrzoK71PO5Mi@~CQU#GZ-kzMmdhgEko@d?`6N_LlVO3YGNua~1*P@3+ACDZ@oBRzR2%|D!ZI&l$y^^BeQ z&FF%;RwuLEiAv!0lso+Ntqy3KE*VSLP`ZPj5F>^mQh`aZrp=+s_7LZlQg-J&a)rjT{mqHkWZrhE#ZyG;2dVZ z!D;DN((C&MoeEB{YuwD}=*uHRq)JH`Qgq9|K6jVZP0==yE+>9r(jtA*G_L|mWO=by z{`GCEF&4v!tR}$rFN-n+e5+%UXWjHD7w@CP6<4zSs{c@1 zAX38cE5XZ1taRo#*V{AaWhHpWOGEHy?(n+j$jOhy1idXx;HW4*(Macikk=XseU9UT zpd}12KRNsvYytrAVo-4K%=2TXRxZuKn}INZV%ggy@;I$x!k%}4-WJU4&sjG)_iK!0 ztWoBdf*n0s28P}FYr7=dP=PO4iZ^e zY3Skl;VpH^mM&&8{-^5LW4rsnxwGj5;x#(n(Ywi#p<$HcDz8)0>{Rl`*kPQc%h|Y0 za^na<5#XqciJWq`l!%I#7|t>C);asr+)vx;(rWZe^8XCb+{`uj5{;iv>(Dh?9y$jV z5vrMMp9~NWqmI|M>j29IbZgG$*e1xyroG;#wj%L4P5_-02(%XS=W<`|92^{gN0TR@ z`xQ=VkALiH&HX=jR@``sQPWG{|F3jJnZTCmE!h}F%<{;MDKPrsv3#9^eqCZzf{T)mPA=VL#y?}@(Z)QGqhsAwPvj&e;0R0Is-1VSrwadO z@^sy4QNoDf0Fl_k-ax==n zzvDt$B>_Ss1I;eI0^bTP#?zB>LgJIp%)?!wG3>&Bzs(NiC92e9M5;*gm=`)^h4Zfr zL-3akw1tdC!~1_+^b{7|c7o4Ej?;)FFfcIgR;s4y#GKjsDLTwSKwB@_Kw#ug90`D()jWJf zQtEt`&2~25$>PWG82jDN`@q?dMT2uNTv%U9YJI=(Q~PTyDurNYZrqz=JmbLC^!HDN zNL@N2CvbAojHZXm2$4OOaVzXq1C6cu3Yox50Zao#;jz)Nv9WP*%-MF8erR7S;N#_e zisD##^A=icY{PC^&Uh^190w?cw@CvjA5&7RjJy-b?24Piz>NInh%K{c2l|26bHb(~ z;+i5)#j>wb#rc?Y!bKznXlIj0l+weff0?w>h5zd{#S?ys+$CXBg7$Pe5{GKLD4NFq zv-_&u4iC8kxVGZ}#CXnrtMGq7>Q-)wz5fBJJAzGuVwDF-*q%OXy0dnf1*z@82{fY# z4N2O-30ZKC{Z-QaK7WuCrx?d=lF{`g``wsOw;p+~*P59|iM&^=I+JhAi4V8$51D<= zmyHd>4!!CL^RKNL6SUroN_sYSl0omauol`noWJBP$hpzp}Bn&y5odnb?zv8tG`BZGZ%<97X@{6mj-?(>$( zA@F;33dfC7Y9Wv#Q+;rwsmvDG`G7T#sn5lUIu)$sjT;_*SN66)#6DmD7-}!#-%qKKAO@bFCJHr&|?~fRUJ_V$G)O@#!_jy2uNpU*P}Z(A?FJ zI!9GG59X757dJpDY2YdqRF;rv6h!id?VY-{sn@Cm*s0@xjpSDCN0sa(?cNtd)W8cV zWcy8ad;2YF6?ZR>#ET7K4*;kQ_AH+Pixy6sz4j8fsaZ`c{&Fj_GQ-G%Q~i?`XJx#` zRnBb+=Z~6EeOMXL0~?_?Ai3k(4KU&gTVQrrS`M6Pr9A5VjD3emxTt;KCmQ3bp0tcz ztu{;v>{|1b&My5%3Z6LWVo#k+&gb1A{uM z9ocN=WfLKWj6QppK}Rj6jvjk!wUuEyGsKeaFP#|Kmw2{@_uYRmP?(wQV{0kmBj-=`K`zZCkk z-+F#^I^aE`T2R(Z8Pfm@z!pk zPHd@RNYnaA{ZN+vR*Oq&NMjft-pnPE^I|EJs9rowp0{oAWtr-^EA&sHI5t_*rz-(3 zYvJ&z^!wCzB$dn+eaf=J*uzXFyle#^@=ZkOqG-7FlHVyRy|aGDH7YH#f?W+JC>Zl4?ySqCuh71D* z_1#r)<`?DwFnBy4Vd}DO)asDfR*{`MKZpk1Bs?XbKWSWD_BKDCf0AxG7m$6QgdT42 zFHob6GiBLcxVeD*tuU;Yen{&#*?G$2^PMGaXP*8h?|o8(udHNo1(*F4NE-n?;mh4; ztR`n-06{4s3Q9QoklFswylsYVg$EWuye~&NP>FcmE}x;37!?o z0a<;-Ve?=r>%$@PPQH2pfsv6#er8-^dJFCIOzd{gQ(v(!X~N65WP=e0Cm~!!X8A%A z(v(&gxL_n0;v%$zqiAS@o_FtvYoh-V3V;ifnyV?<^5K)sz^B@lG)?o@y|D{llr-My zpv3rC7G$B}$A(4$W}z9jI$DGpXpaZLl9GL8gAg7CJ1z!;rSFnsrj-5y1%tR3h>IFrE9`@OprF2tkfH! zJ)9D(q-Sov_jG@m?ek#aia!DMmH>O??7jQ4G)zTHTMB#Hh+}|(9mj`Pm zX*>ODFyu(ku4+h+_^N7W`o6t{n(BbWnX6hRXdGI|c9rWeRYf~Bu5p1<3b%V#$1Si6 z@8Ayfl;}n!D%j;1f4Er=Rw-TxWnvk500Vb4;bprvB>n0+;H1xu1)r->c7Z&pX^ND8 zf|IlJ*>F>uzV6rROuOPbCjq4}79hSh!rAiu3@aZT9Mr5g{dT&-$IM(?QZm@HfV|XL z{*Qb3DG7Gzv0^S3$K4OMG!aATZZM?5G`XfANF|;{;>`lb)uK&Ix}!Ng!3N#OSqjeW z>^<=ws0r=SFTqfKBq2|e0j#bK?VD_J5JeW&IYAU!wHH&o?xUOhOcb^HgIO+_c0bP*V;yWw(#CZv zg+E;wLJZU`^ZpQczEXB{tgE4q2tJkR^t!)@5qP-+0NtRqI=fYVxNm@x5jyZTj=fHZ zPE-!eZF}NaDFaBrKt-r)zSQu?WW>95l5M5m#@kKV4M%)dinQO^yU!Znz#?^h=Elv- zf#mbFO`wS``8EQyL9;Y3Yk`*BFb$+Ip>=OH-5}A##p1@y+2tf_H7B=+k zpSrlIGJF@QxhOY6bMd&Y8#I%Qs>7*n`QRxm|DC)h8~hRYC^~v%!Tmi0zT{@>1+pJf z0Fb&2u$8LiYTZ2`bwliWYpz?nAXd&>Jedae|CYf0_l`JD9MR0I6_~#yJeGdBRSCXR z^V%jo5<04z1g;8Q{T8YP!Z5@YUc4CW_QQ;ZV2-7l&zjqPfvOO0U<-nPa%!07F#$v6 z7S-;jd&fHJzH^en$=RoM7J(oI6M&E!CDuz(QIwDvyx1O@1J$wH*;jy+)HIVCE<$WH zmNg2dC4~O@O24uZX>as9a-qp)5rA&@|9(JuGk3>b2MK=L;}2ahzYcBykYlX~TT_?&{2_G&=#a`il*H$I^Oxta* z9~*6jqox>^9zAsHBn%?4`4$gvR|xQWs0St|J80{_BG=Q#h^Gz`ktjnyvx6OKc{X?U zD4)YQU~fL^yOW;Rg_;)6Qq}PiJFDW@BP|kgFS!m25NK>Y-M{VsYaw4Ebb)L`H+{ED zp0OlS+`#0nGne?m7Pw$s8IFL1i~|Hd2;-&?x>Zrax1+Ph4)D3A@0E3C-uzR+jSt?D zY|1AHwOdUkvz^y0Tc&H$nb)xu&3Bv*6%M>@`0{_3?Ok1OH~E~Eh?XKuaPi9I<~aPd}U!Nag@ za2nqpt|Nk)*ArLX=k#qka;2-`%3xHtr?~TNILaKP&Pn?6hkK-zEj*oFrzqbJWchsB zm=+13pjKgekqZ-4Occ)LbUo2AH#eUtQ*E6j6Rcz*Lvzeh!qERCsjOf^(xEhc)lHu! zS&k9P`2CQN=caxY{e{2qpMzY-bH%}$>Zq^$w=;hz<6JcMsQZr)WkM$N&@MsC>m+La zu&}rB6Vd_><%&Ol&7ps-t)MxRqN51q_+4uNcVR2u?A`YB>b#8^Ro{uJ39aC}-}Al< zspLg3*w6tk3W6g;#&w%%#f15@b}D)^%v7jK8A)}AN-0>UXE$K7SZ7bHK%|;(<3VtfIfvk8uu|~d0cKWhB zRwMP3W9|KW_(5S(Yi=JA#F-qHBS@ak>&`#Q>+N(fhsiNXzrtF2Ab+DDU71uGUNFvh zw~|2#)j=I|7JLt+J6ZNiTI}-m1x6;sxEmq;wpJL89!fm|uhJbglJ4G78^e(W`OEnn zjex1hGPby0rfXsRgh5zy=g$4})D$QRM ziZTJQK9c)Y_(ra{hOQSfbi!KxIrfEA6a#QHbq=^O$}#b$ooecc-p%Jf$ep>DLGRaY zspb4?U)iN%6O=>~09O=GDJ}dnv29C9=A!d^(4fjp_h7-u#E>lHlKN^?`-fuA2Nr|F zh(7bepH%|I*nfd_B?!=9=eRcQ42;;#RqGQo8$wCO4@46JyGuaTw*UI|Yop~%(nsy2 z#Kh?q2P2n(ym#4TTB`rSy5s2gr72yrNRi~qdc@`}nWE(-`l0_+6y~Cgy$IexrI7GX z%vm$F$f|s{y;RepiuQpW1u(XLEN-L0j2FdWw-Qv(TZcwSIJ$e8OFC$e zt5m3TzcqvbxXpw=?FN8{U^bs8HZJb{!}TGsP5L1P9ray=Y7@zvZiW?mS}1PM85s3r|?Vp3CGXag)Dp=NtVK`CqDaS{-jsbno!}^bf&O&MbgF zfqNJbv3KZ5v2{MN7P4=<9~@^>{C;nnCEghS3Fq_kCYfZGgdiMcP&A`Bln)saQI8GH z1&*wwx{}3^LYv>o~}lq_JfVJ#WJ$Cq_*p65M}KbEx{R zB}_9ld4qGkKHr7B5WHVHPgDawJiOcSc_%3e<$Oz()hK<5ufBzNcPiNh(MrzosF(+T}uTWTXGe-f)jou#kl`u+!AxKgH&hi;{9Td;@ZZNF zQSeyJfnAn$CK+5=iw@-L?=w&ME=k6gAXoO(uG5#D&tnS>)#-b`60!gCWw5YqXk0X& z2FqBM{oY%zj2}iGpW19PiI$N$3l5T-)zq+LBpp1#&lldhx=wa_@lt5c_)`44|3DpK z@Q9M&g1_~Qb^9)G3*JTq(E}Q?ua@(f=H4R+5|jVM5X69#n)3$`W2}FwZu^OeSk+p< zLQkszSq%i%`DVLSkb9-mkA4Tg?c4D`tf0|9sh^LpX28Y<;8+pj;->2L`}ffS%UMUq z3qT8-?DY0*LaPH4OfVD7V8^4W4_mHe>9x7o#0GzK1iOkRHn(tpZbX9 zO|l?Bf1Es?TOkz3M+c!iQsLKJ8kE@yEp>JK{Y1cLPbM)OS)9hgSPPAR`F6Um3$N{N znbvxw?}Yp^=QfE%%LS~${t*dXgeQzf^LSjDi;9Zoi$~p@EI;0z8&$EA=Tu9hL1m9+ zgSCY?@-Hou95v(&lNdI+^4a_#L!^C%i8a8Wk{ML!sWoef?C$O!AA1AXF5-WT_G0%C zJSF~_i)Nh$t8Z9=fq>w@sKC2 zpCiGD5Bq*qTGS3KC_?b5@}a4}he4uI%o7El(`=P)xq>kk zb2`Nki^=fOQmbwgWB6(Ha740p%dAy=S`7z|02J$yxuiKfK7zAwq*#gsWF<8P;ZGA@>4J1Q07h7iw0 z0T)2(Cf)Rx zECW9RoH$jx!AAwW(2qHSkL zWYpzOUoj#LphFol(;5CQ?ekN3M9*qq41aMCL$$Y5|w8tD zUG~Vb7HLeD!~rM2b@>&dc>m*JbP5Y*Vt69SPrSbiRL3o!(>_m#-14?27i^c2of1Nb zdCjtjRu-#g`q+HR&2u5uqdvqY^yVrN66~zz^(TQ_gK{C*t3}3Vr};4qRN??pi>V@H zxLhE|&{~B?MFnzNPM3g$1cXfV=wC@@$Z(aQaNq0;!>E}9NroUv6b>^PE$yvU2D|0- z8|n9LZUJ0jDCo9;mIL$|>xn!u6%|Z%^5&z}F5=E0kjO+63;2Mi*QE&tGSzO>X=xY; zc*IStt&f1g;k-6zRhO$(YC(woiHMF4S>?Tp+PXN60G93Gzz5{f@Mr7i3J0T8wn#jm z(Oa?N)z^;?JPv@fe1OH|7Gg|w*-VNgqTt2d`-%F@6H)j(Iy7@4kI=vBKBc~iec5Lp zUd+m(wOL#R2h8q#i8~9I-6cMmm%1V3zy}i}Z-b}_=X;kwhi*}6re3^#-ToKD-L@>! zpI{2RF>}XPrKZbegVF{N=kP4}7sw?h|15TQmiItzV*JFs%~#Q`>hqapnI1znvL%%e zTHouYdn6&yHb5V@Zvb@gqdzhr(_8`YI-l3)TM&amnZWvtU=5(X=Bu60z_T&aAW~`%sdxKr z)YyJoCocGHI2!Py5~yS!z!*Sl9tX(2kpIqf`M$dTE(uDfQ?JU9DttKYdIf&HtxB-n zwQY0HkEnY~tyam5%WKN{;+5b92zXq5Uref&N%>T3F}1_Yyp(lUF?XJ_iyp0;lsPZVz65I#L1J1tA~?&DX5BATITKG+xV zy2VRu$CF>%wMR!mgD*YzwoF^w|AOxZWpJ;t@iP`m{)dz}^;mlv>v5M`FEIyD84$a^qtoWkjP0P4&WMeZlV&Te$au8$O3FHfPA#e z`;lEeO@tNivGo>QWn_{pho90pX`#I0>@tL^Si zuP?p_bJeaJedk{KW*sIYYJjZgadRX&6i?Zj7qAPe!RrII5~V_^WX8<(?0v9E0g~f1 z?r+0Dx8Q%YKDyjxdbu|vR&N|!QxabSshVDw$B%1$Gy_%~Z;{6BgAY{Xyuz(Yek9OP zmqImtQ*qw$7U_({KePKj??I8#ilkCzX!a|f`Ti!s#w|}QU$@QBU#3?`^S=sLH}A@D z*GZKsb=Sg*!I`PAizZRa@}fmVnx6U>t=hq(c2&AZoy2*q?RWbt0_ym|NwF6nR`%sN zE&t1a_|ezwT52K+tiHNaxB%ntoBtffEi6F$1619=9&~{hEw~g&s;)dbBq$(Nv2kz) zXB!N6`)iLDo2!AET*KoW_F3mTy~rZ4``y6Sg&hv?9DeHwfpqVxQ{Sb%<;rRnB&38_ zTX*N1;Ng#9b@*RzgrE@qbljGzqQQ`%!jRxZbF3M8JlfhtjIIQr8sQ+}^@#u0t($yb zA$(suwg=;SZ5AD+C+L4jRjM6sZi=8m6>MKL*F(?Owt_cqjok?g$_gyOLlH=0Qi9ZF zs0N$GldJvDW7z^uPEJ$%&h~<~fyg!g9a%M#V-6d$NKjBw^-%F=SF4o+D0*WMh2(rh z<@;Z!d<5AYa(CV!(OucijsfOi@Wz{)o1j7VBO?PH7Z>7sJ({M>9Ny0@xN37LVYY=T zp-qKgIuRf8!0VTQay^x-a(sLW!!kAec_XbId#01Dr_d@7cC(I=x`BN%pRYrB49DSY9j*9f>si%P-yLS50 zs_80Jae}h3%i2FCKWwc$4%fUp|HD`~44d*Q9_vLaX7prmT2GIfr=*I4=72c#f$;E0 z6~O^>N%vw7B3u9_4XS?ejph@(!oci#)Cg>wQ)(Uv>o&mP;_m6*Nnc;T>id8;5O`Z0 zHU)?L(9&2f(A6J8K+Xz`Q?EgMc<$Vo5unV?43oI?whdj!2s zR8TD8;dy{1*Q*DN1~Lh?y($jN=|Q=D2Hl^m6cj-t8uQ==1Rb}W0e>1+Xg6J2tOzIjQQ=0fL%YB9lHd2}z0jB{s;0 ztmkVc%GImCDjOS9>~)Nf8yXn&gD#ot?Fk>v6G#DowD;NT?z`oTB@}GvY?-QAZ%DJ1 zx!*&8Qxws&#r~v;!2q~pdzp}%N9zz?fHOL5`qL9+nQD2b%du9|Q?@UP-^s)IK&k>U z)b7EIm0;^krMBJE9lS^gQgFRYCO0xdZXdUr)5{Zd4I&&nJEBH$Mvp$>Q(6EvbRma9 zk0>XVww|+nDcc4pMN)8x?O5<+Su^_w;ItmEF?_Z}#Ph!IuOCxAqd<9l=*yM~hIx_641q*=fC4;5a3g?nX0d55u=X||LGd&_lK%J2IbY~-rinVB%H7G>wX~X_uDJes3ltzX#z`NKWG%mI=-EQZfL+ydcF3R zN;`u>&@=#VIrRMt=n~{aXf@j+3&V-dfdUlFVkPCihfqR`-q}q)pF$c2F9xOKR?JSL z-HlnI0^rL7S!9^j-*IYz(kw^h0tCJuQ@Y z5LyQi1dD{R62_YcIC`dzu!pdudr!RNeJ zGi02V?Q}RB1>WP$-h>nQ7znu=U<+NJ?!tCP(=&P94QDGBR=qh04}P5@99^vXa;#;$ z55@Oy{`N)*26x1A*DJBauj-=W;sIdBP^h%O-V2+~YGKHV_a&O3(P0w|?{R~V2{CaI z92g+|4}q28SGsGEXMtIaxh3As#HqRF?(`B z_I`V{zX^_7t)333ntVV(k|_sD)fe2)KIT(J*PsRksTP8nK}rP`VaHou`d%)Jo6qv@ ztRjl@Gm`9hQOgI!=^5=fEi85O2#JmEy%T5nYYeV~@nMrMCoiXl1#-!jWH_YyWFLm1 zygmq}W`Bf9l~C`=KHVWDkrhb#;CjPR{vCh)ynZLUSXKPJ0ZTYkgTz<#3k!e0^9!OG z_OF7YBsVn@J`PW|e}basNQD#&hOVksHToRT&S(QCwysdMp=d2R^9W%xRm~GWYtQ3x zr+V=VbaV#j=Df;it%X~U17h*mS0%b1K#Uk)2;p}ERaPC2P||gn#u|1@A~a{(cBMm6 z&A=85yK!y4S~+y(pbtI?ija;yemEV786f0d9%*tW*VY*JU&wd<}kRMwvHjPFT zE-o)E0dUz;t5b4c9|f8;c<}&C8{(TA2>V*9RES_5;QJT*qt>7F+o?oaWqdZv7MsP{ zwY4?Cjcl-8#-_O296${W2mnwDueD#@WBmB_U%S0>6$MUN)mJM|6n-RUrO3Wi;V(KK-o==}W4UViY>rSqu#~`} z#oAT+yy55VdF#XFBRt#fKI#|#8Fw@Eukws-c5QgzmoSZ{&Y}Wecvut^{*xHQQ2l~~ zMp}|B^KeWh!&(Kpygmw{18JCxrNTsw;rx_pX$8`;4WDJ_z}d4%s!U12)IaEQf{1qo zp~>>NFWJvl8-KFAU_J0>aUG&@RFEZ6d9ByuMv8RT-6KfEkiVd+g>k}0KQF=RGA0c1 zKbZFwXGenvPLQ|+#;w6t+NL^6Iug5<@79&2qZHdB1KT zCc8whgL~TG`T>NYc^tN!Qt?QfDi&BGHYTpI6HbQ>s9Ft~cw=w?c%03BH~J*UtzA!+ zf)Rk)TdLD4b$@|%FlT2EZfPJt?oE)-niKKP^A2O9zaxNpcm_u=ozsC#yT{O*{_CyB zyDEe#sOe3xAHeJV;0ls=NciOS^5CBS8DV8emsh1zlEYz&A9=3Up~iZrKe2eB3#JJ> zu|slHBk5MqUWaiAO(LVz#rpS+^y#xZ#zRnj-F6cYZ*hXdRIGA{Vo26SCZNRN^q>v~ zoN2<)8CPo~@=Wo+B0K1Ka4^7ZM9D7l`FwzKN9FAP=kOh4ZC=+VuzTn`rezRK|ACSaXvA-XkG*kHQ2B{~0(K#{89W1y)35JU>a~6!F;~WU9aSjC zmR4#vYc(CsVbQ~3CPWvz*eC~ukkv^nT;2%F>Vaa)iXRbu*+y5(sa_KH; z`iKVI)LlFUC-8TH)NFtMUj9bp#88@frrdc>(VZyl{zyDo=DbcQRhTi;g_@Cjy||ui zNBF}`QzEh__^A}Xc-f3;3G)}J%0(A4Uo!(^x{*IcnUTNL2l^) zS}@56Lc--zHr1lFISw-|LmD5*JV7kf%xCwM)Qd$Fpr?N z-t2ZB{~hj9`fc!_O1t^*@^XjTM<-5|aX0%s5HX4i3cys!X!9L_=_sCp z5M%P|)1`b)qo90~)f_fOUOHf8SBJ{F^dQx!29mt4?SgD(y~h5)_m$6-!xm?_RYkEM zI*Rk1&#HOaP?D>t5>@MeaVK+ry`$y99ExMqf%o0fVzHsdvRx0PEa9`*BYy!qy|tob2EoMI3od#YKdz*SvB?YrhxZL~zylQdAJLNcF~1mk)S=gHvye-Em1ga0l^1dO9q^nMU{Fc$?nw}z|L{l)6e*lTKD z38=upnIK|Ut=1cznwlCNJqAK+APlnC!_@*f38d$5ZAQCvENL(?rdtrej(STz~((QPm%EvW`9vH;;gYapB(D1#^i zR5RV$JT7Z^X%Nmxth6E3J;5Ua`euh0E-o6{Ah+955I0&O7F}YsS|y(L6ar1?zeX$Y zF=veYM^|Oh2a!ukO6+{3k*6}`iiVA+)Fn3bZuKIuC}Z&MhMZi>W3pZ<1*Q4yXR-tRut)Jy?bB`ZdF~rhKHD8{l0Ae;YNpn1w(-2US{UyRJeoc65&-pFl}<;I zTdm>yhuh6?xAuYXg5J{Vw2}8^9$R0Zt46}AnXJ%xJVJiNZ##(^A<6C|e65j!qSg7N zL8JM)-%)Hix`%*&(h8k! zO-b+-C|y>VVV!0eJvzR|iy@zWUF1WM#Epo;AP?ozMxk_@^J(qYoW6RsuIJ8?W|RFT z7!|SG9!`#nv%cZOASQlY49CLvdCeTrb}Nv18o}`;=Smtei-`zRteL|Ic89U!4-n6Y z@N*#uz+^NZAPxR*&MG&OhD-X%Q(RIWk`k+TWI{d z_UqosUv(x?&5D9QpZeQ7mM9I={;r`$?J%?W*CdLr{Nku-q5PRYl`~#ymhtjvAte>5 zhe>%Mg*p5!@t0`qP6{Cduk3b3NFQa}(l7PZ=qQ}@%~6@H5( z#KaJJ^|C#Tn${4jTlq>B#j4+nVF4GHM9un1n7ns4j8FRFo`-w(@<%6m$xv~2)UxZ^ zuLrjB#U|TPEX^8a2k`{ST!len76UCOz5EHBNby#gq?I;y93+np{tj*12&K|QsX~{> z9=$h>b+uKxgZtadlQ#yhaK9n5n4&4xf1a-4^7o((otqYyd%urKhe?ObO{-5sL3{UO ze5#0Tz1c@y`~^*;u~i>uh+Nb{WO@f>PhPP4Z3aYpfa7-yl^hap(7GZLsxkXvT8tqS ztte5a+;ROKL2~yO#tWiu4i^bVhtcswm+4Ey49!NyLAES4*zoR`{Mn!|G0054Y85=y zvPgc*d|?X-Nw!Z{lHV@odH%C2q_7Wl(GaYxYHixhJ!lj%&|`|Df&)m+fPrF*xFHHw zykJ8Mob2XK*(g`3mSY|ly;hef_SC-_Ty56(7YW7kPWY1!2Uq*E$NyeCOc0ZOd$;U5 zEtZ>f-P|~no9!=WD<$>4m-D`*{~k?8#p8A!Tj^MW!FM@cS@s=Y3z1E4v|hYJ8Ik%%=$}|&hYv%fNebLF!Z}Io}a+&e;`C`YRNsFj^JdrUNE>M+BA~&F$F0Kc% zgOh?I=Yv_WX-d_X8zPCY-9ow+GQ{zb+gK^fpfn@9_Q&eT^*CV&${&A#v7i6g;_qMU zpHd>z?T$M$aI)en=J037fGWvC*;!bss9zjk#x?fz-H5^682&gYRC>ja!kG{I*W{(*9mD2l1wkyW6_J9SCF1l=rd2}Zf1w@l zcutD23gPO!I_N4xoU5jCnbm_xTA{(HhJqjy$`G=7pC&21p>o6x za-l6RM=O^{C^XtTuW-84Q&jDG(sdjuGP1jAoURR&kL&0v=jGK^Z3!0=#R}=ql9$Qd zD?B2TmB*=eW0-t2ECckA|;fK(F0%RtgctGP-JI z0)N=Fo0Y|@-bO5K%(;u3aY-IBV#h`JfZ6@rN4Wh@rH?1#e2>9uXm=j6mDA>~nSU?K zo4=NCL$hw^pi$RsuAN@Z$(z}|JTwo6GOYv#yWwHtHG+lOI*z9H*SSf-?zT4{Z z+`iPzY1bxdt5xaAPW=gRzYIab+uPozjFU)XwQYYs?ONWtc&*gwXB_DANpLS)tfQ31 zV=rOCgzM<&ppGV9?a-bx14KuDqv%*#G`J|qoQ6*AI z)!U0~^+K+~$tPR~rsqD1JIAl`m!g~jeozu^SC@N^2q8tzngo0r+t=j(oe+0bv0KPS zhSAfxAvGv|!T)Q==W;l$S_LQMhzL_Ix*|}r5lav#uH(_(AHQtFEl;nE%e^g(+B{6! z4dIwNk!a!?v=&E}`)ewnLZ7wT@R*S_nwx@672o%6y(m!rWtzp(rtDwd5-0o@|GqeB z$$0af{~DTX9+}z7&R5~Gta}(C@>J4fYj_P=Qf*f|MbO(phm7Cj>25v$%h8v7FrlN% z&CYn!-TOu1Bkz;@S3$o_!=v#|z9+Ans zW?7UeL*y>$+11ot@85Oz5r!uLN6%9WaIB2!tVZ-gQz(IMnMlvNoo&}RXM?7ma3Sptz z+188XPWJ2jwmJ=rYBEi8Aae&QnibqpQ04@o=MKt}#fG=v<+=EqBsCs$wOOQJtaL8f z21Au_zAO0FoYkS#U^`VOt9>(7Vo_iI`ut_8L5C`sk82|# z!(UuywgC=BTe)kS>Bpg~^DSaw5N6C5$v#L|j?T99`{MMBwaaBmpO2-FLF0AhmaHfL zDM|H=S#Ce%g=zig#NoI(@i>(yLmkW#!k!j{-l-t^0ZCpeTx#&WHjG-PLito3YDi4= zYEhjXNwc_!aupQ{X+sq5Et7we(%92lcPPs;gUtG(Ccllb?MEe^=|G3rTzjK3aB zPyxoM|NCuaoD{G*AChIu+}-3Ew7+>TV~<#}X6e;k%o%KV!GFB{rqNp3Pxq%%!P7f) z=aPQzkU-;)HqDNUJu8%#W{GRP2PJejPTUS7O#pEx);B+~QC2S-1cCo$?ZfCP)D$<{!Cr`hJ& z>hje4@yeguW#i*#h8Z|In@?EbB=F&pGxMk~GLu$ftn$JOp3V$AA|J-hM$5xR$Wb5& zyj=+1`N9jw6Khbh)>z|ET&!P*AVbBxga1#dG)SJ=my=T+VOz5+M<~`h&;<K?{+Q+S*n$Zz{@tzXWFrKqC``XnNzR%$h z*L2X+Rcq>$^B*;On4m1QS{*5CHQHTYU;g`G*H#&dLfq;4>N7*98W0#jf=JldWb@C@ zGVS)#t4X-({N^S}N>o0ZS5nq{Q8+ot9S=kKraxq0QO1Aq^5C4FtELn5P-RL_Cm{m3{hTh(37 zOUsxx~BN9(vs8g69XF@0*2emuj)I4Ji_t%Rf;pw*;gSA z8dUr2J|v`hgI?U60UDqtbhlIZZ2D&{9xk4;i_raP^^$@exg&_{xqR0f2PeRI^d~Yt zh=`9jFR|BC71mGBw}2Uo>Uo2Nylp5vTdqC#^%H@B!$#l!RL&HmZYx=W)b423Or!LF zO^_t$VOq_W?z<-)PX93yaJtzKRO#{nvAe@nAG}VwL?%?MH8?~cO}MhtDS7@{LgR0{ zC(GooFWQw-KXyjbYANl10>!V}K@h5J<^bh*F%{7}U~^-$YEPMQe3-nn`t*#|G1I|g z|EKIz&wR&8A(bB5L3v70V@FGCfKq2p`=3k0r*eFwig zwPQB3I{zkb!v+=P7;YZSXwMkc!(_hf{r08`{P1_<B`p5h zwD|Tj-St$^T}37`xwx3*xaL?Tc;hDU5jC5a-}l~8%F zz^?G<_;5;eW)1{DgA`9x;-1p{Jfk(2_Kx-=?0FeE+1AUo?&mKtj5@6q3N)MO=w9s| z_ZHOn)P;hXk2O35s}KGdxKZNruBcU$_(Xi(4-6a7k2BrsRz%}3FfDP~x2LrO@F)yt zVN<8Ldn9}wm2fee;&aqASA>=Y7F}o*U4y^l```@Six(YEBoEgzhIHvrda}rr&a4+Z z$v3t~{NF#o!W3wtdS7Py^7}j)Z+%}kFvt)z1fHeqLsP}T4L2eE@2FNXqEl1HqwNB7EF%WSZ*~V*NA&TI_&_TdF4!!cxGr2_X-*!Eo@Qa>3Oa^EJhbkIn8p3v%T^tnZ-n}$H#Oh%Rb?ftG=lt`1F=!rptOsLW z=$*D~!zG^ugJTi;&5ksMjT=ygPu{;W=(P42vtB?4kaj$JvD%|GlM=d~tm@zHnvUDC z%4$EVB8hO6=(_g(^8YcCp8biT9{a`d>JM%Hil9=W4%xy_mk!nSpfBw>SNrCdKR*3= zC>$A1+W0+?CR2p$``Wm>=HItvJlNA4cHHJKdbCvaT;uax8Gp3MRX?WFY0Qd41L1qH ztM6>S9P+Ukx9BkkLJ|S`{oI!+-)cQ&h9FPqq8UpL>-)oO@-Kn~LbD$BW95&cd1hXPb{nEnwI?t*3h-;46F^(k0=V+^xNnBS)A+LQ`BcOie5gc8~t+(FF(94 z*&$T+IO@%Ms3fuqw?)aZg7J)x+IRO3FgX$W2IGW=LECNVd(vbpdC@6kp`dVZ>VWg?FXYLgtfgg*#IHo9Td-P z>*H_uxEOZ^y}hN^*bZsTg{l!QPGA^H{?DP}KUiPa9KN($8zzU(1N4yLs*JjYVm7Zz z-Fia&c#R><%#r@sv0ey4C_(}3^&RwTO|_&n3tVH|q{! zt3a*iuC303D;{g^!n;395uR69`wPDRu-47U5 zp2#yk&vl$yloyWs#S%pss@qJCTW=bqY;RkqkBvG;Il6?Bcvbpzx zsjTw!yO~gSffEgc=LW+0dcy!q!<0ZCrszUx#S8fMIkpibwYI9o0vjnw*_XFM5KJC= zDt^p2QgFW=aj%!XLL=!U8X+YLtUotT#NKb*R7_Fjb{+(i0zT*KDb~zgEIZMsT9vC! z29rmlB?%-e9CrLBs}JpKzpo!XzlOS(-*xabDrD}YXE87>rq(m+HMl#wi3SQ42G@O~ zIGbx`C1_RMq52B@#=f~dq1W>JxKqH|guZI7XRKU&kM08g<{EYhVHyPmV)(r{wZcp_YB)a$S%Oq#HhrJAWLRz@Y{>f9p? zbheszIbRjao3aP>G6Oh?WDu8am9)PE4JKNUH+~7Q7t|AO$GdiD#g)ZO1U!f8`k$#E&jpdwsbxV#?x%l7dM@C|@cNy8i@& z@^Th$y91+QtHhcO#c9cGb(Y@l{Z!clqn!Gv(=1~5nSjSJwV@0jrRJbETHL+K@sl!? zCqIvNjBjGM`4^AN+_hi)^W_jf8V)A?nq~aURrCFK0`w8D?$0+$aT@&wtfrbm zhs-hHeq?8p>2>T&+f)S|K#y{mXj-9gfzBATS=pfM17YfqXG>MXfxH9xrONfIAei+J zs;IN3tj!L5)IdgLg} zsE(Kk9FuAl-0r(@o=p+Z{8>Jm7dg=q(fd~@5T2wi;KOLakda&zhy=4ytjtc`rA;Yq z?JuCoS#~|f-!Bs>66)u8x1iG}E7jCz9J`DqZ>LlBaMRn&I{RLy3{8>it1U#u;yH&) zhsoip_$|6bR*9B+2n}Kd1^--GHbUIjr=c0MRT#$^QK+Y9k+2+#jP;9wsMGzr(=>LO ztK~@ivOE7Bbviv=eOBiWnOlU*bwsSzy$ePHS-f|S6|*n_U4k!1h%4v>f547gY`+b-Sg&VXgKoNmGB{$@au44(UbEZ`vitgPDrIh z9Tq?46b_pui09wqJfc7m4FRo65QiOQ*b5vtJoa)qz?>)1b8tMQxAq$pzY-I5eK79B zW3${e(eM3qNqzCSeLZo1wlrc>i-w6=yLpf$@Y>so%^y!CuYEHj+(s!n>^jpP85tTG z9sPc`a=u9-FqSbeuKHlJRO4tiQPToB*-)S4jaQVEIO2sc- zF=s_&Ufptf+@Bb5g5yQ*`*ggTuCuw{1Ul#u@IP?8)hHFem~{DnqL$UKMBwju;T51A zBKV$a^4xHW&uQ%|>ZF22V7!)EZw=ZV8O%Buf406UJdrY+NbQ4hH%QyHQm-7#3(g-I`%)tD0)bBb^X)6n(9|Uf%55EZltp&rBRe^Yq$(XK z(JvfIDv?fCJI3Xfqw~uZ+OO#H4`foq3j>X+GX+?B`cdSDEH-PkS}&#`PWlFa396m$ z70Wu!7|#nunuPhlwywU-Cnm_)MM_qQ1^!v-c$C6;)&gAo&&y!iuS#cG_B*%gSD*mPWp7nuf!X1vn zz46l()U!3%xuo>CT&3diO#bV+-cTRw^-)_d>_Z+=aF1kdjjyA|8Ha7v&SHNvay;6IrB~963G8KjR%WUpPXQj{^fZq*S+ zoJ^j8=ZLS?pBNcaj=|l&ey^@6kM*ut9%)FLChQ#~jDMdsJQ3FO$o=DOF|)Dt{}(^Qm~2Qi;lsxEB%-dJ;Dx$fNgPAoAB@v_w- z+QX9BZU}Qc^%67*_~wKCx8s4|Je|4?f+TeaGAsB}(JF@U=N9BQf(@69NtSFMNpu=i ziYaRkZcbKztXV<_X33J_uKR$s&>Q7)+APKWOi#Z(N{0vbygwwc=V?(4dWB>@zZYf+ zYMlzW=|6_OGrl<=b>&GwKtP&JqyyB5W@!#j-lzD}78l!<=ABALAG;@`>zq6ZFVEKo zyS0)=^E5epPJrV2eJto!%hmebV`bh3P*p9q9dE=_17G2hpR|yaU8G$?U0ptQD-FOt zojacQ{{TU_x4%#2&U&?bxJ7;sD8P8USF7Wxv&ZKNdEVCB%jMU;e6?Aslo1gYMj?L2 zK|x8|#ET+$cD-wDK8XT0@#FcjGuQqyGX4h!O}E{L>N`S#Zx`1S3R$Vo^!Xz{mwYa= zK?8&Q%L|P*CipmWP9&4Us7)E<+;Ec^67lBEsgKwk7}tP(_5?ln?Nv1 zcVACrrB28Az(Okro~M!hrO(UjLFVi8X4Qp8`}ZHx#jDjeX?t#xu`obzP2;K{Ou{Ak zLv|MIh)blvkVMfM<>9@T!$PY{=EEcU(sw%WXx?NZB>9yDTJr~qAj=xaUa!2K_|yWK z*)Y-40+!9P4o{Dm_$xn2u)gaLCD6s8A}Xh=mU0B)WmoQ$1FV9y)YPHV1^8ZpO6e9P zrOWS-ZRMhRIaS}JM;9Q}$Ahe^ zGa;lsTU#wP5}S9NNP1MtzYV2J!mg_CAz+uNS0FXQZ*;D~-Ye*FWvxFss{L(%pa8gA zKUWw!4lXX}by#wf1kw3rL2+V8FGuwKXGiAU#!aTKgCB@g`QTwSxZ%U(wG|32i)n=uzWPxzpCifry28?mGy!SH#KD7Kj*n}eK|Wz})qh={xamdpsihOGv%z6^Z1%(l2T zovcGTT<}?l$^f`KGM;&{CvGcM`OwQHD~&)80=6(~g(Q9mkHgyjX|_0YXCUhf=+EWO zK=yHy4R5AWepp!872-uOd9AAf8y+B1-t=vl1E5vgwO06~*Yj9%E47Ni<0?xr^S&Hv zbS#2VQ@_Q<#pFZt$w;84uxHY0!KlgJ&eSLq03_xAyq(b~R+gLEG*nfRU4|H}BmC`& zgIJ<=T{YEgdDXV2``O-K%>cdnLowN# zhIZ>5%iE`Wb1hn~lfoBhQ9lY>DYx@M0ejW}o?%pL{{kD`4E<3Y8MnsZsAl86vBrIm z&RBEKEWC@VOu%N|-R^x&Bd6FKwAEayWkzbzed3U}N9B zj}BlV1m@}c?`$2Q9jY-rPIezW_RPC6thmpO#oCnk02`gF%IDoSqs5cWY4L(oq|s&x zfxTR_$gaa%L;}g@_G)h-p4#Yl~54v>AAz}+sf4(=SH3NoaOl$ zU!Hix;bMhXsp;6kcxFa&3|LxrB-B=;&$(`s+a1%Ui@Wo=kRsNKlK*NdpQGA<3n2_D z0h{&UWOMC7?*R3;)Xv6o65}O@95sD>9y?MVK@s{y$xRw$*NfmllchH^bPURQ%&cs*MBDe?6sXXXFGm-3GkBc z>1hS+^jm}61rb3W?o~a6TO`(`GJ99pt-QR84J6xh^e#vCTp5BSZg($_^;(>`%4h5# z08`pZL6ryy*l2aVU)_^gg(0#7s#Ex(A=6hW#W!zn7kZj+eu!3cb+|8qsYAuZGV0}{ z+aAQ+ZlBXpmhp<>-`{z~@c#xmFd)c*1Bos8BnBF%-V=@qm0Lm)p%? zbggOE)ZN(aPeeUPeA3>;9?_M8y zJU@}lPsky}3eSl_KrmeS;*Pm^R57I5rFQRJ5x@$Qgd)2Uw5Cpm?m}-id91?;LbN2 z1Lm?eKn(hWFBv$n6Vrsx_mQveS1S{odR+&g-f*IfFCNV;fMa1~KTd2cu>wJd^L<4I z@J9p!XHsrlCz6+sETO+72IN<(r%98Bg6@goG($#KND`!xpa$1o0^BH{NCQ|?c04(kzv?$?MHu%_^kNsUbs4%RW8@Xa-?R9`R-fn zW_LA|qAX68I^vjfWb?7$A$gz@5^w|OY?_VRuS_cy7#EM*teCv7<+A#@5GbK#hl!jx zkdUKX04G88=WY1D)gFvjdz+4DvY)otK|-9WuD-&e0@*6Z)sCWEDhDzG2jmZzH|)*R z9p&FnM{kg@44S`<&lCjw`eod&ZL#qb+n8n?NG3Ny?rwkr*WnQeZYU*RbGidRQ3Eu$ z-=NY&>ZmN0)CIV>!@A!v$oK^v;b94M-MWo-YbZzvnV%gD0lwkpa8A3p4RO>cN{TEM zR+v&;GrdGQ7?2lg@5s6kWM$u^HtMF&>S&fYm~>P%qQ2}V_r72h&lmDhc5Jv66Oy+XTG(-|!WmuQ9q+4!5;F2J6n zSHTJi%>+-i-*3;E~fExyAcOM9`oe#zdD`;eT$(ZHRki_$}nJU%Vo~Fnp zR8m^M)qgX#!x#2#LyU2>=HLSd2M6*BF4wzsRe!Q56g&sX3I{5ls4eEHiP0~9`JxFm znDgWI_jj8B1+r(v^~h6mHjPke(0j3r(Ax29rP}GIZHKcV6cFC?+*OK3pylBD(piCcZRb$Wt{_}+4$M~7Npyz2=~vb zflqoRH_;oid)H$L<(1^+u))!fc-FpO=D#0PNMog?%Pfrh*KScS6LVNB&yK9{ zuycz6Y`EPT4x1I>9oPHu45GE)kp%32O6}SeOXo6pJhSI458iH+FEJ?3R@?t-XE!)) z1NSYrw)+TqTz@-0k9WKiF#a=tdLB;tdFgcSE=o1WO1$mUFzEf9~yhYk+3{?@o| z&en-7{Yz=t*!|{WYj}@dv(c*7^9M+=X|2V@i}kVe_wAqCvz37j0kAqlLt!!}HO+e4 z)194Kr_1ekMlF7)-V1O@*jD$~r}6R?fd3Z>NXvWH+d5t>Ym$-{Bzl7U^jq9+!wL%v zA7!e+oC_2()QY7O_+OufO;|GIB`zO<*#;m!Sd6#c9?$ExT@u4dHn6ZwME>E7k;(@q zV=NOx)(5y$U~=dlu<)(}vOUE&MlMA=tVBR!FrRaNud{#o6WFmecQ1Igf-|uOr zbaEL>;VV~S&jMLlb`yocODVcv!k4%niN5~ZVb&oEvYwY$`Fnht?xSmkS0=;VM)6~i zpUCv6D5%;zu`SqArLpK?P}i?aPWY}v1_zr&uOrOu6ei;O!fJmoaGtNTr*Ju|RBMBz zmIXEJ7n7SFE<$iJfedb)zl_E6UXM=xkaaETmNE)YtJmQYb0eZ;!4IXp3p5s;m1%dU_2Nfo%V@Ta&7=fEU@vHnEtu zf25~Y<&q8Oos5Nrd58c5$py;cfr6JHYKYuT=ncG!L&Rv-a_n^=x=hdFsfkv8v}d8% z>qFKK%fm;BD}TWqmXFf{D$ zBA3YI_qsY7AQm~c@?IJ-lJsZLDY*G*F_T(vKAw5}*5+X};0bdz^b#zB22_-q05;4~ zuIZPG_j*)lodNky@Blhn1w4KNm<;ht5=zzUEob)Q74raK0EGwQD+;4U_&j6B`&Mua zr{c&w;8pzPL-So4ze3s>JjijIYjf!wGoxcHfuRVF-4xawGb4I5t|3jZ}rfg0lf-x6d}Qg|RJ<`R@d_$^Pc z_&Bq!y&g0dkE65ZB`wi`Jdw<iuGil-5tp9VY>No9!G#$;YKtR8*vE zKx3Sf61KLsB-0d1@P{7&$BEza=6>byVKn^w!2a|nLqI_AkL&I2T})n#%a>Nd0?Pay z!yWTwC?7lszt3ggJ_?+QLW@~iIyoVk69EyuMJ8VA($dYo?q??mzQDva!zk z_m|N8wP+|UMJ8grfa_utip$jKXEw?>oOG&hls!gHb$$lP0OBjq<|%Mx%XRq03x$#Z zv3*>8o%&-L#?Ys#v?zNnHFIew2g1LNrJODRm@0#YVu(_VVl%O407 zpEivUnSm0@A4_gBMC2-i%zVK4xwRt(3!t*W38ArxaGoutj*t&}05on2J)jT)o*ju8 z7LcAmp(l!fe`ldnuVDjl{MK=R>4RW-jsf)toRa8Y z`VC1~Dxm~g@8aGJ%sVf~FKcGHM#tUnQ0e*B8Pa))a(MjDj(>kh{?8B9@$8+q2|n3Vz<{{BB9&@ReJQwz<1SKN;7LTv=P`P{<|VmXM4;4`vdec6>>QLv6?E47GVl208WYN2AH`NIKbSv zftMAN3y zx&=0VEwNRfx3R{rfTLZ$(eNB!wr(sTs4_QasJEuQcz$72D+D(%(BXU*gEuKb&Km6O@cI27CIpDe75~l zH-yL&C;ErU6+Iwc(#*z%LYk&6JM zWTe-0>;59aVYy&ew|0A;Se2@DT~oHqaI_oJiT3}E0a)qqzygEz4E(Os^8JcbuE~=l zMv{U}PWk6j*9cP4&e@h?yD%tj*V`r`cvg-6^l45~L5fLG*<1h5kb*opeVNF<=jf{C#_8R})m`7iIo$~MGFEJ#Q zN18??*blBAC7Q4HT+UZo+)p)QLyqTwkbviKR3EQ7@Zu~z=OMrPi(RTQ3x75Lmv(v< zf(!#i>#nhEjYZe^Y-a7Y_fpCe9VsLu?A5f17x%x4t|647?Q~*5|qjI>`o0VW~TI5r=Wq@xZTr_UxoCrJu+Yu&%*tZQ2|EY&-j?T#e9!ra{7-yeiA zthRV?l96?;fz!^E^6v=0@OnI*bi7v(Ki_XWJh$5p{*Bm3jeLJYYxhDP6$l?&b)v89e;({P6TWjgbZmp(szOxV5!4`z>RoF`Agi z`{0hSNdWkF_p71R`}Pa(%MzgDQy>uVKHith&^@Pe#SA5!pnG|mNP|ZpOtV$x*4LlG zuwD-J^Lf2_&ldEgYrE9jyZ8BZ(p;oyh1(p6b;0^tKOsRA7Xt^M;n#fgwc|XFifkTh zSMCwiN@$e6HTN50QnnLts#D}m^TNtMTxjBIAcVVG_eELBTL`=0!cLR>ddM>iXE+1b z4R{UW=>-0t!ARHVzXl__5PV|PB&}=Oq(WElwN`ZGKOp>bK@o`@c(|#|R-7o{Qt%HD zmP%SuwO87T@*i33(Lzesp6}Eulzz}}U%owEPY@UQ5MyA}crD0(vO7=Xw7ol;8=07R zKMXa(2!*24Zg&FdcX%5Z7zmMesWa)4(IPzUPp)8x_qDnEaNVw0VD*`y)_b4+2KrP~ zRJ|QXh-p5_<}<-<9zO3osPie#)C%bUdvDONFUu`U}s%UnHxPSTqNk>xi%v<(H}9KJR^Cjn5uOU?Z6H6eRC9t$q}Yx&N;a zsF;!^;f7F6k7xDScpWp#thLbNobsb(wCBnfnJki3jj^9Jz>0bKGfiSAttqstu7$Tf zmV_WBErNd=5xR|@2~q5#&j{*xTD9e-XbbbWdXPHTZ9{^2-B@W*t;Sma4La^2;`8_S zM}76^E!l>-IYnI4Kt+v4{o)J-O^F4kKfvho4!B|hRpC`pv_JzvgzL>9Km>>$F~0Kk z1)D~Sjf?y3eX5zE#$$T2I5FVUrN-lYH9Kg~!`K~Jq+2UKV>-smyP6<9XB)1%n5~${ zemt+_S z$p|#0@7Ll>qH;PsI8e{3K8)=`H*U;w`&@OOvEoW4`*yXXz;AF|MaM)zanl(qqK3^` z>yT(F-CDf=&n zgMLsNO9A*#QQ;w*;aei90=7Q~853?TOTyPiBLoR9ZNsTPSNF<6o*0TaF^*aY6lPL9rbf9;>>@L{Tt zI+{_rd#2df%K{}KqZif7wo8gUAUns$u)u>(LxCXG%kQ||kfnNzWMPc|f>$d%uCYe| zWavPC@y~45+zSD5zS)l{{9i;w?IO>j2%#G4@?Oq&_7THn2H(N6wnd1Yo*Fm20G5c+ zKm;^62f(w+-qg2s97hlD!;%6FYobT4-K3d^1pIZIAe5CA>u+z`S=Iy#K90w*qh~b0t@l>03^VNL( z2Z!|OkP+Fo7Y`A{ZJXV=z#YzdVel=|`l$6Wg$OF55Kg9^9qj8Jbtb0C0_V{y=;A>J zp)4`{LOc00ZhDtFAu)flvC8Va7mR(Z|56vUlO-N%Ao-=9)R@OL)>#fYUND};Yv@fb z2_a7=?m177j&4vH1{aS{rQLIZ_b+ef9SL;mOU-r@0Iaj= z3rMWJ_D`1NQrRg9e?gx96i?4^XP#>HVX}I9#}e3Y?7hBsCh=Ys>cC#?KuuqjCrF)8 z)vrhvHP>b0rJG{2)3Th!osT=%~cFI71d( ztJyN}CB%dAfxiBqbUN-266Btqo{L|6m5O(jxDNokvhZ!%1zH@rN#~XLV9nV+Xhjb^8_df#r>!(FYAIy!_9gCy0Md~Qvwd@V zUETEy<(#jA?>bCLS{&_SBxs!qi$BAsoRN&$9ge?msV$NwL9=Lo(sN)TM|ndB2NstN zcljAR{n_!Y)V&@auQ4Es&pc5K+g*!vqu&wg7Nbsic*J^Qu?qC8O;ol#R1N-_tz-5Q zOOQ3p=donhZ&63^Z_V`!RyDoWPdr_@+q_Q2+;^Y~6+Xw8S<@P}HgE@?mk&N?kl_!U z|GcF$uWA45@u%5lBp0Q!Z`GHWRK6clc{~!O^S7m0yO?-G$=IFO)49b1a&+6C{Dl0z zD&-o(A9jlauGxh;ZY0d4u?4toT`}P?ab&R?9enN&A!9WkkzmF*=$8pi3)9gDa_3lg z)Tq4Lm}q&I4{6EsbMMJFxE?6bldk5&Wt1lE`Jg#{S@|Hs6KC*2_)#TKZiiK&w1}#6msV+2j93eZ&-elcp5({hGwYHvJPUTA)<Vl!0+O` zT6RU)8`K+?r5FkZNEqZY)fSiDYaAIIMpGGm`q`=DTk8+L7%?)9wriSAn>csZGpo%y zUtGR8ZIbBGJY1DZmGPFUwE^8~Ri(Ii0bFj&`wE@s`_p%mx0f79Sl2%nenZCYK!$6!5Lgl;h??BuPO6Dxp^@-7!*8F)=@hdpI6Yj!oV9}gYD@u0BEw=O*=g|*nDlb z*y(?LzN=;rCz0nSkJ?+28)}&-ZC#TZdY-dmz#5WKoS|c+-o{L*dqjU&{}iZj>B%>k zblE>OflK_5O`m!wTCSY3UvCE^`{6Tyee z6Ml?gej|E|p&!K16A&OKCe~6%rkJTa+IWP8Ia_HwKT>u?1lMY7ZG#MeFu>FTd@fpA zS_Dv0_390wpEWvMbex==GJZSH+bu(p#gxO0rt_5ouH~+_YftXezytW$Vfgq?B;d{V zk{8|Yb@`*R^1RCjh2Y@;OeFxaoA%}9WvR{j^6JXp5!|}LD;OnD+=ncFWWHSY^$hfL z3JmQ1MoLsj1%R9<()i2(g2Z1}eQpnz9`VTTEWR`@TVAc&qAgF>?Ix^f*NYO<0q*+B zXAj)&WORxlWh>nL#Ahu@Re-(mR)&+Lys71olnR+Oy0)EuJ~;J%#d+_C1MQ7|lYbq# z+3M5XDU|s4}Ncw=Fzo&Cp3um5Q&Q7 zIW}2K0qU`+-Cg4hd062nore`^L*ZQU(%6wbAaM}SW9H}Ar2%6+=tJP92?f}fk&)GI z-&di1>FCv3xzZZMDrYu2e1JyOvo%p>W=>AdNm)ZvQ&SQ;I^Z`9?&k+MDKIlD8pnnw zW~}FeDJdIBq{#MTU%H{AqdQbPTP1P2BICjnLO*^|{vtG37!a%lZJtbItYZ?*v{ zxv5D_>*Xmwy-ol+s^pz+mO?mHG-A6Hg;;OLeFM)l#eAq#E}=b+_gWk3wp`hq5H2-q z@Z8ZVH*WYK=ERU4>K7CwXG9-Ba-Ic`Um4(SG&4S%O41CbntqK|Iq974G5w|2atAnMrKN> z&J0Q8dHd@>*TttN*bCmqb&uatR$@k;s1?EAZm>e|pWlTyUh`%g+0c&vvz`D)C$+DA z-0)oF<3svvn%+l-wj%BrP>&oml+h9(w^-}1!wd!y;u)eZ3bTkz(O5+C9ONifa}bOi%Ba#aX%`eVcqH=Wl#Y$ zk?zlyXC43@r~L4EU4(qA8R|$hNjxNx?kr9)qJRC1t4%h2O`nXdXQU4g>+alXp&ELi~e_a z?_&g)*0%D|g?ZlB3tKM;jDCGX!04+^t|T?c$wd@dWePu;f|77k%4=%OW<{k#b;t9m zF(v_iydn@%kj;PhcunQ$xNx1P;7Q^5Sdl6uD>s*YiDP(ENl3h#>7u&AEQZ})sXnp! z+8>eb*cb!l-}DjdHvuCx%ZN#Yb|>FqA_cPArycr^^Cu5!F^a*QvV3H@GgigIM-th z7#Wf;uw?0fk#Yp!F@mW$p#1g9f;aN4wXEXK4HeuxH9C{uw|`+Z`Ydkwxl<}Y;q@Ps%5c=6egeay8-4zv``Tx$KBJm5PVH4GNLcP?r1orLGh{MgAeV zkJ&q5m7^eW=ZLe-_`_LW87wMFQOcS?Y)_eeW0`>d#y{lxO$&4%G@X$3tn!I=G%6a1 zL_ij@?xUY@{~wmS*~%3RYxWoW@1-^CU6Q}VYvH{dbdF5BAw(reWyZH^X}_*zpRpBK z@Tubh4@_4<8bebbj4S&k1AEzVdOlSa2D0dapyXZVGP4@4#@BSEg-4ZNLG)`0q%T&H ztvZs?Q+QnQ(5{iFHdZJ}l9LMZ_1;l#&DeOtz8)$4@y)nv31}}g0njxLEOAp508azW z1_yU?`8+eC4vvr-X4-LHDOrgP&we=!qhd|rChLf3Ny#FcAT|GW8I{RXE19>a{!cs@ zOr#0zFOsf%Q)x$ecD@1WZH3_xoL%6x1;!*kw_I6LZL3=@PCn=$#?%GU^2arYEe-Mo+g{uf)Yw{1>OWve(>9B)XM>wXyU0dlFr8sBU5W2 z;ntEbZAP|pOVB5%rpb98T|_k-7<=fkuBWYykY*`}U+GrVr5G{_mhMjIr9b>b`NOIm z&`3$=Ext9E`Q;7uE?IsN5?M!ZHN_6D{cDT`JUJ$m5-wPPK?_Bj%GHJryBhhq$VrwX z2^kGOBv9okuMfWCL^e{vYh}vrn^4`B%!Vc94~TZ|kijIrHDHx*Hsp)g8N29wMb$(T z*gR+&&eYYDj9MIvAXwf2JjoA^e2CIEnrbzce;a1?_>?6a(N<*tkuwQDAMKKxcABij;hnsyaJGj*)=5GfWlUhjKUi-gRc^7Hv|9lgDD z@;?oBHKlOOJ&e;kQJY%eK=GorzwkzmI9i%G;ACb?fc;NXavMRMK<@fX;$uy%QaW~w zJ=V~5Y&?8%LFEFqPb=G&3GYEfEXAkMBuhocolyJO%L3*O$|$Yahr@&^WqE&yx;Z$K z@a({mR-s-_dd`(aotRq}a%Y%*pLZJfiBKNT*D)3%3vl>_+St0L_Z2saiQGtHMtNVv zC}}p(kW|x;vLMp}=w4Y*y4MQ;*P4E$AOPBV|Csn4)aZ9?D0bogv;WS3^G(PwWk2mi zbf3tD)k0IC!O_Kt4A`0j&8$X5P+TS^XO8CTmKB~WEp0uQri*WGywnLkOH2|5cr1S% zd={DK>fi!=LG=jcfvp_qfCbDx*6W}z<9GQF#PRlHb7&R(!~T_t43H&(?|(}fv4kra zDAjjj-%-Y7!-^b-o{4h9mb-k@Z*=MLn=~M9uF6^tI&bUNP8UZb*X=wTH1gILlo@) z?q*9q?vlEcf%Bw|R9GisrXTjGXpq7Xrt>AF!#PYZFD&;#<@yU0ZdL^IM16c1iyN49 zjf%q%9bWHN*o2pOU4o<75ea-I=}b)Gl2|8oE=J@;?zLw&8K64(-&^$8Ki{|%Bu5bn zqZ+sA)d+B;ptXph6b4Tlp(KHqV`F_3K~>Nw82j3c)>RZmbOaM;+7O3g|zQ8E-`@;lMrXS-*Y@i=OwyHX-b>CC5A*MxQTSNI))g!M_ZgT{^ zmX25k5oj{m@|wtx1`LEL^Anjr;&N>Uee#llH9Y~>^m{UDY4UTa=aHB9+gTkpo-K<1 zw>902M*~KH^uHZN_D}c}G8^o~9pTRo7tHjUWty3aaA7NFc=HI;0|Foxb~z`@Jgb(9 zcE4`A>`zls%30a3llc&jRs+wT>vN202zA~dpj0Ev=TOLu`zp8^{`uP{sy2~BwtpvA z0aL;y0ih|n(wGLBhBZ-u-uUO{7&wc@cVZ%#%tbfaNB}tO2so|bLTZZZJslZ}_G|h| zNbQbVQ>KE$(Q3{#v-3#kX3yS6)p^{$Bo%%0V^b`m1Za%t4=n~7t))EvXI_|!UKfxp z{r(SdhVSsRROaI<>}!?HCzW=d_$q^ouQE#09cRkFP?vzN0*Lgg748#hmK&~_XF?~R zX@>J0*9QQeqUdnTC^O=*C?uw=U27P_FACqrI|C*kf*I2_ z3jT|R)nLc@q1Je&oDP-&PcvN3OfJ0}t&$D(h&ef#x_UK>je-Ob-c6}WcwD3#^^T3R z6Cw;akcL@(`;r7)L$Z^qsPh9EoS{rs-$5B2)3Z-93RE3d*~{dglrz>HvYkj=%R=k8 zvRogct+~?bpCejdEso>?vV9*uPSn+zQkKWtuLFZ$2K~geIK+oQ>rhEX9SQT~XP!iDM>~Q;-ySX`xQPV=|Tz0rXQQHe9ph0&;mi=R>1BOQ30$WmFi~Gt*IeZOD$@ zjg@6E32^#VuJWR5&{2dx+egQS3GL&^9{F|fKj0hB>;DN2#qu6h)Mc3hn)kQzlRgruVLUvk{ztGdQ) z)BE(Koi2eCMswx|v(J~S`MvAsuWd6GJq?e6mQUwHEX+Ba7X>%Y#Pd`$mx&jmnl)ON z3$zK}1YbTc*2+a9%__#ly}2k~?FIkVGznCGcE`G(xIvz+HQ!0zgICbSeZ&G!cuzjD zI!G+%%6<&8g7>@Gz#jR~-vazA{nLp_}znOn=BV zuB3oxE`i~#H*G`<%wXQ5Vd*L^6fOpYFxFzCpb{rVN5Nau8W*UtJiu3qz?pd@@UCYl zTQj61JrPYMBDGLhz}csx(&4XJ~=Xtpf{-=Rk&T zriLtQEnR>&%8d&H{>Gh8wgl8G8HbJ_07F~;9X7&j)QCh4?Hxm9c9U7U^Nndt@T9V( zx3UT0ZYYTuW)jP`?@?O(J8#agCXb0+O;{$+Y^g#m+YbK3#sacdG6|03pCD7WA?a(` z1`QG3Vu<7Stk&|^@6K_WBZCy$B+^_K?;rN#H5(i|`))GuUGIO8_I##W>e4sn-P>J1 zdb^0H|85C{A_8bD3Cd$qN!)QxP}UU#4=_A`V0e-UYryarqUGgxG>9`4X`hViAEzw5 zz=I4?|4H-A5DU%7z6(epMG4M~CenIi3(tJJ6nIH#z0^xMEfRA>qo6xvlJXeWn% zBKMskz6XzY20mQfdmflYkv_r%#2#_;oN3f4rZX8z$Hi4Bt2H^* zxn`?-xBt;~73H?m3X>EJc?h(@ggedA94JfMoGCKIYjy@uqSY`_SBo=exYfZrZ=xkV z?XIbRxc2qjgaFHhs%V=4+pK2i3dia}XXLB%U3r?H*RkpIca%P&IM=^s^KWfA zgx6aBX%zQ{;`t`2Dj&)p{nJSMuMQKcCsw)8?2UgzVg`bK8Xb|mRc5&-Ar58fF8C7` zkGv~(>cABtC8B{fvsVW{FEZI`uXpb(0PgQQIrXFUo@4eL*^U5&7pGif-tM3;KM%aZ zRNxh=0Ir`SdVg0~WMK0F`U$PEgxWVec#a}03qoJNCXx!%UT{R$e5RGcL7BRKENs4_ z1nd4zHq41T9VLZt2|t&#dC{C$ek3yBn4##F6$$7%Hc0ga5_5lG<28f0MHsTKb)0Y$ z3Mibb4VlMAPfw1G`FLg+3hmS#)Wkwm))0LIYs1WvZY(F&&6w}4y*k$I zyK|&VNuI?|0aLJi{CJMUzEzFCycNFfwN}gk^;2!)C&KRe%XqZcfE_>tYD(LJv9N_q zpR5DPZzj^Vp9Bi3e{}#`c92)7NRuRZiHrV!1El|ATuWKos>h~q?l({W9PUOYh6cC= zE2%gw5bwlc72L>Jn-Oyjj*@1+rWHP_X4Q~dtl&C-aQKvy5+=j!Tt=_)2!f$I>%_kP z#ZH=~4{J>K|MB&X(Uo;kyI`zJQemaSie0g7R%}zm~iN<>)?kIw~LrUW0adL1FT`*JF zNrKmz9WQC?b%9v{Q24TN51Ld(ij#5=29p>0^rRU7nWm^g*KT5u2|$OlsX!^E>G?UP z=|zt_(wkK$CX(<+zxD_NGm_E65xuo3NZ9SMK`KLNS)0zV>*EFd@EFV+jqPe|ESHue z;CE%re#4815E4s3Tpl1il&JT-9{e6XJ9yp-MX7TQ#4R3*DasL!QjdTuTm%B}0K^w`FT~4I!bc1cd`~I% zpk1micr5fta+j#cH36*C0^6w3O(^fxxhCy6wrkWMjCJ@q|8KB$--;N- zUYZopdm-+qV6fvblztM7P4Q^}Z~V@rzSq~01_}j}WVk=RS{u&>s{ zZWSs1H(0zeqB6y18P}*fOj~EieYqlaxb7=Z1vd(>>tr)T27#U65(mjnsV$JR+^kgp zeW|5XI64dxvUB@GHCeN4oyBEG4b0SSfFU23@nAExTBrQDVXB44R*3!&j5K8EU#jtS zA2l4b)AyjY7_2j;8of-~pAi6T4f*qq;KNk;{GYGP;=eH!;g={VqaD9Q=uCWM97EFv zVO-C$`CBKv|I}xM?(Dsjkeg-AJmTlmb}554Ni4~s2rGdOy<)vs!37wJV6XLozO!o3iF?5V*&@p0cJ;*|g)PF3pg&_G;GCRpO7M zlQ{GRDl&*G<$8a*7f{7G^@5$-B%rW5g0?iF%}x@vJ?C>ve&b_&Bp$Io%2u0RgIg3O zn||qdC`C#T=?BhsOa`C0!iyl#uw469GnMC?J83bHZH)&F0+llIJwOM`eGEP9H4Iad zdl|QTF{^>YY@kD8{G?wv%|s4>*4(sURNa%6b!4LMq=>BMs_a9~@>%EU%={E3raZb@ zTkSkdAQjom|H~o6uEx_i+U?QF?lMb{p1IvDK1NTeq)s}QsLtA5Xl`wZm{gQy6?g(X zgMZ7GnLlN?o-;{l&GtaWC7y38EKyrpS3_A;YIinGOmM-iJVJWx&@(EcyvcrYSrPn+ zH!_i8v_xQ1aZV$20sTMMc)dQPewy#)a;o3{S?bNxbF>cTV;2ou@-$fJr?aAe0lN;5 zyKHEcIGMEO+!cFGm;DNwq0r+s#eapxV~gCG!UC1cHXq#cZmrQSCXDgwE#f3s|E@Ii zq%f|wK?JJ1KG^>FCz5fZ zv{Wipg;Mnf+^kU;>)D8#^ihm8;jvYdO}6=oxV z?I&@Yis5wP;<(tRY&vf9x|RO;`rYR?Vx%@NaZ;C)qUPvJ*;DAM{0*VqI&?=?Hn@ckctDo+*|Jbh)(NxSSei>s+ z&&aMp7Ua)2P*+BMFr)d2+vk)RgKtG`26liFkm4EtJ0yrPP!#(|CkrX1F`I3xdYVP5 z$2k`(^}qBIMmiGkCj;Nde(=XX9k2LSlui{{>VtVDN5muui5RH@I$k*|PHMT+^tuF0 z#hU43-t8SH7xZoAX``(uPnLsf>yJr4z$#zVEjGqh<@w5 zE%7iR^~nJn@jn1mnhRLgCN^MM%LawoZ}MA5v2416Q~${%khF-e|8(Z-VJ;z7e=uBE zk(M((N&===E3@P~wZ?ivWylcvzP`#Q#<{`Jrbw=*C$N+U+>4UJ zdDHrqw~y`uG^Flp!@qxc!g|5wX%+MFC;dR*6ki@_8RG#$)vJXXSvqbj$Faft^+aB$ z#X1fn(TSwSYEbQ0ZP?;iUA$33r%o;9mwU7t1&g0vou{sp#OBN@0!Rm7;cR_yC2WOY zXKWBIWC_!$_gAp%?4X7Z@k0;+(#6w7a~vu!JL><-vd2*6%U$N;>YcmO`U5r=%*s z0UQaVQ{A;W#IlUs^iE52}*l;syA`0x!{$z<3h9pCn;KBw%1XZ6@rD^T5H#pM4=q6eL9i6GKEE zb7_ZK^W#tx3n7q*m9U=UX0xJ@e#A38^hP}KQhrX|aE~BBWKh;Btc)7zGMIDnPTO{7 zBUVC=vGC&X+Zh9=BAM06wt`6vU8+{rE#IONEd{k%Egw!Mp}y`mFtJsPQ)-F?#u@b; zOpKMZU-&f7+KawjGa`_J?O|~%)P`Bh(|&FBS^_XDk`I*RGdMjECH)0cz*yj3Yev(f zjP?6g!d6MrMr0|=dubfZIC>2frFUGphO#2ft%v_Eg{k}7!8pWdkVL)mM!Dl=VYy_& zRigUG)Dj0^7C2xfiudur6)ctb)$yamOqeCSiS)v=F@)_~?n=Uzd_rT!!f$vO-`#+9 zgwUrJo149D^cD*Y!lk-eUEG4~1x9?UbqZH9$U5^(x31Es3Jj~Q8%Bv+Q1aj;t z2mHw;Ix<2~0%YV?8f%`y_y`AL{4>RWzyAL1LhtVQ!7{AclipU2+sSY>8N13!&55Om z1hhc@*jv|_f9U9mRz_zBb(cN(1?3EV;7pL5QL>*LHzjCR7p0b?=A5)&|JrRQoJm3w zq>Nhy4_>06t(Mv+Vj=3S5C=c*UVh78V)Dgb?yfkhKD!{OfGuG&%5|@5EpPAGK18Jn zz!$@-I24LIt>I%vvSpx;&M8n*|0gBTb8uGHz&g~o`}ESn zNjp{zQSSZgxvdl%+k;qej-yt^kToKD@7}KWPzTjXYwDMFYTcF&iHa$>aqT%mK8N7I z-#|AhxoHd2AkMjlOzS(Y0cSudil(6xdI{2Uw(T_4fV|*|rIuoAjBuijHq|jb9tvdT ze(1g)=JV1U)~ZiV|GRXu|A-tgn&T0A(ZNBwp6==F*OHE)TDq{mVv2b{yK`q5Pa^-l z7?ziWwlc?&QXRqPhp!Lan#WZmKb)*9MtOPSLOYhix#%T{I&`~Fw}!C z;*?tji^8N8sOJvr(V231%XDMsp~?o0tJ@nA)2;=?)) z8h-w-7DS`gEo(Vz#S#eVjRD28AccXgcx!SQTk4R~@W71vlSLrN0JL*<05ixJ4WdGC z(1)@Hjy*Z((I%?Ud;5qHD2gT5cxMy2e}; zJ&F|!UsKp(`xo`?fFEx8P6N6zQg#gmK><(S+#nF+%5pRm(LL5)&Q3WoU}b~?7AOf(l!WPt?SoB8 zo}*kJqrN?KlGzEf*q764@piLz#lqk1v6h=}+(k+=SUjujkrDvPAz826;A^}pOq%Zq zD9FxqKCx^HA#?<+$PL9!Vixy$fyxzSwb>DVT-LODZ^g~BWFu+Z}D#+30C z`wEi$6Z)GNh5E=6E>w(X%Wu~Tfrp~lDTlkO$@3HYU8#bj$Xjyz+69=nQQ|UscpHVw z(_kc`e4cUq_r81smcjOamcihR%}eGwQEvZ_&r{Pq$RV8!J8X!Vi3ou>SXe~RahFwE`7lq-6M-4FvcTM|i?*L|{ z{lV%d)$PA%Gy|fM{ePmd#t}!hw9eYqOD3L%SI;iWpPhJkd#(7Up}<-=S&xaH@k1h5 zoFUmbuwdL$+ja9_7FJMo0H=aZpP||Kb-ifZEGwC$zmVroa1bNlqzg!EozHZBcYRs_ z+yaT17WhSdK!oq$KPV%N=0XIxD{Fj&F&Ut?CPqd)d=nQ<^_8+yH9Dze;&^DP)I>>Y zwYHjiDijR1aE6Y8l0$shgO9EI+?9wZF)ExY6sj?%eO8rmx=qciaBMk-5HRBMq=g;PmL>gTj<#Mr?h z9GEwjopw4KTd<^KCT0+uvpt>OkLo+p@(3%^o--GT2P-ShI7>8OuvqckeKm!s-J@=$ z=}fDBLre`MGJmY&pV!S;>_z?iae)#i1~KPDG2XssV!jUFsQzU(b~yl@W~zw~wYLDU zskOr0NRlE7LciVC1pCAX<69eWMi9F2MqW}Qcd3|+fn(et)3RO2}AselEul@5$-C30WgSxdHBpm}$bd4uzg#hp~Osl6T&Iou;wf#}clL~9H9u*dMI#QmTPb78ig;w=42p+lC`Gy}HjkYh5D5U0p| zMlgC%KnGyauYKCw1XaR}dwdzUanPn1YaQ3-56?c%!$_a|)>LWq`1R^29N{I2e(vc zNnSm(*k@qVEBz?9eiMr~iHk)ALH-T0a=h_(C;TDm@B8>mc?JNjlik@)2a$qc*$8L4 zfR}8%K7pSc{9C=(aoP!N<8h96y~bmO?3J(&xqr5+rHq9s0^*=L;IEZPHLM2Th19xx zFNbBV+u9WP29wdGt+Q$9KKk3TEs~GMgwb7H*e}J%73***KmXMEMs-hdwx$5oSq-&| zw+$-|&$;WfO5;G*yA0rU8U{wwnvnk!8T_0P_%pwX&X>hFO8mGebcoVH{QJLEA@IQp z*sLM%r5^;Y23HI@&n_@ht~61giFaMyr~rhCUq`>YWqR8;muLVYE+TX$q1*hIFSlrR zPxh}K=a8IqHT>+EJP4uH0Y-Rz`9C~es0g3tJSOU~*9ykIwwDGv+ZEVn73yzArQq*! zEW&9s(VCT612M8`Tw5n-*QCC{DQXdu7n5HmFv0LPW$ zFrfc&B?2Eg+x>YK!yN()FI~qYUThs^4n8E^@p>H){5*;p>WSeH(sg_#jeh3|=x&kI zTCrAGICMY$0r2%4?jbN9xvi@9P_xr3)8;K6cUdFZcxCI1DM__ox0h_G1~066GKBc< zEc%YPsqirp5i7Y{b?&IQgR1O~%TQ=M+G5?ID@u}RoknSOm9V&-js-p&iWi_>5d2TQ z=r6m9xjmAhgGQKhNS2hHq27 zGG#bhfD_-R8eeuCgPv&E7rHgkWQdpA0 zA3ILGLWV7xwqP@{x%Mn8w}TuE4pON-g4%OG6%aLqPWNd*$b%)LG=_y<(ss1*N){S2 znhp5uAn$>ZgZlq8DFC{|(fix8L0qD$@qKPn&MH_7nVR@lGa_1yp5g4&t!Kf-`S*a# z{@O}XCGQ`GYlB?HEW0OCqUE(__6wTz6C*8;&cKTi)S? zJsX%1B$0jjrWmJgzi}b4b}1TK-yQ(?hFAp9j{UDY9sOt1Km=79kMvGAq!8OEMuxuy zj6F@oy9a-?Ie_15P8}i`z8OLbU;BdzP%;eigUTHc)Vk;GGYzp+dwat{TAJx(x-EvQHyLPb%h!{g51eg{%)Ah43M1e z^~~*aU?H$IVnoA8GlYg#ZrZ)P`&YpUb;H{a2Fz~jyhpAmHW$#bTJ*g)FRa|TZ`}I9 z2DcyAk^ty&tqF1_7jW!e(nKh{F#b0lj^KPsUiGbLECt-m%}67|VKfHwh}K-cbS5$v zt&G=j#a3;&C3?iVw4RP}QwS1EWG|iX1~fcKssAUI`WHZbjQOy?83)m5kULVzrkGWA z@X$!azJ_%1B;1$HC3CcYcTav+Ppg4hv@vQ{BXFQ~ybQJ0X{|oq8bm)4$9>Lby*Q`V z`uL>}=n-3^;&txrtyHKUqNU^1TfDv`EA@Z^Q*-S;EP$g1>K=lTD3ICt;FzRL@AV$! zXj{+1dcjohDnd#KKo@LnU;&q$13vxsnXb4_%PNyDj(76N`rTPTiCVz9hw2kPA#9mbkL0D={$4irFjKpsrNHDYzas$!wU zL`g1sx1L@uTf~M;kLBU1iAMlpUnXm-O~*8lFZH3ffs;K&GU`o3yXxYd^KAhAgU3dS z;Gm{<$Gn{_W^)|-T#1F4HCmbv9*#UmDx7I+LS}s?<@#kZn%JfABJT;@L{5nq8JQjT zi)oGv2RNfykWs#_6;aBPsrn+QQ6D>#dkD@{Q{N_QFEkC0#BU9x^l|GE>Z*$Bgoode z3(?Hk>oeyL0?PtO3E0v+db8B;c)H3vn8wdaIe|aNNMq_w`n!!LcMWS_lo~^it}_5E znHUZ5f`+gqeBR+dmIOuD-zSr9=NeMwKs0cYvi$im`?s*+aHEJ#Bjc{M9e$B(9FhAt zKurVkvFxLcN5gW_P%~|9LW5@HCBMKc+0??%LMOuTulf3Q#VGAE<|QAHNOB13X(mhu zGuAA(=9tMc_7&YZKxxbdK^tcJC8ggPMzDpVr8D)o^>UK+=U3Xd<$nPPue}&|%MyLv zYoKR!7zV``9{(P8AA7hiUK8?OR;w}CVnUeGv}w-<0uYCG(}{Fc%SyghNka^oORV^M zJcyPx*}qEv3OrMX^}OoZXNP(i&KvBm_20qB7wjPye=Lc5v5hcOp;IeP1LW!{ef_;Baijt~hZ;Gl<{ zApYB~Qy*Ih)1Yi}3q3o-`f6mDILptqR5+u_j(6V_afucMt>MS>3cP6uKo=vy4cG(!WV#V_A*&!+kc*!p0m@qh2>-0lhAJ_|bFaOvOr3*}leb{oKv^o8yT0 zS<^Utwbl%XE0~!Km%*$za~s^{S%St(MZ4~-2xe1k_V$LIjs= zE|U_1$A0>sWsOkDprB#pdJ~5}b$I9*_5a%iI`dm?rKP%`4Hx%ieta{r%aVQW#GN$E zoz4e8e>`3=zsM)FZvwhL>Ll%vGFERksSE*}O!-JQ2AmTS6L-XV9L*%9wvI3I$TqY+ zbeji{-T!HIaC+$+kdnaZ`sbwjH@z!vTog7D0DqVa?Yvi|MKx0K_K{a8N)Gws%ig=* zQDQyr6Gsj7Dmac*2wg^F|4LU`@T^pCVlMq7e<@ycU=1hK6&+^2CtFeFmyI)J5*~al z`D4-Ms1tn3c7f&=a&ITCp385zaJf8PZCG_D+n~_2Mcu0&r$38-$v0G8Sj4?|DdTot zyZ73I_`l)_x`b^pA2`j?1)Xm&#V0QFqYNj-%Gik_Kc|fiIn_X0=}t&4XQgzt`-Okf zya>rbO6NrzPr{+5hnoXit`ZC9Y3_1A{G5Upl4pLyE&kELi+AvxW+Bk?#Y0X;_yg|f zn^={W6;o)u>5?88=0y8@wv*ERc;?z;_$!GH&HTB6=?gnqxgb-j^5v-KNqo9SLwx#E z4O|o|a2EgbCeTG02AzD4J=C5sYpk>j_7SoobW~Z^INcK+Mpx?QVrnQU5J>vHfFvVpLkj(YxS0_XXTSK2q5%utROSyjt_eo9eF{o_st<7p zyE~>iSSAhp=J4Q+&}t&BUFvQ)30EJaDj4MGq^jLnl1}x!q;%Lz?FxGm>(D&r8kGPC zYDX1Z)tU<7gZ7?)!(NcnI)h?W1z21^B$2W;FgoRn{CX@l;5clP7fT39Ua!ck)tvPE zUKTpZdP7Ju6S_1yVH_@S4!yOR&)D)9}m*aUld8LOX4wCyILyc8te1<42-0`fh1 z;(aOsfy=|ik<*Ne9s}BFaG70E$KLKjlh!C&It0;rSe<)^fCR(ybT45ebdmi(0VeIw zwt#2}i$HiSqE@-lzyD_h144uKaQA>uyC1 z&*>^_y1!5Re`0orzW}05F3?Ii@^eOmYJ~&U`rH%~EJ^dht<`=B>5T(Cz`P|)!)v^y z#3TUe;ahx->jnDp&$k){NE!tYU?IR7RLn5?sb2IwMhR0PRe!We1bpG~BpWE%1A0;o zTA{iO2d`y7IO8w z>3I@5WRFz=&BuD%qFor%|%bwr`o`Q`?I=hg+ z*~5vxdA4Ga`(e=Clk)1NG^PJ*61vO~y3BB4>y)C_y2v5L|Z{_G50Mo zA3v;#JpO7iHRSvyr<1L4>Dm_~d#5yPKf5uEU$itvDg;8o6s%l{p)Q)B7!CD9g0Oj; z-fAlPQSO5j$F-v1DihKM2Y5lR0UK8sQMuY32x83bpMPc>6gHQ{ZM@gSBsGAprT%?obc`&2>WXhITPkB~@3px4| zarI6|zPM`~0ZdJ$egso>U4TVt&f&BwIW^v%;z|+CV8+-UNHtCYAuh2i5bJ0Rxs1WQ z>K|A7flVNcX^fa9_xt|_6cZO_Vf<~&C!dTEL>hzy)}u*$2wl&E51)k6Sk@jYR*j*1 zP_YP5N@Q{+<%z$Ki|+JH5$ORX-@0B5TDcKoKUF=>C+=`5(yt)F0qNv9R!k3W+=pe{ zcXrS7P0b3$7e)YPIPMTiIM)e;Jb)4d4q6&+B7rB~?lUY8a5`_QD7Q;P!2hHBFZJA4 zP4B2lD%8G@ve1xR6j5#xS6jhiUU_Ip!a}xLg+`gO@ZzxJYTaR~`r1 zXwMaB2>;LhLxn8=Jf9@cV7y(zZTs0%3>hp1#2BWG(h}gy0!~M5fKya8kYa&jqEAMN zC|RdrAFfOG`*vB67$YRXma15?n@P5#0<;$|tcbcm2pk)bKy<3U`Yic<5>W7gp{L^} zr_dlF@PFK5OuyJOb$5{=$+ke$pf1jl`pk#>Me3^rF`MS=}Aa_)-!aZ2r&qo}}uoI6sNp%SW)PQB!4 zt^~X?iCac#6$*kv@v{nD0HTQufaEy@1>o+`H*M=zMlBItd>Nydbn>xkp3B>1&QuZfq5|6 z4nK-W%{N71VD<+?#ci-q8!`FeV1elPA4Tu~jxqq;)^^seit&h7MlloohEQs{%+zo7 zz-#1Ky^`h!%9DMHoVLDKJOlk+s!?}gL&k7)6T^>i($LnM&Z49B3jZ-Fv4mT+h_Yjz zsx(DD6plcB5B4bEsEQxt-xbz!mA!?;V&Xmebrg{k@6jwfzUCnF!+ok2`hw)9;$z+* zecGCXf*`O10x3A5J5OjSwhyR#@PqdY(NDQB3+nkl2ZQl zMIeQk!2?^Gk!b_Wz78G=Tr-A`eCXd@K&Vg3J~J&t@xbNxr4c;n2}_=`<%M0!Uga2K zNZ(VDeg9bsd4(;JO-Fs(X4NoBGc=gXu0g<^j2{TpVKhLf5+4%uzZ-Ukl`3XtXut39 zEI_wMBoJJMtftIu^q0pz?4_-vjjKy?<~)=el=ed~=1F&HO-L6``*TV`eCNH|i zM}I>x89={*C7thjp~JSUhX(qp#^(&RsOH;TX2o3$i;fI-N``s z+?=AYY0293Qlvz_goL!|YF=<^>&uBsB_O<8AWxaiqtYEC{Yxw?GPKp>W?_xfskbM@ z#o5_f)T=kZ?tryI=i~NjC+YAoYcs1#w|{kQO;1mETUT!~ojWxyPO;@z@+r2f*g_wb z{p@?oa0DS#$C+AlUT2yVkr*C7;ARQ;-)RLf`nN&5HVbc3ON?RR(fe+viCP;w@XdEb z7u7Y8DQS#QiZ5DO&PXMk{>93_+n7*XUJSWx3krM5#pcqhM;_sRX4*fPMNT%Hm>f?^ z)}3IouF_4GA`(7sxS7$2U)RU~MRyy5jX@;^QI^flXq?o!k99-p=H|vP=18HCgoMP4 zmLbk-%zkP04@7fmM>6#^nidKurxW^qCUUgZf~mj`T0M$=^GjCS#M!b zda?U}Kc~h1!2#fHVv+)d?0m96PV_hOu>N1yW>%y~I9T@3ncpsOEDKouyda1v|E`h% zvNWA4$u`mw&;6P1%`RHVW^|pnWU3o(*2vP=JOub`M*8|!2rWtRO@)=nN@fOGV-+dU zShPqJ6!Jr5^?$|wO<|nH^vOFK0^ALVR9j3;M>L!D2&j&pLoW?VfLk^#;X4u&%C# z0NroMzYu=@ezsASS@5Y$W-K-{c~MnWhee0ush*99b3(QVfdxWvXn?ED|5|`kjy^!A zmm=k}a0rzb2X-DN2F^hF2n2MunS+cI{esVCLLp!{E-c{5T)Zthqpdii#nTzJMEA?OB=hEhl5ab-&hK2?^esmtH^ zySGZ|`h_Dd>TPw-NYS8qUF<|`+K<={KkC+7-*h3TS(TW_ZXX_y_o`R-xax5USDwvr zpsF}TFn5oBh14fY9Dzy>F9I|9m+!_J`|^vp<#YBD;YVSCIX5Hy`Dd-A%U z0H+JdIonyOOuUsw0rOvXyMUR=r<9mh5f<+9{mn1*CM!n~lH*;3pM#ID<$8fDfDbz3 zb{?bIS-x?4h9V$_&j%)+lsU+LGj@8qzGmq3{xZfzq(l`sJ<4X;;~cK+w)1=^2rcm@ zfNua1Sm3WnF5Az44r)KhkB|QONy)x<7$n(HV|6T=ps(LrQd90pgdo(1Jrnrvxm_m-(*@v)N3_)=u@ zkAHU8gA_*)eVB?n~QJ0o-k)$SiQv}kcBn-ZOk$^-`4P2u@yy3Nw+QsQ$%sEkEA zNL-#flhag<167~_O&Vunaxz7#<-uHVY*=b=nHnQu4yAD1-SzeL-Hjk}T~-!|{@2qD z(M{*r{qa;5GfE|L^fuTv&gXRH@uj;P;DNa;xsv37acGdhn;JcKNmiKFTxfEsG*_j zwgWT+dyo-=eNDxc@r;`pmv8f2cW>_O$Hrk$`!8>9tk!dy<+Hh54;P*}0_d1L9yj?T z4q6;f0@so8_s*v!@Ib2kX22xZY2ka9&K$Kj0m~&>gM-O*C${wTR{Mld$wJGw7Epd4 z7gB|uaO@gb+YdfboV*+#N<>?$EKWqQVi@34-h@I_6sK#znlG)$hG22n%ahRSxqDS6 zGMSgnJjHVeO;5MZpX&($1O?xX^lyeE{)1odzD#5azwSacSJo608?BTl_-0X7cL1*V zMB{y`As&mD?cD3c`zquCb(uFgy{uHAfD4MKXRB_e=j!`fGZ?2rO$fOC=}f;=Ya|Yj zc{N&RcmKe^{{FtJiyN!?oGgn=6q?rReCd_V6`+aNudSl1$H>5tm+}BPc*D-lzPK%E zJX>4YR1>+?=KSuvtk3X0{2dguKvTg|xZTt5M#vb&GJcaR9APr*MI+3{Vd z7HLftZ$a6EaZ^h?$a(MIy|PThq=2{_%#;HkM2)~7W_pQ`B0TzxZ&ixeQO^1Dxgz03 z>h<1qoF3P4=GXWzJss^Y);JeS)kHRKmmX@KQOsV8>@I=SPy>;KGZ23rheEQrc)o_RmDtv@10S~Q4tP)km*x!5kyb#~`%b7Mx15LG6 zGNlP9Q!tKS$h9rYtPUm9M{=YreJ)>{n;^pW9uu*Sc+D=fRzksIDwMKN6mR6V|1z#J zNe7TWMNf0U(cVRl4lW*?CfB+c)_U>rS&Iefuh!V)F6&z^W()2VND)gCxH+ENHm_Fx zN?WQBd;yHt(A=0UXYxdx5sFFAlGP4un_chErCbPK5=DSy5X@>>XS{6tSQOol)%Ikn z&W1|MN_Matj7r@L2w9Vmkov0V3g{Y&7)m=z1D(m);UTCWl*8G&R0(_uE|2rlk-g*T z+|&6WzRm4r^l4eyfK;l8kaE5^O}xJ_=k_G&zWCAM@3%UiuT3L_5VlTPw21P`|98qM zCU+9W!5<%JtKvRs{6312?%sKJswF9dM0`})vu;|VwXpJ$6O7kJVK&mSD(+?nZ8g@W zYv_5g^B`^4F6R@2hM7&a?{M|j8L{3upqjayb_b*z7011>rL=s)s(Ft$kvZj3u{7f0 zg!j3b^>@AFBSXAVH%GIDl@~j*(;-g_C+S4l`H{lcm8YF|Q%%YBvnN1YA8=3Up*R0n z_n4740rbrnjV3@478*P_izm_*`*KY4f8tq_k%v4#KSy{S_1n-&f9L%3+JvEFKHtJj zw-8qHbls;CI*@aF^YHb{7x15h{r$rQGoZS(_typ~e@y2qex~9ZKyhs2N5U6v;~PLu z{8w<;fCOAjzJY0j;$zw)>GP4?1!{nvN3id3_jF*=spI<^uZ5GqFuGIAIk!DwQthtBjI15J;$l)`?~ z%m&tdwx;M*Mkg{q_3cdbrHf*7!=-|-FU_|a;c-9euM!aVX#le^IP#vnzCP^5O257B3^e|k zdZUHk&f|GH=f(2-mLD``U@;~-`uE!^%Ox@-V6<^P^qGKv@Hyc?$Rh)vc`>rc5p3R_ zSdmOouILUFiI^`s3v+J;lM%@qoW@x7%x*FvlA^j0lvzQKV6eEs<}$Vst1(aAe{N2R z3L3vAk)95PPZ}ZQv1Ln_6m&tL`%s5gM=U2iUCG^?<`x9E+7{q49L)MopkB$B6b$tL zCd*7GcQ&xnuDM&!#+^5HD4a;2qr9so5;aNTaeb^>**pIyg%_vFPSGI5CM=hm>GrMn zs$8Q%v(s^*i2jLA-CU-(tBA)BV-+Et5u%98HV>=p$U>_|T!7zh-fs z!}_;6`YhLqOz=@ceKr&*ls(8~(+qsw*KJKP*gor3)}jnYk}lLf1eBVakln+%-;~|i zUBXah(MdPIJF+Bl#|-zOTVsJ`)6s9{`3ZjcJ~xtMIcW-pr3n&@ss>+_upcF;HUnn5 zQw0VEdchQ_Ta=Ygml_JIm}r9BkWj83O69H7bUC?UcIxQntS{s&RGj?;2?{v4*cQMS z&6%<*agc|^G(z{b>G%o?K*8e#={@R{sAKZl&S4FCRXJ< zJk=f~yx%hNBgx#IU@Lv0jC%Pmj#26ep}_e{=v8Ka676rOW87U(;C4AkOz@T9YU-Bl z%vQU*`d$ZMhD=)xD~mybSiZjPpN_U;%5SfM-VNB7)bK;9mPXyQMs+~!j1R5lwDRKU z4)Md^{Rn)N;bXcpAlfBZLXBm={DSe+ zVaP_to42n(f9ZM$s6(DX#ub_W1RJd8lNDYpH>+3gOt}%x80IoQ{0%AV;WW4B!c*c{ zUR6~E?1e2>+SsYN+Jr|F`qRu&vL;2Mgk}q*nAI&#_eMi8-eifmUe8P}M*4+S?{6l7 zu4i1M;XA!4&@xz)umH-z@s^D%qobujm2^0so5n_f?YN>t%G$sVRDL+f61E`^aLb!bL)!dqbU4kzJf^(oKbh<)+)f}$CXoNi z-;LRq+vFpuOODI9lGvOS%Hp8fji&x4?B6TWH-YVru=#U^?%w41QznA)Abc2 zoBkBNv(P8n<;SG|u->vBp-(4V$CaJ%xr_OEx;p!0wqrpasF39B*ks%wnPlq7d4YtG zVZP%-7deGY!E)c*yZ=^9gC4L$-gB8VRb zxyM~;44nrdsSn;t8a+#4@o+U(RUPXO?R>8R+<}~)p)W@Jg@-05U-n0vEfdWSgSISI z*1n~a5E1FUER-KiW{`-(4YAYneF>o?zjWBis$ZA6Gg;3G&_uW8_5Q-v6ejsu2sacs z#7toFd_NQ52A|VvEJ$YjuM0KF$`@n;7@KO6K#}&>V3D)neXTABKlVD@br!f@xs2ZH8~KEOnc1A2 zpXWv|)^_i{K0r4M3|CTc7W`pqs8LA{ezjNZn|maUzh#O!tb%od^-O7qH@pJSss*G= zyH=p(>^L6vIaIA6@$!D&91*~@I-ZS8jG3?2nE>LN`a8HF1o{-@NW!WVL3j;C>cB{; zz{C|0I$Z#h6mR(j;rT<@uB@&Dvnm#CIagH1Z#pSHx!LMM`@`GY za;bgI4b8X9>k{q&VAy0g^=wCgY3WN75#%DIZ z1+uXVQWj?g2f-B0c@HwpIkgpiwkfxEDSf7U{Caf=t5G&(_!7p!cb@~~fp9wb97O^) zpDD|!)Ty!eSYy%(vM&_0C4QXezuf#~+Ii`rj!WeFgbBX~lj8;nHt|A=dB;WzU|WjJ zS<4kb7v|vFfV9SHSWnMz3oH(O0S}QD&Vsaj|NA8&KCv7oP%cBbd5x>*>b2?lnKk9` z4sL7$1`9>1s>)6p#A06_MHdGRlwT_?i(slz9qaF+JnDCe8($Q`2!k1&^by|7odsF8 zh@emp&hI>{8h3g|f}tQqzwpt&*!S_{aRXa*Jcz@HQt7I~hb3Ozzt&}kcHmKHJvZdy zz8OqN&P5`TuF$$1;N<9KF7DDPn^ie*^N2(1iVgZ!l&_Ea(e?vJG0#d-~- zZ6+6(Xj)$i+scY)nZ;W$2ztuJzKmfDoH4&tmayT7PaNBqiBJIzXbO9@3=^YBqb7iw z9sI>{be<1RvkE5+si0pSf}8@UJwZliD4QN$!5R1;uPnp@*%PFPeIFlwj>EzLMf}g_ z3XnRWUHE|K`mZa4_Yj0KA`8i6DEuG=pY1G3hi=}3ZMp{f+xLi)`t7|QlRbq>#=!>0 zmqoi|am7S}lHxCN!ovjrq|)g&+&=Bw3uTS-Qg(mJja(=X{bWSrZ23Sw9895ZS|_Ezf#)R28b`{WC$ti}qV zfXlt2MeYm=K8YP2*$@xg>&ZNDlyV4S|EL*~~-nP%Xc&BX$1~hH*jZ{7s9W;-u8h0sV!%S#+XM%ZVm+ z{8XznjZWd|)ve}^l&`j2wb^zw;V0r>!NOTcXlQJBsFVU=mu+in>z!scmDL@JN;*eb zNVkx+XE2&@#%tZBTW?D}YP%}>!+omWOr^Q0L~d`*=Am?(9Bs=Z`rDw;PiUm?TLNB+ zLBeUW{oI6j$wboIuAn!s_otfD-JBMDx$LS0ntz>O6+{oM@h4|aS0{)?OSCjux`>{I zymP>x%Y$j>NmbE{2X8cA@7x__Le@q?%uvJ}K*GFR)GEx1N-9{@R>bmW&<2(^EL<-7 zI|!owf_}EsU)&eU)NE0}ntyaz@cchFclZSh}qZ;v)RfnTu~fZSA})lz3U z4>!~trx*=nEN}-ht4r%LjYiAyfAwg>^~TdVo^Q`TH5yI<4c>XJvV{NFcG4g$N}EC~ zos4WGi0zkj07OKrVp>;gbQyY4)ZZ$38%z)cBywGxu#yp@;A67z2jz6uHFs0G7D4Aq z5g+*$-%I7~JCC8WV8m2Db`wWci@TWhcW^V)o?CrE-u^6dsgINtYG}9VzAE3Mjn%Zr z|BI=wii#`RmPHzOCpf_xhv440B)AiT26uPY;O;KLEx3Ddx8NQef?I&MbIu+2zMuZ! zgVDYBT2rcO&O%YNG=1o5*RLUB2!gR9uO!m=JjbpDl-CNiY%qZU_=A6`oR`~lpT53P zVwILrgzF>rhb7$V%z-ua=+Q_`tnp7PbD3+u8vaPBybMx?GT7D zdx{xo1yR@{86GTA-saz7AlJ|8KLXKxBWxlSz2X02SR@>Cz>JSl>qJtb#=vFSxL|6+ zcRu;&9Ok|GLPo*%Z|xNMsd3JOgP?MdCq5GBYAP1hHGvgG9`v=}q8qct7l`eC`3c&!<|v-vO0+`; z$D8!@PCe7JRWfi++`o)=Z(E`?R4#R^4r2vpo z5ZB&S_tu}Mn7@lK>K6)VMbee1m_$I61%he1c~O0=P<6(J(?*Tnx|JS!ax5uw*O=GY-3|1@8cJPx<4d` z2G>SII#jMF&>kKht*xzj^P8LcH3Yf1X`g5#3Y_`B`1-y+lY7S{CUO`*-SE2{`=4_i zssk0Qg*c>oCu5&~$TJ0jZW$@goLQzM=YA6WrQ6*wOLKbvk&U8pEX@u%e8uNLDA z6+NSuYdrNLRbMzPciQdDOwB$P54v0JSY@v^rp~rwoa(ol$~#(?N4f?H!D1a=oGcY7 z7itd0prKcK?qZQGN3{rS!}b0|jAYeH)nlryE5#;2P-^2HfaE7;9@B9`8OdwRYopt4 zr2kddJQa*k2D8HDM$IR3=n%uttL^fT<9*?t$t4+EP5sz(ZFt~v6^Q*07~}xr2o}(m zW578Nsbl<_BmUCe1&vG8*QWmVIgsa+el_;>Ojj6d!5v5b$*7C#;S|L3S{s)ef+)EB z2se1hiiPXM>=kl+%da7hD(~=nJpC<`L%M3lo7>AZnux1N>U^Z>Y*n*LXQApdPv!zL zF2x}}EG3W0Xi_K|v8k!a%kxFI*;G#QqR9uM=r8Tg-y$NOwui_8XQsEi&vx2XK=m6Qa1XVGn;C=+I7Wwmc;EGX#GZ$K>V zN+4DvGt?1gVhA>wk_=V>^P-dQ@hGPg;<KdYGRS4QdP$Vl}$FI6Qp_2{QiM^C&ddY=F1PozrZb@ zP0;!tw4S>&?sUn3%}6wwfY0^^W#Rh$3OqeTR+r3&H^@*u^nByo<4Z?p05}-JK=|+W z>6NP;a>(q%nl}|JRSpW&jL^#@2YwU|0J|rBWhb{|Dysg9Yi;UzpgS%Cxm~FlbwDY5 zy#UiOsdQc<=rz-nQ>G^}rcnXpP=TbM!(Bv})lxMysk#6|d1;uv1 ztoV)wl1fy{t1R!~`771PNH|@{>tHe)vSq67m3Nlo|59kG&;LKy5kbf=U( zA>e@e2K+H0A;BLVlo=FT3*?~NlO-=5yl;__u<|y5PlSNL=QF;jhK2@_*9YT~*RWxuc-FVNN4w)7i%D!IKNg zSm1TB;*u?EHyeJIAUJTbN?l-hO5~Ra1t$fVK``sRtbHhyd%#k;WJr2?a^qIXAVu$W zM{evCF^*oAu!UpIELgLxa$O?4->f^?j(>j`n-drqsc$sAA(v95G)o+o{7>39or}s0~V6sKf-1Enk zqv4rCz&G1=u>-IWXD)v77Z1bmd)!a;x<7+`Z?hzScfQ{4^L)3Ll*DbbqTBBK(ieh~ zN3~ugo0zKSX)&EAD%9qN@X}cGdlF8Jg%^DIc#unez2+q3bqCsEBi@tw{u~;gQL@Df5GN>ER79cp~k3C|eu?f^iSnS|5TXv^1+`uKLN&EAkGMlx zOKS5#lEMTxN^M5v`Oxs(c58olxma7r!-vaH{gs+=9LSblxyxv=RhOh|yU#cVP>X?Qo3Aul#8wNey_OmnnK2Dwxa0~p- zMw0vYicvi0T)#x4isejzM8sz_DK{3HJuEK|Ys$6)%FF1-E8r*!QpNnWG{vLJNY-Cq zDJ<7v7rYX-XS>&K)1sk!A+e<_3UvVY4H=i#|9&>`IlNm?mO;%DPPXBGyUX0p{d?1Q z2EYzZ&BU?l9OG4R>hh{T1S5<){HB`=*r4M9g6Na%83vrUFrd}%`<&l=Q2UmT{6|a) zPz68cQ1dz}b)r|$C?YU`xI(ce5b~4!c@rMy=g1PhX|SH_$P`18k`3O$%TT3`?RR`z zJ)0aG`}pxA?1dv~%I)2quhVSN?}-fPBNI*{3^HC!a&lIpP4DZnk{o12#6S1<7Yh|j zpH)kao!gAsp-8Pd5o+@lD&QE{X=vcAukKdu+|E`Orlv4tTA*K^ySW_-#PY#S%)DtE zot|hUyqIc{<=WTLOZpfX7*k_YB7Wy2U?KNE6iNwQU0tdrpP(0d*!@j=FF*NS%Qxzv zIp@vGNd6gU+hstED8Nog5P7>Jwtt1DxwzPUetafp0LMBr!3;TVGCw{(n|wS&4{M&` zeeOKM8B(M`Qr@s%tGaj-`xKQWhB=KpeN7213i#M3%c}{m*VJY0om zk;@ak9T??h*80j*3BvqB7-ME?Dp!s1?e1)qRjYPujI|5w?Q^@I>SDPBj}2ynbetgx zVyNlbE5&KXL;Qf~OBiY~)8Ww{ie{1+c6fN$WU~S#4?eJi(TT%`6bQ^z5fA(1XIGuTc?bhMV9IM_x?_r+;+8b&a&S3 z=DfkrPruc=*NqAuEu})kGeWO4Qi#=E7gTyFD}Q@}0Ae||Ce+0FrsT+x8B{$D)NLRD1qgoFQpZq1hq&n` z2OqRN$b-)%=%+*Q2U20AwG!jrhgI}iH4OG;a)g;uMe#;{l4v=K%tKL181nxkZufbi z!u4!LC;B-%?=e~c7H{(brD9SL>w*+>OjHetqPkk8#Q_vMc6oO`OFc`FkOE^>z) z6G}qILdb`rElYuJ+B6`5hRF*L7uUH2R-S}c6LpG7;E$g@Vcrs~bQ24p<^7qY))?Izm ze`Esn)+fSCl@iEU0EEK;3qUxd2mplRX#iSw6Q21B3e>`!4@`*SEl`oQuj{64Fk^QU zlf8X|melrqQM!9bJ>Ay!zVnz$36FEZRnIGx8qwFL)Up+djf#n>#=}!rQmQpQ)0xIg zsdB45o)W3A{~;C_l*wg9n<@BW&9^VAV@konp*o6B!$XJQ{NrQhvlu4eF$eORVgS|_ zX_$T|gx;@~k$z7ay)w5nH92y*XGq2kGrt9$$FMvPTtZoCnsw!AOfYxR+oq0J;b} zE}pK1wLcmhFMFmxU%9x@eCSEFFa5kQvo5ltyi0_rqo4Pw6FSSX+HYB*^Jb5 zvphYPSZ+;+mgf8FIqZD8L~s3QVFMh*L4kinQH)x;C!3fNN>NmP6ZUpfs0 zZuNN|r(FIPjF&FDXYjF=QvV`O)utHNtCqXwxTY?$?l3?7*HaiSWjva_-2F+`I0jgm z1d08gs4Lb)Rv$REtkH(NnJePAy))Qu{TWv_WU)q{yi|C4zs>ih z?Q3c{P~;71{QOQ9O4mnvfQ$L;x+g}y=WR!AMu{wJ02j`SE9roG|AA2X6A8A*-OgbD zQ0#~a86-q_z3r{-&oi7;m-|69k8j#@baOA5K}1xm+aqzW53c(GaB|0=d@L|N;f7p5 zGb3;tTfk@iVqC0VcG~ivSEDJJ<=-jigmk<#I}L4~EM@chDV&*D&zGCjl;o1#ogNxe zN#C7qb^|&Q2gk1$(6AZJRu#9md@h%LB5$wlHb9-UXUVV9_ViDpAO`~w6^^iN zyX9c_v;42!-NU{W4neFDD{NI#ElpVhPuyYz;e+4+$(x_VF+*bQ?_0!%V|QZ|B-sVz zF2M<5W%Nqt7E<2MRX2;fb$kxd1C}Nd)6B9pKZ|B{!GA{XL(GC1f{d;PrB__bnj2+r8R% zo3y^UzfQy!g@(Qb6cP4yKL#xUSF{M(Ip_Yi+uz=tPJ48_)Q3&x5oj$Q*{8{W@8}S0?>DU1sRCMn$4827 z$5v-}@vzBk0hbGndf(2uRF>DrC4EWhd~pVje~Kuw5D zaLUMuGl-P(LoI|MEw?L2Nzx;;lOAx~Q@{ja5+x}`2F;v~i1iV@-f#}2hbMr_m3HJe zdNVshBx6~ll<8+`MPZ9oJa&IZ7ZnxFl_LrzPX~l?#@zL4hp(Hma(M+59dyhcoK{H6h}T>0IvZ<8AHgB_Sb^ zxmd*)1N7Z*5b_G~Fmy?R7TDXGpMzZ1ziPGTzB42vm-0@l=>W3GxsqPP(~VBAx7U}v zkH2?!cU{|E_`lTXb)J8Gx4{Yu-68a(X3-q|X`&_Vf>_hBJwMhm3pL$siJGNR5K%aw zzB5n^*CPNZquGB7!U*Rfk8)L%k+AdlG zmw>9)j)~*+u=mZ6+pdqjQp&uv;j9|=S#@@{r-`W1^M<4Ub+!Jv294PF(Mf$g`Byb5 z|8c|0Pc)*N@G~oN6MovY?H&r!sG#_^y{kFU+6bQbzRO`!9lzC^U?K;+E zW3jAlBj6HIsg5H$vqmx(FK(uWyk^n3%)}iwasES~!ILy1A0%Zj7*+t5!leK9tzi}I zn6Wp6g@J)nP>`0Jo1LAViSuSgkT_6~Ez)%$S3aqbQ5xZ-1Pzy!0(00nAI6I;jt&z@ zZL@j#FVp@{U|Z>AnDV)T$+5nW`v=&UR-euXpU%gZm*9_c%ECD6Sm5oROut~Rv_N=g ziD~R75=hC!)59)M>cYB!1`_yKV-3^dwzhS==8hSa+&G%cPL3*#7Z~nLgc8ds}7&pO?O_@=-2Fqpa(^8;SCyM@Q z%}t=i6aWnk$hADrTMuL+7}in)3wo*}E!YC77Z}vHvA9e1$vNTF-t(f`qdq=9LZr}1 z`JMY7E^*Bxl7bjDzzd_mH3u`p+X@F-Qeb!LmDZyxH{c{^2E*XRLFNCPlF4oiv?U2- z!0Oa$)rF#?boV=YByd+W)7fg-)U1K0qhqUn@Vf0Q{^&~1@BZ-Mp!kJah~rvpoW}kx zFheIglscT_VCsU;nT?){i<17^9VZ;y;q9w%m(dbQKg`SC0b(-#VK}3-QH}oQ!=~SD zCfC_~BO`C)cq?scKbh0f%AE}XlZPom&vp;n+Oe~4tRlo6nrH&Gf606;c$p z^B|`2G_@v$szD!;yxQ9hqz4+1_4dpeg%Rsgf)o*@lOSwjsH)$v&0nUbiFPG+JE45y zv$9CS=8%H%F-0JVBXE+nT1*hqZ~07i{BsfU$;rv-=}7#efaJ(G2ik6AWCY?9@MMIW zSjm)PBHA{fZ3#s5<>h6_70|o7dwA5LCZ^<6&mH+wfHXy>nGSseU=s_{fW@@5_P;zk zyADSY{DGz9r84tCNct5mADlj)YN3>Y2 z8kgjL_3KhW@tz6>Hc(s~D`Qf2tY{t50uZ`!zx0DVJUG5PBDXYS=kg=gyBk(;?)qZXOeDT<{*_%uYczNHQtz4h#FCk zB%y9Zv9ojSD^i>*56T8 zk|GPo@KbnCgs+z_RhN^-z%OWU7Vl^tL1Zo--rJ#S>l&TdZ@U^m~9Vwc#tqNJdy~oe|{YJ?VXAdwI*$Z=ZIj zO}!Z7-U(YEeOiS^>H|Y^SM{vj!5+FlV5Z*c9?S}R|6HxAeyDfy=N)4Ev=-JA)DO*H z^*IdvAACU#l(g;jrayH%j~(_6dtg>T7lK2EAiZwa8=iVIt9c{qh0zh9KP~Idj-N$_ zS>-QejIwg<_I{j^ZsIr)dq=BN^&LEVYX3Fh#5n9udELvM9+x{)h>J^I7am7a9lpQL zCbNM~vGFVMa>+HqhmkXpQjxa;uL&JxFK(ORDTPa{y+*5TUT7Vvg$%X& zk&jjIbec?|3nU`dA9IDTVkncL>>uF>w)4T_=t~2^zF%6)W@?xj&EWOIpj!WPU5k;ciPJgA!5ZU`vkZ^s%re$j;_&8TEv_J zQzr}bTS)JCj+d8cI}nSAej(q~x4RsM8@BLGojSJ?!kfzl_c%;jkx!RQ3Dk7vFPIBG zR~7*i(-=YPw)$MVK{}e%oNC~|;L)m?LpV`s<@}_;4#(SHBZ(5u4P10W=X){pQP!c- ziXeN@Ra$*Z<^?>!mr~a;va<) zE|~)>;yv53u!a4-QPt4gblLSuXg#+<@&ufFq!OzV+#3?L+0qTFleEzlrOfq*5`Vp}Cn+B$rmUex0mx&VhxXe4&nn z*nd|*`*&+D{)sdHBLzh)#=k5g_D>A@3g8EL@Jp0MvAl5S3Jq0Qn`W37qTw*Y#J+<6 zeO6gS;tl;X{E=A4+*7d-vwV7|=>ZH(CS?+8ZB9%YC1-c;jC%CCA(T-a@IK=zbTB&m z9YmRVN64J(WeP7`1@AW`)`hq(jk=zNsaiX^|dtwj_M!IBFy%vIW(9+ReNe?#xV@Z z3C=UC=|sXwV|Pp69Q=OX6m@pz3{m}h+b@s2<-9{Nq;r;yTd@k0n)HBFT?MHuDRGxl zot&`pho@NRdpY+L&n&e%gXAsr-M#qf5l4+cHe* zsL^In-na04RkdCfyOGF7Eak;fEQZ2f{zN($VX=~QK2JPRL0J@Qf>^3NX<*-~%+FdN zJ@a7pkj?ru?QlxuHizFMHc)PSl6#+^g%o|>($GRD2&YBmU8%~&-!q=DeoAubWEyt% z89>GMrQLPQ=V#QrAC1RKr$#8^s$vXC0RF)cd}!b^(+eNzrkALSiMU4zUWC){x{%sN z%pDEidUul6tT+jSe0N>fuQX?!Brnd?!P{TO$qO(@9s)*>NYOq-Bid&c3KF$Bl58jI zO(AOvGmQ2#2+(mK9M9JH;HDT6#fGkRK>MUIC-`G7G%ljWUvr7q-A4EDvjuSYvr|(q z(!OzQy!~xo+Ia3Ou5!7%LPOmLCGEq(_lIQZ&Mlv`PPD~(yY3)}>tzT#j}Hu>5TJsV zn~aA{Rp|;@qxjY4Y2Sv>YUZ7exE$M^hKou*#;uS#vzP6eE;3jzB>#9l4NrK}Rw z3Qh*N0OKL!gw^|Z3yoH(P$G7PdaK1&&36E`(Pckl*ti%GMRN0(5HK#Pv&*%LCR%|P zJmWc`dfDTdeG(d6L=;z^Nu?o|H!<1l@&QnhxOb zDI*DO_HV>U)FhWQwG+LUxtSVYW(&2CTs+H5iB=&C1|fL)rO$JvR|U(Hb!RP%4ZkkC zPZ8Cb>SMlW4W*>nw5TnN*?09lIE2F66G?7s1BI!>>HMG` zhb@c`^pv7`=?dBWRr=kp!|_yTM4S|efhs48Br7;Lxh>DXB>f8c`xVehg^92pfGJPi zF7H;!Nc`U3-sk%Z6jU@ywzaH8r>DcZr`uy!GX5ghvERL-y}qKNTp2tZ!Aqs@uyF- zYGyM^N&lFZFgixYiX#s3&uB!1WJE+{guiZ&O2UK%_@|fXsF;PAx$v^m2qVhob;$Mo zlpa&{eLaqfQ*GB;pl6Zg9A4!LmO~ywB(qxVKk-vJLIRfa z;AI^=K%FFG0{GL(z`^|YB^T$A9*AHYety5v(lUPk;6S zFMwl*EQiBvirZps*p!=tbK*nPm|^qpgRtNQr7|_`^mJ<38P59c8WVPcn1IobDNM`l zZg%T!GZfjmsjHQ?(ep`BX_1#*8=jGT0yRBy341_wdVjH5Gj~MdDlo;56alP}5#UfQ zRyjd~4?RG}R!NM>c4^BJWDV_YShWELPy}3lHyqfX$BvJGq9B51N&U!;2TgdPq7&tG zFe#hNXzOmaed*tyA|FfqFY~7ZS{jwQ|9N#fZX|Mqas1uypD^GU#Bd$)5Mti9h$_X3 zpS(sM>WoOqVC7L&>kc<-clvm{E0EBPUkQ#maQ2%!>m*BMr^gr1996phO!8!+G92;~ zxPya-2Y_-s$-1P5@kB44CM$eWysdp{BW9vSBz6Nv-{--7(~i#0e`*Y`kEy<1GUhhH8mIGNXr9hr5H45@soFav*5f_i~WH(E-ap4`wwGc_M==ks*ltWT66~ zAw@0UZnMiER?;}dpMTb{!D>n2hd(SVv&>IyW3|9t=m~r>3|_+8_OsRIvB6lNPB^c@{EblRblXGhfUEf*}N?#rYA$ zbM$~x++KLfCow+W;by$dl~jQLltpw4l!M?y3p2E!b9QdC>SnVx|HBCZd16dK(4hHy zMpc{ZmmGFNs~@%*lkLikN>y_wr08Z{3uK2U(FJ|2X~Y)XqXI3oF%IvJmRPeyR+?;f zYiqaGte3jZq%)mQXUrge?Zr^x5D82bRn=ZEbMw*-gXw3_Tw#wNlKoO#mh*A3mDK(} zV6bK6SoOQS|2|x*5V6^=@ftuQ<(>Qc05D`iCm}$;uQ%Cb&X_0tfb>DrXcSzdg)ek^ z-3Nk{^xZBeWwXZ%5H#GWu?+~sLs9u$Kiz!YKzeu$U`yeMC9w~HOVy?)C9Qn(l0yKV zks9_EGr7w4{~WVBgXFj&Waoio6reX&ZaiV*%uMiZq!3Ze$9&uI|KQN3D=bRclr_Is zpZW49yAb|~$AXZI?0uF{o%h&NYz(=U=pWZWHI$A#4f>!LA0=EGdzC`v5<1cj&sPN1 zpRRT`S0xvmX@8l78}yr4U7(Et&BE{KxsrfS5`&M93RM~>7Z$ z^Ml*HC|&Na!jH9qSNk4KCgL<_ran<>8Zjo@!93KbioQ$z{Gm${? z*=-0akyHEgCfyiXbn#Bh)SFHeaY9-1nvCMcL7h#du^ZnWFT~CeAOHyaD2AHDK58P# z0e{nki)Hik6Ahe=rUCfDSKEOE{(VgUACNVUnNuFv9YKn5Otm+DRO&4G?1>@6RkZAw z@0P@w7LqD9NrBix6lhhD6#${Y01VlmCzeyaIAR13%Yt6pl0pSXPQQ(0JgvT?M++8; zyAQGbJnU0yAC&nijLxT82rm0 zN_`by8Sw(D`EiePtgb$tfW_>R$&`ND)YQ>}@2JzugU4pCMj6~0RZctODOdH&jbgv2 zj;YhGo#@s}N0IFN^|g=J9V$BFmR5?X7Otd!%C1Mw^{0`@sOrvx?zf-9JW~H&#rGYl zXrkMLT))wG7{Gzm?QpM4685|?SFRz7`&1|$n=)&_NS{!Ynwr|6!xN_hS;6~qS4Frx z6w8`L)a-VlM}bw`AYs8!eRv7=0T zHu&9n-wh}%ChPy;D^m$tKmrEYff3z^=%fnWUIxlo48n{b9kl`^5J_m!1wb8|XV=0< zCm_JwpOyTjS@h*@b9|wj!)4s6#^vx@?}N~uQ~@z1s5#StZ+RMOJ)H7ZIAiT~0x4Rc z;V0+MDA~72BB5HnRVh)@jK^ln!{|SR7p9h>N6w-zI?g1ddlfZ8_K+6>Jwz0Ac(2;! zGip))&NQ%PmYLwCOm^SufAGCqFoJ=xQd5dF@gS*q@Ud|*dZQj8>QU`d-U%@!|1KcwF z2Xq+$*&`%v+2ITiKAd)3rkAvd)YO|QZUDvjH^mB+5)r^s&}6EPo;enRh&9!Kr3bq!+_5uu}7wXC<8w@je+XXoMJVW*^I zWQ^=_NHI}kNOo2;$pGm$HJ@Onja^K;N!3T!YCpNN4P=fuZ3#b@*D zckU-U=lZv16_!%`|3-e`vxsmSOEboRFeNt?p@={>fg*C3x0a15(e8s8HBE_Lx8dYS zBfb`Eu1H2gLY?u_EeC;ivLtw77r zM>k~+NL0qS(of%``}z50QRvz>Q~WU~0m%|Y>oG*bQ`yUTkTXAFMu+W_EEp+tTS$R5 zcsICI#(0c&gGVJR$^aGh=K2GXkB|2aJRq~GRVlM?_YcOghm$Nz67CYVY?MRN1Kuer zhPZMuHC$FlqQ~{`&ZpxFM;iNG-`fSiSBzfuJ1&a|6x6X5@LDmB;u&dIM}J&BP(cCu zb9Kbh9Wqdk$@n$xwTS#~mMadkB(sM(NYvW{vk=v3CyRe)-p|8MWWUW@<%g!r{|&(+ z0$H3@aLSMu&<_GrWfDlChDYBJ1o(|`i<&%Nf%dc1so$%WMvmoQtKVZH8NZZ z!5@`)3pn#y7EAAc?BTJIh|^=nn4Kyd6#uFmp!S{n-BIxkvAFMD%z}9XIF$b#k2wy2 z!uN>x_xt>P!6d;!{A4!03);3{8|rAmrYCwLN37STfj%AV6O)pVfU-!9kB8nsDJF=s zf3{`$`z7kbG5fUIx5P^_)_=U97zEF4)7~}mu`oX3#V_4rV*+Jow*^ncPdW5>E3>PxbI;P{SO)NrG6Y%HWlQw71UpxD=4c!&MAtFlx0@x zbv|JU9R34k8i9NJx@80R9V3j9uXAAKd3gD9KCIJ*$v9c@NK&kaS>3!CltWexN%xW1Jg|A5-rW$H5w%}hC9fI=}h}sSze1b8U4?a zzMrhvIm?*GM_i$tM>6VVc-NI?JN?>wuO_9gf90Dc^ipIy252Q)$hh=r<%lH1Pm3T6 zVZ)@P&k|u`T>@A8A#-A4*xijH+y0%Z1vSb;NK#r$SJqu2UIuq3jq$=hgYLhT6i|=@ z*lN;y>UxA~EKO+ZjkZSRiWHKuw)OMCzuqA#M~>~_5V4xMIa{8H0%}QY-he_vIZV1( zvWVsOd{=jMQcgi_*ekCK;$@?M>!z6+jC)PNu-%# zaTW9YfcR%5yOR6#cM2%zFf9_-LMd?rP=xV8OfDg(f&VXEdZL3yBScD?GvD#p_W;M`y!lzk7vwW)1K4Yo#m7CaZnVxRRacK_s8WUxZLR=$gdB(v69lp_=UevJCWi3#Z>gtol&`s2E8K8Ip;Tb^guZ?R@JxJwk4k*Xu(6k2ZU~4+= z`rlwPM~y9i_X%ryk@~)`HT&U;W#Bt$495k3?vFR4mCF+kByM%=lY<)zdzyX|&hOrT zHT-A0c851^U5>enl2#sC+%vZANf6Eua|q}VZA(_e`emWjtvG=NCgOqO1I7&51&*bh z7HZA5>p)UDnkyN5Ts>N8w3;b~19sGCs+G$^HQoUQszUk)$;nL+VPq9GdQo;#%UD2w zypgf-g>y?lCm?aEIvi+4hWiH|Np6LYe%S8vq`f%nLSH)6>e&kVW~Si>PVbay2&VGHIyhY`TC{qf~W<1E6V?g@>Z zML~c{mAAi4nw{x=>Mn7Po5lPGQnh%&I%_@=uP0k*qNM$hD3XAS!7}Fwe4o*z_)hAR z#=K2TS%ae?mWsah*uL4)g8=#<(z053Pf3*3NYOxH#Lh==BX9u~+y1!vamu=h>H=so z2KLXQ_d)#I{CZd(HBBZ(To~+Rj28?5a4{swXYwrB&c_vi0Y)2NTsd#MXc9`s>$?CH zDDRw5PZw))e`m4kpEz=NmU6|^8^4QY&^0%&6QRY>* z^>(MQ$)+w-(zn}_nAUht(4lPrZJUMvfOsy}eF=rMKzXj!z%7+U0T+ zO{nIu8kmONK@szV?d_qfN7#B`dk7_q6k+%?Z%~X70u4zKNkIK>4rD8;1-aNH5}#ly zXYR;O*i1s1qJmBBRCqnf9%?2i^gRstDp+vF)Z}+|I0|Zw_S^CPN1$)Uvz+G2lfnMW z^#c_ctD9Ga4Sj@L;O#JOoFl=(NsYz?$q}6@Fi~*{0r;J0f=+f$kECLoT$QlbvGeu! ziM=nPqyK^ABm)@E$^P8IjFsC}nY@$zR-ha34Yi8&W}&+m#Z@W()<)p9(VB%)EGgKx zCo(N`_{H_d?tsGbUayCz-FdUBAa?cFWpiV=AX$<)`hyB4#fMW~TFS+fD`oa5G>}U5 zzd(Wu1QJOcT-*U(Qd9sm)oIk(b)3Z&^~AUDmrYP(P>1A~B@u;)RV@*MRYpEcwxMNy z#_K0;^r9&@{d%Tzi!z>4^;V^QJH)zt)JmxMwaD~4HSN&g7rq9!=cY!K*&SC;;>Pe~ zbc`!u`}5%ji<-)plN#@OpTVpBR&7(b;(fx6czvZpDYQp_ihX3jExN3&2P^rW!td7G z=$2sl9@P?tTGuzG?MxNAUSr48&Y<>8FOl5_gs045{Yd}mf@Xms)Z?+F_1bL5Q*PC` z<%hD@boj|%!;?vMaPh$WQy*cnTftA|6#-u7<;(K(pB@RoKGD}F(RK&f6v`gIjnLJ< z)q=4Q3j`0|tEwd9KY6R6}=NtPLYCW(p;vO+$jKhX-C3E|r zPI{7|*@W4om}}J7mSFgnP(epetJO*7b&2Ziu}{&Bhe^Vsukoeqxpcaz7<3rr#8@Qe zx_&o53PNMv+rxdMGfU65H8Y3celu5**ZkYq7#P$)yLCjeHW${J0jG{J z=ndt-8#Ph2i8f4O;qw-b7-MPc_U4s4Yr|O1u|&+D14IVnSd zUeu4JY<;a*$bu=k}=~RFD%sXnU_NkuKql{aTZYGG@MG ztWH+icvrEweUciVL~&FkdB5Z9j*+~#_owkXnP{;R$$OH|RvfgFZhsn4j^s$I7l|Aa z3>+py_Nl1P^Wg4_c}I;Z)?2tEFOg}|?dm06q7jj=s~7S@DG3h{D`uo?t_t6&D?n+t zyDgRMiw7hzwrboX_~jf7{Na30j&6f_q<_Ukh**RTqrSFoPqry~s_hcHodh0TWsWEf z71g)4F< zE{iJL8HLUJcNdz%95Fc&M^Q~eR_r0joGi^Q2)LpA$XCun(xZ>%NYmC1M;dvXMV0>) zhz%>qgp&zFB{W8QzAB5YepKn%p_GA<4izh7+iBOne}f~UXkoU8-wlh48h~T+rFR^Q zt#w0P)WYlyl77Tl_WxVwWGnUKzw4Z&i54%u6(|>m64Yc{a`29y8DIrgDQ^mNd{ZEo zIqXP64gt1UA+e_;r0ScKk)aM~mXB0hZt#Hf>gi`sNu ztg%*V&*8ok`$|cCOHk%t7^xpmS4D~%!@~R>f=DQe#ll#q#$dCQj3eEtsBHh_98zm8 z{dZY{@5$V`)^`PRI2x)(lNZrW?9n~dJGb*??Tb3e(0f9%n+5m}Y`RTrpkmw@@yuUY zY6nL`pRUw5GKK_fI+$}O6dbziNF1%9o+kw zEqh;+PXHQCSSPJVY3#_Z%2+hux_#-BF2e&P&^H_hE7f{k_;~N4Eno;U?l6#+ES!A< zdR+(7vNH+*eNYkut$MsU$8S^JkuipFb4&w9d-{bU#afo51dp#_&3$71dqMt5jQ?8E zV+fumLr1@*&R^&Q*G>5WkM|kw(b*0qisN`rf-hAi%QwVnDv|VR;9?0R>_MbUNtHB} zXa+TFjfmTB^^PjY`gb?>=1d^?tyV7t&c%2xLUrQUE9rsy;FeV8Ef_M(X%*uH6t=1= z@DUq6FPCR-Ij+2ZiP5??hh{f`IUo>Qv_0i-Q788r$I}QapVQg^!FVYBo05hlb%-VO z6Y9KYm1zege3QR0}-t`ziHWR@$jD>th1!Nt{uXR3nZL zvxpJ6Ns}#UHb|EOTCYYL8%L1`t|j^+eT=nV5nTGmTjs;W zBD+3A9_8PCtdaR_;~$%+2V)PP+wpMebrT2HHr z*B-5DIwx4VG(ic-pYokaHv9L#Tk@kNRgp=sk_;_l*fDU+)q{~yT?~Vp#tiuMO+3Wb z96D$=TQ4;yb@I*xGI&guHT_ug2zmLys18Bo9dmO{(cKjvs#mo{7h1bJ&_Gw1z)9f( zb_9{3G+Hhyv>VBC>R(~7he|whn(O!T3`10c#Uvj>SKc2RQp&$jWfJjjM`U(}CunA$ z@1i`{(4~eqvlydDKYIgjIqdmq%3UPp5 z9;2mKdc6tbqIUFAz`#9VO#Z-ecF$Y=x2%@Hq>DFC-!*Rp8~swYv}@p;IKPOyy`J_} z%RKQX&xDVVc^IoN^}kesU(IBH)?z6;6Zw_B3f%(~^-efH`rJt8S3!}}0cOgHcWQ?zsKrLcHe$lo1&2DO0IXn0EeicOG+nvA6H!XQYh-z# z5Jb#*q=wV46p|6nm$WD$$kv2j3Gk&fiUahR=e( z?yIIA3_yCLj!xh}b3`=(ujq1Z7eXHW&ZU^$Yez>~G>Ua}9SH83XZsWhWL?1mj4y9AW(xv8lS$%_^a)eQvfT!F%Lr!a) zeJsrooxP%j3xV3F9+3k5Ezn|&S6e%*mv;gpY-xXT z>i5u}ui|m0+YN9B+a^EFn z1F54|b8z-FAFw`uA+EPuAKa^0h73Y8|39wYDypug3D?D4f(M6S3%B47!GkX#NRR{x z?(Xgq+#$FV+}$BaaDuxp+-2?g{pZ~5eam1l7_+;pyWXmLURlp#E_DSmhQDe37LmK2 zvqQe{bo$ajIE}Z22RqQge?-+f9ZAEr}Anq^y}Lq2a58n)tT6>DuuCKxy|c&8sqeG zjZ`0}@5=~P^Tm`wk)Fm&%-{d{?RLCNa^|F@Q7sCcAxZKq0Oq+d`U6yH2>4sJ;X7VF zs>KBT6DBw#t&~**7pZ}G_{X^xRSpQVE`6HLkauLes=^1(`$ip4Z%!KNgBSlSh)69GHOZu0rr7Wunby0Zl=@MP+ksCl!TF zK*o8&Fz2;yhQBhdQTVf5=kFTy+ zlO%7i1DqK#7$}!3>)KC(pQEUERak?%C%;$rGQXum-7tgGo7}v+)je{;Lqgdg)1&qez8-R zGj6&8(D!<7E(6N^%^$eK@>6-_Fo$&hU z4L&U$-I`oiMv@CF&w*|ZPi8-Pi+aarr;m~KBzD<`;f7Tl-5EUn`7|^%ML-+x|7u3r z{!G;-pG5Ayk!CrJGqH&+-cQuT6l`4KuZIe~d0&kbciH(I@tBdAPb$DNP1@oVWD3K) z$I{)blJ>>Hr-sAG55`l7#l`}Yi8`aBP95rumZtfLfAy7Pr78uI*b-E+KD#-#!c4W$^WivpEOBcih zeqYq5+IkYilyujxSLn=nip+;XmT$=<6EWay&@x%kU_^WW$$okM?AcQ(ZI@^L`ij;* z2)l2_F(v`jr2AE~#B(xsXDMMwZ9Qrx_cuzQcwT9fsjN@)+mnHmvk0;WCJElv^3>SR znlJnkiSC1SUWxjR<-P4>uCR!0;7KV6Whma8V0!1(m;IA9$xz<=Al&MI-&JvDbIR5D zR7I@5Z-;<0twY4An&JP`S%`mEfVt9i!z^x>CML0qXWAyo|2+G|W_3rL^x<4@tGIOL zXz^O3*Ma1J;@l$qqf1_=%={}dmRmAu3ofpn!aM7j(UuI&!&m@LV?{+0x zQqHm(IVF^g>yc!TNR3yc7{VuAqA7*RyIvEBCzFE2AqfA8iDDN3*K<@}4o4NEo_tj< zefB7mhB!ddDQju8c%$cLJuhiOxzYNG?qFPd^!LAjTxf`evpP@jS;N`u0W4Der7bdn z&c?~({qzU)iPoAdwlCM&@7eZ>wSR+p5dM@)uqVPA*OlpRR%i_TH&wP<%KAS7FBRig zX$gmXqXXTn0|g2qFXYYC!FOOzcQ_od6fZ%5+Y(ySo6;4_d{g^}{3h$ph-Y1vWc&jv zf=~mgp2w{Y$KJL(qEF_uKJbSPg@KLZ)_PFKfgEiaX`-AWxbda9)5(pNvASEkmA`A& zx*v+?@nk5=z zVVgG=9f%7AX2XLjuX&uL2*pCE`+FGLYuN2_>QLR)CPFoZBYOUnP!!7sn!;*05B3w#Mf48^hVw)fwGF~L0Q^hmn z{9klljx3DAF?db=vX<{E3G%77RmUOu;v=o>xeaIfHfvooSLf=_zm&u~Lf*XNFS_TA z>7*?G-B<0f?muUegyjP{f!8W>f=bQ16$sC^fx_Qlgvjal|3#tV6dsdC>KViO{V$P8 zNRHKjl*~k~MC$x>G+r{-dIYJPh}PH+*E^{4a&?SgD{HUdAFsxYti=DvAh%(~!CzxN zeCKXwXnc$IiBbB_i`|`J08~F4AN-}`*+}0G;dad;V%ce(-u0zQF4oDkFg|@W9+Zc8?3uH(X<5$ww^5T{PqN8sY~4?uJx=xI8Yf=a zTb2EvlG&&Q_kuoY2ZBlae3GhYZvC?V#L71>qN^wJlR3kC%#1d+i9K9<8;95a4|x&x z*Plw0!rg(LK-#9($%7OG$T6jogYDUQl;Na49wjl#ZA_`2Fo9!Mrx@$LV%&KC!S#F0 z$BixANX0uBX48);+-~B=AYwB42e6HpW&}8B*`ZqF8PO^rOXA(xh4vbX?hvX18pbRp z1$IMj65;`AYK~m4kiK{EDmjHNy+}la$aoOp2TS=Pko=wyvD<0uX-!F@vD%$ljZm&n zBKaNK7DEoNb%4P4yUd}1CGT7#-|f%ch*r){zKyrU6MsLpZV}~$2vpS5k`d zk*y!kcwO85!FslEdPta9t>E?uA^9Ojg)V_;FKp0n2)-eQ^~?fE{E+RaBz-1)I;FK4 z7F9=w5n}lArepiGM|#$CFqaF>e>x?yTI}UlY}aCQ9?VH(rj}bT*4+J&E5w6f*>mTJQE#m zs@IDwyOAEnYpv;F1`+rHIeNLrzw|8Rf1CD6ilJDo zWymIqH7Zx9Bw};`t2Ilf->D;(9oO%$Fn2X7LF_UvvuqxE$ye>`N*>WJ*atDnV}(VS8E zHQC61Nq&IudRnuZz7B<*^2E;cSKDrSJn_9|9vRaj4Kjz8ov3B(Su52J zF!}@aV$95DNk`nXGufA99Tfq+J%yrPv z$8mv2?RB^dZ}@e+Eq^@X*9s!O*n+bu5iK;N+9J(6S=e~kXZSdrt_2;4syHT%fzRa@ z=J~8I1UuY`6vv6>sVwvmlK&=7h2>C1{cv5hKBc0*U{M-vy9+(W_@#tR3CFn9YEa(4 zZ?;$S(%bucXi@AVhIcFm8cl}}Pn95Yml!)y5gPAnuih>WkLiHNTMK)Lu}%Al7bbOw zH);X)j|s2+59dGWSl})XVac7Rm5{StrcIH_-Imb;-2J)tsNRXsXW%fT)gSJxkazoO zT^yx#EDD;$mF0@$n@y%YJ=)#ZPI&b4q<3<`|ux<=tf%fj7U0P zM+n_c83p|Cpu~!EHlA0mRKgIpTGjOoYy{(;5<=3_lhLDQoTm^byBtX?DO zma>{|!$-26zg(9`PKZXKZ$?B@e{w$hN3?IYJhEJ{adf~W$v~nH$P7E>ZFOUF*9+K2 zn%araX20)}z~KM#=S+)39gG&rgm+C9)Zf>u(@)5h^xwb_rt;jv8|J5j8@505ulH zM3I0})Lq?Z5LZ5LD9Rrt!>rpLSJtt_>}SRgCvt?SUo)$bHaw6rC zVy+J;EDzF-^^mTIw}O&sMC7)kym~f0>iCraW#FtS@NWY~DcH8Zr+j&#G0IDBH5yP> z1~y9R&&2P~5SpozT=Ok12S#mn#Ww14V<-Iz>UW0Sbf^xfRCrYfld(dr{@tjp`CyPm zQnOe+9l;BD;pIUBiB45{&i<^RyN7AMgP+)lr9xp7N=;RowTGkoB_uTah?{o zD;8j825}@EizJjfoUDke;me`BY!mdSzYd{?VI16@>`XG@^x~+gaPM)Sn-7iN3WMx1 zqAH`jp2r_Er;p?V8JXkuqMq7m{lOa2d_!uz+1_7y1Dpt7n2Sw%su26#FBlx3k^2FX zo5?Z_Rdt~iVTw6df)X>)-kYGIXS%OmeEYVL=!P{oK7HK6)7w^43AV%GbL#;nWOwZVQkvJ4Po6 zID`+CL0C0zQxvAqV>O9j>_3JSIEQihaxCv5$M{S)DUhm-POF4QDLPed|<6ZKM2CryN4ahbkg&k zz=8785sMR&Rabt5RBu4Ns!L-#FXT#e5JxS6B68{?2 ze9c>(5JgE1hz4RC2{&M=^TqZMaU!x^Sbt@K5j<%+w}I9va(my8pB#Mcax$Bfjr*k4 zdTdr?1N7QNY91Y!m-Yk;Gykv4$I5>2UIw*xpv6BBthb*dh(2Y)>8W87WC%T5CtkU34JXR#e=e6 zM7jLxCexm?7+PVWa|O{Q-lNZoKx^K>7H(wzmeY}z>uP@+Ug0}>LctS}y6H)17<7^} zF$lII4H~>_1KG|oo!$$BH07QXCbLp`mUFmSqekq3{7;v*a#Eawe)sHWg_u2Em1KST z0>f!e!l4Ng4sdjGa1s#kw`~apxEflN4e@S1GhGmmT{GHbJ0>5iEZSFlb~h|74eS&0 z5OJ7kM&z*CnQ0JGM0k znsZ9xtjWO2e)Iu3!R-$jTsx#7*!Jrq^P=HB$IBcF6p7Vgj+CUNq!4r>$f{09+)X?{ zS%v_V7IvZi;FCa zzh1{$Ht?cvn9N-LF=#cU4}Mnm>|z1GOlOtE&u60gR+ZW+G9nbI#ZbX6ZdpDjOv7~o zh>DcEdvAN__aWaMrS`BwNpmUW(c$XtqRuX=qVV}ouC!V22-3W3V3eLAb+^>hE=Q@- z7MNw1#bSh`^r$)Y5PiGl<|0Qudq z0YDQ$%`>%5m-i$0lrXo&4DH2ao!fvYKEw0Ij)$8XP@v{3FV0TG3hE^IQZ{u!hX7lY zl!tyS?Dy{F7O1^==ymCX(JBR2d~Pcjmv9Ftwn!^aL^9m)-SESsB8-#Ht(t3YprgBI_};E^%)so@Ta1JSQOld*CgLT)HODI{3~qO?cgS|pADW4G$#Dm zCm#1Qcbju&vqX$!BK#xHzbiEAHzv9I<8(v@3tUoZr__83{=0JD7#wH)A$BIiDzc)RXL>7a`_3}qE3ZrcpsnfMAWBjZKG=XBog zfiW^C57_=?@)p}r0dE;5tiz-rup(0pjq)Zs;b*nKuB2Xks0;x?dZfyS3_e!qRR>bW zR169&7cv=cez@?Puo7vwVf6Y5gq*k`Sy9~j>vqt4^QndSun)}4%%Y+O3c11_>I%Zb z$XI0YxUz8+tb)ArCV;2wKPzA|4~Xv-*8h>`l2JDz48JsX>B6zLvg_mL-D~Q8w)%bk z%HZNXp2cq1c&;~GxDg+yGIk+sKIxbv6n}qmP%0@cJ(qgcEH!WarE&`G?Gq+#IWd%z z7@s;b2cx_}2usuAl*RBuoSkpHAn84HpSMSc+TPzQH-=(BZm>C5uDR!T&uDH-SO-dQ z%Ki(E=pRoyU;VD`^E(1bYP7CBBn1`S2oLM-0^%)(c`8nAZc?U zq+t7nFaKi52~U-_g-m?JqL|g;eGptjun3jH^E%gOM%ivB@)a|x+WgJ{?~IbgKRb1M zx4P8WpWWRb;;E&?0pkV}VA46^a?4{Ygy_c8fokf%NijNFfad?-qz2Vl<-&8Cqu;QU zvm7JLU(?qg{1fPZY+jez0ZHQ0^@HCyK(ag9eo3=z8O#v#-nj= zzAd^(=7(KqCzab9cy*K6wD)|sriZNR>Cx{Z%ETkTCBqi*g87{#5f5}!!YrB!XtZ+r z2pf>QEf{D`xR7ohpHlG33+*-;6>j3^Csxx4%OZqq{qyohwKl-Y%8#~rNMAOb~O3jBSC~eC9_~*ikbSPvB_5ph+S_4Umw=F${ z=rdBtC_OgZ)Za@^X9c);gWzT{0%D~HLc>9UgihYNLM1T2Nb(ED@i*B`a-RE@ZJ-vTrZ&ga6cCmv?9*A;@Y@ zeaqiBtV^(eeIAtgP)A)VGn{(>&64W6V}*EKuhXIwH|MIG>N7{%q0Z&O z$u?T%=h^c03q?h(;ZY{obv^E9yRBc|-o`{lU0;=d8`u92F&>1BjTE7n%Et4`{5*pyBY&H^YsR_yi5>%79Z&?ON(b3TUDxM#->*| z`u~k~j)r4>);`=mc?eXmgtB?5r4_8b>nAn57AW(cA)x0BRSGxO*bd18)39AoLZ#+x zKWKN7-wjDWKL>p=$m+{O%2vRiFn1Sb(Ov#czR-d<-;t?bljY8(xk>|MEV2O}%M6i9 zV*8^0@ywVG`dRO81_d>*tLp}()+wDPqQrU{wwa8Lv<+xwo2?>SIDF6JsC#LPpaQce2k{__=DLUvPb z4R=A7n%q~UPkr1l5KSi(SgB}!99!+m&)+;0RXUqwxteZ0O^9AWlYB+UU3{N1vj-3r z2^4-s>H)wz;0mYFJ4XcGO)-xL>2nLY6CbD024y+KP(VyA*&umhS>?aZB;iLLOO+<$ z`+GotxHLN%eJJ?y7e}gH+M>BtDTB4(YBpHSO`m!}6Mb|Cs&Uv&`eHA$lJNwqH0JaN3E?Up>|2s$aZMpgBRgOBvq@)kc6=N?VCTw>d@GUr zLdGT9#*P#jag&(WY0z`-=nf+w5q8lXU)m@1Uh{#7(%&Xd#hHRX;;=CkawbQ4sdEOO z*nI!q>#^dw7DuipK%?8Ssr2h_^Sq4`>81{QnXHEZ%jT zA%JJH3N|ZQjY+@0U`1XNomAZ{?-9 zW@jlORtGTLy?a{4fss-KMspty5*$F?J zZNyX~?wA*O;Lt?*&r$8@sG40!CHN4%)h){XqYe=4f_`a!Kkxc_ldTst#jfoc3^tG@ z3*>KxR(}x?TKsBB`-N&(d^myRCUQHSk5hqBPf=p?3x59~<)-VQ)AJEQu7wls)oRDv z3c348XOI&Fpsn-uKs^v+?()}z?FP$s$ahVu&wOs#OPuCKeFA?=zK zT3>m98 z;4rQ0=*Sgs;23~>K>+w2?Exqf+r{c^YbLn(77@=IfW`OUtj_h67`t9nDgSQ){(s+2 zFkyU9T-{3EhjKDeBJ9+k$7}fYfOYNaguBEg#2w%ky$V1>?b$%{xU&qbG{O60DP!m7 zUQt8aU|eN5z;Ho(m#Nt`t4{MiYx5u4=Q*fb*J_8jakys>x@w;Ys{Xj^*( zGyu#Wtjy%}FqSppRrez`-DQP8RKVkMD2f|*{jtyCHdJ4qV)tCc)$}GQOJ}2g^vFn- zeqrLmyEg#O(SaJI@ZR~6C3|Y^?VE)I$;;Un<*dbT?oA~;lShtk^)#+ag~3NoXQ|t} zB=_*uTCk|v*4;gUR*?5;m{>EV$YHc8mU}2+blVE!3U4M`d%tRQd|wh2z%vEIl9%hbFiar_W!01|u(rY&}4ShQAS&E)_F!zeTOZTT3Ylad!)%}0c zt(DIH_Q%Wh2f$729}NGm5|~(;$mB!jLPbH%t5nY7SGzOa_7AsQYrBmkU-YH{*Mhd$$O#-Cy6H&nbN$s2^s;8K=LB z7cZ2m(J(Qg9UA1hJ2^Q)0Ve|hg~?*j@nt;^g=KtbXebaf3T-Xle*zB=FMywA3>cV; zw2(#xMr7aFG@EyHEf39G?Nsz6eIeGO0-?XBf7J;z98B%wXe4~xAUn5+V)oQ2FPBa> z5W=EntYI|#2jAzzNLG5&htBaZIFGQew6#De;xg66s7F1Ik38|}P35y!`v(xndeoBQ z$5i(8HL%(R9I;pZSjl$wJ?PYZ#Q0UZNe9C0kzo?t#@N#;xWH#7X#QFudYf6 zwNdtlsMA3H$qL_oruu6*^!kR8iCQ z)Q>GTLW(a@gi9%y#A~URulkvgJOl(A+X^U#;s^eM=N;ErBSV9O0dX*ML`%;Jbc+7~ zN0UDjUt|iU60mAOXdw@q1fY4qge2${&Ia`k1%Y;nT+V;$@cbM*cw-;}4_!Nq8NoYO zJt!gUT6upe7n_7J@uHZLU_MsbcgE6fdW`Ltj z?w!tW#YMjkeVA5xpfm+kDneCK+Pz|TZw)LHEH1g%%zNxXTtBn2Y;YJfxwsG8oYtt28kcNV#iG5QVKn~)5Kl_YL~8b zWa1J{z-iFoL=u}90ZWK;H_mH=(uo>uSDJzjKNuIqqOVk2dY;48j)>RP`&H~I6u%9_3M-&yvhTuHSrziyFZ$j8dBD$6 zg7M-}AXfVP;@Ys^QQaR7!7F}}Bku$M^%{kFrGD#Gs^LI##ZVk2_P~%oEWEe(u0WPJ zBP=XQuO#So zR|y8QabR$p{dpfXnE&^OD`Zu`4YCT*Gvo^>0~R79BRv6zRL_>rMK7}YtK+ANc`ORy z_otFIi$OlHn#EcbK;v3~`%1leT(1#~%eo)br_6CVB0Rj*M+iWpmjQQIgt8hC5eUzE zppV|&*u*bL#rIc59IOGNX&LYzrZcZvZZn+cecBeRhPb%+)!BkpmFHcDsZnfi{&w;A zTdgAvwxds{np3m;x7m<`C|oeb4oS1Y}QPcnL3d=XF|1w107*-zSPbGV6N6EMc*3HH0q^lo@l zeS@aP_a}5h*z=})+E03rR&HR&3P`P4?9A<==BUPWQl%6&0F$qTU?pIAQdsrqi7C@8 zW{U&d@>YRsUBj8~L=s>@0RzhD!I)Fm09-q@YOfc#9@q@NSOWxh!Oo^*uz6Z3PW7muI+nZVxY~CjH=_+Wk>V|x{o&rD?deR$amQ1vZ}srlVC&|3 zS;uQwg0mXRPp<7ZaI1ce`@Srk!o~`tDGh&Tx%ZyxAZ>iHUQE~hF@4cV%MK|Y%vQ~D zn!4lE^(?Z1M<*Sy9YEQQ^D=b({?T8X$!4dm(f1jx%5c_SDbJ(h}C^h`8eg-%q{U?@a=&xBR6|zUxBQgG0B$% z;9ZFb=-_t(H=!}{@aL2vV0IUqLKp=%kwFCu1$1i#IDUJbH7<&O13-?cY+nj}sKNWlH~_sKq1wu6CU0`RM2=i%^1x z#XgyTyIb-~N{A%5v`7HcJYKh9H6l7X$*gX0cvvwd5~y5Vg@s#Ik_rr-*LMe|QlJ}n zt6u*_dzr6!P@4_@Wp@>{u^HAK5(E8oxq!WHXosrf$gCe$zAVehJ+2gPkU}-^86lbxkbxqR%MA| z?ZEYYc52!RBk?Em-hiBw@%+Rv%{uYDpZX@VHs7?#Bw)bp=8tIol&Kyk50#uEQj7HcxoUyO9{&sg6}y+{O)B^WaKfV)E+fx4%`H$r`ld^21(qsLnp@drb&*;)fH4F)!0h@^AAzWJ3zL^2 zlFrV~a^deCz5?H`)o~9^DGF8Mhj7y&=Uk64| z9n_>MRhOCz*J^@PojnIS+~^I}o_obWr}@n?Y%iFPtEI}?SUJzf+<%oZ{Rg7q(%3ZV z{+HuTH_K^d^r;>65M8Y6AUGjCO_L;5&{n8cP0H6db}TQ_L@f8?apJda{6(=b2DM%B|E+hnteFPJv5{s z3XnbA(n#+WxTN>diT(>wXTd4w*aZ5$HR?;=r!O`FPC^*{a>lQ8O1JUp-s2S|+y5!2JEjB2icL*DOJS|HHw*e40*{yv2vU>(e7NnKEY2jGU9 zhycwanQ#>G9;nl%3L$GZH6~DFO9ezdLw+o1BReUZ(6rhH_7i~0sFE#py+Lm#kK1Tv zU}b>|QV=Iu$F4Vy_)kO>fgCp*k$CPCFUU+IT&(K_T`)H6+ILKuc+lO5ui9@KIB6dK zU&He8@m0-I=pE@rI$`6rcirRt>n)<+ZP(v+nxeG7_Vq`a3y#yWdc&`4@>t0YIR>Cz z?19n9q}owB^TpoFLhJfZx> zQKJ$2Nsam=3@RoEF1}_0#tx1I8l`%M@9b6~T>szDMudXuj}n>?kZLpvD#qKL&)&2_ zi~5nYs<_mcX)_Hg=de?y*GlgkpO}+jw9~5oIHZ@+5t4k3j3gG8g$w<$3vN}{By)hN zvyFla?e0cl;DaSa#Zcmb$Sv3~PFH(1{p#anVIjfBPwni&OQ59-P}@fPcOOOj2Muw4 z?I*2Lgkq6M&j7E*8gCE0cRYX_Wi{w{2wQo)9Hu;&$h^NO_)J%*as!iFarz(lweP>9 zq+WaE4f$VfPn#9C&*bmVXcOeYB{bCpbtCIs`>RBQUxuROZ>HyYW!Zt?-8D!_-Z|HK zrk$)XxApGttxX>1=}pX&MR*~1N)hkfhXX^o&vNmWT54Ts+y}`Axjbi2)hX<^Em@B5 z1GhoC2PgNLm4?fOybr1^%>@}-U z&LL-(lUZQDHSB)}$XiI+e6Y&(3G6gkRBVbc!9QC6?9sq`7wTkhuKfgyO0CfzTH`^S z0}ALkKNG7TlU0TND(ByZY4LkcX<(=%{A0LX6(dQ4pcDoCx7yHx2f(7h*_i<5Tq$7^ z8L!F7F6YFVWW(}aNxY0h@Sxfr@yEgh85hw2;UgxjEOi3GZv^Up{}+4WbIy^TCM2#6 zF)I+i+RrD%a2E4t2D+>`DCj80y=-V07i4$}y?-;Q+jB2J`&PVTrc!6(`v7^S?1qZc z&`AAKMLM$@KT|6ud)8F$!_ek^q<*@$RBx`_9HS~WlIJ?ij+Rs~m)bltoK2hxTUXnQhqh(fJ(>ozWakf<27Ab%n>vTi?Z}=4$Wr!9*#uJ z)>G4jiPfW82$=)!aZW*$atwSoRqO{#ef>ajVPyaOAyoojtDj7tvg|7?*ze%p7@ zTr}VHmY=I;RZfqJiAl~662^!jiP+(-G3@r8TDFy!m!G*p0`kKY7MRHVLY!!9Dn_71 zfxY!sIY*dLryTZvuieX0bMjWjqy(l{f9d4 z?QB(EYpYm%>GXJRav@!4wp~HO|4BQF9;jY6@Vnec2#GR)$URvBQFMPNn~`Dlg&IUz z6JLgRT=i%mkVks>p7atIE&wLLWPmYW`BP6;^T`|MRE4ZpYo44?9OBp_^TnRp?ZWHk zEkx1e6Nq1qDr~pzN(KkF)N1}q6i!1=#Tf)>$xTA1!1|YEXV5s>Tf1q6eEjeJ=*rNw z6-{89HYqzSZNAG=QW!75Oye6U%*YmMZxDY=s#yM`n*@OgO+Yo~uX}5!RMI`ou6Vrx zzKknrz$3zFaRLA|Ms`bUHAbk-&U8 zKPfjoy-ZzFHo(O+n;0m8hrV2^Xi_F&vE?Lu=w#oRNvzoReS1707jo5acb%|o1QuZa ze+v*LNwiuS@U!t{@CP{Fax@*k9bFBDjQQg9Vd1US)phc%k|kr4m;^^S=r3gdNMbTq z$h`K8yMa4U10>H%QKd;;F9MlP6)06&!J%DiqLt^3rnYJSw>H9(e4wQBi&^3 zzp{LoyWd$X(4M-7tVpltaRpe-zfED4w%>Vmt8CDo$OZ%<*VMTkjw>IYOx1_O3hSHKU?aA0Wrh{%e+uDqqGJ&^?hz(~r&aMSZ)dA>45^n)L8jA>yNjs5FM*F_vA zBkveLjF{*8(Ca`@r=kLh!>hl=WeK`L^h=b<aPN#?3sHw!KX>qpIQCPBzQa$Vl1DJ+WCjqwnrJX0AR#Gd zd_<)Mn8Q3iPtK$6ZiNnUgi%FbsQ$a<7*TeInQJ;e5TEZ35*dD0z}5Bz_V85HQIBzd zD3FE1oIBDMiQIVt`!3_71spDbc3Syu9Awgg$C#mLDpRGU*sl+)4oGLL57_JFWEK_{ znS6HtL7&VgGHwS#8`v-pfiy;;+EmEg2A`4`*!Fmmu|Wg}n#S(^R4xIDF{6(DZ@AUd zH?cFmLR8x)UBB$yu#mWvt9_6Id*E@91=$cD4~um*DVU}*9G_e#j#;2}kd2Lb-Ak8F zKf=ct?W-(? zxeh268ss^RZ?ElV!qfbewv3AL_w9h->pp@&WxUoODO?R%Qkh_BS$*nI`He3wzW5Qw zbF8L;jNnZ)8uK2WpbpJov<`nfX{m^m&|KW+hQksFkM86~G7w&yte0_VyI!uw0U*Np zMzbTnU~9drYjlcCBVl@E;?9{&xMMnVF!D+~ss)ZS0FoHy-ZsQnG zf+KqYx&_uf4zdAJR&4BmpN*ywp8HGr{}^_0NdNCN9FRX@PN0grEd7YReGu_~uYtoKPmKvb z@6upRW7lO)P80C!BXi3aiY(F@Ew{jc$@G$Uom0s6c@;@HIaqD%i`zAT9rEZx`!}w1 z@z;~ZYQ-r2HFDL1r$#FW2L~hOWiT3B2{R`(?40-SJx}KO49D_AIhUOupVgLgCsISZ zToOw|xC^u=H11BK@ji`?;|fm~tdGR4Pb-ltGT{qm;V&+`(xOrMX{H$nh|aMZkH?dj;0% z4!Gq3jFQo{Zlk3VP&6p_IJmL`l-UiyP|ex-qnzLM1RoVT7678i!|3$_{;Ge`w7k1v zMYH_3+esybdLsDJ;lBHPIZ{H6K7Uj^dO3BSCw!l$8;|{T^PYPcQIdDfhJLS&;3^Q1 zIufJ#onPsW$ajUH<5OZ-}xy>0~(;owD>0t(iS zv^+0s|BxYD6&(p9cOJ?OHLym^Hq&=@(>R?ZaHQaPv?fq5G3>cpIs29lOhar>Y-M z>;P`^$cytrr8yF|huQSzmQ=2X>%d5(-v%$p7O*Fnit&Xc>eP#87^meDu_M`Fk+WzK zl0u&{zo~4~iHGf^(kaSfk@A{s=JmcJ2L^dq^aTS)a(wV!YR_Rz6aFLS$tUkO*H=GZ z)wshbtNHbu+snca7}AJ$u-)rDM4@v}PC0evUU2;&40uVYkv}eP?F`Qah^exl1sCo5 zTHn|W-g8}UhszU%cKZ7EKqtjsw}BthDZMOR?c|=OkMlop;~=mqt4sJkH4o1}zFN7o zveB@q6_GpOg3stjPSDQGnh% z3ot#P2(JbjKh*FM3%_nP(2xy7pHA4RF2tX%_Qs#@H+Vg8rT-2_5!HNcCp_ef7Xf5i zU`tB80$O5_HPA=^xE65uy?Lvw;Z7ep8!i4PgUQLEw15LU&w)}WK(XE|cey)VK0UQo zh5bPAZWMm>;>1ToEY-5+V0g&y3GMMc@MbdtR!d0r@B7fA!a_jC{=U}c zvgswKq5}NKuFrSP-`EKPMQgub`%fdAqsnyvJ#K*MeL{3{`c{8fkQjD6j30QjMwv@8 z@;~P?@oxDe2qxTqj15~6b$r;T3`C+#W4~4>jyXFO6uv(Y3%!K-byyz8OOMBS;Uv=| ztgT~i3oJqnN3x*6F1$m&AU^y-#`%$dhyI>d&L@(-`VBvNJ08i9J)5?x2mNb%_aT@XQwRt0jRmXC20qRl>YQ2*a6`S8R;%r(IEOtH1aM{r7&3nWy zN&$A!6q(*y@(ew?zFqwzyUs;a>q%=(?X4UyrV#cITon1*HqTFm_YL z$m(*ERH(u9?*S|(mC`$W3AIT4y>AjYKj~lO)CK~-^#)>+g7Wc6mEIjuk<%sxr$~C% ztgJxKa*VTXl&0vcOWP9Dm#VRrJdvhA4-a$ zuh!pLK!wOh3=ZmYbjvnyeS9@rY@nchUF*r}AOU0*%Wt@=v|OIKnN_k#dK)8soid*H z(`$c)LVZbC2|MfiI#nqqnV+`Q&OX&frosHeYQlUZR79=ama9A(k{M8%#`)Ngn9 z^;$)jS!m0MMP*#^TNVT>hj_MVgOxmAsg)1Yc5VF+dKHuS#p7TFuiZ(BE3-Q{JN2ob zPU^+0yLEfJe+O#qby(UrPA(;Is5HOUkMoc(Hp^o=A&z7wvocGMteY-Z*UPewQ*I6i zDTh*ByPb|Q<5zp9POr!w_&k72K#nbMmxpA}cBbM_7cqC|?q=X~1K|&M3@mPL#*BK4 zjL&C|hx&W)nQd+DPmYhJpi=G*)8l}C{b)XWJ=h*<&Z`|AonrWo&}*_hVeW%MzTyzT zbldquGSC(K55^cIuBAzJZZN?`b{($uKTq@z z*^}DL7~5Z#^x)HOG@na*iVtLVu8H0vdTMbft>R{diyyj+qA$c1`nMR&`rxekE2_a| zv^|RIt^|!5crUhk^@{rvYkaRYzQUCiw=-m=lypLsbi(B4>T{&UNArx6P*J5h8&sin z<4}*wcL+%^-{xSN%6KXY6J7eF^qgl!?D*78} zB~-5l#K=HnD)*2iP?6kiufcigH+qODI2*?eBcNh0z^`(u*tZg}^$s$xY+M<1RIRf) zFTO3@Ornd0ATk=EA>^!53AUZ*pluoeSG?}$?>tI}cu-N8u@j_5D~$UIv_I<}E_Z3h zd#6-!paxk~={YkxTpSv@mT&K&I5-zo*z!X#%)Y5xPuh?(s#v-^eM-;!KviL>USebt z@f&Y&&ERMJ^?YxA(gm!dotx#41Z{NN>iPzbGC95*T@FjWf1^k&%Rr}0uSsN`oxFzU zY^A|L&vC%j7Fm-5-IA*%G?(LW4`EMm+wgAVfVPFN(a6Y%m(9vu(A^!ri$&x)+sUL3 zu4uBR8yQS0j<*IU9c0g}-48P3;a0O2YzbqQ=Z#G}J&~|!u=ny8vgPUzfDoeNYgw_$ zNe?JU3AcIkI3fY`kw|3^a`e1enN-@Vr-<%RX*eTYkrh&oH0FK_ zxuVOr2+=pora_U0X3@6cMW4;uN3GuO%Bo|2E_v6k78ju)-tHn=rZ@lcf`YmG8Vc!r zk@#qG%-Ljm=tXd<%j&C=!XJR}wKe}DjH^|n9SS-nF%=zwr2vjio}`Q*At|X$aHvKd zjhB~I^*ye&)e@n6`}QYZCs@sz+02`j?<|HPT~3d}UnB*`*3{NIG3hS01zWH#M0Nv^ z!L!A%x)i~;I%;#x&i{Tu!es%?>EI5`EmC?E(_37Ial56zO6I}HiRl(q?^$)?wbLcL zhdk_Ac8Z&@XD_)ne)ZOCKx#$m7T31L)qhg#y5@39T8ej#t!VVTGraVisddW8*b$sc z=C<|Ss@THAekX|X)DeB<5F3bly8 zeI#5hzCx}i>ygPZZLYaI2ak%mH*c>-%viU|6iO!d`_c|{NTINeZa4G?;-ZbGCGpNj zItN!wId%jeA99A#(g&C)Nt;GgDeO)Biu=K5Y4L^k^0~&aSc-BJhg^kKzZmv}#cfS9?;9G5W)0EpI4rM@ z9`edEX{#0pE0V^f0xh%2$uqs~Zk^{moW-UFSpNi~6G0nvL~~$TOg?Eois!@u&Wyuf z`q@Ie=rS&cU56%HyXu$?nP0u)PH!L>Lz503Ft|8Z-SnO5I)ZmFPQLOYZ+y+GLl&QP zaci+^9bZ1A^!vFVLk_>!x>0jIpB}-sgqAavU!Bp;yO+-s5)$;LgqP{6pi0La;j4{} z#n9(E2dAgiGTJoQcwC5RRdTDjX4eqyHv}pKWI9{IXmsf8Zrx35{U8Re%8=Pr{pwff z#%x1fVUnAZQCx~wB7>M;Vk0&oM^I{F`9sv4Y={@{ld`KN<{rVC#d;Bj$RH=Ix|#|R zwJDpmk*gSmcnJ*+V?+PkKMM-P5hTO%h6@V|px1~y;P=vi^91bw`D9~%XCkZl>YoJ+ z=6p4v$GO+*0GB?37y^2x-2Hs!dv>2|FpSx@o4v8hNlO-=NFUx)KNMj)@f;SUSweI_7Tei11lCJbuE3;qT4}f#K z5*jq;aYkZ}I|Q15g?P1FOu!68H*%k^aQsN*4znHE)mXE_%Y1|q?D8a5+u-B+pV2mh znC~Zcp#oNH-%r$QV|=l0a5dIgv64*DQ>q;+2vZTq=X@P`(kYkwep$+m2dmYVUUD&J z1fwPTc`^?21CWP31}U@UEPq5$x{TLW2W7*QKe&w+b>UD;dt5)eC1dPM;i2YZj?jMS zYCC>85|l|CQ~I7@5vkx&6~_QY1h*X+t}Pne#mx=S^Nq4;ycV_~hpNz~fm&LteH{8UL zW)#xJt!PxGA+6?4xu4D?-wEA77Hay!h3xQT-={uL+0;z>kA`zVS*4 zW%a_Go@-`5@7Z=#j--xOWBquOinfR2!C(%stt%yR_Hr?PQF339X`a!R)XU*wVKtM@ zeLmmU9sOZ>{pdSgEZv6>(N!7ca^c8s`;;{s$PWvh2I)+WkEtXxW({6+t?Oj;8GO_j zPwQCE+c>2uCp=y&(SilH!2{-^413(&Lz2y;$cyXXCP4imUEL}{t7NC;h$aG=&v=0% zN0(i5_|bgyYgzycCubt7zggBeC7!$N*ouxe(W{uHboVYq?aGv%yf3nwc$;46gz(*u zX2+4lKVPLT&7PS}3{G{Zd*PJJNUI%{l{w7RI-{A7g&!`jN+&7O;f-m)j!$U3LpWIpHF zPC%)ad7!`x#Fw`>p?o;eQBFJK@=Ico=`>?8_ltoaBx`$pre^twu1a0&^VM=e3y%BP zW{UC=k@{yxf2o)y{x8hU(ltG@Ozml(eld;q%TIL_u=WMFAHR}xi>Y>wXh<7zZO|r< z{EHX%d-3S-Y@<7hDdnay*NhBd9*%K|T;_?!yIakei z@oYuTQrEp3v5pA#q~1K)6!pqa3*$i@+=qW#D|EhB*-xmo29YOR9&a%=V7}(Xnc6v31YP4u)yFe9N62`?S*~Pp8LrmVj z?l$>ISTdrRL5%Vz%mE#0Bge}Af%O2vS>TEciTlz=*7YLH2$z zv~;ZT;&cl635NTkmjX4CKoCuRd5^a|8%ByMAW8z6O~7v~#>nYqvi7 z#9@8d_RqK&l}xJQp>C%Ei>tqb!WlYQpX0=5SC__<)9$J{&!hSE0bN~PPft(ao;d@O zbsFu1*Ui$|GaRy|QJi2>m*YrUg}f(^A3v_P$RASgFHj+pi!nF5w+TTf{UMq|@6k!Q z&q0^E;g_5a>wwf!%lmtAv_?Tru6hN8lE70n-r)igSfJ_}{tmHU1vj{=@p~Q5ixuF8 zbWA!hBcos#>;NIQuP)mzf(s^B&c9kS;ZDMny$|h7T&`I_m&c zc>+3B^{OQR4WNV~X?p9)%3wm!5O4x+O}52A%f-d@_HA~0y7wf&#vVYtCdY<5@;VD zB1s8C7LI}VUT|?aCm1@hOf}kc^~t6pk)!UDu5N~Cac*a}+_m$nY>KwZw|LouKSDNd z#d%;ju~53`2^m4T+T>*7OPPb?V_cabC8EQRznL*9-4LC*$EH3R#bHWDKD$1#C>OYJ zSF=YjV()LQV~YUy{U*GRbwZ)2=3_C;jpx3szP`TaAH1Uh;3*Sza5x62N3AY52Cwj; z_1#HK=4hC5)v zIUqM@H&EwpQ3AO|u=vVd$OIeaMZY_;4@3|E#O+R2g;q(jI&G_t*0^6Bg0M{2q+n&o zud2i+U&GCPpHubZ4s8(0WcLwI+bNEbQ_noSx?j?JRaRl36Wgz0dyV9QPwmhxk2+`*hi%4|K`?Mv1=ehO?Z@M|1;yIhH0C78@ z>AnRa_olnsD-bqlw3uLVGF4k#S{fP}q78m!0Wv{>Q2!%n{2EKIQjSMXPEJ!$#)d;k z$O)PTj`Dh5e@^4|;02v)!H9-Ztfs1WfF?YV-8xmqI7O-mwY#8wU}!md0W@>;x;asa zg&MLXtT*pX!6Q<0Pfz9i?{4Sfr$&*!sjCd; zhm_=F#mzr#2pMKaDxmr$BtZ6y8V5Cp1tGPu$UJs}S(b{8v`G+R7lsGc1<&r>*7hwE zQwi`UR>+JypLSHsUoQn!BI@egK7R&wAVlKg;=-cVI2Uvo25yQoh>+B*OxfAnqdb3U zbFe64g|N7HUw|LjHyIopd@U_sp2+ROVvgoDX5e~65nl9KX) zg=HL<0k8(wWihzpq@U+~VEy58QWT$&$C0y^5}#JhRxSvu+m%>ddh;*CH{C$6O~-YE z(kg?{YPNnNSDMJGIZ~^C(9`BEkBYJO-#PZo6)yz|fd;U2zaN36+g{kO;=snnwp;GR z^7PhJ6BH8a;jAqOXI$`;yF2$|L0x~)w`s6UzXK}DvADA0IRDEB_+0iqhEGvZQJ+4Y z$G1501_(La>YJRyvTNw!@v#B@iv`_e|A(nIpS6LvxkGeNVN$LJ%A>Xh?akE1N72DG z30>b^%O{4BcH2q|0A}sb(ss0|JL?fjRaOez&eN-jz}1DKh4mv%H!BrQ+k^3}_rr^y zLEq*n07XH-ad2oTOf;*ou&}9#FDDleFCxOi4x7Ug9FM}on7DwB9K@9r6co_V(9oaw zsWRl6KSn{peEIGZU`s&9)74R?sbCyxPcTz}MHviRKXElSHs<4N0xTn{IAE;PiQCiS zy#E&Vrqu=sD&`CQlBUA(Vj*+=)&6^IV1(~{-Vg9%v_L^oI0E~VwKfj^`g?k3xij*( z6LDf;V(4lC9EjkM5WS7z*48Y;o;V<+*q&|RYM?sim`Id<&}|#`lD>JRAgmwbd3Fk< zgrESuio@;4NG%^cW#(?IJ-VaR^`reOw#=(9C>uD{1H5xjFhn3?L4w5IDTGQPIGJmP zch}@#r-8cz=;FvDYwGHb{JQB1Vb1E(xP+{P=mDZ+WMruRn#?igyO;J?%z0&O9`t{m zkfl`uE>9!iM>DvAL=N zAxG5Kj@|SlrtqBP4|KVJ&P2bb)%dlh>@RH_aA zkWi@?DM5}cxi0xDlR!;4&GUFHK5b`p)Q>Z0gPsI8H}}y`oh)fvBuZTeO?^8sq$I8- z3iUch;sHW2dBGV;$u6~n!Ty7>3Pz(8MGMNZRNp{f;tXNqi^XVglu2GApazT5r1T)>0o{6Lby~g1J6_#=@AQ>o~h1A#(9+(Gn}0q8w#gtTTbld zM74}r%+?D&$rF|mkTJU{RbycBy4YweZ9EUH!x%>0)~dxd zwFh?Mwv9SWR@7|vs`QrBi?zdGbb`(rcevUBJV*ZXQRz)#7-{UUakdO6FIr; z^@k7kAS)1Dgo~LXp#?ax!Y7A6i75{HRtel;snPU!obQ%ckM6FNFk@@+#9z;T1vTOvJp17) zp6*9&i7sx3_QTVLa^~woe!QIP$d5!2f%j9@Eg0fQg#xCk@-4`*sEipd@(C+!RP!UcsUVf_atz5K-|~so zd;b{HlQ`lwo)N3kPvuqpNp_Vnc2xDphl1y#y}cD`X${9Jp7_3+#aR&;mq-HgCAxxd zFw)DvEvC~7Li&8(u5HFyhbnFLqE|ekep{7s<6?z?CMPFPTgE^s#~z~#xq=>GhEq}c zhf+o)k6Gi!YW^5ms!frHiWd&%A66ASELP8{_%2+{l9Ir5Zg5h<9&d4R8ryUdVALSd zYBfY&ZW8wRS^N=i!kMuro3Ex8zkJDq`vIW-?*YhLG=00+@W}>PiF$fvOju_A-kw#l z;ZRA<*An}y&wLjW2a}LE=9Jrp_tN46Or72u+v#-SfsM0>sr@DMa!cJ|Q! zjz}8rSEC&>J%*VF_X!qS-mWa?_&wmah-UNSE-1GkfhX2iQ^INa+0Fmf2ZYmU&PTA$;DQ4C7VTb1?_mfM_=8AY*L_e(=i@{&c|9(Zxm}{FNN$Se)J!kZ ziqAjXx|WFQ06Z^Ut1LM%0Fn$$uYjuI!>*D)^)><1C9MAxzsquOxEcieT zl>pIakXukd4#PkckaP8kcDaFs5hyQIC{!zi?)uq6#J&40GF?V04JGS6XTWib9*ZZxQMiq!*AtrD~fpl8{VUC4&*g0qURkShfNX;k1U?om%@#QiEt!E>0N z{#rN0ZL1ir?RjB1S}m3(VLP$$IIW?Y>p-;Rx133j#ppOy2DcF#5heL#dSwx8OLGQK zQdxR^0Dti#eS zpC!F`YSA&G8}AE_BOOcGxAJMfg<0fDH(M>apxGJHss(XkbLXeWoiHEWV5N7h;k3v3wQ-ZvGuwoowd5%VJMztaTsf)Hv-jdtE(+Y0e1Amo%mW zs=)9i0g5z%Xa_6JlW4=Cjbn6bm@$SGWPyp#Ej%-uW7%kFbJJ{wnF+bL%aaZl)pPNM zll*%-M6!<0Xx?@kz9Gvicp!iVx1Pljtxi||RT5<)q+85^sgLUj@E=~FY%DJehYok) z(-zsO{KVpQUZ{e4m^o-U(bl1PKEyM#F^}Od6flC`PO_io&cI%UsZXx!h0JkALuAbd zlKxPAXnVj38S8IXeYCbdGwRhmDpw5E*1YTf8dgrcL6TZb z(^3{6o1)4j6CIb{Q<-WSPDDW+_hm(E*DCC(3iCTyN#iGBV*c0+d=zQIZd>$6^vx%x zOYiTauZBTwZEe5-lJk4m1xyXCdD*QVh`|{q0fcD{@{sHH8nf01t1YK|kWuijjMkH{;$GeaJZaj8AX(*0Ny}*7NO?sCkVJKDegeqO)Xwe@VZY|UIRgM^ ze)K~;o|oN{4ozp%_OeH-y%ReG`1qvUpTBW#;HzS0I62=|2n7wIUh4ye$Q{UL-xys#Z2}#A=RB{%JO_s?hH}w) z)E5-8VmAUN>ztWq9`l5PaNr#%kuq0lio??fJpBrg_Db3GcpWcYY&y4Pq;ECehHHoRNOfHqtuzjE#420!d>bUM{$A;-RUJ~!(U4pD@aAs;I@I_g z8MEW$<=~qQ<f)~O)(|0`AJZFpjW>}q8+eP9_H_jkQlmyaZPR43mO;vi zLdiFN$?hf|)CuN=OuH3)#2ed2(tC0`axsOH0HQ0R03_x3l0@a+l$NfsWWp4OP#!&T zRkFH^&EY_$zP-H#-WOy{qZ+8s0NI@C+W{OhqyE(16I39c@q@i;XVVSIn(|tSRdGGr z?JX8|BTYyE=a5^31Zqp>zW=~bd^7voDTua~Pe?c3UYd7{TdbfCQ~>6KYNgT+Mm#gt z9ZOH^P*(V&b`%sS5Jz`??jDjwgxG7mQf-p6uwdZPsa5>GxZdgolxx6xE-2GULukXT z=%}ayHGZm9nqcvWTQxT;Xez5WUxLQ>ZMZ)iM>nJxu!H3bhm7!4QOYOm=tFJ#NHn;JUtvZ91DJ33ND3re*`%Rf1 zCTUY>6Opi|?iq!PghVMSAuOO6mj0+yOPLLHn@r$_K-BVv2HZwK5KDWL(930G#};&* z(iO-MrqjK8hF$jd^=t2P9t|I{rq}FNvnDu`xx)iV5Cp_5wiZ~W>2mRyxH!>0?G$Y> zYjI=aHIOLe%K{{a1wX!i&@z`8#$h~=M2lk}0OM3|_Uc3Hn?LhU*n$cPQI5v+`t zaI2ga6fyCN6vTqd;m(M6HArj@m{m>thCy={)vG1dgvKR;!_9+*W41ui2ijmQ`c|OL zGSx}esC(|f?7%hcE1f@d*<(;%RK&3B^q5JfQS*>#oh>vauMSpUAF?-d*!qwprI!Ef zrohkCmM%qr5i2x@B|)ul%wUxu%*NH2J&!;oBIjv*>h}t}%LoaAXddpEfg;5H%ms}I~?;lSuV^;gY5{7a&&2KXxRR0gMvw#t=SuB?zH~bhh+q~_R7WTC%x=* zxNbp;(aoRE&#s$XE?h+YB5z+E2X1d~4;jml@!F}LD^tfPM%>w7ZzC$E?c{-2M1DYi z+E-k-39aK6BHHxR$H(UwKNG$+Kq0nsw^ICpBTtj$7X*Y(p3!0?a()djBrt0*1!!m{ zzMSB>wN`!>4T+4D)F0r$6T}w70_qNFW4nL+paGLHTC4%?djm;axw09))Sjr&o6A%zM9$6Paelk!T@F>V(`>$>1{F{3QQiz|3@M}z=wlv)u;(M3vlkCq9xrk>viMpT zwYZs)T})H;1)WO4PP=+QFZZc2KDcouP{x#bSt5w_b!&OWT;1e|^&3zdc(S8<2(W8P z%C#C?Pk=4eDbs5QndmhoQ-Jr2V^9N^goYJj6}M2GJ|zZsbJD*W;=27qrXTO``pnAi z>MXESXpsbV_C1nZWo2c3(6!asX>s}Az^i|A=kY)Uq3$b4%zyHx{Xsghit{=4bW~)s zwDGTJQxZ9^@4GV3X97Q1z0yQpK_L7z53o5KYzU2}u-*6>M}B@JI9<$}1JSq)ISUpd z8qckf#QI}m0e_sWk52+%yk}XqJWt@V!Tp}rtNpg}`AnqKuV!h#t(dcNX33iswsZ*( zhL;q(ucTg3Iabm&o3PEKh7X2VDKkaV&`wKcw=~=3WX6t_>hJ-64H$!xLVwO4K|t!F zBFNdO;xwvBJU6zsrW&=bgn}^TleQR}+uPeeF&qs(K@&ktdjIdgN;QL61*NYI4@95{ z)2@p}opjC3_-dAS{+3t*VaBY-*$gJ%wT+`Z$jkqcZ!16;mJ4{{=^cELvpUe)8=%wy zGougiBSn%H{mt*NpiKyI=tSbgTUfqKahG)OA_eh#!mlz+z{>8{!u4GR`|A4daNQ^; zVnsMAM6zR`xOQ1x1{y3q?SrRG0*!XeAvP+C2ZR+er>$V5c=SvdQld3isL(#cu(BWY-$AP~DRFxeaUSSHr7#=ok%Os-^* z9Dw_4n-lYHl#u#O=FN6{ULnHD;%QqT8knKk^J{NoYas)*P{g!)08S50%LQ%yp;Q5V zfd*l;Hr4GOqb^se_aDg(2E1THSU_Q+!=IWuL{GO3fE>Sm@!uBVt#H{cw%u3E01&!F zy$WQQG%kkf#~=ffa0);%sGmcPyWO8!)h8B}lq5N2wKG`-B;4+6Db9c->{4b*D=lTF z9Emc7dwN_M8XJp=iP`svbQzQb{A9*DIpgM}Q|nGkLE%^TOCX&_Md6-Fz~UG}LPA*! zFQlxjtDs;pho<2#2v}*Vpz9hFrW>?iDC6$hpaH-oE89;g83&RJm;ur$2AmzBN<;B; zw%M0~O*Aqx`$)Ku@Z^utk?&(Plf7sSiMJsU5qYGwY5?O;5;@sd@G?(|q~4Rhd08k! z1xoZGQdH5VAeF|fD)BNudXVrW-u;_{Gl(Qr3Q5Uk6n#MdE6u1;T?C-gHr+CaYZU#Y z;vVwe`8aO{AczIYn_}gwVFg*o-RXo$Fnv?yhG?v$9>)XJY3_qgE*ssDA^rg3Gb!Y` z`o^oaJ$W;&3{~=RRs2ZNVhx0$t13Jlo_2H4w%bG6Yq93euJIO%7#^D7M9&e=9yBYZ z%<->1M?qXHCn^pUJc^ajU}%vaG|zP?Bc-B^`p%e%kR&6%S@&8iqZt8U5LBoTw-yJC zFyP0T11f8e=z{bV~&>Y}2G@DSse4!E&YM_V;$e-Y|TNZac8-zE7hW2P!H;C+o z0A14f#Dq(KD$f*XdSCzfJ*B8C^9^gpXj?8|~RC+^mI8Xb_9-KXwql+B|^}p(` zteCzGG7mJ~T&Y!z#yxy zH|-DB^vI|;5Evo1JCGxE2uzBUfD&v~hTvC-tY*r6M*O8`#*(Zg6tZWAJ1g^Id5W1N za05-D=NGq(9B9DYFJH)z3iYdKZc)CIi6~iMv7T<#d;K>KndbkTF1O5Hh zKpP&j2-0CiLR}jgfz<+aEC6+#y}!4#WPiTD0Kyj_OCge+xcD9Lvb7sr%LuhD20sh} zPMNmFw&!7QB5PemPl{MLvF_R$%?We+g9i_=W++6TlL^r8as7<&+^az&eiQ=c513ME zfe_?#Owo>!*OQ10E#k?6j2V*2jRjZp7|XGNN0sKB@?#J5E)ttd2Z&4zg=nr zC#mnGGx`V@l2>H3OGbs1Ec3{0Y#m)aCpxik+_wAe?w9=nFwz@X6+Qo;RmGk(}< zigfYNw-q|1kj;U+&B7HE;Ja9^12V+6$1puxY$`@c(*@LZ%#{*BcSZjE85hzx59IN$ zUcG9%z1&hx0uf3|M#iuP`tdaG?x^Hs2JT4b_avMS>EkZPy_uS0em@FEfejAX z5IAwFz{0}XenNXb;FlqDdmvW_YScP7ZZaF|#AU>4X=<9>fV{mLjx85BfDe<^mXgjf zX=$?TAOcGO>{T^O#&b~uc|V>i;GP2e+PPwwTJ7UYyfa;)kxt;FjcQhDHd1hnOcDSX zQ#3(1e?&B+^7{Tl>+xn;br!Mw#o)H1*PUa#!C;~=zHwPmaZ9KtEJ>?CX=9HBBv5q+ z9abpr^Ahp*2N&~*0kS(HvO1<0Q`X)JfcalcSH{whB%$J#rJT!?F>oe6JldU2xfq;Zkznl z@dY4Z|6W;wqAxpKmCi7Z_Vx}uu1uJCjYeQ0BeVx+j z?&%M7v6>@Pr~k_p;k|Bufa^10I|8`i)!^^$-PS1&Z>J(2p-@WMjx5m7GA)K9o@7<| zLW=}s$kC$N71aHbS?dye@v~;nm+2|Qq&8yXmCoDE>zGp{6ghhw)U%S}?JfrwW_B^8 z5wSQ8 zAD=;0uDnkoG9PU4n8xvE&8@Ai2sGhLkW%6SWM3f2{xvLY24SD~uHAB~nvs!lC&4&% zA?~qiNEUr<9l~CV4eWdr4AOPN*(zZ4i}HqX#SRY-F^DZ1cp@Na)VN-`U^McYW(|ECUKjuqayatN&SP%o_H z7Dxm@{6d;aK}MzzaF6i}YUOTcR-mAyB3(xq(HTh6Q(($0lry_r3}vRdJ=quv!tXV* zFI%z$8_pFFZh#&s&!V|kn;G`tJ8_havrWgaXjDrZDH{RO4n!F-NO*BQjXB5`Ub?>3 zl>9X`R3UaoiaU6I$tY3-$ksGY$B-1_WUDma6+q&-p00N(+i1R|HO9R6aMgZ*y%S`o ziT4wGy3+H3uIH#JcDgNK2}ka3=I(6KMr@XThXGp14h?;Lvj6V#dg(@V$cwsh3A5NC zvNH_7o5CnTb75g>J2*hd72Q&dKAUot?aVQnt1D`$oX^8?teEIkUy0oZj|z2$;~^=P zg-N3_Rp<`&+6>orhSm1(LcnM60OnU5084cA9ELnOnp)>QUXUMm8-oXGUXO!|T24;R z)zuXcNq1*WcZi8xd1)w=6HxsA&v3@gqyY5<5H*8;3YYH`5>6NdE(j#iw7pjIuH~Mu_m)db##yi zH7tD9pOi@wJ-}V*zV}zcghG&M9*cHNF!M@Y&6LIbA3`7Rxjb@56cDUNMZp%*8|{9U zeh0R4Y}@p}OhU$K;d){&g)90Ki`tg_b2PgQRA!Y(%}sLi*_I9y+~Ax{-m|K`GyabB zYF@(F+hdMuh{6y169+r%-OQ1f<**}4mNLyZIln~b@<%HTLhY(? z#c0LpB15SAw!QY&OQsnG^@B2#?`2F?0=4cJb|ue{;1@MqT9Qm(dguH4VwBR!1{l4o zd=P->-rw_=BU||@z?f7Q2Vo`m)|aPSL4M-gi2Eu&F0)#dnzhX69YS%!%j9aJ=XZAd z>N;AxXoUa+R!@q7XqH-R>B!bs87M-Ls!ZC*G^JwjvXwLP+07hzES&*tL%;v5?(B_l z4V5rc>@g^XsRHHW`L_Hv`jK0_omE5b(oj=LTEvo3(awwYG8+f#(I?)U{9w_wexz;1 z;fzj3Wz+X^z*vE&zM+v9)Nl2jEGRm9l29j!=p!%pJ#l4UEmJIYi}eK-hDGA) zf1ku7T~>qniMrdOWiKh$eYfU6xzBXqm3jGeRw&;-T9{o~X#ZW|Oh+b>Jt zfr0q7a9)ARPGf8ytsVC1Z|Vwu_{uq>RmS=mEs`Rc5&HugS)8;Y7M8O8B@YRYDOZ`z znM~909u%6;&?E)b8ZQgQ5P8aqRFXcus4qECM4`Bar-^I-?H3!lz}ycWlpqNILkYwo z@)Lai~(nNFkoaa{q^bc(1H>`S-Yv+clue`sdzx#88jAuSgv2uSz ztHBXfEXtQwcKN3#D9VMT5F+twnH3GG=$S#iCj*7Dk?2MpL_1bYzZN>ph5Yk1e4nBq z$xRWi{5Si^U>)(y$)lA>8{@84`_8en5@pF=tY?0+Yd}JhOCp>*j{Tm9osI!u#CVQv z{E|Oq&Hiil5&|ToO^_DSeXqD={|00)gI{`Vr|}A z$CiDNm8SUt5(jY*&A$g7{~loV*#5s!pJ4E{-mRwR|9$dH@X0w4Wk~qFG%X5g=`12N2`irfF%}ffbsyTPr@jGa>bIIofpf@y#hW zyvdWTwVReX+ADB{XFYK3axHCAC%mfJ<8iSL)Q_SGiuG2aX-{-Yf4POYL#|I~2V98*(f&X#FI@Y?I-M@h4`-|jxqENi-E`oRNGhN4I-bH{-5b<~`moG(sDkK7JNJoiGD zzSnKiA4esk9l6o@VkM|%ZHW1d6Xbnq(TyEVE-5>4q~zO}7}cw`s-kT{5_23>h#PaR z9UA#S^ACrx*)~Sp1_wE6KHip`RkPH~#pUCwyjw(E7di3!LrC+ zDW^ZSt)cl?;f!&m|buh;v{G3!0nkD5yCwZgRg{@Yy4U=I~! zzKIA2@o{rZ>b=I8hEJcjd~rMEEJQO_#2q{?pG%I~mM$ey?j zj|J)n&TjM*KB<7vYP3$i&En4+yn!poY)HQR?e1~yzft|rjawqeL5sHz z-CEx(w-GkiafXady=~yh-wIGVJG$#DA-+B5d9zI(*6eU7if^u>;{dyDrpIf`d*7h` zjO>r|2iFQuW5n?{sj#9dV?)eJr(KTCm&SRTDxyC_+=PsJVwamua(w~yb{LJ zW_nWF{isgSjcy#ctgoFA!}W?ObGWV+%q3hslei1B-(P6wKNZ`aMr}%g&PTAIA31B> z2)6~Z@9JZo@8$TV5l#nc2{-cERFu1nWQ@4|GdGvM!1jxv7ZZ2H&&PdzZuOdik`Nad zbk(L$)pJr%(r{H0R*mVxzhA5#91EK?U7I*O8KcC`SvBo%Hylbm7UI#c(~^tioV5|W zP3`{jZMCRjO%T;w?k$%MB&DkEiG5T1b&fwX{K*x9lfKA$wNnETlvz{we0Lje>cr>y zE~zR0C^Kkpo+2T|rR#PM*K?dmBm1d}#n0pvx@lBSzm3o)1g5HMIFa@`SGFYDtqDvA zb0zf5IsMo6PVRRX9WK|$bV+YXv~KWM?g>F=V3?K0Y`SfY7g5i#lh<};n16gA^fMje zySrhnt(Hf!aV)noTo8yY3Z#e^SHH4BnG^`v{M`CXUe#=;Rk}Sgs?cyMQpDCwjxcRJ zJ`{HS3!;mNCByAl;{=NvD^~Zj`fm}|&P_v15#w|J5#g@Qd}f(LtdeDS>eE6S`fbj% zKTq7t*JzUe1`uFPy5G^C$&e9JB}e8+lTZ*6-dMcBb+sO*88hD< zpIEqn$(^OOd`se?<|Uoqvs4pfxAAW32iO@<(zCR$EEHIDWb zd!bgKhx>jAZ|SWR9HrTUJXARQ&vat}(_J-e4Mvr>F_qX@vG&|D09*5YD4X_r?Y`{o z+&&!R5G8eHXaJrYj&QY{PAU4U`%$eCViWB+$~Ng|{J@*<$Dl#ArgT~3*%QaZt(WV% zTKUhx#P5gPw5SB$u>-T@)c0ZFsiITs$nPyDmGA6@)d!F;=Ar>72Ze4F=hG~?R#tXSsC+1fK0R{U>hnsPsEfaEMWFf_qKKZ8>k9A>;YmkSfeIa%r-aE{k&Eaj9 zUus88-#l>k(L-a%nQaWs>GL~so0T@JX~8N;7iB;C%Bj|--JvTl(oa9S3;XB$NBDvl zo93<0E^4{TDD>52a8gCQEj#9?j43|JGxGWoW&XwtDO5VW%T>JiHEd=T&}QLyr*ei$ zL35?TtWhD5pY-2CqJf31-E6!+H|uVRjl~GG7 z83}G${QLe*)WU^*O2VIF4Hg`47Rth7hR!RV?oXB3f1{>XN~wv9O*Q73s&X93G!7|5 zce>5x=E-Kfd#DVC;W~#Jrds^p9(M+Nd_*aJrDj=^WQ9Fue!F>9cCO;{i>8S4tBp2G z<0#d-CtcZ5cj%~wJL}ok%+|8GDuw4r>F>W|h#CGQ4CkRFgg!Ow{oZ8i)TG|~1YJ6Z zO_Q;~>bfkP7BSf>zp?Et;dvZyLw{$_7|r)Nsq?mut}pAq%&Mhjek)7oPCsoN!7u3(b>A7a=8*4~VNCT6Kxr}O%le~Gv$BWrv>*)z3UPd~cgHF+h3FYPMed@@Cmp9&9!6}~%s_`usKPZd3{ zTJmF;`>_F@{%-dxxf@YMK_=Ytb4Q_wEmG7??%SkT9ajh8F{uFcg`93V}1S5Z+ zUE~WnF_#Ew10LD#t2WLJ+9Ix(t&_2^1?71ie~N)uEg@txR|8{#Wegshy;tY?92wsU zneWH__XR+0!`_oj9e~sOPlgBJtP|?5UwPdbJX(!<{N0?8*s}GF*jHC#^i-c0HQ?xwYD^3{IYA^YO`0hz=95JRap&gnT$% z`y~&GbK}F^>ET8Yk>{eH2^_Ojk$$Du z6y#r_Q@`bY8};nSnIQE*>ipIqL`kz%!|mX4C35^wUeQHRio0+2s+son?lz{_;^8;xHb#7P-&tLP?|SGr*-T2& zD23tP8)B2!_lqxT8MCxlQR)7S=}&*cRsbEAOy=ukbXg9Dpi=?b&N9bVM?A3 z#9Z1|#WC~g$Dl^r`QACE3PH*ROh_P1sp%g)MFz-QPT%Y&vGF@KwiFp1H;z}7HHomk z0X?jY-uQ@}mPyJ1nT5kL=Sh1{NQe?WwbKgz<|D69|WlV9kJp-?~oA!K=*|- zZRq~v$|JcyQQ)A1X07|NZt-6?q-3MFu(^A2tf$W=Yq$>J&$*O}|4n7Bi8ZN;N`@{!T`RM_szfCix3Eky$O}825f=o z(vl;R)83{>Uh9qv_7n*z9b=zjh4-4P`4im=4I}WuO-$~0rs_zy?OElK@U#1mL8I>u z+f%!AR|i+h$B*F4SW8h?YCi4NCS{O{Q9 z0>ShD`M&PI-}k%!#vt(gf4<-P@AvOV)O!E?f4(R9@AtuYyoK&J6x#jxz{@unzuw&2 zI;@x_Fn%Af;eN?~VZ=upd*rRo=6nO`ww`_n{#4}A`{FIhp5V>Lcfjo!Cb^c!K|&&a z+*pA`$O5Lm*6+a+B&7Kl`vH&t{sPYRFzvM|_z#4&_F)XG1*2jm`4S3j3^P6 @@ -39,7 +39,7 @@

Project Goals & Scope

and basic cluster services such as: 1) distributed block storage for PODs' persistent volumes, Longhorn, 2) centralized monitoring service, Prometheus, 3) centralized log management service EFK (Elasticsearch-Fluentbit-Kibana) - and, 4) backup/restore solution, Velero and Restic. + , 4) backup/restore solution, Velero and Restic and, 5) service mesh architecture, Linkerd .


From 095b28a7923b090e4c03ae3f6e1394704ca5c878 Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 5 Apr 2022 15:36:52 +0200 Subject: [PATCH 44/45] Prometheus role changing dashboards directory name --- .../{files => dashboards}/k3s-controllermanager-dashboard.json | 0 roles/prometheus/{files => dashboards}/k3s-proxy-dashboard.json | 0 .../{files => dashboards}/k3s-scheduler-dashboard.json | 0 roles/prometheus/{files => dashboards}/longhorn-dashboard.json | 0 roles/prometheus/{files => dashboards}/minio-dashboard.json | 0 roles/prometheus/{files => dashboards}/traefik-dashboard.json | 0 roles/prometheus/{files => dashboards}/velero-dashboard.json | 0 roles/prometheus/tasks/main.yml | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename roles/prometheus/{files => dashboards}/k3s-controllermanager-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/k3s-proxy-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/k3s-scheduler-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/longhorn-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/minio-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/traefik-dashboard.json (100%) rename roles/prometheus/{files => dashboards}/velero-dashboard.json (100%) diff --git a/roles/prometheus/files/k3s-controllermanager-dashboard.json b/roles/prometheus/dashboards/k3s-controllermanager-dashboard.json similarity index 100% rename from roles/prometheus/files/k3s-controllermanager-dashboard.json rename to roles/prometheus/dashboards/k3s-controllermanager-dashboard.json diff --git a/roles/prometheus/files/k3s-proxy-dashboard.json b/roles/prometheus/dashboards/k3s-proxy-dashboard.json similarity index 100% rename from roles/prometheus/files/k3s-proxy-dashboard.json rename to roles/prometheus/dashboards/k3s-proxy-dashboard.json diff --git a/roles/prometheus/files/k3s-scheduler-dashboard.json b/roles/prometheus/dashboards/k3s-scheduler-dashboard.json similarity index 100% rename from roles/prometheus/files/k3s-scheduler-dashboard.json rename to roles/prometheus/dashboards/k3s-scheduler-dashboard.json diff --git a/roles/prometheus/files/longhorn-dashboard.json b/roles/prometheus/dashboards/longhorn-dashboard.json similarity index 100% rename from roles/prometheus/files/longhorn-dashboard.json rename to roles/prometheus/dashboards/longhorn-dashboard.json diff --git a/roles/prometheus/files/minio-dashboard.json b/roles/prometheus/dashboards/minio-dashboard.json similarity index 100% rename from roles/prometheus/files/minio-dashboard.json rename to roles/prometheus/dashboards/minio-dashboard.json diff --git a/roles/prometheus/files/traefik-dashboard.json b/roles/prometheus/dashboards/traefik-dashboard.json similarity index 100% rename from roles/prometheus/files/traefik-dashboard.json rename to roles/prometheus/dashboards/traefik-dashboard.json diff --git a/roles/prometheus/files/velero-dashboard.json b/roles/prometheus/dashboards/velero-dashboard.json similarity index 100% rename from roles/prometheus/files/velero-dashboard.json rename to roles/prometheus/dashboards/velero-dashboard.json diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index cc26d029..59287711 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -77,4 +77,4 @@ loop_control: loop_var: dashboard_file with_fileglob: - - "files/*" + - "dashboards/*" From e6238f817adae3a19c7f6f7506c93f8f94ed2f3e Mon Sep 17 00:00:00 2001 From: ricsanfre Date: Tue, 5 Apr 2022 16:35:58 +0200 Subject: [PATCH 45/45] Adding linkerd grafana dashboards --- .../dashboards/linkerd/linkerd-authority.json | 1316 ++++++ .../dashboards/linkerd/linkerd-cronjob.json | 2355 ++++++++++ .../dashboards/linkerd/linkerd-daemonset.json | 2354 ++++++++++ .../linkerd/linkerd-deployment.json | 2354 ++++++++++ .../dashboards/linkerd/linkerd-health.json | 2419 +++++++++++ .../dashboards/linkerd/linkerd-job.json | 2354 ++++++++++ .../linkerd/linkerd-kubernetes.json | 2302 ++++++++++ .../linkerd/linkerd-multicluster.json | 998 +++++ .../dashboards/linkerd/linkerd-namespace.json | 1029 +++++ .../dashboards/linkerd/linkerd-pod.json | 2329 ++++++++++ .../linkerd/linkerd-prometheus-benchmark.json | 3777 +++++++++++++++++ .../linkerd/linkerd-prometheus.json | 1392 ++++++ .../linkerd/linkerd-replicaset.json | 2400 +++++++++++ .../linkerd-replicationcontroller.json | 2354 ++++++++++ .../dashboards/linkerd/linkerd-route.json | 1317 ++++++ .../dashboards/linkerd/linkerd-service.json | 1366 ++++++ .../linkerd/linkerd-statefulset.json | 2354 ++++++++++ .../dashboards/linkerd/linkerd-top-line.json | 1141 +++++ roles/prometheus/tasks/main.yml | 1 + 19 files changed, 35912 insertions(+) create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-authority.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-cronjob.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-daemonset.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-deployment.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-health.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-job.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-kubernetes.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-multicluster.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-namespace.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-pod.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-prometheus-benchmark.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-prometheus.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-replicaset.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-replicationcontroller.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-route.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-service.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-statefulset.json create mode 100644 roles/prometheus/dashboards/linkerd/linkerd-top-line.json diff --git a/roles/prometheus/dashboards/linkerd/linkerd-authority.json b/roles/prometheus/dashboards/linkerd/linkerd-authority.json new file mode 100644 index 00000000..9d719f11 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-authority.json @@ -0,0 +1,1316 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1539806914987, + "links": [], + "panels": [ + { + "content": "
\n  \n au/$authority\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 2 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " ms", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (le, authority))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "P95 LATENCY", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP-LINE TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 10, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (authority) / sum(irate(response_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (authority)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "au/{{authority}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\", tls=\"true\"}[30s])) by (authority)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒au/{{authority}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\", tls!=\"true\"}[30s])) by (authority)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "au/{{authority}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (le, authority))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 au/{{authority}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (le, authority))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 au/{{authority}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"inbound\"}[30s])) by (le, authority))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 au/{{authority}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY DEPLOYMENT\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 18, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (deployment) / sum(irate(response_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\", tls=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\", tls!=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY POD\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 26, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (pod) / sum(irate(response_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 26 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\", tls=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\", tls!=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", authority=\"$authority\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 33 + }, + "height": "1px", + "id": 34, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(request_total, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Authority", + "multi": false, + "name": "authority", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\"}, authority)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Authority", + "uid": "linkerd-authority", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-cronjob.json b/roles/prometheus/dashboards/linkerd/linkerd-cronjob.json new file mode 100644 index 00000000..f3da12bb --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-cronjob.json @@ -0,0 +1,2355 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531763681685, + "links": [], + "panels": [ + { + "content": "
\n  \n cj/$cronjob\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", cronjob!=\"\", dst_cronjob!=\"\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}) by (namespace, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND CRONJOBS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}) by (namespace, dst_cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND CRONJOBS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) by (cronjob) / sum(irate(response_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) by (cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{cronjob}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\", tls=\"true\"}[30s])) by (cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒cj/{{cronjob}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\", tls!=\"true\"}[30s])) by (cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{cronjob}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 cj/{{cronjob}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 cj/{{cronjob}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 cj/{{cronjob}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND CRONJOBS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n cj/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (cronjob, pod) / sum(irate(response_total{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (cronjob, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\", tls=\"true\"}[30s])) by (cronjob, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\", tls!=\"true\"}[30s])) by (cronjob, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 cj/{{cronjob}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 cj/{{cronjob}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{cronjob!=\"\", cronjob=\"$inbound\", dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (le, cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 cj/{{cronjob}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "cj/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (dst_cronjob) / sum(irate(response_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{dst_cronjob}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒cj/{{dst_cronjob}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{dst_cronjob}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}[30s])) by (le, dst_cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 cj/{{dst_cronjob}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND CRONJOBS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n cj/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_cronjob) / sum(irate(response_total{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{dst_cronjob}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒cj/{{dst_cronjob}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_cronjob)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "cj/{{dst_cronjob}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 cj/{{dst_cronjob}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 cj/{{dst_cronjob}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", cronjob=\"$cronjob\", dst_cronjob=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_cronjob))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 cj/{{dst_cronjob}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "cj/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{cronjob!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Deployment", + "multi": false, + "name": "cronjob", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, cronjob)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_cronjob=\"$cronjob\"}, cronjob)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", cronjob=\"$cronjob\"}, dst_cronjob)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd CronJob", + "uid": "linkerd-cronjob", + "version": 1 + } + diff --git a/roles/prometheus/dashboards/linkerd/linkerd-daemonset.json b/roles/prometheus/dashboards/linkerd/linkerd-daemonset.json new file mode 100644 index 00000000..3f4eab3c --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-daemonset.json @@ -0,0 +1,2354 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1547542312069, + "links": [], + "panels": [ + { + "content": "
\n  \n ds/$daemonset\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", daemonset!=\"\", dst_daemonset!=\"\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}) by (namespace, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND DAEMONSETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}) by (namespace, dst_daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND DAEMONSETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) by (daemonset) / sum(irate(response_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) by (daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{daemonset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\", tls=\"true\"}[30s])) by (daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒ds/{{daemonset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\", tls!=\"true\"}[30s])) by (daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{daemonset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ds/{{daemonset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 ds/{{daemonset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 ds/{{daemonset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND DAEMONSETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n ds/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (daemonset, pod) / sum(irate(response_total{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (daemonset, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\", tls=\"true\"}[30s])) by (daemonset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (daemonset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 ds/{{daemonset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 ds/{{daemonset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{daemonset!=\"\", daemonset=\"$inbound\", dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (le, daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 ds/{{daemonset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "ds/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (dst_daemonset) / sum(irate(response_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{dst_daemonset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒ds/{{dst_daemonset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{dst_daemonset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}[30s])) by (le, dst_daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 ds/{{dst_daemonset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND DAEMONSETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n ds/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_daemonset) / sum(irate(response_total{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{dst_daemonset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒ds/{{dst_daemonset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_daemonset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ds/{{dst_daemonset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 ds/{{dst_daemonset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 ds/{{dst_daemonset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", daemonset=\"$daemonset\", dst_daemonset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_daemonset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 ds/{{dst_daemonset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "ds/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{daemonset!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "DaemonSet", + "multi": false, + "name": "daemonset", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, daemonset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_daemonset=\"$daemonset\"}, daemonset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", daemonset=\"$daemonset\"}, dst_daemonset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd DaemonSet", + "uid": "linkerd-daemonset", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-deployment.json b/roles/prometheus/dashboards/linkerd/linkerd-deployment.json new file mode 100644 index 00000000..4d8cb63c --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-deployment.json @@ -0,0 +1,2354 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531763681685, + "links": [], + "panels": [ + { + "content": "
\n  \n deploy/$deployment\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", deployment!=\"\", dst_deployment!=\"\", dst_deployment=\"$deployment\", direction=\"outbound\"}) by (namespace, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND DEPLOYMENTS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}) by (namespace, dst_deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND DEPLOYMENTS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (deployment) / sum(irate(response_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\", tls=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\", tls!=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 deploy/{{deployment}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 deploy/{{deployment}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND DEPLOYMENTS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n deploy/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (deployment, pod) / sum(irate(response_total{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (deployment, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\", tls=\"true\"}[30s])) by (deployment, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\", tls!=\"true\"}[30s])) by (deployment, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{deployment}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{deployment!=\"\", deployment=\"$inbound\", dst_namespace=\"$namespace\", dst_deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 deploy/{{deployment}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "deploy/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (dst_deployment) / sum(irate(response_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{dst_deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{dst_deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{dst_deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}[30s])) by (le, dst_deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{dst_deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND DEPLOYMENTS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n deploy/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_deployment) / sum(irate(response_total{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{dst_deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{dst_deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{dst_deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 deploy/{{dst_deployment}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{dst_deployment}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", dst_deployment=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 deploy/{{dst_deployment}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "deploy/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{deployment!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Deployment", + "multi": false, + "name": "deployment", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_deployment=\"$deployment\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", deployment=\"$deployment\"}, dst_deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Deployment", + "uid": "linkerd-deployment", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-health.json b/roles/prometheus/dashboards/linkerd/linkerd-health.json new file mode 100644 index 00000000..1d520de7 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-health.json @@ -0,0 +1,2419 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531764407999, + "links": [], + "panels": [ + { + "content": "
\n Data-Plane Telemetry\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 400, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 397, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"linkerd-proxy\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}/{{pod}}/virtual", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"linkerd-proxy\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}/{{pod}}/resident", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MEMORY USAGE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 399, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(process_cpu_seconds_total{job=\"linkerd-proxy\"}[20s])) by (namespace, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU USAGE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 2 + }, + "id": 398, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"linkerd-proxy\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "OPEN FILE DESCRIPTORS", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n Control-Plane Traffic\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 401, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 11 + }, + "id": 23, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", deployment!=\"\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}[30s])) by (pod) / sum(irate(response_total{deployment!=\"\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 11 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{deployment!=\"\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{deployment!=\"\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n Control-Plane TCP Metrics\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 731, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 179, + "panels": [ + { + "content": "
\n  \n deploy/$deployment\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 282, + "links": [], + "mode": "html", + "options": {}, + "repeatedByRow": true, + "scopedVars": { + "deployment": { + "selected": false + } + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 227, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{deployment=\"$deployment\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 132, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{deployment=\"$deployment\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "OPEN TCP CONNECTIONS", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 229, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "scopedVars": { + "deployment": { + "selected": false + } + }, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{deployment=\"$deployment\", namespace=~\"$namespace|$namespace-viz\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "repeat": "deployment", + "scopedVars": { + "deployment": { + "selected": false + } + }, + "title": "$deployment", + "type": "row" + }, + { + "content": "
\n Control-Plane Telemetry\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 27, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 30 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"linkerd-controller\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "goroutines", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 30 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{job=\"linkerd-controller\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}/resident", + "refId": "A" + }, + { + "expr": "process_virtual_memory_bytes{job=\"linkerd-controller\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}/virtual", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Process Memory", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 30 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"linkerd-controller\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Open FDs", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 37 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_threads{job=\"linkerd-controller\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Threads", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n Control-Plane Clients/Servers\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 625, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 46 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(http_server_requests_total{job=\"linkerd-controller\"}[30s])) by (component, method, code)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}/{{method}}/{{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Server Request Rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 46 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(http_server_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 {{component}}/{{method}}/{{code}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 {{component}}/{{method}}/{{code}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 {{component}}/{{method}}/{{code}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Server Latency", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 46 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(http_server_response_size_bytes_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 {{component}}/{{method}}/{{code}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_response_size_bytes_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 {{component}}/{{method}}/{{code}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_response_size_bytes_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 {{component}}/{{method}}/{{code}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Server Response Size", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 53 + }, + "id": 623, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(http_client_requests_total{job=\"linkerd-controller\"}[30s])) by (component, client, method, code)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}/{{client}}/{{method}}/{{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Client Request Rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 53 + }, + "id": 570, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(http_client_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, client, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 {{component}}/{{client}}/{{method}}/{{code}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_client_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, client, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 {{component}}/{{client}}/{{method}}/{{code}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_client_request_latency_seconds_bucket{job=\"linkerd-controller\"}[30s])) by (le, component, client, method, code))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 {{component}}/{{client}}/{{method}}/{{code}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Client Latency", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 53 + }, + "id": 621, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(http_client_in_flight_requests{job=\"linkerd-controller\"}) by (component, client)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{component}}/{{client}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Client In-Flight Requests", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 458, + "panels": [], + "repeat": "component", + "scopedVars": { + "component": { + "selected": false + } + }, + "title": "", + "type": "row" + }, + { + "content": "
\n  \n $component\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 30, + "links": [], + "mode": "html", + "options": {}, + "scopedVars": { + "component": { + "selected": false + } + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 63 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "component": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_memstats_alloc_bytes{job=\"linkerd-controller\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "alloc/{{component}}", + "refId": "A" + }, + { + "expr": "irate(go_memstats_alloc_bytes_total{job=\"linkerd-controller\", component=\"$component\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "alloc rate/{{component}}", + "refId": "B" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"linkerd-controller\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "stack/{{component}}", + "refId": "C" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"linkerd-controller\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "heap/{{component}}", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Go Memstats", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 63 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "component": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_gc_duration_seconds{job=\"linkerd-controller\", quantile=\"0.5\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 {{component}}", + "refId": "A" + }, + { + "expr": "go_gc_duration_seconds{job=\"linkerd-controller\", quantile=\"0.75\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P75 {{component}}", + "refId": "B" + }, + { + "expr": "go_gc_duration_seconds{job=\"linkerd-controller\", quantile=\"1\", component=\"$component\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max {{component}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GC Duration", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 63 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "component": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(grpc_server_msg_sent_total{job=\"linkerd-controller\", component=\"$component\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sent/{{component}}/{{grpc_method}}", + "refId": "A" + }, + { + "expr": "irate(grpc_server_msg_received_total{job=\"linkerd-controller\", component=\"$component\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "received/{{component}}/{{grpc_method}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "gRPC Message Volume", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 141.4 + }, + "id": 515, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 142.4 + }, + "height": "1px", + "id": 519, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": "Deployment", + "multi": false, + "name": "deployment", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=~\"$namespace|$namespace-viz\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": "Component", + "multi": false, + "name": "component", + "options": [], + "query": "label_values(component)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Linkerd Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{control_plane_ns!=\"\"}, control_plane_ns)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Linkerd Viz Namespace", + "multi": false, + "name": "namespace-viz", + "options": [], + "query": "label_values(process_start_time_seconds{control_plane_ns!=\"\",extension!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Health", + "uid": "linkerd-health", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-job.json b/roles/prometheus/dashboards/linkerd/linkerd-job.json new file mode 100644 index 00000000..375e39ba --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-job.json @@ -0,0 +1,2354 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1547542312069, + "links": [], + "panels": [ + { + "content": "
\n  \n job/$job\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", k8s_job!=\"\", dst_k8s_job!=\"\", dst_k8s_job=\"$job\", direction=\"outbound\"}) by (namespace, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND JOBS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}) by (namespace, dst_k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND JOBS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) by (k8s_job) / sum(irate(response_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) by (k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{k8s_job}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\", tls=\"true\"}[30s])) by (k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒job/{{k8s_job}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\", tls!=\"true\"}[30s])) by (k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{k8s_job}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 job/{{k8s_job}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 job/{{k8s_job}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 job/{{k8s_job}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND JOBS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n job/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (k8s_job, pod) / sum(irate(response_total{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (k8s_job, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\", tls=\"true\"}[30s])) by (k8s_job, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\", tls!=\"true\"}[30s])) by (k8s_job, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 job/{{k8s_job}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 job/{{k8s_job}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{k8s_job!=\"\", k8s_job=\"$inbound\", dst_namespace=\"$namespace\", dst_k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (le, k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 job/{{k8s_job}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "job/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (dst_k8s_job) / sum(irate(response_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{dst_k8s_job}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒job/{{dst_k8s_job}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{dst_k8s_job}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}[30s])) by (le, dst_k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 job/{{dst_k8s_job}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND JOBS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n job/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_k8s_job) / sum(irate(response_total{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{dst_k8s_job}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒job/{{dst_k8s_job}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_k8s_job)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "job/{{dst_k8s_job}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 job/{{dst_k8s_job}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 job/{{dst_k8s_job}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", k8s_job=\"$job\", dst_k8s_job=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_k8s_job))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 job/{{dst_k8s_job}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "job/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{k8s_job!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Job", + "multi": false, + "name": "job", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, k8s_job)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_k8s_job=\"$job\"}, k8s_job)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", k8s_job=\"$job\"}, dst_k8s_job)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Job", + "uid": "linkerd-job", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-kubernetes.json b/roles/prometheus/dashboards/linkerd/linkerd-kubernetes.json new file mode 100644 index 00000000..c6f6b317 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-kubernetes.json @@ -0,0 +1,2302 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "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.", + "editable": true, + "gnetId": 315, + "graphTooltip": 0, + "id": null, + "iteration": 1565301085323, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 33, + "panels": [], + "title": "Network I/O pressure", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "height": "200px", + "id": 32, + "isNew": true, + "legend": { + "alignAsTable": false, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (rate (container_network_receive_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[1m]))", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "Received", + "metric": "network", + "refId": "A", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[1m]))", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "Sent", + "metric": "network", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O pressure", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 34, + "panels": [], + "title": "Total usage", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 7 + }, + "height": "180px", + "id": 4, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) / sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"}) * 100", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "Cluster memory usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 7 + }, + "height": "180px", + "id": 6, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) / sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"}) * 100", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "Cluster CPU usage (1m avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 7 + }, + "height": "180px", + "id": 7, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "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", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "Cluster filesystem usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 12 + }, + "height": "1px", + "id": 9, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "20%", + "prefix": "", + "prefixFontSize": "20%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 12 + }, + "height": "1px", + "id": 10, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 12 + }, + "height": "1px", + "id": 11, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " cores", + "postfixFontSize": "30%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m]))", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 12 + }, + "height": "1px", + "id": 12, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " cores", + "postfixFontSize": "30%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 12 + }, + "height": "1px", + "id": 13, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (container_fs_usage_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 12 + }, + "height": "1px", + "id": 14, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum (container_fs_limit_bytes{device=~\"^/dev/[sv]d[a-z][1-9]$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 35, + "panels": [], + "title": "Pods CPU usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 3, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 16 + }, + "height": "", + "id": 17, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name, pod)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}{{ pod }}", + "metric": "container_cpu", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pods CPU usage (1m avg)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 36, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 3, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 23 + }, + "height": "", + "id": 23, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{systemd_service_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (systemd_service_name)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ systemd_service_name }}", + "metric": "container_cpu", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "System services CPU usage (1m avg)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "System services CPU usage", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 37, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 3, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 24 + }, + "height": "", + "id": 24, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",container_name!=\"POD\",container!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, container, pod_name, pod)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "pod: {{ pod_name }}{{ pod }} | {{ container_name }}{{ container }}", + "metric": "container_cpu", + "refId": "A", + "step": 10 + }, + { + "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", + "metric": "container_cpu", + "refId": "B", + "step": 10 + }, + { + "expr": "sum (rate (container_cpu_usage_seconds_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", + "metric": "container_cpu", + "refId": "C", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Containers CPU usage (1m avg)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "Containers CPU usage", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 38, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 3, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 20, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (rate (container_cpu_usage_seconds_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ id }}", + "metric": "container_cpu", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "All processes CPU usage (1m avg)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "title": "All processes CPU usage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 39, + "panels": [], + "title": "Pods memory usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 25, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (pod_name, pod)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ pod_name }}{{ pod }}", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pods memory usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 40, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 26, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{systemd_service_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (systemd_service_name)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ systemd_service_name }}", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "System services memory usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "System services memory usage", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 41, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 27, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{image!=\"\",container_name!=\"POD\",container!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}) by (container_name, container, pod_name, pod)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "pod: {{ pod_name }}{{ pod }} | {{ container_name }}{{ container }}", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + }, + { + "expr": "sum (container_memory_working_set_bytes{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, name, image)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", + "metric": "container_memory_usage:sort_desc", + "refId": "B", + "step": 10 + }, + { + "expr": "sum (container_memory_working_set_bytes{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, rkt_container_name)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", + "metric": "container_memory_usage:sort_desc", + "refId": "C", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Containers memory usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "Containers memory usage", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 42, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 28, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) by (id)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ id }}", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "All processes memory usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "All processes memory usage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 43, + "panels": [], + "title": "Pods network I/O", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 16, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name, pod)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "-> {{ pod_name }}{{ pod }}", + "metric": "network", + "refId": "A", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name, pod)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "<- {{ pod_name }}{{ pod }}", + "metric": "network", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Pods network I/O (1m avg)", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 44, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 30, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, container, pod_name, pod)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "-> pod: {{ pod_name }}{{ pod }} | {{ container_name }}{{ container }}", + "metric": "network", + "refId": "B", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (container_name, container, pod_name, pod)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "<- pod: {{ pod_name }}{{ pod }} | {{ container_name }}{{ container }}", + "metric": "network", + "refId": "D", + "step": 10 + }, + { + "expr": "sum (rate (container_network_receive_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "-> docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", + "metric": "network", + "refId": "A", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, name, image)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "<- docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", + "metric": "network", + "refId": "C", + "step": 10 + }, + { + "expr": "sum (rate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "-> rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", + "metric": "network", + "refId": "E", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (kubernetes_io_hostname, rkt_container_name)", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "<- rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", + "metric": "network", + "refId": "F", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Containers network I/O (1m avg)", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "Containers network I/O", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 46 + }, + "id": 45, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 46 + }, + "id": 29, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (rate (container_network_receive_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "-> {{ id }}", + "metric": "network", + "refId": "A", + "step": 10 + }, + { + "expr": "- sum (rate (container_network_transmit_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (id)", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "<- {{ id }}", + "metric": "network", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "All processes network I/O (1m avg)", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "title": "All processes network I/O", + "type": "row" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "Node", + "options": [], + "query": "label_values(kubernetes_io_hostname)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Kubernetes cluster monitoring (via Prometheus)", + "uid": "k8s", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-multicluster.json b/roles/prometheus/dashboards/linkerd/linkerd-multicluster.json new file mode 100644 index 00000000..9e719642 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-multicluster.json @@ -0,0 +1,998 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531434867463, + "links": [], + "panels": [ + { + "content": "
\n  \n Cluster: $cluster\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) / sum(irate(response_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 2 + }, + "id": 81, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " ms", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (le))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "P95 LATENCY", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP-LINE TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\",dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) / sum(irate(response_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\", tls=\"true\"}[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", tls!=\"true\"}[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 gateway", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 gateway", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 gateway", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n TRAFFIC BY TARGET SERVICE\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (dst_target_service) / sum(irate(response_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (dst_target_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "target-svc/{{dst_target_service}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", tls=\"true\"}[30s])) by (dst_target_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒target-svc/{{dst_target_service}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", tls!=\"true\"}[30s])) by (dst_target_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "target-svc/{{dst_target_service}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{dst_target_cluster=\"$cluster\", dst_target_cluster!=\"\", direction=\"outbound\"}[30s])) by (le, dst_target_service))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 target-svc/{{dst_target_service}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": "label_values(request_total, dst_target_cluster)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Multicluster", + "uid": "linkerd-multicluster", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-namespace.json b/roles/prometheus/dashboards/linkerd/linkerd-namespace.json new file mode 100644 index 00000000..c4261dbc --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-namespace.json @@ -0,0 +1,1029 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1566417010901, + "links": [], + "panels": [ + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "1px", + "id": 14, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "height": "", + "id": 28, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=~\"$namespace\", deployment=~\"$deployment\"}[30s])) / sum(irate(response_total{namespace=~\"$namespace\", deployment=~\"$deployment\"}[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": ".9,.99", + "title": "GLOBAL SUCCESS RATE", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "rps", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "height": "", + "id": 29, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=~\"$namespace\", deployment=~\"$deployment\"}[30s]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "GLOBAL REQUEST VOLUME", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "height": "", + "id": 86, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=~\"$namespace\", deployment=~\"$deployment\"}) by (namespace, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "DEPLOYMENTS MONITORED", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP LINE\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 7 + }, + "height": "1px", + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 9 + }, + "id": 21, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=~\"$namespace\", deployment=~\"$deployment\", direction=\"inbound\"}[30s])) by (deployment) / sum(irate(response_total{namespace=~\"$namespace\", deployment=~\"$deployment\", direction=\"inbound\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=~\"$namespace\", deployment=~\"$deployment\", direction=\"inbound\", tls=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=~\"$namespace\", deployment=~\"$deployment\", direction=\"inbound\", tls!=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST VOLUME", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 23, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=~\"$namespace\", deployment=~\"$deployment\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n DEPLOYMENTS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 16 + }, + "height": "1px", + "id": 19, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 40, + "panels": [], + "repeat": "deployment", + "title": "", + "type": "row" + }, + { + "content": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 19 + }, + "height": "1px", + "id": 13, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (deployment) / sum(irate(response_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\", tls=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\", tls!=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST VOLUME", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", deployment=\"$deployment\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(process_start_time_seconds{deployment!=\"\"}, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{deployment!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, deployment)", + "hide": 0, + "includeAll": true, + "label": "Deployments", + "multi": true, + "name": "deployment", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Namespace", + "uid": "linkerd-namespace", + "version": 15 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-pod.json b/roles/prometheus/dashboards/linkerd/linkerd-pod.json new file mode 100644 index 00000000..f57e9ea9 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-pod.json @@ -0,0 +1,2329 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531434418636, + "links": [], + "panels": [ + { + "content": "
\n  \n po/$pod\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}) by (namespace, pod))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND PODS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}) by (namespace, dst_pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND PODS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) by (pod) / sum(irate(response_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\", tls=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\", tls!=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 po/{{pod}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) by (le, pod))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 po/{{pod}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"inbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 po/{{pod}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 201, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 173, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", pod=\"$pod\" ,deployment=\"$deployment\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 175, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", pod=\"$pod\" ,deployment=\"$deployment\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 177, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", pod=\"$pod\" ,deployment=\"$deployment\", direction=\"inbound\"}", + "format": "heatmap", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 199, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND PODS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 19 + }, + "id": 81, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}[30s])) by (pod) / sum(irate(response_total{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}[30s])) by (pod)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 19 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\", tls=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\", tls!=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 19 + }, + "id": 83, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 po/{{pod}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 po/{{pod}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{dst_namespace=\"$namespace\", dst_pod!=\"\", dst_pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 po/{{pod}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 88, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 89, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (pod) / sum(irate(response_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (pod)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\", tls=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\", tls!=\"true\"}[30s])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 po/{{pod}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 po/{{pod}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 po/{{pod}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 197, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 36 + }, + "id": 191, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", pod=\"$pod\", deployment=\"$deployment\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 36 + }, + "id": 183, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", pod=\"$pod\" ,deployment=\"$deployment\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 36 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 189, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", deployment=\"$deployment\", direction=\"outbound\"}", + "format": "heatmap", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 187, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND PODS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 84, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 39 + }, + "id": 85, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (dst_pod) / sum(irate(response_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (dst_pod)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "po/{{dst_pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 39 + }, + "id": 86, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{dst_pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{dst_pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 39 + }, + "id": 87, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, dst_pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 po/{{dst_pod}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, dst_pod))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 po/{{dst_pod}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", pod=\"$pod\", direction=\"outbound\"}[30s])) by (le, dst_pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 po/{{dst_pod}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 46 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Pod", + "multi": false, + "name": "pod", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, deployment)", + "hide": 2, + "includeAll": false, + "label": "deployment", + "multi": false, + "name": "deployment", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(request_total{dst_namespace=\"$namespace\", dst_deployment=\"$deployment\"}, deployment)", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(request_total{namespace=\"$namespace\", deployment=\"$deployment\"}, dst_deployment)", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", deployment=\"$deployment\"}, dst_deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Pod", + "uid": "linkerd-pod", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-prometheus-benchmark.json b/roles/prometheus/dashboards/linkerd/linkerd-prometheus-benchmark.json new file mode 100644 index 00000000..4e2025ff --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-prometheus-benchmark.json @@ -0,0 +1,3777 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Metrics useful for benchmarking and loadtesting Prometheus itself. Designed primarily for Prometheus 2.7.x.", + "editable": true, + "gnetId": 9761, + "graphTooltip": 1, + "id": null, + "iteration": 1549379947837, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 49, + "panels": [], + "title": "Basics", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_build_info{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{version}} - {{revision}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Prometheus Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "time() - process_start_time_seconds{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Uptime", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Uptime", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "dtdurations", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "time() - prometheus_config_last_reload_success_timestamp_seconds{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Age", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Last Successful Config Reload", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "dtdurations", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 46, + "panels": [], + "title": "Ingestion", + "type": "row" + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "Time series": "#70dbed" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 9 + }, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_series{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Time series", + "metric": "prometheus_local_storage_memory_series", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Time series", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_active_appenders{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Head Appenders", + "metric": "prometheus_local_storage_memory_series", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Active Appenders", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "samples/s": "#e5a8e2" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_head_samples_appended_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "samples/s", + "metric": "prometheus_local_storage_ingested_samples_total", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Samples Appended/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "To persist": "#9AC48A" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/Max.*/", + "fill": 0 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_chunks{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Chunks", + "metric": "prometheus_local_storage_memory_chunks", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Chunks", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_head_chunks_created_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Created", + "metric": "prometheus_local_storage_chunk_ops_total", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Chunks Created", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "Removed": "#e5ac0e" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_head_chunks_removed_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Removed", + "metric": "prometheus_local_storage_chunk_ops_total", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Chunks Removed", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 52, + "panels": [], + "title": "Compaction", + "type": "row" + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max": "#447ebc", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "Min": "#447ebc", + "Now": "#7eb26d" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Max", + "fillBelowTo": "Min", + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_min_time{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Min", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + }, + { + "expr": "time() * 1000", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Now", + "refId": "C" + }, + { + "expr": "prometheus_tsdb_head_max_time{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Max", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Time Range", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "dateTimeAsIso", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_head_gc_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "GC Time/s", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head GC Time/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Queue length", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_blocks_loaded{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Blocks Loaded", + "metric": "prometheus_local_storage_indexing_batch_sizes_sum", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Blocks Loaded", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Failed Compactions": "#bf1b00", + "Failed Reloads": "#bf1b00", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 31 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_reloads_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Reloads", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TSDB Reloads/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Failed Compactions": "#bf1b00", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 31 + }, + "id": 31, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_wal_fsync_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m]) / rate(prometheus_tsdb_wal_fsync_duration_seconds_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Fsync Latency", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_wal_truncate_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m]) / rate(prometheus_tsdb_wal_truncate_duration_seconds_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Truncate Latency", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "WAL Fsync&Truncate Latency", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Failed Compactions": "#bf1b00", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "{instance=\"demo.robustperception.io:9090\",job=\"prometheus\"}": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 31 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_wal_corruptions_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "WAL Corruptions", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_reloads_failures_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Reload Failures", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "B", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_head_series_not_found{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Head Series Not Found", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "C", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_compactions_failed_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Compaction Failures", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "D", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_retention_cutoffs_failures_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Retention Cutoff Failures", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "E", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_checkpoint_creations_failed_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "WAL Checkpoint Creation Failures", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "F", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_checkpoint_deletions_failed_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "WAL Checkpoint Deletion Failures", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "G", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TSDB Problems/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Failed Compactions": "#bf1b00", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 19, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_compactions_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Compactions", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Compactions/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 33, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_compaction_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Compaction Time/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Allocated bytes": "#F9BA8F", + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "RSS": "#890F02" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_time_retentions_total[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Time Cutoffs", + "metric": "last", + "refId": "A", + "step": 10 + }, + { + "expr": "rate(prometheus_tsdb_size_retentions_total[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Size Cutoffs", + "metric": "last", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Retention Cutoffs/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 45 + }, + "id": 27, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_compaction_chunk_range_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m]) / rate(prometheus_tsdb_compaction_chunk_range_seconds_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Chunk Time Range", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "First Compaction, Avg Chunk Time Range", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "dtdurationms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 45 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_compaction_chunk_size_bytes_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m]) / rate(prometheus_tsdb_compaction_chunk_samples_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Bytes/Sample", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "First Compaction, Avg Bytes/Sample", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 45 + }, + "id": 34, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_compaction_chunk_samples_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m]) / rate(prometheus_tsdb_compaction_chunk_samples_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[10m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Chunk Samples", + "metric": "prometheus_local_storage_series_chunks_persisted_count", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "First Compaction, Avg Chunk Samples", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 55, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": { + "Allocated bytes": "#7EB26D", + "Allocated bytes - 1m max": "#BF1B00", + "Allocated bytes - 1m min": "#BF1B00", + "Allocated bytes - 5m max": "#BF1B00", + "Allocated bytes - 5m min": "#BF1B00", + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "RSS": "#447EBC" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 53 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/-/", + "fill": 0 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "intervalFactor": 2, + "legendFormat": "RSS", + "metric": "process_resident_memory_bytes", + "refId": "B", + "step": 10 + }, + { + "expr": "prometheus_local_storage_target_heap_size_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "intervalFactor": 2, + "legendFormat": "Target heap size", + "metric": "go_memstats_alloc_bytes", + "refId": "D", + "step": 10 + }, + { + "expr": "go_memstats_next_gc_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "intervalFactor": 2, + "legendFormat": "Next GC", + "metric": "go_memstats_next_gc_bytes", + "refId": "C", + "step": 10 + }, + { + "expr": "go_memstats_alloc_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "intervalFactor": 2, + "legendFormat": "Allocated", + "metric": "go_memstats_alloc_bytes", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Allocated bytes": "#F9BA8F", + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833", + "RSS": "#890F02" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 53 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(go_memstats_alloc_bytes_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "intervalFactor": 2, + "legendFormat": "Allocated Bytes/s", + "metric": "go_memstats_alloc_bytes", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Allocations", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 53 + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(process_cpu_seconds_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "intervalFactor": 2, + "legendFormat": "Irate", + "metric": "prometheus_local_storage_ingested_samples_total", + "refId": "A", + "step": 10 + }, + { + "expr": "rate(process_cpu_seconds_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[5m])", + "intervalFactor": 2, + "legendFormat": "5m rate", + "metric": "prometheus_local_storage_ingested_samples_total", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "avg" + ] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 60 + }, + "id": 70, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_symbol_table_size_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "RAM Used", + "metric": "prometheus_local_storage_ingested_samples_total", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Symbol Tables Size", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "avg" + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 60 + }, + "id": 71, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_storage_blocks_bytes_total{job=\"prometheus\",instance=\"$Prometheus:9090\"} or prometheus_tsdb_storage_blocks_bytes{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Disk Used", + "metric": "prometheus_local_storage_ingested_samples_total", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Block Size", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "avg" + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Max": "#e24d42", + "Open": "#508642" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 60 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_max_fds{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max", + "refId": "A" + }, + { + "expr": "process_open_fds{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Open", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "File Descriptors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 67 + }, + "id": 58, + "panels": [], + "title": "HTTP Server", + "type": "row" + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 68 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_http_request_duration_seconds_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{handler}}", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP requests/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 68 + }, + "id": 37, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_http_request_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m]) / rate(prometheus_http_request_duration_seconds_count{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{handler}}", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP request latency", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 68 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_http_request_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{handler}}", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Time spent in HTTP requests/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 75 + }, + "id": 63, + "panels": [], + "title": "Query Engine", + "type": "row" + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "Time spent in each mode, per second", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 76 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_engine_query_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{slice}}", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Query engine timings/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 76 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_rule_group_iterations_missed_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m]) ", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Rule group missed", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "B", + "step": 10 + }, + { + "expr": "rate(prometheus_rule_evaluation_failures_total{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Rule evals failed", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "C", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rule group evaluation problems/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 76 + }, + "id": 23, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_rule_group_duration_seconds_sum{job=\"prometheus\",instance=\"$Prometheus:9090\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Rule evaluation duration", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Evaluation time of rule groups/s", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 83 + }, + "id": 61, + "panels": [], + "repeat": "RuleGroup", + "title": "Rule Group: $RuleGroup", + "type": "row" + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Interval": "#890f02", + "Last Duration": "#f9934e", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 84 + }, + "id": 43, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "repeatDirection": "h", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_rule_group_interval_seconds{job=\"prometheus\",instance=\"$Prometheus:9090\",rule_group=~\"$RuleGroup\"}\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Interval", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + }, + { + "expr": "prometheus_rule_group_last_duration_seconds{job=\"prometheus\",instance=\"$Prometheus:9090\",rule_group=~\"$RuleGroup\"}\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Last Duration", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "$RuleGroup: Duration", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Chunks": "#1F78C1", + "Chunks to persist": "#508642", + "Interval": "#890f02", + "Last Duration": "#f9934e", + "Max chunks": "#052B51", + "Max to persist": "#3F6833" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 84 + }, + "id": 66, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeatDirection": "h", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_rule_group_rules{job=\"prometheus\",instance=\"$Prometheus:9090\",rule_group=~\"$RuleGroup\"}\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Rules", + "metric": "prometheus_local_storage_memory_chunkdescs", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "$RuleGroup: Rules", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 91 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 16, + "style": "dark", + "tags": [ + "prometheus" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "Prometheus", + "options": [], + "query": "query_result(up{job=\"prometheus\"} == 1)", + "refresh": 2, + "regex": ".*instance=\"([^\"]+):9090\".*", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": null, + "tags": [], + "tagsQuery": null, + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "RuleGroup", + "options": [], + "query": "prometheus_rule_group_last_duration_seconds{job=\"prometheus\",instance=\"$Prometheus:9090\"}", + "refresh": 2, + "regex": ".*rule_group=\"(.*?)\".*", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Prometheus Benchmark - 2.7.x", + "uid": "prometheus-benchmark", + "version": 10 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-prometheus.json b/roles/prometheus/dashboards/linkerd/linkerd-prometheus.json new file mode 100644 index 00000000..d2939f37 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-prometheus.json @@ -0,0 +1,1392 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "info", + "tags": [], + "targetBlank": true, + "title": "Grafana Docs", + "tooltip": "", + "type": "link", + "url": "http://docs.grafana.org/" + }, + { + "icon": "info", + "tags": [], + "targetBlank": true, + "title": "Prometheus Docs", + "type": "link", + "url": "http://prometheus.io/docs/introduction/overview/" + } + ], + "panels": [ + { + "aliasColors": { + "prometheus": "#C15C17", + "{instance=\"localhost:9090\",job=\"prometheus\"}": "#CCA300" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(prometheus_tsdb_head_samples_appended_total{job=\"prometheus\"}[5m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "samples", + "metric": "", + "refId": "A", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Samples Appended", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(5, max(scrape_duration_seconds) by (job))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{job}}", + "metric": "", + "refId": "A", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Scrape Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fill": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_resident_memory_bytes{job=\"prometheus\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "p8s process resident memory", + "refId": "D", + "step": 20 + }, + { + "expr": "process_virtual_memory_bytes{job=\"prometheus\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "virtual memory", + "refId": "C", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Profile", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 37, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "prometheus_tsdb_wal_corruptions_total{job=\"prometheus\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 60 + } + ], + "thresholds": "0.1,1", + "title": "WAL Corruptions", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "None", + "value": "0" + } + ], + "valueName": "max" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 5 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(prometheus_tsdb_head_active_appenders{job=\"prometheus\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "active_appenders", + "metric": "", + "refId": "A", + "step": 20 + }, + { + "expr": "sum(process_open_fds{job=\"prometheus\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "open_fds", + "refId": "B", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Active Appenders", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "prometheus": "#F9BA8F", + "{instance=\"localhost:9090\",interval=\"5s\",job=\"prometheus\"}": "#F9BA8F" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 5 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_blocks_loaded{job=\"prometheus\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "blocks", + "refId": "A", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Blocks Loaded", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "description": "", + "fill": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 5 + }, + "id": 33, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_chunks{job=\"prometheus\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "chunks", + "refId": "A", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Chunks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 5 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "duration-p99", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_gc_duration_seconds{job=\"prometheus\",quantile=\"0.99\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "duration-p99", + "refId": "A", + "step": 20 + }, + { + "expr": "irate(prometheus_tsdb_head_gc_duration_seconds_count{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "collections", + "refId": "B", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Head Block GC Activity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "description": "", + "fill": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "duration-p99", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(prometheus_tsdb_compaction_duration_bucket{job=\"prometheus\"}[5m])) by (le))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "duration-{{p99}}", + "refId": "A", + "step": 20 + }, + { + "expr": "irate(prometheus_tsdb_compactions_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "compactions", + "refId": "B", + "step": 20 + }, + { + "expr": "irate(prometheus_tsdb_compactions_failed_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "failed", + "refId": "C", + "step": 20 + }, + { + "expr": "irate(prometheus_tsdb_compactions_triggered_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "triggered", + "refId": "D", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Compaction Activity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "s", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 10 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_reloads_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reloads", + "refId": "A", + "step": 20 + }, + { + "expr": "rate(prometheus_tsdb_reloads_failures_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "failures", + "refId": "B", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reload Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 10 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_engine_query_duration_seconds{job=\"prometheus\", quantile=\"0.99\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{slice}}_p99", + "refId": "A", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Query Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 35, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(prometheus_rule_group_duration_seconds{job=\"prometheus\"}) by (quantile)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{quantile}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rule Group Eval Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 39, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_rule_group_iterations_missed_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "missed", + "refId": "B", + "step": 10 + }, + { + "expr": "rate(prometheus_rule_group_iterations_total{job=\"prometheus\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "iterations", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rule Group Eval Activity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 22 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "revision": "1.0", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "prometheus" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Prometheus 2.0 Stats", + "uid": "prometheus", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-replicaset.json b/roles/prometheus/dashboards/linkerd/linkerd-replicaset.json new file mode 100644 index 00000000..9cbd9170 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-replicaset.json @@ -0,0 +1,2400 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": 16, + "iteration": 1573121539385, + "links": [], + "panels": [ + { + "content": "
\n  \n replicaset/$replicaset\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", replicaset!=\"\", dst_replicaset!=\"\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}) by (namespace, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND REPLICASETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}) by (namespace, dst_replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND REPLICASETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) by (replicaset) / sum(irate(response_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) by (replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{replicaset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\", tls=\"true\"}[30s])) by (replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rs/{{replicaset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\", tls!=\"true\"}[30s])) by (replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{replicaset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 rs/{{replicaset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 rs/{{replicaset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 rs/{{replicaset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND REPLICASETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [], + "repeat": "inbound", + "scopedVars": { + "inbound": { + "selected": false, + "text": "web", + "value": "web" + } + }, + "title": "rs/$inbound", + "type": "row" + }, + { + "content": "
\n  \n rs/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "scopedVars": { + "inbound": { + "selected": false, + "text": "web", + "value": "web" + } + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 22 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "inbound": { + "selected": false, + "text": "web", + "value": "web" + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (replicaset, pod) / sum(irate(response_total{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (replicaset, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 22 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "inbound": { + "selected": false, + "text": "web", + "value": "web" + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\", tls=\"true\"}[30s])) by (replicaset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (replicaset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 22 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "inbound": { + "selected": false, + "text": "web", + "value": "web" + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 rs/{{replicaset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rs/{{replicaset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{replicaset!=\"\", replicaset=\"$inbound\", dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (le, replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 rs/{{replicaset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (dst_replicaset) / sum(irate(response_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{dst_replicaset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rs/{{dst_replicaset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{dst_replicaset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}[30s])) by (le, dst_replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rs/{{dst_replicaset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND REPLICASETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n rs/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_replicaset) / sum(irate(response_total{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{dst_replicaset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rs/{{dst_replicaset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_replicaset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rs/{{dst_replicaset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 rs/{{dst_replicaset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rs/{{dst_replicaset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicaset=\"$replicaset\", dst_replicaset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicaset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 rs/{{dst_replicaset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "rs/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "text": "default", + "value": "default" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(process_start_time_seconds{replicaset!=\"\"}, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{replicaset!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "rs1", + "value": "rs1" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, replicaset)", + "hide": 0, + "includeAll": false, + "label": "ReplicaSet", + "multi": false, + "name": "replicaset", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, replicaset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(request_total{dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\"}, replicaset)", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_replicaset=\"$replicaset\"}, replicaset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\"}, dst_replicaset)", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", replicaset=\"$replicaset\"}, dst_replicaset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd ReplicaSet", + "uid": "linkerd-replicaset", + "version": 1 + } diff --git a/roles/prometheus/dashboards/linkerd/linkerd-replicationcontroller.json b/roles/prometheus/dashboards/linkerd/linkerd-replicationcontroller.json new file mode 100644 index 00000000..c552d749 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-replicationcontroller.json @@ -0,0 +1,2354 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531764114061, + "links": [], + "panels": [ + { + "content": "
\n  \n rc/$replicationcontroller\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", replicationcontroller!=\"\", dst_replicationcontroller!=\"\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}) by (namespace, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND REPLICATIONCONTROLLERS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}) by (namespace, dst_replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND REPLICATIONCONTROLLERS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) by (replicationcontroller) / sum(irate(response_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) by (replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{replicationcontroller}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\", tls=\"true\"}[30s])) by (replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rc/{{replicationcontroller}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\", tls!=\"true\"}[30s])) by (replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{replicationcontroller}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 rc/{{replicationcontroller}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 rc/{{replicationcontroller}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 rc/{{replicationcontroller}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND REPLICATIONCONTROLLERS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n rc/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (replicationcontroller, pod) / sum(irate(response_total{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (replicationcontroller, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\", tls=\"true\"}[30s])) by (replicationcontroller, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\", tls!=\"true\"}[30s])) by (replicationcontroller, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 rc/{{replicationcontroller}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rc/{{replicationcontroller}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{replicationcontroller!=\"\", replicationcontroller=\"$inbound\", dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (le, replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 rc/{{replicationcontroller}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "rc/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (dst_replicationcontroller) / sum(irate(response_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{dst_replicationcontroller}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rc/{{dst_replicationcontroller}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{dst_replicationcontroller}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}[30s])) by (le, dst_replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rc/{{dst_replicationcontroller}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND REPLICATIONCONTROLLERS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n rc/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_replicationcontroller) / sum(irate(response_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{dst_replicationcontroller}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒rc/{{dst_replicationcontroller}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_replicationcontroller)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "rc/{{dst_replicationcontroller}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 rc/{{dst_replicationcontroller}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 rc/{{dst_replicationcontroller}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\", dst_replicationcontroller=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_replicationcontroller))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 rc/{{dst_replicationcontroller}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "rc/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{replicationcontroller!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "ReplicationController", + "multi": false, + "name": "replicationcontroller", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, replicationcontroller)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_replicationcontroller=\"$replicationcontroller\"}, replicationcontroller)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", replicationcontroller=\"$replicationcontroller\"}, dst_replicationcontroller)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd ReplicationController", + "uid": "linkerd-replicationcontroller", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-route.json b/roles/prometheus/dashboards/linkerd/linkerd-route.json new file mode 100644 index 00000000..35b9a8ee --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-route.json @@ -0,0 +1,1317 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1539806914987, + "links": [], + "panels": [ + { + "content": "
\n  \n route/$rt_route\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(route_response_total{classification=\"success\", namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) / sum(irate(route_response_total{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 2 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " ms", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (le, rt_route))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "P95 LATENCY", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP-LINE TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 10, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_response_total{classification=\"success\", namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (rt_route) / sum(irate(route_response_total{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "route/{{rt_route}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\", tls=\"true\"}[30s])) by (rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒route/{{rt_route}}", + "refId": "A" + }, + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\", tls!=\"true\"}[30s])) by (rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "route/{{rt_route}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (le, rt_route))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 route/{{rt_route}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (le, rt_route))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 route/{{rt_route}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"inbound\", rt_route=\"$rt_route\"}[30s])) by (le, rt_route))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 route/{{rt_route}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY DEPLOYMENT\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 18, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_response_total{classification=\"success\", namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (deployment, rt_route) / sum(irate(route_response_total{namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (deployment, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"outbound\", tls=\"true\", rt_route=\"$rt_route\"}[30s])) by (deployment, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"outbound\", tls!=\"true\", rt_route=\"$rt_route\"}[30s])) by (deployment, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (le, deployment, rt_route))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY POD\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 26, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_response_total{classification=\"success\", namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (pod, rt_route) / sum(irate(route_response_total{namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (pod, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 26 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"outbound\", tls=\"true\", rt_route=\"$rt_route\"}[30s])) by (pod, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(route_request_total{namespace=\"$namespace\", direction=\"outbound\", tls!=\"true\", rt_route=\"$rt_route\"}[30s])) by (pod, rt_route)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(route_response_latency_ms_bucket{namespace=\"$namespace\", direction=\"outbound\", rt_route=\"$rt_route\"}[30s])) by (le, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 po/{{pod, rt_route}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 33 + }, + "height": "1px", + "id": 34, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(route_request_total, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Route", + "multi": false, + "name": "rt_route", + "options": [], + "query": "label_values(route_request_total{namespace=\"$namespace\"}, rt_route)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Route", + "uid": "route", + "version": 1 + } + diff --git a/roles/prometheus/dashboards/linkerd/linkerd-service.json b/roles/prometheus/dashboards/linkerd/linkerd-service.json new file mode 100644 index 00000000..71fe14bb --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-service.json @@ -0,0 +1,1366 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531434867463, + "links": [], + "panels": [ + { + "content": "
\n  \n svc/$service\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 2 + }, + "id": 81, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " ms", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "P95 LATENCY", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP-LINE TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service) / sum(irate(response_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "svc/{{dst_service}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒svc/{{dst_service}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_service)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "svc/{{dst_service}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 svc/{{dst_service}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 svc/{{dst_service}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 svc/{{dst_service}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY DEPLOYMENT\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service, deployment) / sum(irate(response_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service, deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_service, deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_service, deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n INBOUND TRAFFIC BY POD\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 82, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 83, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service, pod) / sum(irate(response_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (dst_service, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 26 + }, + "id": 84, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_service, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_service, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 85, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", dst_service=\"$service\", direction=\"outbound\"}[30s])) by (le, dst_service, pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 33 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(request_total, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\"}, dst_service)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_service=\"$service\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", deployment=\"$deployment\"}, dst_deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Service", + "uid": "linkerd-service", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-statefulset.json b/roles/prometheus/dashboards/linkerd/linkerd-statefulset.json new file mode 100644 index 00000000..03405f9f --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-statefulset.json @@ -0,0 +1,2354 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1531763681685, + "links": [], + "panels": [ + { + "content": "
\n  \n sts/$statefulset\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 2 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "0.9,.99", + "title": "SUCCESS RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 2 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": " RPS", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "REQUEST RATE", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 2 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{dst_namespace=\"$namespace\", statefulset!=\"\", dst_statefulset!=\"\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}) by (namespace, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "INBOUND STATEFULSETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}) by (namespace, dst_statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "OUTBOUND STATEFULSETS", + "transparent": true, + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n INBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 17, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{statefulset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\", tls=\"true\"}[30s])) by (statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒sts/{{statefulset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\", tls!=\"true\"}[30s])) by (statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{statefulset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 68, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 sts/{{statefulset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 sts/{{statefulset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99 sts/{{statefulset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 148, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 167, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 168, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 16 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 169, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"inbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Inbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 152, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n INBOUND STATEFULSETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 76, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 59, + "panels": [ + { + "content": "
\n  \n sts/$inbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 22.2 + }, + "id": 39, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24.2 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (statefulset, pod) / sum(irate(response_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (statefulset, pod)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24.2 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\", tls=\"true\"}[30s])) by (statefulset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒po/{{pod}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (statefulset, pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "po/{{pod}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24.2 + }, + "id": 29, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 sts/{{statefulset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 sts/{{statefulset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{statefulset!=\"\", statefulset=\"$inbound\", dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 sts/{{statefulset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "inbound", + "title": "sts/$inbound", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 34, + "panels": [], + "repeat": null, + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND TRAFFIC\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 32, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 77, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (dst_statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{dst_statefulset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒sts/{{dst_statefulset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{dst_statefulset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 sts/{{dst_statefulset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 154, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_close_total{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\",errno!=\"\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}} {{errno}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTION FAILURES", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 166, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "tcp_open_connections{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCP CONNECTIONS OPEN", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 160, + "legend": { + "show": false + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "tcp_connection_duration_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", direction=\"outbound\"}", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "TCP CONNECTION DURATION", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurationms", + "logBase": 1, + "max": null, + "min": "0", + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "title": "Outbound TCP Metrics", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 156, + "panels": [], + "title": "", + "type": "row" + }, + { + "content": "
\n OUTBOUND STATEFULSETS\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 80, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 27, + "panels": [ + { + "content": "
\n  \n sts/$outbound\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 40, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_statefulset) / sum(irate(response_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{dst_statefulset}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\", tls=\"true\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒sts/{{dst_statefulset}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\", tls!=\"true\"}[30s])) by (dst_statefulset)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "sts/{{dst_statefulset}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50 sts/{{dst_statefulset}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95 sts/{{dst_statefulset}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(response_latency_ms_bucket{namespace=\"$namespace\", statefulset=\"$statefulset\", dst_statefulset=\"$outbound\", direction=\"outbound\"}[30s])) by (le, dst_statefulset))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99 sts/{{dst_statefulset}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "outbound", + "title": "sts/$outbound", + "type": "row" + }, + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "1px", + "id": 171, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds{statefulset!=\"\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "StatefulSet", + "multi": false, + "name": "statefulset", + "options": [], + "query": "label_values(process_start_time_seconds{namespace=\"$namespace\"}, statefulset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "inbound", + "options": [], + "query": "label_values(request_total{dst_namespace=\"$namespace\", dst_statefulset=\"$statefulset\"}, statefulset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "outbound", + "options": [], + "query": "label_values(request_total{namespace=\"$namespace\", statefulset=\"$statefulset\"}, dst_statefulset)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd StatefulSet", + "uid": "linkerd-statefulset", + "version": 1 +} diff --git a/roles/prometheus/dashboards/linkerd/linkerd-top-line.json b/roles/prometheus/dashboards/linkerd/linkerd-top-line.json new file mode 100644 index 00000000..b449d334 --- /dev/null +++ b/roles/prometheus/dashboards/linkerd/linkerd-top-line.json @@ -0,0 +1,1141 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph (old)", + "version": "" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1563896358132, + "links": [], + "panels": [ + { + "content": "
\n
\n \n
\n
\n
\n
\n
\n\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "1px", + "id": 14, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "percentunit", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "height": "", + "id": 28, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", deployment=~\"$deployment\"}[30s])) / sum(irate(response_total{deployment=~\"$deployment\"}[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": ".9,.99", + "title": "GLOBAL SUCCESS RATE", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "rps", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "height": "", + "id": 29, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(request_total{deployment=~\"$deployment\"}[30s]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "GLOBAL REQUEST VOLUME", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 3 + }, + "height": "", + "id": 30, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=~\"$namespace\"}) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "NAMESPACES MONITORED", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 3 + }, + "height": "", + "id": 86, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(count(request_total{namespace=~\"$namespace\"}) by (namespace, deployment))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "DEPLOYMENTS MONITORED", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "content": "
\n TOP LINE\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 7 + }, + "height": "1px", + "id": 20, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 9 + }, + "id": 21, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=~\"$namespace\", direction=\"inbound\"}[30s])) by (namespace) / sum(irate(response_total{namespace=~\"$namespace\", direction=\"inbound\"}[30s])) by (namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ns/{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=~\"$namespace\", direction=\"inbound\", tls=\"true\"}[30s])) by (namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒ns/{{namespace}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=~\"$namespace\", direction=\"inbound\", tls!=\"true\"}[30s])) by (namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "ns/{{namespace}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST VOLUME", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 23, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=~\"$namespace\", direction=\"inbound\"}[30s])) by (le, namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p95 ns/{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\n NAMESPACES\n
", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 16 + }, + "height": "1px", + "id": 19, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 40, + "panels": [], + "repeat": "namespace", + "scopedVars": { + "namespace": { + "selected": false + } + }, + "title": "", + "type": "row" + }, + { + "content": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 19 + }, + "height": "1px", + "id": 13, + "links": [], + "mode": "html", + "options": {}, + "scopedVars": { + "namespace": { + "selected": false + } + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "namespace": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(response_total{classification=\"success\", namespace=\"$namespace\", direction=\"inbound\"}[30s])) by (deployment) / sum(irate(response_total{namespace=\"$namespace\", direction=\"inbound\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SUCCESS RATE", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "namespace": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", direction=\"inbound\", tls=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "🔒deploy/{{deployment}}", + "refId": "A" + }, + { + "expr": "sum(irate(request_total{namespace=\"$namespace\", direction=\"inbound\", tls!=\"true\"}[30s])) by (deployment)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deploy/{{deployment}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REQUEST VOLUME", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "rps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "namespace": { + "selected": false + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{namespace=\"$namespace\", direction=\"inbound\"}[30s])) by (le, deployment))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "p95 deploy/{{deployment}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "P95 LATENCY", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 18, + "style": "dark", + "tags": [ + "linkerd" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(process_start_time_seconds, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "deployment", + "options": [], + "query": "label_values(process_start_time_seconds{deployment!=\"\"}, deployment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Linkerd Top Line", + "uid": "linkerd-top-line", + "version": 1 +} diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml index 59287711..9b992dd2 100644 --- a/roles/prometheus/tasks/main.yml +++ b/roles/prometheus/tasks/main.yml @@ -78,3 +78,4 @@ loop_var: dashboard_file with_fileglob: - "dashboards/*" + - "dashboards/linkerd/*"

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%0D5&j0}B7FZbhkfegZCMn!Sv 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