Diagram of product resources

Grafana in Kubernetes

Grafana stack (Grafana Operator and its Custom Resources) for Kubernetes
$350
Dependencies included: $50
BUY
126

The module deploys Grafana Operator and Grafana as a Custom Resource to Kubernetes cluster

Log in to Corewide IaC registry

Once you have a Corewide Solutions Portal account, this one-time action will use your browser session to retrieve credentials:

 shellterraform login solutions.corewide.com
Provision instructions

Initialize mandatory providers:

Copy and paste into your Terraform configuration and insert the variables:

 hclmodule "tf_k8s_grafana" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-grafana/helm"
  version = "~> 1.1.0"

  # specify module inputs here or try one of the examples below
  ...
}

Initialize the setup:

 shellterraform init
Define update strategy

Corewide DevOps team strictly follows Semantic Versioning Specification to provide our clients with products that have predictable upgrades between versions. We recommend pinning patch versions of our modules using pessimistic constraint operator (~>) to prevent breaking changes during upgrades.

To get new features during the upgrades (without breaking compatibility), use ~> 1.1 and run terraform init -upgrade

For the safest setup, use strict pinning with version = "1.1.0"

v1.1.0 released 5 months, 3 weeks ago
New version approx. every 7 weeks

As of version 5.9.0, Grafana Operator allows deploying the following CRs:

There is a proposal page in the documentation

While the operator supports management of multiple Grafana instances, this module deploys one instance. To configure resources in a right place, every CR refers to a specific instance using instanceSelector. A label for the selector can be retrieved from module's instance_selector_label output. The examples are shown below.

Configure Prometheus data source as default one:

 hclmodule "prometheus_datasource" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-crd/kubectl"
  version = "~> 2.0"

  api_version = "grafana.integreatly.org/v1beta1"
  kind        = "GrafanaDatasource"
  recreate    = true

  metadata = {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec = {
    instanceSelector = {
      matchLabels = module.grafana.instance_selector_label
    }

    datasource = {
      name      = "Prometheus-main"
      type      = "prometheus"
      access    = "proxy"
      url       = "http://prometheus-server:9090"
      isDefault = true
      editable  = true

      jsonData = {
        tlsSkipVerify = true
        timeInterval  = "5s"
      }
    }
  }
}

Configure external Prometheus data source, specify basic-auth credentials:

 hclmodule "prometheus_datasource" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-crd/kubectl"
  version = "~> 2.0"

  api_version = "grafana.integreatly.org/v1beta1"
  kind        = "GrafanaDatasource"
  recreate    = true

  metadata = {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec = {
    instanceSelector = {
      matchLabels = {
        dashboards = "grafana"
      }
    }

    datasource = {
      name      = "Prometheus-main"
      type      = "prometheus"
      access    = "proxy"
      url       = "https://prometheus.example.com"
      user      = "basic_auth_user"
      basicAuth = true
      editable  = true

      jsonData = {
        timeInterval  = "5s"
        tlsSkipVerify = true
      }

      secureJsonData = {
        password = "basic_auth_pass"
      }
    }
  }
}

Note: it is possible to use credentials from a k8s secret. To do so, follow this example.

Deploy Node Exporter Full Dashboard using JSON URL, specify data source and plugins:

 hclmodule "dashboard" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-crd/kubectl"
  version = "~> 2.0"

  api_version = "grafana.integreatly.org/v1beta1"
  kind        = "GrafanaDashboard"
  recreate    = true

  metadata = {
    name      = "node-exporter-full"
    namespace = kubernetes_namespace_v1.monitoring.metadata[0].name
  }

  spec = {
    url = "https://raw.githubusercontent.com/rfmoz/grafana-dashboards/master/prometheus/node-exporter-full.json"

    instanceSelector = {
      matchLabels = {
        dashboards = "grafana"
      }
    }

    datasources = [
      {
        inputName      = "DS_PROMETHEUS"
        datasourceName = "Prometheus-main"
      },
    ]

    plugins = [
      {
        name    = "grafana-piechart-panel"
        version = "1.3.9"
      },
      {
        name    = "required-plugin"
        version = "1.33.7"
      },
    ]
  }
}

In this example spec.datasources[0].datasourceName matches spec.datasource.name of Datasource CR.

Note: Currently, it is not possible to change Dashboard name without editing JSON. You can use spec.folder parameter to deploy the same dashboard for different environments. Follow this example

Deploy Grafana Operator and Grafana with custom node selector without ingress:

 hclmodule "grafana" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-grafana/helm"
  version = "~> 1.1"

  node_selector = {
    "cloud.google.com/gke-nodepool" = "maintenance"
  }

  ingress = {
    enabled = false
  }
}

Deploy Grafana Operator and Grafana CR with full configuration:

 hclmodule "grafana" {
  source  = "solutions.corewide.com/kubernetes/tf-k8s-grafana/helm"
  version = "~> 1.1"

  name_prefix                 = "dev"
  namespace                   = "grafana"
  operator_app_version        = "v5.9.2"
  operator_chart_version      = "v5.9.2"
  grafana_version             = "10.0.1"
  storage_size                = "10Gi"
  storage_class               = "standard"
  grafana_log_level           = "warn"
  admin_user                  = "admin"
  admin_password              = "super_pass"
  grafana_recreate_on_changes = false

  node_selector = {
    "cloud.google.com/gke-nodepool" = "maintenance"
  }

  ingress = {
    enabled  = true
    class    = "nginx"
    hostname = "mon.example.com"

    annotations = {
      "cert-manager.io/cluster-issuer" = "dev"
    }
  }

  grafana_env_vars = {
    GF_SERVER_ROOT_URL = "https://mon.example.com"
  }
}
Variable Description Type Default Required Sensitive
ingress Grafana ingress parameters object yes no
namespace The namespace to install resources in string yes no
admin_password Grafana admin password (randomly generated by default) string no yes
admin_user Grafana admin username string admin no no
grafana_env_vars Environment variables for Grafana container in key-value format map(any) {} no no
grafana_log_level Grafana log level (Supported levels: trace, debug, info, warn, error or critical) string warn no no
grafana_recreate_on_changes Whether the Grafana CRD should be recreated and not updated during apply phase bool true no no
grafana_version Grafana image tag string 10.0.1 no no
ingress.annotations Map of ingress annotations map(string) {} no no
ingress.class Ingress class string nginx no no
ingress.enabled specifies whether an Ingress is created for Grafana bool true no no
ingress.hostname Ingress hostname string no no
name_prefix Name prefix for Grafana operator and Grafana resources. If null, prefix is not included string no no
node_selector Node selector labels to assign to Grafana operator and Grafana. '.' in the domain names are escaped automatically where needed map(any) {} no no
operator_app_version Grafana operator image version string v5.9.2 no no
operator_chart_version Grafana operator Helm chart version string v5.9.2 no no
storage_class Grafana persistent storage class name (will be used a cluster's default if not specified) string no no
storage_size Grafana persistent storage size string 5Gi no no
Output Description Type Sensitive
admin_credentials Grafana admin credentials map yes
instance_selector_label Selector label to match Dashboard and Data source CRs to Grafana CR attribute no
Dependency Version Kind
terraform >= 1.3 CLI
hashicorp/helm ~> 2.9 provider
hashicorp/random ~> 3.3 provider
tf-k8s-crd ~> 2.0 module

Not sure where to start?
Let's find your perfect match.