Plutono

Installs the web dashboarding system Plutono to easily collect, correlate, and visualize Prometheus metrics with dashboards.

Owner

  1. Richard Tief (@richardtief)

Quick Start

This guide provides a quick and straightforward way how to use Plutono as a Greenhouse Plugin on your Kubernetes cluster.

Prerequisites

  • A running and Greenhouse-managed Kubernetes cluster
  • kube-monitoring Plugin installed to have at least one Prometheus instance running in the cluster

The plugin works by factory default with anonymous access enabled. If you use the standard configuration in the kube-monitoring plugin, the data source and some k8s-monitoring dashboards are already pre-installed.

Step 1: Add your dashboards

Dashboards are selected from ConfigMaps across namespaces. The plugin searches for ConfigMaps with the label plutono-dashboard: "true" and imports them into Plutono. The ConfigMap must contain a key like my-dashboard.json with the dashboard JSON content. Example

Step 2: Add your datasources

Data sources are selected from Secrets across namespaces. The plugin searches for Secrets with the label plutono-dashboard: "true" and imports them into Plutono. The Secrets should contain valid datasource configuration YAML. Example

Configuration

ParameterDescriptionDefault
plutono.replicasNumber of nodes1
plutono.podDisruptionBudget.minAvailablePod disruption minimum availablenil
plutono.podDisruptionBudget.maxUnavailablePod disruption maximum unavailablenil
plutono.podDisruptionBudget.apiVersionPod disruption apiVersionnil
plutono.deploymentStrategyDeployment strategy{ "type": "RollingUpdate" }
plutono.livenessProbeLiveness Probe settings{ "httpGet": { "path": "/api/health", "port": 3000 } "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10 }
plutono.readinessProbeReadiness Probe settings{ "httpGet": { "path": "/api/health", "port": 3000 } }
plutono.securityContextDeployment securityContext{"runAsUser": 472, "runAsGroup": 472, "fsGroup": 472}
plutono.priorityClassNameName of Priority Class to assign podsnil
plutono.image.registryImage registrydocker.io
plutono.image.repositoryImage repositoryplutono/plutono
plutono.image.tagOverrides the Plutono image tag whose default is the chart appVersion (Must be >= 5.0.0)``
plutono.image.shaImage sha (optional)``
plutono.image.pullPolicyImage pull policyIfNotPresent
plutono.image.pullSecretsImage pull secrets (can be templated)[]
plutono.service.enabledEnable plutono servicetrue
plutono.service.ipFamiliesKubernetes service IP families[]
plutono.service.ipFamilyPolicyKubernetes service IP family policy""
plutono.service.typeKubernetes service typeClusterIP
plutono.service.portKubernetes port where service is exposed80
plutono.service.portNameName of the port on the serviceservice
plutono.service.appProtocolAdds the appProtocol field to the service``
plutono.service.targetPortInternal service is port3000
plutono.service.nodePortKubernetes service nodePortnil
plutono.service.annotationsService annotations (can be templated){}
plutono.service.labelsCustom labels{}
plutono.service.clusterIPinternal cluster service IPnil
plutono.service.loadBalancerIPIP address to assign to load balancer (if supported)nil
plutono.service.loadBalancerSourceRangeslist of IP CIDRs allowed access to lb (if supported)[]
plutono.service.externalIPsservice external IP addresses[]
plutono.service.externalTrafficPolicychange the default externalTrafficPolicynil
plutono.headlessServiceCreate a headless servicefalse
plutono.extraExposePortsAdditional service ports for sidecar containers[]
plutono.hostAliasesadds rules to the pod’s /etc/hosts[]
plutono.ingress.enabledEnables Ingressfalse
plutono.ingress.annotationsIngress annotations (values are templated){}
plutono.ingress.labelsCustom labels{}
plutono.ingress.pathIngress accepted path/
plutono.ingress.pathTypeIngress type of pathPrefix
plutono.ingress.hostsIngress accepted hostnames["chart-example.local"]
plutono.ingress.extraPathsIngress extra paths to prepend to every host configuration. Useful when configuring custom actions with AWS ALB Ingress Controller. Requires ingress.hosts to have one or more host entries.[]
plutono.ingress.tlsIngress TLS configuration[]
plutono.ingress.ingressClassNameIngress Class Name. MAY be required for Kubernetes versions >= 1.18""
plutono.resourcesCPU/Memory resource requests/limits{}
plutono.nodeSelectorNode labels for pod assignment{}
plutono.tolerationsToleration labels for pod assignment[]
plutono.affinityAffinity settings for pod assignment{}
plutono.extraInitContainersInit containers to add to the plutono pod{}
plutono.extraContainersSidecar containers to add to the plutono pod""
plutono.extraContainerVolumesVolumes that can be mounted in sidecar containers[]
plutono.extraLabelsCustom labels for all manifests{}
plutono.schedulerNameName of the k8s scheduler (other than default)nil
plutono.persistence.enabledUse persistent volume to store datafalse
plutono.persistence.typeType of persistence (pvc or statefulset)pvc
plutono.persistence.sizeSize of persistent volume claim10Gi
plutono.persistence.existingClaimUse an existing PVC to persist data (can be templated)nil
plutono.persistence.storageClassNameType of persistent volume claimnil
plutono.persistence.accessModesPersistence access modes[ReadWriteOnce]
plutono.persistence.annotationsPersistentVolumeClaim annotations{}
plutono.persistence.finalizersPersistentVolumeClaim finalizers[ "kubernetes.io/pvc-protection" ]
plutono.persistence.extraPvcLabelsExtra labels to apply to a PVC.{}
plutono.persistence.subPathMount a sub dir of the persistent volume (can be templated)nil
plutono.persistence.inMemory.enabledIf persistence is not enabled, whether to mount the local storage in-memory to improve performancefalse
plutono.persistence.inMemory.sizeLimitSizeLimit for the in-memory local storagenil
plutono.persistence.disableWarningHide NOTES warning, useful when persiting to a databasefalse
plutono.initChownData.enabledIf false, don’t reset data ownership at startuptrue
plutono.initChownData.image.registryinit-chown-data container image registrydocker.io
plutono.initChownData.image.repositoryinit-chown-data container image repositorybusybox
plutono.initChownData.image.taginit-chown-data container image tag1.31.1
plutono.initChownData.image.shainit-chown-data container image sha (optional)""
plutono.initChownData.image.pullPolicyinit-chown-data container image pull policyIfNotPresent
plutono.initChownData.resourcesinit-chown-data pod resource requests & limits{}
plutono.schedulerNameAlternate scheduler namenil
plutono.envExtra environment variables passed to pods{}
plutono.envValueFromEnvironment variables from alternate sources. See the API docs on EnvVarSource for format details. Can be templated{}
plutono.envFromSecretName of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated""
plutono.envFromSecretsList of Kubernetes secrets (must be manually created in the same namespace) containing values to be added to the environment. Can be templated[]
plutono.envFromConfigMapsList of Kubernetes ConfigMaps (must be manually created in the same namespace) containing values to be added to the environment. Can be templated[]
plutono.envRenderSecretSensible environment variables passed to pods and stored as secret. (passed through tpl){}
plutono.enableServiceLinksInject Kubernetes services as environment variables.true
plutono.extraSecretMountsAdditional plutono server secret mounts[]
plutono.extraVolumeMountsAdditional plutono server volume mounts[]
plutono.extraVolumesAdditional Plutono server volumes[]
plutono.automountServiceAccountTokenMounted the service account token on the plutono pod. Mandatory, if sidecars are enabledtrue
plutono.createConfigmapEnable creating the plutono configmaptrue
plutono.extraConfigmapMountsAdditional plutono server configMap volume mounts (values are templated)[]
plutono.extraEmptyDirMountsAdditional plutono server emptyDir volume mounts[]
plutono.pluginsPlugins to be loaded along with Plutono[]
plutono.datasourcesConfigure plutono datasources (passed through tpl){}
plutono.alertingConfigure plutono alerting (passed through tpl){}
plutono.notifiersConfigure plutono notifiers{}
plutono.dashboardProvidersConfigure plutono dashboard providers{}
plutono.dashboardsDashboards to import{}
plutono.dashboardsConfigMapsConfigMaps reference that contains dashboards{}
plutono.plutono.iniPlutono’s primary configuration{}
global.imageRegistryGlobal image pull registry for all images.null
global.imagePullSecretsGlobal image pull secrets (can be templated). Allows either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style).[]
plutono.ldap.enabledEnable LDAP authenticationfalse
plutono.ldap.existingSecretThe name of an existing secret containing the ldap.toml file, this must have the key ldap-toml.""
plutono.ldap.configPlutono’s LDAP configuration""
plutono.annotationsDeployment annotations{}
plutono.labelsDeployment labels{}
plutono.podAnnotationsPod annotations{}
plutono.podLabelsPod labels{}
plutono.podPortNameName of the plutono port on the podplutono
plutono.lifecycleHooksLifecycle hooks for podStart and preStop Example{}
plutono.sidecar.image.registrySidecar image registryquay.io
plutono.sidecar.image.repositorySidecar image repositorykiwigrid/k8s-sidecar
plutono.sidecar.image.tagSidecar image tag1.26.0
plutono.sidecar.image.shaSidecar image sha (optional)""
plutono.sidecar.imagePullPolicySidecar image pull policyIfNotPresent
plutono.sidecar.resourcesSidecar resources{}
plutono.sidecar.securityContextSidecar securityContext{}
plutono.sidecar.enableUniqueFilenamesSets the kiwigrid/k8s-sidecar UNIQUE_FILENAMES environment variable. If set to true the sidecar will create unique filenames where duplicate data keys exist between ConfigMaps and/or Secrets within the same or multiple Namespaces.false
plutono.sidecar.alerts.enabledEnables the cluster wide search for alerts and adds/updates/deletes them in plutonofalse
plutono.sidecar.alerts.labelLabel that config maps with alerts should have to be addedplutono_alert
plutono.sidecar.alerts.labelValueLabel value that config maps with alerts should have to be added""
plutono.sidecar.alerts.searchNamespaceNamespaces list. If specified, the sidecar will search for alerts config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It’s also possible to specify ALL to search in all namespaces.nil
plutono.sidecar.alerts.watchMethodMethod 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.WATCH
plutono.sidecar.alerts.resourceShould the sidecar looks into secrets, configmaps or both.both
plutono.sidecar.alerts.reloadURLFull url of datasource configuration reload API endpoint, to invoke after a config-map change"http://localhost:3000/api/admin/provisioning/alerting/reload"
plutono.sidecar.alerts.skipReloadEnabling this omits defining the REQ_URL and REQ_METHOD environment variablesfalse
plutono.sidecar.alerts.initAlertsSet to true to deploy the alerts sidecar as an initContainer. This is needed if skipReload is true, to load any alerts defined at startup time.false
plutono.sidecar.alerts.extraMountsAdditional alerts sidecar volume mounts.[]
plutono.sidecar.dashboards.enabledEnables the cluster wide search for dashboards and adds/updates/deletes them in plutonofalse
plutono.sidecar.dashboards.SCProviderEnables creation of sidecar providertrue
plutono.sidecar.dashboards.provider.nameUnique name of the plutono providersidecarProvider
plutono.sidecar.dashboards.provider.orgidId of the organisation, to which the dashboards should be added1
plutono.sidecar.dashboards.provider.folderLogical folder in which plutono groups dashboards""
plutono.sidecar.dashboards.provider.folderUidAllows you to specify the static UID for the logical folder above""
plutono.sidecar.dashboards.provider.disableDeleteActivate to avoid the deletion of imported dashboardsfalse
plutono.sidecar.dashboards.provider.allowUiUpdatesAllow updating provisioned dashboards from the UIfalse
plutono.sidecar.dashboards.provider.typeProvider typefile
plutono.sidecar.dashboards.provider.foldersFromFilesStructureAllow Plutono to replicate dashboard structure from filesystem.false
plutono.sidecar.dashboards.watchMethodMethod 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.WATCH
plutono.sidecar.skipTlsVerifySet to true to skip tls verification for kube api callsnil
plutono.sidecar.dashboards.labelLabel that config maps with dashboards should have to be addedplutono_dashboard
plutono.sidecar.dashboards.labelValueLabel value that config maps with dashboards should have to be added""
plutono.sidecar.dashboards.folderFolder in the pod that should hold the collected dashboards (unless sidecar.dashboards.defaultFolderName is set). This path will be mounted./tmp/dashboards
plutono.sidecar.dashboards.folderAnnotationThe annotation the sidecar will look for in configmaps to override the destination folder for filesnil
plutono.sidecar.dashboards.defaultFolderNameThe default folder name, it will create a subfolder under the sidecar.dashboards.folder and put dashboards in there insteadnil
plutono.sidecar.dashboards.searchNamespaceNamespaces list. If specified, the sidecar will search for dashboards config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It’s also possible to specify ALL to search in all namespaces.nil
plutono.sidecar.dashboards.scriptAbsolute path to shell script to execute after a configmap got reloaded.nil
plutono.sidecar.dashboards.reloadURLFull url of dashboards configuration reload API endpoint, to invoke after a config-map change"http://localhost:3000/api/admin/provisioning/dashboards/reload"
plutono.sidecar.dashboards.skipReloadEnabling this omits defining the REQ_USERNAME, REQ_PASSWORD, REQ_URL and REQ_METHOD environment variablesfalse
plutono.sidecar.dashboards.resourceShould the sidecar looks into secrets, configmaps or both.both
plutono.sidecar.dashboards.extraMountsAdditional dashboard sidecar volume mounts.[]
plutono.sidecar.datasources.enabledEnables the cluster wide search for datasources and adds/updates/deletes them in plutonofalse
plutono.sidecar.datasources.labelLabel that config maps with datasources should have to be addedplutono_datasource
plutono.sidecar.datasources.labelValueLabel value that config maps with datasources should have to be added""
plutono.sidecar.datasources.searchNamespaceNamespaces list. If specified, the sidecar will search for datasources config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It’s also possible to specify ALL to search in all namespaces.nil
plutono.sidecar.datasources.watchMethodMethod 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.WATCH
plutono.sidecar.datasources.resourceShould the sidecar looks into secrets, configmaps or both.both
plutono.sidecar.datasources.reloadURLFull url of datasource configuration reload API endpoint, to invoke after a config-map change"http://localhost:3000/api/admin/provisioning/datasources/reload"
plutono.sidecar.datasources.skipReloadEnabling this omits defining the REQ_URL and REQ_METHOD environment variablesfalse
plutono.sidecar.datasources.initDatasourcesSet to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any datasources defined at startup time.false
plutono.sidecar.notifiers.enabledEnables the cluster wide search for notifiers and adds/updates/deletes them in plutonofalse
plutono.sidecar.notifiers.labelLabel that config maps with notifiers should have to be addedplutono_notifier
plutono.sidecar.notifiers.labelValueLabel value that config maps with notifiers should have to be added""
plutono.sidecar.notifiers.searchNamespaceNamespaces list. If specified, the sidecar will search for notifiers config-maps (or secrets) inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It’s also possible to specify ALL to search in all namespaces.nil
plutono.sidecar.notifiers.watchMethodMethod 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.WATCH
plutono.sidecar.notifiers.resourceShould the sidecar looks into secrets, configmaps or both.both
plutono.sidecar.notifiers.reloadURLFull url of notifier configuration reload API endpoint, to invoke after a config-map change"http://localhost:3000/api/admin/provisioning/notifications/reload"
plutono.sidecar.notifiers.skipReloadEnabling this omits defining the REQ_URL and REQ_METHOD environment variablesfalse
plutono.sidecar.notifiers.initNotifiersSet to true to deploy the notifier sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any notifiers defined at startup time.false
plutono.smtp.existingSecretThe name of an existing secret containing the SMTP credentials.""
plutono.smtp.userKeyThe key in the existing SMTP secret containing the username."user"
plutono.smtp.passwordKeyThe key in the existing SMTP secret containing the password."password"
plutono.admin.existingSecretThe name of an existing secret containing the admin credentials (can be templated).""
plutono.admin.userKeyThe key in the existing admin secret containing the username."admin-user"
plutono.admin.passwordKeyThe key in the existing admin secret containing the password."admin-password"
plutono.serviceAccount.automountServiceAccountTokenAutomount the service account token on all pods where is service account is usedfalse
plutono.serviceAccount.annotationsServiceAccount annotations
plutono.serviceAccount.createCreate service accounttrue
plutono.serviceAccount.labelsServiceAccount labels{}
plutono.serviceAccount.nameService account name to use, when empty will be set to created account if serviceAccount.create is set else to default``
plutono.serviceAccount.nameTestService account name to use for test, when empty will be set to created account if serviceAccount.create is set else to defaultnil
plutono.rbac.createCreate and use RBAC resourcestrue
plutono.rbac.namespacedCreates Role and Rolebinding instead of the default ClusterRole and ClusteRoleBindings for the plutono instancefalse
plutono.rbac.useExistingRoleSet to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to the rolename set here.nil
plutono.rbac.pspEnabledCreate PodSecurityPolicy (with rbac.create, grant roles permissions as well)false
plutono.rbac.pspUseAppArmorEnforce AppArmor in created PodSecurityPolicy (requires rbac.pspEnabled)false
plutono.rbac.extraRoleRulesAdditional rules to add to the Role[]
plutono.rbac.extraClusterRoleRulesAdditional rules to add to the ClusterRole[]
plutono.commandDefine command to be executed by plutono container at startupnil
plutono.argsDefine additional args if command is usednil
plutono.testFramework.enabledWhether to create test-related resourcestrue
plutono.testFramework.image.registrytest-framework image registry.docker.io
plutono.testFramework.image.repositorytest-framework image repository.bats/bats
plutono.testFramework.image.tagtest-framework image tag.v1.4.1
plutono.testFramework.imagePullPolicytest-framework image pull policy.IfNotPresent
plutono.testFramework.securityContexttest-framework securityContext{}
plutono.downloadDashboards.envEnvironment variables to be passed to the download-dashboards container{}
plutono.downloadDashboards.envFromSecretName of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated""
plutono.downloadDashboards.resourcesResources of download-dashboards container{}
plutono.downloadDashboardsImage.registryCurl docker image registrydocker.io
plutono.downloadDashboardsImage.repositoryCurl docker image repositorycurlimages/curl
plutono.downloadDashboardsImage.tagCurl docker image tag7.73.0
plutono.downloadDashboardsImage.shaCurl docker image sha (optional)""
plutono.downloadDashboardsImage.pullPolicyCurl docker image pull policyIfNotPresent
plutono.namespaceOverrideOverride the deployment namespace"" (Release.Namespace)
plutono.serviceMonitor.enabledUse servicemonitor from prometheus operatorfalse
plutono.serviceMonitor.namespaceNamespace this servicemonitor is installed in
plutono.serviceMonitor.intervalHow frequently Prometheus should scrape1m
plutono.serviceMonitor.pathPath to scrape/metrics
plutono.serviceMonitor.schemeScheme to use for metrics scrapinghttp
plutono.serviceMonitor.tlsConfigTLS configuration block for the endpoint{}
plutono.serviceMonitor.labelsLabels for the servicemonitor passed to Prometheus Operator{}
plutono.serviceMonitor.scrapeTimeoutTimeout after which the scrape is ended30s
plutono.serviceMonitor.relabelingsRelabelConfigs to apply to samples before scraping.[]
plutono.serviceMonitor.metricRelabelingsMetricRelabelConfigs to apply to samples before ingestion.[]
plutono.revisionHistoryLimitNumber of old ReplicaSets to retain10
plutono.networkPolicy.enabledEnable creation of NetworkPolicy resources.false
plutono.networkPolicy.allowExternalDon’t require client label for connectionstrue
plutono.networkPolicy.explicitNamespacesSelectorA Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed{}
plutono.networkPolicy.ingressEnable the creation of an ingress network policytrue
plutono.networkPolicy.egress.enabledEnable the creation of an egress network policyfalse
plutono.networkPolicy.egress.portsAn array of ports to allow for the egress[]
plutono.enableKubeBackwardCompatibilityEnable backward compatibility of kubernetes where pod’s definition version below 1.13 doesn’t have the enableServiceLinks optionfalse

