We are going to deploy Grafana to visualise Prometheus monitoring data.
Pre-requisites
We are using our Kubernetes homelab to deploy Grafana.
A working NFS server is required to create persistent volumes. Note that NFS server configuration is not covered in this article, but the way we set it up can be found here.
Our NFS server IP address is 10.11.1.20, and we have the following export configured for Grafana:
/mnt/storage-k8s/nfs/grafana
The owner:group of the NFS folder is set to 472:472, because of Grafana deployment runAsUser: 472
.
Download Files from GitHub
Configuration files used in this article are hosted on GitHub. Clone the following repository:
$ git clone https://github.com/lisenet/kubernetes-homelab.git $ cd ./kubernetes-homelab/
TLDR; Install and Configure Grafana: All in One Go
Create a monitoring namespace:
$ kubectl create ns monitoring
Create everything with a single command:
$ kubectl apply -f ./kubernetes/grafana/
Note to self: this can be a Helm chart.
Install and Configure Grafana: Step by Step
Step by step instructions. Note that this homelab project is under development, therefore please refer to GitHub for any source code changes.
Create a Namespace
Create a monitoring namespace:
$ kubectl create ns monitoring
Create Config Maps
Configure Grafana to use Prometheus as a data source.
$ kubectl apply -f ./kubernetes/grafana/grafana-config-map-datasource.yml
This is what the code looks like:
--- apiVersion: v1 kind: ConfigMap metadata: name: grafana-datasources namespace: monitoring data: prometheus.yaml: |- { "apiVersion": 1, "datasources": [ { "access":"proxy", "editable": true, "name": "Prometheus", "orgId": 1, "type": "prometheus", "url": "http://prometheus-service.monitoring.svc:9090", "version": 1 } ] }
We can also use a config map to define our initial Grafana configuration like TLS certificates and logging options. Create a config map that we will later use to populate a custom grafana.ini
file:
$ kubectl apply -f ./kubernetes/grafana/grafana-config-map-ini.yml
This is what the code looks like:
--- apiVersion: v1 kind: ConfigMap metadata: name: grafana-ini namespace: monitoring data: grafana.ini: | [server] protocol = https http_port = 3000 cert_file = /etc/grafana/certs/tls.crt cert_key = /etc/grafana/certs/tls.key [analytics] reporting_enabled = false check_for_updates = true [log] mode = console level = info [paths] data = /var/lib/grafana/data logs = /var/log/grafana plugins = /var/lib/grafana/plugins provisioning = /etc/grafana/provisioning
Configure Grafana dashboard providers.
$ kubectl apply -f ./kubernetes/grafana/grafana-config-map-dashboard-providers.yml
This is what the code looks like:
--- apiVersion: v1 kind: ConfigMap metadata: name: grafana-dashboard-providers namespace: monitoring labels: app: grafana data: dashboardproviders.yaml: | apiVersion: 1 providers: - name: k8s-cluster-summary folder: homelab options: path: /var/lib/grafana/dashboards/k8s-cluster-summary orgId: 1 type: file disableDeletion: false - name: node-exporter-full folder: homelab options: path: /var/lib/grafana/dashboards/node-exporter-full orgId: 1 type: file disableDeletion: false
Configure Grafana dashboards for K8s cluster and node exporter:
$ kubectl apply -f ./kubernetes/grafana/grafana-config-map-dashboards-k8s-cluster.yml $ kubectl apply -f ./kubernetes/grafana/grafana-config-map-dashboards-node-exporter.yml
Create a TLS Secret
Create a secret to store our TLS certificates.
$ kubectl apply -f ./kubernetes/grafana/grafana-secret-tls.yml
This is what the code looks like:
--- apiVersion: v1 kind: Secret metadata: name: grafana-tls-cert namespace: monitoring type: kubernetes.io/tls data: tls.crt: | [... your TLS certificate ... tls.key: | [... your TLS private key ...]
Create a Persistent Volume
We want to keep grafana configuration data and store it on a persistent volume.
$ kubectl apply -f ./kubernetes/grafana/grafana-pv.yml
This is what the code looks like:
--- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv-grafana namespace: monitoring spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs mountOptions: - hard - nfsvers=4.1 nfs: path: /mnt/storage-k8s/nfs/grafana server: 10.11.1.20
Create a Persistent Volume Claim
Allow grafana to request persistent storage.
$ kubectl apply -f ./kubernetes/grafana/grafana-pvc.yml
This is what the code looks like:
--- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc-grafana namespace: monitoring spec: storageClassName: nfs accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
Create a Deployment Configuration
$ kubectl apply -f ./kubernetes/grafana/grafana-deployment.yml
This is what the code looks like:
--- apiVersion: apps/v1 kind: Deployment metadata: name: grafana namespace: monitoring labels: app: grafana spec: replicas: 1 selector: matchLabels: app: grafana template: metadata: name: grafana labels: app: grafana spec: securityContext: fsGroup: 472 runAsGroup: 472 runAsNonRoot: true runAsUser: 472 containers: - name: grafana image: grafana/grafana:7.3.7 imagePullPolicy: IfNotPresent ports: - name: grafana containerPort: 3000 resources: limits: memory: "2Gi" cpu: "1000m" requests: memory: "1Gi" cpu: "500m" volumeMounts: - name: grafana-config mountPath: /etc/grafana/grafana.ini subPath: grafana.ini - name: grafana-storage mountPath: /var/lib/grafana - name: grafana-certs mountPath: /etc/grafana/certs/ readOnly: true - name: grafana-datasources mountPath: /etc/grafana/provisioning/datasources/prometheus.yaml subPath: prometheus.yaml - name: grafana-dashboard-providers mountPath: /etc/grafana/provisioning/dashboards/dashboardproviders.yaml subPath: dashboardproviders.yaml - name: dashboards-k8s-cluster-summary mountPath: /var/lib/grafana/dashboards/k8s-cluster-summary - name: dashboards-node-exporter-full mountPath: /var/lib/grafana/dashboards/node-exporter-full # See https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ #initContainers: # - name: fix-nfs-permissions # image: busybox # command: ["sh", "-c", "chown -R 472:472 /var/lib/grafana"] # securityContext: # runAsUser: 0 # runAsNonRoot: false # volumeMounts: # - name: grafana-storage # mountPath: /var/lib/grafana/ restartPolicy: Always terminationGracePeriodSeconds: 60 volumes: - name: grafana-config configMap: name: grafana-ini - name: grafana-storage persistentVolumeClaim: claimName: nfs-pvc-grafana - name: grafana-certs secret: secretName: grafana-tls-cert items: - key: tls.crt path: tls.crt - key: tls.key path: tls.key - name: grafana-datasources configMap: name: grafana-datasources - name: grafana-dashboard-providers configMap: name: grafana-dashboard-providers - name: dashboards-k8s-cluster-summary configMap: name: grafana-dashboards-k8s-cluster-summary - name: dashboards-node-exporter-full configMap: name: grafana-dashboards-node-exporter-full
Create a Service
$ kubectl apply -f ./kubernetes/grafana/grafana-service.yml
This is what the code looks like:
--- apiVersion: v1 kind: Service metadata: name: grafana namespace: monitoring annotations: prometheus.io/scrape: 'true' prometheus.io/port: '3000' labels: app: grafana spec: selector: app: grafana type: NodePort ports: - port: 3000 targetPort: 3000 nodePort: 32000
Check Monitoring Namespace
$ kubectl -n monitoring get all -l app=grafana NAME READY STATUS RESTARTS AGE pod/grafana-6fff94cd6b-d8gmn 1/1 Running 0 6m47s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/grafana NodePort 10.110.20.247 none 3000:32000/TCP 6d4h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/grafana 1/1 1 1 6d4h NAME DESIRED CURRENT READY AGE replicaset.apps/grafana-6fff94cd6b 1 1 1 6d4h
Create a Dashboard to Monitor Kubernetes Deployments
We can access grafana dashboard by using its service node port 32000. Default credentials are admin/admin.
We should have a couple of dashboards installed already, Kubernetes Cluster Summary and Node Exporter Full. Optionally, install a dashboard to monitor Kubernetes deployments: https://grafana.com/grafana/dashboards/8588
The end result should look something like this:
What’s Next?
We will be configuring monitoring and adding Grafana dashboards for our homelab services: Etcd, Bind DNS, HAProxy, Linux servers etc.