Move internal project to open source

This change adds the current status of a project that aims to create
a simple monitoring setup to monitor Gerrit servers, which was developed
internally at SAP.

The project provides an opinionated and basic configuration for helm
charts that can be used to install Loki, Prometheus and Grafana on a
Kubernetes cluster. Scripts to easily apply the configuration and
install the whole setup are provided as well.

The contributions so far were done by (with number of commits)

  80  Thomas Draebing
  11  Matthias Sohn
   2  Saša Živkov

Change-Id: I8045780446edfb3c0dc8287b8f494505e338e066
This commit is contained in:
Thomas Draebing 2020-03-11 13:46:52 +01:00
parent 4314ca0fbc
commit be862d863e
33 changed files with 7659 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
dist

201
LICENSE Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

189
README.md Normal file
View file

@ -0,0 +1,189 @@
# Monitoring setup for Gerrit
This project provides a setup for monitoring Gerrit instances. The setup is
based on Prometheus and Grafana running in Kubernetes. In addition, logging will
be provided by Grafana Loki.
The setup is provided as a helm chart. It can be installed using Helm
(This README expects Helm version 3.0 or higher).
The charts used in this setup are the chart provided in the open source and can be
found on GitHub:
- [Prometheus](https://github.com/helm/charts/tree/master/stable/prometheus)
- [Grafana](https://github.com/helm/charts/tree/master/stable/grafana)
- [Loki](https://github.com/grafana/loki/tree/master/production/helm/loki)
This project just provides `values.yaml`-files that are already configured to
work with the `metrics-reporter-prometheus`-plugin of Gerrit to make the setup
easier.
## Dependencies
- Gerrit \
Gerrit requires the following plugin to be installed:
- [metrics-reporter-prometheus](https://gerrit.googlesource.com/plugins/metrics-reporter-prometheus/)
- Promtail \
Promtail has to be installed with access to the `logs`-directory in the Gerrit-
site. A configuration-file for Promtail will be provided in this setup. Find
the documentation for Promtail
[here](https://github.com/grafana/loki/blob/master/docs/clients/promtail/README.md)
- Helm \
To install and configure Helm, follow the
[official guide](https://helm.sh/docs/intro/quickstart/#install-helm).
- ytt \
ytt is a templating tool for yaml-files. It is required for some last moment
configuration. Installation instructions can be found
[here](https://k14s.io/#install-from-github-release).
- yq \
yq is a commandline processor for yaml-files. Installation instructions can be
found [here](https://mikefarah.gitbook.io/yq/).
## Add dashboards
To have dashboards deployed automatically during installation, export the dashboards
to a JSON-file or create JSON-files describing the dashboards in another way.
Put these dashboards into the `./dashboards`-directory of this repository. During
the installation the dashboards will be added to a configmap and with this
automatically installed to Grafana.
## Configuration
While this project is supposed to provide a specialized and opinionated monitoring
setup, some configuration is highly dependent on the specific installation.
These options have to be configured in the `./config.yaml` before installing and
are listed here:
| option | description |
|-----------------------------------------|------------------------------------------------------------------------------------|
| `gerritServers.[0].host` | Hostname (incl. port, if required) of the Gerrit server to monitor |
| `gerritServers.[0].username` | Username of Gerrit user with 'View Metrics' capabilities |
| `gerritServers.[0].password` | Password of Gerrit user with 'View Metrics' capabilities |
| `namespace` | The namespace the charts are installed to |
| `tls.skipVerify` | Whether to skip TLS certificate verification |
| `tls.caCert` | CA certificate used for TLS certificate verification |
| `promtail.storagePath` | Path to directory, where Promtail is allowed to save files (e.g. `positions.yaml`) |
| `promtail.logPath` | Path to directory containing the Gerrit logs (e.g. `/var/gerrit/logs`) |
| `prometheus.server.host` | Prometheus server ingress hostname |
| `prometheus.server.username` | Username for Prometheus |
| `prometheus.server.password` | Password for Prometheus |
| `prometheus.server.tls.cert` | TLS certificate |
| `prometheus.server.tls.key` | TLS key |
| `prometheus.alertmanager.slack.apiUrl` | API URL of the Slack Webhook |
| `prometheus.alertmanager.slack.channel` | Channel to which the alerts should be posted |
| `loki.host` | Loki ingress hostname |
| `loki.username` | Username for Loki |
| `loki.password` | Password for Loki |
| `loki.tls.cert` | TLS certificate |
| `loki.tls.key` | TLS key |
| `grafana.host` | Grafana ingress hostname |
| `grafana.tls.cert` | TLS certificate |
| `grafana.tls.key` | TLS key |
| `grafana.admin.username` | Username for the admin user |
| `grafana.admin.password` | Password for the admin user |
| `grafana.ldap.enabled` | Whether to enable LDAP |
| `grafana.ldap.host` | Hostname of LDAP server |
| `grafana.ldap.port` | Port of LDAP server (Has to be `quoted`!) |
| `grafana.ldap.password` | Password of LDAP server |
| `grafana.ldap.bind_dn` | Bind DN (username) of the LDAP server |
| `grafana.ldap.accountBases` | List of base DNs to discover accounts (Has to have the format `"['a', 'b']"`) |
| `grafana.ldap.groupBases` | List of base DNs to discover groups (Has to have the format `"['a', 'b']"`) |
| `grafana.dashboards.editable` | Whether dashboards can be edited manually in the UI |
### Encryption
The configuration file contains secrets. Thus, to be able to share the configuration,
e.g. with the CI-system, it is meant to be encrypted. The encryption is explained
[here](./documentation/config-management.md).
The `./install.sh`-script will decrypt the file before templating, if it was
encrypted with `sops`.
## Installation
Before beginning with the installation, ensure that the local helm repository is
up-to-date:
```sh
helm repo add loki https://grafana.github.io/loki/charts
helm repo update
```
This project provides a script to quickly install the monitoring setup. To use
it, run:
```sh
./install.sh \
[--output ./dist] \
[--dryrun] \
config.yaml
```
The command will use the given configuration to create the final
files in the directory given by `--output` (default `./dist`) and install/update
the Kubernetes resources and charts, if the `--dryrun` flag is not set.
## Configure Promtail
Promtail has to be installed with access to the directory containing the Gerrit
logs, e.g. on the same host. The installation as described above will create a
configuration file for Promtail, which can be found in `./dist/promtail.yaml`.
Use it to configure Promtail by using the `-config.file=./dist/promtail.yaml`-
parameter, when starting Promtail. Using the Promtail binary directly this would
result in the following command:
```sh
$PATH_TO_PROMTAIL/promtail \
-config.file=./dist/promtail.yaml \
-client.external-labels=host=$(hostname)
```
The `-client.external-labels=host=$(hostname)` option will add a label to each job
that contains the hostname. This is useful, if multiple host are scraped for logs
and only one Grafana is used to view the logs.
If TLS-verification is activated, the CA-certificate used for verification
(usually the one configured for `tls.caCert`) has to be present in the
directory configured for `promtail.storagePath` in the `config.yaml` and has to
be called `promtail.ca.crt`.
The Promtail configuration provided here expects the logs to be available in
JSON-format. This can be configured by setting `log.jsonLogging = true` in the
`gerrit.config`.
## Uninstallation
To remove the Prometheus chart from the cluster, run
```sh
helm uninstall prometheus --namespace $NAMESPACE
helm uninstall loki --namespace $NAMESPACE
helm uninstall grafana --namespace $NAMESPACE
kubectl delete -f ./dist/configuration
```
To also release the volumes, run
```sh
kubectl delete -f ./dist/storage
```
NOTE: Doing so, all data, which was not backed up will be lost!
Remove the namespace:
```sh
kubectl delete -f ./dist/namespace.yaml
```
The `./uninstall.sh`-script will automatically remove the charts installed in
by the `./install.sh`-script from the configured namespace and delete the
namespace as well:
```sh
./uninstall.sh config.yaml
```

1
charts/grafana/Version Normal file
View file

@ -0,0 +1 @@
5.0.3

View file

@ -0,0 +1,12 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
#@ if data.values.grafana.ldap.enabled and not data.values.tls.skipVerify:
apiVersion: v1
kind: Secret
metadata:
name: grafana-ca
namespace: #@ data.values.namespace
data:
server.ca.crt: #@ base64.encode(data.values.tls.caCert)
type: Opaque
#@ end

View file

@ -0,0 +1,15 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
#@ load("ldap.lib.txt", "format_ldap_toml")
apiVersion: v1
kind: Secret
metadata:
name: grafana-credentials
namespace: #@ data.values.namespace
data:
admin-user: #@ base64.encode(data.values.grafana.admin.username)
admin-password: #@ base64.encode(data.values.grafana.admin.password)
#@ if data.values.grafana.ldap.enabled:
ldap-toml: #@ base64.encode(format_ldap_toml())
#@ end
type: Opaque

View file

@ -0,0 +1,11 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: grafana-server-tls
namespace: #@ data.values.namespace
type: kubernetes.io/tls
data:
tls.crt: #@ base64.encode(data.values.grafana.tls.cert)
tls.key: #@ base64.encode(data.values.grafana.tls.key)

View file

@ -0,0 +1,27 @@
(@ load("@ytt:data", "data") @)
(@ def format_ldap_toml(): -@)
[[servers]]
host = "(@= data.values.grafana.ldap.host @)"
port = (@= data.values.grafana.ldap.port @)
use_ssl = true
start_tls = false
ssl_skip_verify = (@= "{}".format(data.values.tls.skipVerify).lower() @)
root_ca_cert = "/etc/secrets/server.ca.crt"
bind_dn = "(@= data.values.grafana.ldap.bind_dn @)"
bind_password = "(@= data.values.grafana.ldap.password @)"
search_filter = "(cn=%s)"
search_base_dns = (@= data.values.grafana.ldap.accountBases @)
group_search_filter = "(cn=%s)"
group_search_base_dns = (@= data.values.grafana.ldap.groupBases @)
[[servers.group_mappings]]
group_dn = "*"
org_role = "Editor"
[servers.attributes]
name = "givenName"
surname = "sn"
username = "cn"
(@- end @)

503
charts/grafana/grafana.yaml Normal file
View file

@ -0,0 +1,503 @@
#@ load("@ytt:data", "data")
rbac:
create: true
pspEnabled: true
pspUseAppArmor: true
namespaced: false
extraRoleRules: []
# - apiGroups: []
# resources: []
# verbs: []
extraClusterRoleRules: []
# - apiGroups: []
# resources: []
# verbs: []
serviceAccount:
create: true
name:
nameTest:
# annotations:
replicas: 1
## See `kubectl explain poddisruptionbudget.spec` for more
## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/
podDisruptionBudget: {}
# minAvailable: 1
# maxUnavailable: 1
## See `kubectl explain deployment.spec.strategy` for more
## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
deploymentStrategy:
type: RollingUpdate
readinessProbe:
httpGet:
path: /api/health
port: 3000
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 60
timeoutSeconds: 30
failureThreshold: 10
## Use an alternate scheduler, e.g. "stork".
## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
##
# schedulerName: "default-scheduler"
image:
repository: grafana/grafana
tag: 6.6.2
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
##
# pullSecrets:
# - myRegistrKeySecretName
testFramework:
enabled: true
image: "bats/bats"
tag: "v1.1.0"
securityContext: {}
securityContext:
runAsUser: 472
fsGroup: 472
extraConfigmapMounts: []
# - name: certs-configmap
# mountPath: /etc/grafana/ssl/
# subPath: certificates.crt # (optional)
# configMap: certs-configmap
# readOnly: true
extraEmptyDirMounts: []
# - name: provisioning-notifiers
# mountPath: /etc/grafana/provisioning/notifiers
## Assign a PriorityClassName to pods if set
# priorityClassName:
downloadDashboardsImage:
repository: curlimages/curl
tag: 7.68.0
pullPolicy: IfNotPresent
downloadDashboards:
env: {}
## Pod Annotations
# podAnnotations: {}
## Pod Labels
# podLabels: {}
podPortName: grafana
## Deployment annotations
# annotations: {}
## Expose the grafana service to be accessed from outside the cluster (LoadBalancer service).
## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it.
## ref: http://kubernetes.io/docs/user-guide/services/
##
service:
type: ClusterIP
port: 80
targetPort: 3000
# targetPort: 4181 To be used with a proxy extraContainer
annotations: {}
labels: {}
portName: service
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
labels: {}
path: /
hosts:
- #@ data.values.grafana.host
## Extra paths to prepend to every host configuration. This is useful when working with annotation based services.
extraPaths: []
# - path: /*
# backend:
# serviceName: ssl-redirect
# servicePort: use-annotation
tls:
- secretName: grafana-server-tls
hosts:
- #@ data.values.grafana.host
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
## Node labels for pod assignment
## ref: https://kubernetes.io/docs/user-guide/node-selection/
#
nodeSelector: {}
## Tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
##
tolerations: []
## Affinity for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
affinity: {}
extraInitContainers: []
## Enable an Specify container in extraContainers. This is meant to allow adding an authentication proxy to a grafana pod
extraContainers: |
# - name: proxy
# image: quay.io/gambol99/keycloak-proxy:latest
# args:
# - -provider=github
# - -client-id=
# - -client-secret=
# - -github-org=<ORG_NAME>
# - -email-domain=*
# - -cookie-secret=
# - -http-address=http://0.0.0.0:4181
# - -upstream-url=http://127.0.0.1:3000
# ports:
# - name: proxy-web
# containerPort: 4181
## Enable persistence using Persistent Volume Claims
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
##
persistence:
type: pvc
enabled: true
# storageClassName: default
accessModes:
- ReadWriteOnce
size: 10Gi
# annotations: {}
finalizers:
- kubernetes.io/pvc-protection
# subPath: ""
existingClaim: grafana-pvc
initChownData:
## If false, data ownership will not be reset at startup
## This allows the prometheus-server to be run with an arbitrary user
##
enabled: true
## initChownData container image
##
image:
repository: busybox
tag: "1.31.1"
pullPolicy: IfNotPresent
## initChownData resource requests and limits
## Ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
# Administrator credentials when not using an existing secret (see below)
adminUser: admin
# adminPassword: strongpassword
# Use an existing secret for the admin user.
admin:
existingSecret: "grafana-credentials"
userKey: admin-user
passwordKey: admin-password
## Define command to be executed at startup by grafana container
## Needed if using `vault-env` to manage secrets (ref: https://banzaicloud.com/blog/inject-secrets-into-pods-vault/)
## Default is "run.sh" as defined in grafana's Dockerfile
# command:
# - "sh"
# - "/run.sh"
## Use an alternate scheduler, e.g. "stork".
## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
##
# schedulerName:
## Extra environment variables that will be pass onto deployment pods
env: {}
## "valueFrom" environment variable references that will be added to deployment pods
## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core
## Renders in container spec as:
## env:
## ...
## - name: <key>
## valueFrom:
## <value rendered as YAML>
envValueFrom: {}
## The name of a secret in the same kubernetes namespace which contain values to be added to the environment
## This can be useful for auth tokens, etc
envFromSecret: ""
## Sensible environment variables that will be rendered as new secret object
## This can be useful for auth tokens, etc
envRenderSecret: {}
## Additional grafana server secret mounts
# Defines additional mounts with secrets. Secrets must be manually created in the namespace.
extraSecretMounts:
#@ if data.values.grafana.ldap.enabled and not data.values.tls.skipVerify:
- name: tls-ca
mountPath: /etc/secrets
secretName: grafana-ca
readOnly: true
#@ end
## Additional grafana server volume mounts
# Defines additional volume mounts.
extraVolumeMounts: []
# - name: extra-volume
# mountPath: /mnt/volume
# readOnly: true
# existingClaim: volume-claim
## Pass the plugins you want installed as a list.
##
plugins: []
# - digrich-bubblechart-panel
# - grafana-clock-panel
## Configure grafana datasources
## ref: http://docs.grafana.org/administration/provisioning/#datasources
##
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: #@ "http://prometheus-{}-server.{}.svc.cluster.local".format(data.values.namespace, data.values.namespace)
access: proxy
isDefault: true
- name: LokiLogQL
type: loki
url: #@ "http://loki-{}.{}.svc.cluster.local:3100".format(data.values.namespace, data.values.namespace)
access: proxy
isDefault: false
- name: LokiPromQL
type: prometheus
url: #@ "http://loki-{}.{}.svc.cluster.local:3100/loki".format(data.values.namespace, data.values.namespace)
access: proxy
isDefault: false
## Configure notifiers
## ref: http://docs.grafana.org/administration/provisioning/#alert-notification-channels
##
notifiers: {}
# notifiers.yaml:
# notifiers:
# - name: email-notifier
# type: email
# uid: email1
# # either:
# org_id: 1
# # or
# org_name: Main Org.
# is_default: true
# settings:
# addresses: an_email_address@example.com
# delete_notifiers:
## Configure grafana dashboard providers
## ref: http://docs.grafana.org/administration/provisioning/#dashboards
##
## `path` must be /var/lib/grafana/dashboards/<provider_name>
##
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
- name: 'gerrit'
orgId: 1
folder: ''
type: file
disableDeletion: true
editable: #@ data.values.grafana.dashboards.editable
updateIntervalSeconds: 60
allowUiUpdates: #@ data.values.grafana.dashboards.editable
options:
path: /var/lib/grafana/dashboards/gerrit
## Configure grafana dashboard to import
## NOTE: To use dashboards you must also enable/configure dashboardProviders
## ref: https://grafana.com/dashboards
##
## dashboards per provider, use provider name as key.
##
dashboards: {}
# default:
# some-dashboard:
# json: |
# $RAW_JSON
# custom-dashboard:
# file: dashboards/custom-dashboard.json
# prometheus-stats:
# gnetId: 2
# revision: 2
# datasource: Prometheus
# local-dashboard:
# url: https://example.com/repository/test.json
# local-dashboard-base64:
# url: https://example.com/repository/test-b64.json
# b64content: true
## Reference to external ConfigMap per provider. Use provider name as key and ConfiMap name as value.
## A provider dashboards must be defined either by external ConfigMaps or in values.yaml, not in both.
## ConfigMap data example:
##
## data:
## example-dashboard.json: |
## RAW_JSON
##
dashboardsConfigMaps:
gerrit: "grafana-dashboards"
## Grafana's primary configuration
## NOTE: values in map will be converted to ini format
## ref: http://docs.grafana.org/installation/configuration/
##
grafana.ini:
paths:
data: /var/lib/grafana/data
logs: /var/log/grafana
plugins: /var/lib/grafana/plugins
provisioning: /etc/grafana/provisioning
analytics:
check_for_updates: true
log:
mode: console
grafana_net:
url: https://grafana.net
users:
auto_assign_org_role: Editor
## LDAP Authentication can be enabled with the following values on grafana.ini
## NOTE: Grafana will fail to start if the value for ldap.toml is invalid
auth.ldap:
enabled: #@ data.values.grafana.ldap.enabled
allow_sign_up: true
config_file: /etc/grafana/ldap.toml
## Grafana's LDAP configuration
## Templated by the template in _helpers.tpl
## NOTE: To enable the grafana.ini must be configured with auth.ldap.enabled
## ref: http://docs.grafana.org/installation/configuration/#auth-ldap
## ref: http://docs.grafana.org/installation/ldap/#configuration
ldap:
enabled: #@ data.values.grafana.ldap.enabled
# `existingSecret` is a reference to an existing secret containing the ldap configuration
# for Grafana in a key `ldap-toml`.
existingSecret: "grafana-credentials"
# `config` is the content of `ldap.toml` that will be stored in the created secret
# config: ""
# config: |-
# verbose_logging = true
# [[servers]]
# host = "my-ldap-server"
# port = 636
# use_ssl = true
# start_tls = false
# ssl_skip_verify = false
# bind_dn = "uid=%s,ou=users,dc=myorg,dc=com"
## Grafana's SMTP configuration
## NOTE: To enable, grafana.ini must be configured with smtp.enabled
## ref: http://docs.grafana.org/installation/configuration/#smtp
smtp:
# `existingSecret` is a reference to an existing secret containing the smtp configuration
# for Grafana.
existingSecret: ""
userKey: "user"
passwordKey: "password"
## Sidecars that collect the configmaps with specified label and stores the included files them into the respective folders
## Requires at least Grafana 5 to work and can't be used together with parameters dashboardProviders, datasources and dashboards
sidecar:
image: kiwigrid/k8s-sidecar:0.1.99
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 50m
memory: 50Mi
# skipTlsVerify Set to true to skip tls verification for kube api calls
# skipTlsVerify: true
dashboards:
enabled: false
## Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
watchMethod: WATCH
SCProvider: true
# label that the configmaps with dashboards are marked with
label: grafana_dashboard
# folder in the pod that should hold the collected dashboards (unless `defaultFolderName` is set)
folder: /tmp/dashboards
# The default folder name, it will create a subfolder under the `folder` and put dashboards in there instead
defaultFolderName: null
# If specified, the sidecar will search for dashboard config-maps inside this namespace.
# Otherwise the namespace in which the sidecar is running will be used.
# It's also possible to specify ALL to search in all namespaces
searchNamespace: null
# provider configuration that lets grafana manage the dashboards
provider:
# name of the provider, should be unique
name: sidecarProvider
# orgid as configured in grafana
orgid: 1
# folder in which the dashboards should be imported in grafana
folder: ''
# type of the provider
type: file
# disableDelete to activate a import-only behaviour
disableDelete: false
# allow updating provisioned dashboards from the UI
allowUiUpdates: false
datasources:
enabled: false
## Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
watchMethod: WATCH
# label that the configmaps with datasources are marked with
label: grafana_datasource
# If specified, the sidecar will search for datasource config-maps inside this namespace.
# Otherwise the namespace in which the sidecar is running will be used.
# It's also possible to specify ALL to search in all namespaces
searchNamespace: null
## Override the deployment namespace
##
namespaceOverride: ""

View file

@ -0,0 +1,15 @@
#@ load("@ytt:data", "data")
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: grafana-pvc
namespace: #@ data.values.namespace
labels:
app: grafana
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: default

1
charts/loki/Version Normal file
View file

@ -0,0 +1 @@
0.25.0

View file

@ -0,0 +1,10 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: loki-basic-auth
namespace: #@ data.values.namespace
data:
auth: #@ base64.encode(data.values.loki.htpasswd)
type: Opaque

View file

@ -0,0 +1,11 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: loki-server-tls
namespace: #@ data.values.namespace
type: kubernetes.io/tls
data:
tls.crt: #@ base64.encode(data.values.loki.tls.cert)
tls.key: #@ base64.encode(data.values.loki.tls.key)

242
charts/loki/loki.yaml Normal file
View file

@ -0,0 +1,242 @@
#@ load("@ytt:data", "data")
image:
repository: grafana/loki
tag: v1.3.0
pullPolicy: IfNotPresent
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: loki-basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
# kubernetes.io/tls-acme: "true"
hosts:
- host: #@ data.values.loki.host
paths:
- /
tls:
- secretName: loki-server-tls
hosts:
- #@ data.values.loki.host
## Affinity for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
affinity: {}
# podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# - labelSelector:
# matchExpressions:
# - key: app
# operator: In
# values:
# - loki
# topologyKey: "kubernetes.io/hostname"
## StatefulSet annotations
annotations: {}
# enable tracing for debug, need install jaeger and specify right jaeger_agent_host
tracing:
jaegerAgentHost:
config:
auth_enabled: false
ingester:
chunk_idle_period: 3m
chunk_block_size: 262144
chunk_retain_period: 1m
max_transfer_retries: 0
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
## Different ring configs can be used. E.g. Consul
# ring:
# store: consul
# replication_factor: 1
# consul:
# host: "consul:8500"
# prefix: ""
# httpclienttimeout: "20s"
# consistentreads: true
limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
schema_config:
configs:
- from: 2018-04-15
store: boltdb
object_store: filesystem
schema: v9
index:
prefix: index_
period: 24h
chunks:
prefix: chunk_
period: 24h
server:
http_listen_port: 3100
storage_config:
boltdb:
directory: /data/loki/index
filesystem:
directory: /data/loki/chunks
chunk_store_config:
max_look_back_period: 0
table_manager:
retention_deletes_enabled: true
retention_period: 336h
## Additional Loki container arguments, e.g. log level (debug, info, warn, error)
extraArgs: {}
# log.level: debug
livenessProbe:
httpGet:
path: /ready
port: http-metrics
initialDelaySeconds: 45
## ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/
networkPolicy:
enabled: false
## The app name of loki clients
client: {}
# name:
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
nodeSelector: {}
## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
## If you set enabled as "True", you need :
## - create a pv which above 10Gi and has same namespace with loki
## - keep storageClassName same with below setting
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 10Gi
annotations: {}
# subPath: ""
# existingClaim:
## Pod Labels
podLabels: {}
## Pod Annotations
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "http-metrics"
podManagementPolicy: OrderedReady
## Assign a PriorityClassName to pods if set
# priorityClassName:
rbac:
create: true
pspEnabled: true
readinessProbe:
httpGet:
path: /ready
port: http-metrics
initialDelaySeconds: 45
replicas: 1
resources: {}
# limits:
# cpu: 200m
# memory: 256Mi
# requests:
# cpu: 100m
# memory: 128Mi
securityContext:
fsGroup: 10001
runAsGroup: 10001
runAsNonRoot: true
runAsUser: 10001
service:
type: ClusterIP
nodePort:
port: 3100
annotations: {}
labels: {}
serviceAccount:
create: true
name:
annotations: {}
terminationGracePeriodSeconds: 4800
## Tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
tolerations: []
# The values to set in the PodDisruptionBudget spec
# If not set then a PodDisruptionBudget will not be created
podDisruptionBudget: {}
# minAvailable: 1
# maxUnavailable: 1
updateStrategy:
type: RollingUpdate
serviceMonitor:
enabled: false
interval: ""
additionalLabels: {}
# scrapeTimeout: 10s
initContainers: []
## Init containers to be added to the loki pod.
# - name: my-init-container
# image: busybox:latest
# command: ['sh', '-c', 'echo hello']
extraContainers: []
## Additional containers to be added to the loki pod.
# - name: reverse-proxy
# image: angelbarrera92/basic-auth-reverse-proxy:dev
# args:
# - "serve"
# - "--upstream=http://localhost:3100"
# - "--auth-config=/etc/reverse-proxy-conf/authn.yaml"
# ports:
# - name: http
# containerPort: 11811
# protocol: TCP
# volumeMounts:
# - name: reverse-proxy-auth-config
# mountPath: /etc/reverse-proxy-conf
extraVolumes: []
## Additional volumes to the loki pod.
# - name: reverse-proxy-auth-config
# secret:
# secretName: reverse-proxy-auth-config
## Extra volume mounts that will be added to the loki container
extraVolumeMounts: []
extraPorts: []
## Additional ports to the loki services. Useful to expose extra container ports.
# - port: 11811
# protocol: TCP
# name: http
# targetPort: http
# Extra env variables to pass to the loki container
env: []

5
charts/namespace.yaml Normal file
View file

@ -0,0 +1,5 @@
#@ load("@ytt:data", "data")
apiVersion: v1
kind: Namespace
metadata:
name: #@ data.values.namespace

View file

@ -0,0 +1 @@
9.5.4

View file

@ -0,0 +1,10 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: prometheus-basic-auth
namespace: #@ data.values.namespace
data:
auth: #@ base64.encode(data.values.prometheus.server.htpasswd)
type: Opaque

View file

@ -0,0 +1,19 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: prometheus-secrets
namespace: #@ data.values.namespace
data:
#@yaml/text-templated-strings
#@ for gerrit in data.values.gerritServers:
.pwd_(@= gerrit.host @): #@ base64.encode(gerrit.password)
#@ end
#@ if not data.values.tls.skipVerify:
server.ca.crt: #@ base64.encode(data.values.tls.caCert)
server.crt: #@ base64.encode(data.values.prometheus.server.tls.cert)
server.key: #@ base64.encode(data.values.prometheus.server.tls.key)
#@ end
type: Opaque

View file

@ -0,0 +1,11 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
apiVersion: v1
kind: Secret
metadata:
name: prometheus-server-tls
namespace: #@ data.values.namespace
type: kubernetes.io/tls
data:
tls.crt: #@ base64.encode(data.values.prometheus.server.tls.cert)
tls.key: #@ base64.encode(data.values.prometheus.server.tls.key)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
#@ load("@ytt:data", "data")
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: prometheus-server-pvc
namespace: #@ data.values.namespace
labels:
app: prometheus
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: default

48
config.yaml Normal file
View file

@ -0,0 +1,48 @@
gerritServers:
- host: gerrit.example.com
username: admin
password: secret
namespace: namespace
tls:
skipVerify: true
caCert:
promtail:
storagePath: /var/promtail
logPath: /var/gerrit/logs
prometheus:
server:
host: prometheus.example.com
username:
password:
tls:
cert:
key:
alertmanager:
slack:
apiUrl: https://hooks.slack.com/services/xxx/xxx
channel: '#alerts'
loki:
host: loki.example.com
username:
password:
tls:
cert:
key:
grafana:
host: grafana.example.com
tls:
cert:
key:
admin:
username: admin
password: secret
ldap:
enabled: false
host:
port: ""
password:
bind_dn:
accountBases: "[]"
groupBases: "[]"
dashboards:
editable: false

View file

@ -0,0 +1,683 @@
{
"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": 0,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 4,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_accounts{instance=\"$instance\"}",
"legendFormat": "accounts",
"refId": "A"
},
{
"expr": "100-caches_memory_hit_ratio_groups{instance=\"$instance\"}",
"legendFormat": "groups",
"refId": "B"
},
{
"expr": "100-caches_memory_hit_ratio_groups_byuuid{instance=\"$instance\"}",
"legendFormat": "groups_byuuid",
"refId": "C"
},
{
"expr": "100-caches_memory_hit_ratio_ldap_groups_byinclude{instance=\"$instance\"}",
"legendFormat": "ldap_groups_byinclude",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "ACCOUNT cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percent",
"label": "Cache Misses",
"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": null,
"description": "",
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 8,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_conflicts{instance=\"$instance\"}",
"legendFormat": "conflicts",
"refId": "A"
},
{
"expr": "100-caches_memory_hit_ratio_mergeability{instance=\"$instance\"}",
"legendFormat": "mergeability",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "CONFLICT cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percent",
"label": "Cache Misses",
"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": null,
"description": "",
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 8
},
"hiddenSeries": false,
"id": 2,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_change_kind{instance=\"$instance\"}",
"legendFormat": "change_kind",
"refId": "B"
},
{
"expr": "100-caches_memory_hit_ratio_change_notes{instance=\"$instance\"}",
"legendFormat": "change_notes",
"refId": "C"
},
{
"expr": "100-caches_memory_hit_ratio_changeid_project{instance=\"$instance\"}",
"legendFormat": "changeid_project",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "CHANGE cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percent",
"label": "Cache Misses",
"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": null,
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 8
},
"hiddenSeries": false,
"id": 10,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_project_list{instance=\"$instance\"}",
"legendFormat": "project list",
"refId": "A"
},
{
"expr": "100-caches_memory_hit_ratio_projects{instance=\"$instance\"}",
"legendFormat": "projects",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "PROJECT cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": 4,
"format": "percent",
"label": "Cache Misses",
"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": null,
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 17
},
"hiddenSeries": false,
"id": 6,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_diff{instance=\"$instance\"}",
"legendFormat": "diff",
"refId": "A"
},
{
"expr": "100-caches_memory_hit_ratio_diff_intraline{instance=\"$instance\"}",
"legendFormat": "diff intraline",
"refId": "B"
},
{
"expr": "100-caches_memory_hit_ratio_diff_summary{instance=\"$instance\"}",
"legendFormat": "diff summary",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "DIFF cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percent",
"label": "Cache Misses",
"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": null,
"description": "",
"fill": 0,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 17
},
"hiddenSeries": false,
"id": 12,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sideWidth": 150,
"total": false,
"values": false
},
"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": "100-caches_memory_hit_ratio_web_sessions{instance=\"$instance\"}",
"legendFormat": "web sessions",
"refId": "A"
},
{
"expr": "100-caches_memory_hit_ratio_sshkeys{instance=\"$instance\"}",
"legendFormat": "sshkeys",
"refId": "B"
},
{
"expr": "100-caches_memory_hit_ratio_git_tags{instance=\"$instance\"}",
"legendFormat": "git tags",
"refId": "D"
},
{
"expr": "100-caches_memory_hit_ratio_permission_sort{instance=\"$instance\"}",
"legendFormat": "permission_sort",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "MISC cache misses",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": 1,
"format": "percent",
"label": "Cache Misses",
"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
}
}
],
"schemaVersion": 21,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {
"text": "",
"value": ""
},
"datasource": "Prometheus",
"definition": "label_values(instance)",
"hide": 0,
"includeAll": false,
"label": "Gerrit Instance",
"multi": false,
"name": "instance",
"options": [],
"query": "label_values(instance)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-24h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Caches",
"uid": "vHQVaGsWk",
"version": 15
}

View file

@ -0,0 +1,466 @@
{
"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": 0,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "upload-pack requests",
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 4,
"interval": "2m",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"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": "increase(git_upload_pack_request_count_CLONE_total{instance=\"$instance\"}[2m])/2",
"legendFormat": "clone",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "CLONE count",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "opm",
"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": null,
"description": "upload-pack requests for fetches",
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 8,
"interval": "",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"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": "increase(git_upload_pack_request_count_FETCH_total{instance=\"$instance\"}[2m])/2",
"legendFormat": "fetch",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "FETCH count",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "opm",
"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": null,
"fill": 0,
"fillGradient": 0,
"gridPos": {
"h": 13,
"w": 12,
"x": 0,
"y": 8
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "quantile: 0.75",
"hiddenSeries": true
},
{
"alias": "quantile: 0.95",
"hiddenSeries": true
},
{
"alias": "quantile: 0.98",
"hiddenSeries": true
},
{
"alias": "quantile: 0.99",
"hiddenSeries": true
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "git_upload_pack_pack_bytes_CLONE{instance=\"$instance\"}",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "quantile: {{quantile}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "upload-pack pack bytes CLONE",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "decbytes",
"label": "",
"logBase": 10,
"max": "10000000000",
"min": "1000",
"show": true
},
{
"format": "short",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 0,
"fillGradient": 0,
"gridPos": {
"h": 13,
"w": 12,
"x": 12,
"y": 8
},
"hiddenSeries": false,
"id": 6,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "quantile: 0.75",
"hiddenSeries": true
},
{
"alias": "quantile: 0.95",
"hiddenSeries": true
},
{
"alias": "quantile: 0.98",
"hiddenSeries": true
},
{
"alias": "quantile: 0.99",
"hiddenSeries": true
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "git_upload_pack_pack_bytes_FETCH{instance=\"$instance\"}",
"legendFormat": "quantile: {{quantile}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "upload-pack pack bytes FETCH",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "decbytes",
"label": null,
"logBase": 10,
"max": "10000000000",
"min": "1000",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"refresh": "1m",
"schemaVersion": 21,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {
"text": "",
"value": ""
},
"datasource": "Prometheus",
"definition": "label_values(instance)",
"hide": 0,
"includeAll": false,
"label": "Gerrit Instance",
"multi": false,
"name": "instance",
"options": [],
"query": "label_values(instance)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-24h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Git fetch / clone",
"uid": "EV4ZCjEWz",
"version": 3
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,668 @@
{
"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": 0,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "",
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 13,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 8,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": 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": "proc_jvm_thread_num_live{instance=\"$instance\"}",
"legendFormat": "Java live threads",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Threads",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": "Live Threads",
"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": null,
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 13,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"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": "proc_jvm_memory_heap_committed{instance=\"$instance\"}",
"legendFormat": "committed heap",
"refId": "C"
},
{
"expr": "proc_jvm_memory_heap_used{instance=\"$instance\"}",
"legendFormat": "used heap",
"refId": "B"
},
{
"expr": "jgit_block_cache_cache_used{instance=\"$instance\"}",
"instant": false,
"legendFormat": "JGit block cache",
"refId": "A"
},
{
"expr": "proc_jvm_memory_non_heap_used{instance=\"$instance\"}",
"legendFormat": "used non-heap",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Memory",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "decbytes",
"label": "Memory Consumption",
"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": null,
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 10,
"w": 12,
"x": 0,
"y": 13
},
"hiddenSeries": false,
"id": 4,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"sideWidth": 100,
"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": "rate(proc_cpu_usage{instance=\"$instance\"}[5m])",
"legendFormat": "used CPUs",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "CPU",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": "CPU cores",
"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": true,
"dashLength": 10,
"dashes": false,
"datasource": null,
"decimals": 2,
"fill": 6,
"fillGradient": 0,
"gridPos": {
"h": 10,
"w": 12,
"x": 12,
"y": 13
},
"hiddenSeries": false,
"id": 6,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": false,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "gc time G1 old gen",
"color": "#F2CC0C"
},
{
"alias": "gc time G1 young gen",
"color": "#3274D9"
}
],
"spaceLength": 10,
"stack": true,
"steppedLine": false,
"targets": [
{
"expr": "increase(proc_jvm_gc_time_G1_Young_Generation{instance=\"$instance\"}[2m])/increase(proc_uptime{instance=\"$instance\"}[2m])",
"legendFormat": "gc time G1 young gen",
"refId": "B"
},
{
"expr": "increase(proc_jvm_gc_time_G1_Old_Generation{instance=\"$instance\"}[2m])/increase(proc_uptime{instance=\"$instance\"}[2m])",
"legendFormat": "gc time G1 old gen",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Java - % of time spent in GC",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "percentunit",
"label": "GC Time",
"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": null,
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 10,
"w": 12,
"x": 0,
"y": 23
},
"hiddenSeries": false,
"id": 12,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "miss ratio",
"yaxis": 1
},
{
"alias": "eviction ratio",
"yaxis": 2
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "increase(jgit_block_cache_miss_count{instance=\"$instance\"}[2m])/(increase(jgit_block_cache_hit_count{instance=\"$instance\"}[2m])+increase(jgit_block_cache_miss_count{instance=\"$instance\"}[2m]))",
"format": "time_series",
"instant": false,
"legendFormat": "miss ratio",
"refId": "A"
},
{
"expr": "increase(jgit_block_cache_eviction_count{instance=\"$instance\"}[2m])/(increase(jgit_block_cache_hit_count{instance=\"$instance\"}[2m])+increase(jgit_block_cache_miss_count{instance=\"$instance\"}[2m]))",
"format": "time_series",
"instant": false,
"legendFormat": "eviction ratio",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "JGit block cache",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "percentunit",
"label": "miss ratio",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"decimals": null,
"format": "percentunit",
"label": "eviction ratio",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": 1
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fill": 6,
"fillGradient": 0,
"gridPos": {
"h": 10,
"w": 12,
"x": 12,
"y": 23
},
"hiddenSeries": false,
"id": 10,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": 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": true,
"steppedLine": false,
"targets": [
{
"expr": "jgit_block_cache_open_files{instance=\"$instance\"}",
"legendFormat": "jgit block cache",
"refId": "B"
},
{
"expr": "proc_num_open_fds{instance=\"$instance\"}-jgit_block_cache_open_files{instance=\"$instance\"}",
"legendFormat": "other",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Java open 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": "Open File Descriptors",
"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": 22,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {
"text": "",
"value": ""
},
"datasource": "Prometheus",
"definition": "label_values(instance)",
"hide": 0,
"includeAll": false,
"label": "Gerrit Instance",
"multi": false,
"name": "instance",
"options": [],
"query": "label_values(instance)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"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"
]
},
"timezone": "",
"title": "Process",
"uid": "MeOVgCPWz",
"version": 4
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,278 @@
{
"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": 0,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "",
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 10,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 1,
"interval": "",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"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": "plugins_replication_replication_delay_$target{instance=\"$instance\"}",
"legendFormat": "quantile: {{quantile}}",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "replication delay $target",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ms",
"label": "delay",
"logBase": 10,
"max": null,
"min": "5000",
"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": null,
"description": "",
"fill": 1,
"fillGradient": 1,
"gridPos": {
"h": 10,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"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": "plugins_replication_replication_latency_$target{instance=\"$instance\"}",
"legendFormat": "quantile: {{quantile}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "replication latency $target",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ms",
"label": "latency",
"logBase": 10,
"max": null,
"min": "0.1",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"schemaVersion": 21,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": null,
"current": {
"text": "",
"value": ""
},
"datasource": "Prometheus",
"definition": "label_values(instance)",
"hide": 0,
"includeAll": false,
"label": "Gerrit Instance",
"multi": false,
"name": "instance",
"options": [],
"query": "label_values(instance)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": null,
"current": {
"tags": [],
"text": "",
"value": ""
},
"datasource": "Prometheus",
"definition": "metrics(plugins_replication_replication_latency_.*_count)",
"hide": 0,
"includeAll": false,
"label": "Replication target",
"multi": false,
"name": "target",
"options": [],
"query": "metrics(plugins_replication_replication_latency_.*_count)",
"refresh": 1,
"regex": "plugins_replication_replication_latency_(.*)_count",
"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"
]
},
"timezone": "",
"title": "Replication",
"uid": "RFLS1GsWk",
"version": 4
}

View file

@ -0,0 +1,103 @@
# Config Management
The configuration in the `config.yaml` contains secrets and should not be openly
accessible. To secure the data contained within it, the values can be encrypted
using a tool called [`sops`](https://github.com/mozilla/sops). This tool will use
a GPG-key to encrypt the values of the yaml file. Having the PGP-key also allows
to decrypt the values and work with the file. As long as the key is not compromised,
the encrypted file can be shared securly between collaborators.
The process of using `sops` is described below.
## Install `sops`
On OSX, `sops` can be installed using brew:
```sh
brew install sops
```
Install `gpg`:
```sh
brew install gpg
```
You might need to add this to your `.bashrc` or `.zshrc` to enable `sops` to work
correctly with `gpg` [1]:
```sh
GPG_TTY=$(tty)
export GPG_TTY
```
## Create GPG-key (first time only)
Create a key by running the following command and following the instructions on
the screen:
```sh
gpg --gen-key
```
## Encrypt the config-file
Run the following command to encode the file:
```sh
sops \
--encrypt \
--in-place \
--encrypted-regex '(password|htpasswd|cert|key|apiUrl|caCert)$' \
--pgp \
`gpg --fingerprint "$EMAIL" | \
grep pub -A 1 | \
grep -v pub | \
sed s/\ //g` \
$FILE_TO_ENCODE
```
`$EMAIL` refers to the email used during the creation of the GPG key.
Alternatively, the `./encrypt.sh`-script can be used to encrypt the file:
```sh
./encrypt.sh \
[--email $EMAIL] \
[--fingerprint $FINGERPRINT] \
$FILE_TO_ENCODE
```
The gpg-key used to encrypt the file can be selected by directly giving the key's
fingerprint using the `--fingerprint` option or giving the email used to identify
the key using the `--email` option. The `--fingerprint` option will have preference.
At least one of these options has to be set.
## Decrypt file
To decrypt the file, run:
```sh
sops --in-place -d $FILE_TO_DECODE
```
## Export GPG-key
For other developers or build servers to be able to decrypt the configuration,
the key has to be exported:
```sh
gpg --export -a "$EMAIL" > public.key
gpg --export-secret-key -a "$EMAIL" > private.key
```
On the receiving computer the key has to be imported by running:
```sh
gpg --import public.key
gpg --allow-secret-key-import --import private.key
```
## Links
[1] https://github.com/mozilla/sops/issues/304

58
encrypt.sh Executable file
View file

@ -0,0 +1,58 @@
#!/bin/bash -e
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
usage() {
me=`basename "$0"`
echo >&2 "Usage: $me [--email EMAIL] [--fingerprint FINGERPRINT] CONFIG"
exit 1
}
while test $# -gt 0 ; do
case "$1" in
--email)
shift
EMAIL=$1
shift
;;
--fingerprint)
shift
FINGERPRINT=$1
shift
;;
*)
break
esac
done
CONFIG=$1
test -z "$CONFIG" && usage
if test -z $FINGERPRINT; then
test -z $EMAIL && usage
FINGERPRINT=$(gpg --fingerprint "$EMAIL" | \
grep pub -A 1 | \
grep -v pub | \
sed s/\ //g)
fi
sops \
--encrypt \
--in-place \
--encrypted-regex '(password|htpasswd|cert|key|apiUrl|caCert)$' \
--pgp $FINGERPRINT \
$CONFIG

143
install.sh Executable file
View file

@ -0,0 +1,143 @@
#!/bin/bash -e
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
usage() {
me=`basename "$0"`
echo >&2 "Usage: $me [--output OUTPUT] [--dryrun] CONFIG"
exit 1
}
while test $# -gt 0 ; do
case "$1" in
--output)
shift
OUTPUT=$1
shift
;;
--dryrun)
DRYRUN="true"
shift
;;
*)
break
esac
done
test -z "$OUTPUT" && OUTPUT="$(dirname $0)/dist"
CONFIG=$1
test -z "$CONFIG" && usage
NAMESPACE=$(yq r $CONFIG namespace)
TMP_CONFIG=$OUTPUT/$(basename $CONFIG)
function updateOrInstall() {
if test -n "$(helm ls -n $NAMESPACE --short | grep $1)"; then
echo "upgrade"
else
echo "install"
fi
}
function addHtpasswdEntryUnencrypted() {
local COMPONENT=$1
local HTPASSWD=$(htpasswd -nb \
$(yq r $TMP_CONFIG $COMPONENT.username) \
$(yq r $TMP_CONFIG $COMPONENT.password))
yq w -i $TMP_CONFIG $COMPONENT.htpasswd $HTPASSWD
}
function addHtpasswdEntryEncrypted() {
local COMPONENT=$1
local HTPASSWD=$(htpasswd -nb \
$(sops -d --extract "$COMPONENT['username']" $TMP_CONFIG) \
$(sops -d --extract "$COMPONENT['password']" $TMP_CONFIG))
sops --set "$COMPONENT['htpasswd'] \"$HTPASSWD\"" $TMP_CONFIG
}
function runYtt() {
ytt \
-f charts/namespace.yaml \
-f charts/prometheus/ \
-f charts/loki/ \
-f charts/grafana/ \
-f promtail/ \
--output-directory $OUTPUT \
--ignore-unknown-comments \
-f $1
}
mkdir -p $OUTPUT
cp $CONFIG $TMP_CONFIG
# Fill in templates
if test -z "$(grep -o '^sops:$' $TMP_CONFIG)"; then
addHtpasswdEntryUnencrypted loki
addHtpasswdEntryUnencrypted prometheus.server
echo -e "#@data/values\n---\n$(cat $TMP_CONFIG)" | runYtt -
else
addHtpasswdEntryEncrypted "['loki']" $TMP_CONFIG
addHtpasswdEntryEncrypted "['prometheus']['server']" $TMP_CONFIG
echo -e "#@data/values\n---\n$(sops -d $TMP_CONFIG)" | runYtt -
fi
# Create configmap with dashboards
kubectl create configmap grafana-dashboards \
--from-file=./dashboards \
--dry-run=true \
--namespace=$NAMESPACE \
-o yaml > $OUTPUT/configuration/dashboards.cm.yaml
test -n "$DRYRUN" && exit 0
# Install loose components
kubectl apply -f $OUTPUT/namespace.yaml
kubectl apply -f $OUTPUT/configuration
kubectl apply -f $OUTPUT/storage
# Add Loki helm repository
helm repo add loki https://grafana.github.io/loki/charts
helm repo update
# Install Prometheus
PROMETHEUS_CHART_NAME=prometheus-$NAMESPACE
helm $(updateOrInstall $PROMETHEUS_CHART_NAME) $PROMETHEUS_CHART_NAME \
stable/prometheus \
--version $(cat ./charts/prometheus/VERSION) \
--values $OUTPUT/prometheus.yaml \
--namespace $NAMESPACE
# Install Loki
LOKI_CHART_NAME=loki-$NAMESPACE
helm $(updateOrInstall $LOKI_CHART_NAME) $LOKI_CHART_NAME \
loki/loki \
--version $(cat ./charts/loki/VERSION) \
--values $OUTPUT/loki.yaml \
--namespace $NAMESPACE
# Install Grafana
GRAFANA_CHART_NAME=grafana-$NAMESPACE
helm $(updateOrInstall $GRAFANA_CHART_NAME) $GRAFANA_CHART_NAME \
stable/grafana \
--version $(cat ./charts/grafana/VERSION) \
--values $OUTPUT/grafana.yaml \
--namespace $NAMESPACE

124
promtail/promtail.yaml Normal file
View file

@ -0,0 +1,124 @@
#@ load("@ytt:data", "data")
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: #@ "{}/positions.yaml".format(data.values.promtail.storagePath)
clients:
- url: #@ "https://{}/loki/api/v1/push".format(data.values.loki.host)
tls_config:
insecure_skip_verify: #@ data.values.tls.skipVerify
#@ if not data.values.tls.skipVerify:
ca_file: #@ "{}/promtail.ca.crt".format(data.values.promtail.storagePath)
#@ end
basic_auth:
username: #@ data.values.loki.username
password: #@ data.values.loki.password
scrape_configs:
- job_name: gerrit_error
static_configs:
- targets:
- localhost
labels:
job: gerrit_error
__path__: #@ "{}/error_log.json".format(data.values.promtail.logPath)
entry_parser: raw
pipeline_stages:
- json:
expressions:
level:
timestamp: '"@timestamp"'
exception: '"exception"'
thread: thread_name
logger: logger_name
class:
message:
- json:
source: exception
expressions:
exception_message:
exception_class:
- template:
source: timestamp
template: '{{ Replace .Value "," "." 1 }}'
- template:
source: timestamp
template: '{{ Replace .Value "Z" " +0000" 1 }}'
- template:
source: timestamp
template: '{{ Replace .Value "T" " " 1 }}'
- timestamp:
source: timestamp
format: "2006-01-02 15:04:05.999 -0700"
- regex:
source: message
expression: "Gerrit Code Review (?P<gerrit_version>.*) ready"
- labels:
level:
exception_message:
exception_class:
thread:
logger:
class:
gerrit_version:
- job_name: gerrit_httpd
static_configs:
- targets:
- localhost
labels:
job: gerrit_httpd
__path__: #@ "{}/httpd_log.json".format(data.values.promtail.logPath)
entry_parser: raw
pipeline_stages:
- json:
expressions:
timestamp:
thread:
user:
method:
status:
protocol:
- template:
source: timestamp
template: '{{ Replace .Value "," "." 1 }}'
- timestamp:
source: timestamp
format: '02/Jan/2006:15:04:05.999 -0700'
- labels:
thread:
user:
method:
status:
protocol:
- job_name: gerrit_sshd
static_configs:
- targets:
- localhost
labels:
job: gerrit_sshd
__path__: #@ "{}/sshd_log.json".format(data.values.promtail.logPath)
entry_parser: raw
pipeline_stages:
- json:
expressions:
timestamp:
session:
thread:
user:
account_id:
status:
- template:
source: timestamp
template: '{{ Replace .Value "," "." 1 }}'
- timestamp:
source: timestamp
format: 2006-01-02 15:04:05.999 -0700
- labels:
session:
thread:
user:
account_id:
status:

42
uninstall.sh Executable file
View file

@ -0,0 +1,42 @@
#!/bin/bash -e
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
usage() {
me=`basename "$0"`
echo >&2 "Usage: $me CONFIG"
exit 1
}
test -z "$1" && usage
CONFIG=$1
NAMESPACE=$(yq r $CONFIG namespace)
function removeHelmDeployment() {
read -p "This will remove the deployment $1-$NAMESPACE. Continue (y/n)? " response
if [[ "$response" == "y" ]]; then
helm uninstall $1-$NAMESPACE -n $NAMESPACE || true
fi
}
removeHelmDeployment grafana
removeHelmDeployment loki
removeHelmDeployment prometheus
read -p "This will remove the namespace $NAMESPACE. Continue (y/n)? " response
if [[ "$response" == "y" ]]; then
kubectl delete ns $NAMESPACE
fi