Example ingress with path

With plutono 6.3 and above

plutono.ini:
  server:
    domain: monitoring.example.com
    root_url: "%(protocol)s://%(domain)s/plutono"
    serve_from_sub_path: true
ingress:
  enabled: true
  hosts:
    - "monitoring.example.com"
  path: "/plutono"

Example of extraVolumeMounts and extraVolumes

Configure additional volumes with extraVolumes and volume mounts with extraVolumeMounts.

Example for extraVolumeMounts and corresponding extraVolumes:

extraVolumeMounts:
  - name: plugins
    mountPath: /var/lib/plutono/plugins
    subPath: configs/plutono/plugins
    readOnly: false
  - name: dashboards
    mountPath: /var/lib/plutono/dashboards
    hostPath: /usr/shared/plutono/dashboards
    readOnly: false

extraVolumes:
  - name: plugins
    existingClaim: existing-plutono-claim
  - name: dashboards
    hostPath: /usr/shared/plutono/dashboards

Volumes default to emptyDir. Set to persistentVolumeClaim, hostPath, csi, or configMap for other types. For a persistentVolumeClaim, specify an existing claim name with existingClaim.

Import dashboards

There are a few methods to import dashboards to Plutono. Below are some examples and explanations as to how to use each method:

dashboards:
  default:
    some-dashboard:
      json: |
        {
          "annotations":

          ...
          # Complete json file here
          ...

          "title": "Some Dashboard",
          "uid": "abcd1234",
          "version": 1
        }        
    custom-dashboard:
      # This is a path to a file inside the dashboards directory inside the chart directory
      file: dashboards/custom-dashboard.json
    prometheus-stats:
      # Ref: https://plutono.com/dashboards/2
      gnetId: 2
      revision: 2
      datasource: Prometheus
    loki-dashboard-quick-search:
      gnetId: 12019
      revision: 2
      datasource:
      - name: DS_PROMETHEUS
        value: Prometheus
      - name: DS_LOKI
        value: Loki
    local-dashboard:
      url: https://raw.githubusercontent.com/user/repository/master/dashboards/dashboard.json

BASE64 dashboards

Dashboards could be stored on a server that does not return JSON directly and instead of it returns a Base64 encoded file (e.g. Gerrit) A new parameter has been added to the url use case so if you specify a b64content value equals to true after the url entry a Base64 decoding is applied before save the file to disk. If this entry is not set or is equals to false not decoding is applied to the file before saving it to disk.

Gerrit use case

Gerrit API for download files has the following schema: https://yourgerritserver/a/{project-name}/branches/{branch-id}/files/{file-id}/content where {project-name} and {file-id} usually has ‘/’ in their values and so they MUST be replaced by %2F so if project-name is user/repo, branch-id is master and file-id is equals to dir1/dir2/dashboard the url value is https://yourgerritserver/a/user%2Frepo/branches/master/files/dir1%2Fdir2%2Fdashboard/content

Sidecar for dashboards

If the parameter sidecar.dashboards.enabled is set, a sidecar container is deployed in the plutono pod. This container watches all configmaps (or secrets) in the cluster and filters out the ones with a label as defined in sidecar.dashboards.label. The files defined in those configmaps are written to a folder and accessed by plutono. Changes to the configmaps are monitored and the imported dashboards are deleted/updated.

A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside one configmap is currently not properly mirrored in plutono.

NOTE: Configure your data sources in your dashboards as variables to keep them portable across clusters.

Example dashboard config:

Folder structure:

dashboards/
├── dashboard1.json
├── dashboard2.json
templates/
├──dashboard-json-configmap.yaml

Helm template to create a configmap for each dashboard:

{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }}
---
apiVersion: v1
kind: ConfigMap

metadata:
  name: {{ printf "%s-%s" $.Release.Name $path | replace "/" "-" | trunc 63 }}
  labels:
    plutono-dashboard: "true"

data:
{{ printf "%s: |-" $path | replace "/" "-" | indent 2 }}
{{ printf "%s" $bytes | indent 4 }}

{{- end }}

Sidecar for datasources

If the parameter sidecar.datasources.enabled is set, an init container is deployed in the plutono pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and filters out the ones with a label as defined in sidecar.datasources.label. The files defined in those secrets are written to a folder and accessed by plutono on startup. Using these yaml files, the data sources in plutono can be imported.

Should you aim for reloading datasources in Plutono each time the config is changed, set sidecar.datasources.skipReload: false and adjust sidecar.datasources.reloadURL to http://<svc-name>.<namespace>.svc.cluster.local/api/admin/provisioning/datasources/reload.

Secrets are recommended over configmaps for this usecase because datasources usually contain private data like usernames and passwords. Secrets are the more appropriate cluster resource to manage those.

Example datasource config:

apiVersion: v1
kind: Secret
metadata:
  name: plutono-datasources
  labels:
    # default value for: sidecar.datasources.label
    plutono-datasource: "true"
stringData:
  datasources.yaml: |-
    apiVersion: 1
    datasources:
      - name: my-prometheus 
        type: prometheus
        access: proxy
        orgId: 1
        url: my-url-domain:9090
        isDefault: false
        jsonData:
          httpMethod: 'POST'
        editable: false    

NOTE: If you might include credentials in your datasource configuration, make sure to not use stringdata but base64 encoded data instead.

apiVersion: v1
kind: Secret
metadata:
  name: my-datasource
  labels:
    plutono-datasource: "true"
data:
  # The key must contain a unique name and the .yaml file type
  my-datasource.yaml: {{ include (print $.Template.BasePath "my-datasource.yaml") . | b64enc }}

Example values to add a datasource adapted from Grafana:

datasources:
 datasources.yaml:
  apiVersion: 1
  datasources:
      # <string, required> Sets the name you use to refer to
      # the data source in panels and queries.
    - name: my-prometheus 
      # <string, required> Sets the data source type.
      type: prometheus
      # <string, required> Sets the access mode, either
      # proxy or direct (Server or Browser in the UI).
      # Some data sources are incompatible with any setting
      # but proxy (Server).
      access: proxy
      # <int> Sets the organization id. Defaults to orgId 1.
      orgId: 1
      # <string> Sets a custom UID to reference this
      # data source in other parts of the configuration.
      # If not specified, Plutono generates one.
      uid:
      # <string> Sets the data source's URL, including the
      # port.
      url: my-url-domain:9090
      # <string> Sets the database user, if necessary.
      user:
      # <string> Sets the database name, if necessary.
      database:
      # <bool> Enables basic authorization.
      basicAuth:
      # <string> Sets the basic authorization username.
      basicAuthUser:
      # <bool> Enables credential headers.
      withCredentials:
      # <bool> Toggles whether the data source is pre-selected
      # for new panels. You can set only one default
      # data source per organization.
      isDefault: false
      # <map> Fields to convert to JSON and store in jsonData.
      jsonData:
        httpMethod: 'POST'
        # <bool> Enables TLS authentication using a client
        # certificate configured in secureJsonData.
        # tlsAuth: true
        # <bool> Enables TLS authentication using a CA
        # certificate.
        # tlsAuthWithCACert: true
      # <map> Fields to encrypt before storing in jsonData.
      secureJsonData:
        # <string> Defines the CA cert, client cert, and
        # client key for encrypted authentication.
        # tlsCACert: '...'
        # tlsClientCert: '...'
        # tlsClientKey: '...'
        # <string> Sets the database password, if necessary.
        # password:
        # <string> Sets the basic authorization password.
        # basicAuthPassword:
      # <int> Sets the version. Used to compare versions when
      # updating. Ignored when creating a new data source.
      version: 1
      # <bool> Allows users to edit data sources from the
      # Plutono UI.
      editable: false

How to serve Plutono with a path prefix (/plutono)

In order to serve Plutono with a prefix (e.g., http://example.com/plutono), add the following to your values.yaml.

ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/use-regex: "true"

  path: /plutono/?(.*)
  hosts:
    - k8s.example.dev

plutono.ini:
  server:
    root_url: http://localhost:3000/plutono # this host can be localhost

How to securely reference secrets in plutono.ini

This example uses Plutono file providers for secret values and the extraSecretMounts configuration flag (Additional plutono server secret mounts) to mount the secrets.

In plutono.ini:

plutono.ini:
  [auth.generic_oauth]
  enabled = true
  client_id = $__file{/etc/secrets/auth_generic_oauth/client_id}
  client_secret = $__file{/etc/secrets/auth_generic_oauth/client_secret}

Existing secret, or created along with helm:

---
apiVersion: v1
kind: Secret
metadata:
  name: auth-generic-oauth-secret
type: Opaque
stringData:
  client_id: <value>
  client_secret: <value>

Include in the extraSecretMounts configuration flag:

- extraSecretMounts:
  - name: auth-generic-oauth-secret-mount
    secretName: auth-generic-oauth-secret
    defaultMode: 0440
    mountPath: /etc/secrets/auth_generic_oauth
    readOnly: true

extraSecretMounts using a Container Storage Interface (CSI) provider

This example uses a CSI driver e.g. retrieving secrets using Azure Key Vault Provider

- extraSecretMounts:
  - name: secrets-store-inline
    mountPath: /run/secrets
    readOnly: true
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "my-provider"
      nodePublishSecretRef:
        name: akv-creds