Setup Grafana on AWS EKS and integrate with AWS Cloudwatch

What is Grafana?

Grafana is open-source visualization and analytics software. It allows you to query, visualize, alert on, and explore your metrics no matter where they are stored. In plain English, it provides you with tools to turn your time-series database (TSDB) data into beautiful graphs and visualizations.

Setup Grafana on Amazon Elastic Kubernetes Service

This blog explains on how to run Grafana on Amazon Elastic Kubernetes cluster and adding cloudwatch as datasource to Grafana. Using Grafana you can simplify Kubernetes monitoring dashboards from CloudWatch metrics. Let’s look into the detailed deployment steps.

Deploying EKS cluster and nodes

We are deploying EKS and required networking resources using CloudFormation template. CloudFormation will create below resources:
  • IAM Role for EKS
  • VPC
  • Two Public Subnets and Two Private Subnets
  • Internet Gateway
  • Two NAT Gateways
  • Public Route Table and its appropriate association
  • Two Private Route Tables
  • Control Plane Security Group
  • EKS
Lets deploy the CloudFormation by cloning the repo  eks-kubernetes-grafana-cloudwatch 

Login to AWS account and the region where you want to deploy this setup and go to CloudFormation Service

Create Stack by uploading the CloudFormation template "eks_cluster_template.yaml

In Next Page, pass the parameters as per your requirement

Click Next and Go to Final Page of CloudFormation and acknowledge the IAM role creation and Create the stack.


Wait for stack to reach create complete state

EKS Cluster is created with all the required configuration. Now we will create the node group for the cluster. Before creating the node group, we need IAM role for the node group.

Go to IAM console and click on create role

Attach below managed policies which are required for EKS nodes
  • AmazonEKSWorkerNodePolicy
  • AmazonEC2ContainerRegistryReadOnly
  • AmazonEKS_CNI_Policy



Once IAM role creation for node is completed, Go to AWS EKS and click on EKS configuration and go to compute and add Node Group

Enter the Node group name and select the role which we created in previous steps

Pass the values as per your requirement on instance Type, size and scaling configuration

After node group is created, you will be seeing the nodes in Ready state

Validate the nodes from your local machine using kubectl


Now all set with Infrastructure and EKS environment, now time to deploy Kubernetes manifests - deployment, data-source and ingress service.  

Deploying Grafana and CloudWatch data source on EKS

We will start with creating an IAM role for Grafana to read the CloudWatch metrics. I have created a role and attached below managed polices. 
  • AmazonEC2ReadOnlyAccess
  • CloudWatchReadOnlyAccess

You can even granularize the permission by looking into the  Grafana official website

Trust the Grafana role with EKS node role

In this demo, Grafana will fetch the CloudWatch metric from the same account. If you want to monitor different AWS Account(s) then in the target account, create IAM role for Grafana and trust the role with EKS node role where Grafana is containerized.

Go to folder where you have clone the repo, All the Kubernetes manifests (YAML files) used in this tutorial are hosted on Github. You can clone it and use it for the setup.
  • Grafana data-source config file : CloudWatch data source is integrated with ConfigMap
  • deployment file : Grafana configuration and deployment file 
  • service file : Ingress to access the Grafana URL with load balancer URL
Step 1: Create the namespace
For this demo, I have used monitoring as a namespace
kubectl create namespace monitoring


Step 2: Create the ConfigMap

Below is the data-source yaml file for Grafana with CloudWatch data-source. Change the  "assumeRoleArn" to the your Grafana role.

apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-datasources
  namespace: monitoring
data:
  cloudwatch.yaml: |-
    {
        "apiVersion": 1,
        "datasources": [
            {
                "name": "cw-data-dev",            
                "editable": true,
                "type": "cloudwatch",              
                "jsonData":
                    {
                        "authType": "arn",
                        "defaultRegion": "ap-south-1",
                        "customMetricsNamespaces": "",
                        "assumeRoleArn": "arn:aws:iam::<AWS_Account_ID>>:role/grafana_role",
                    }          
            }
        ]
    }
Run the below command to create the config map for Grafana data-source
kubectl create -f grafana-datasource-config.yaml -n monitoring

Step 3:
 Create the deployment
Below is the deployment.yaml file and this Grafana deployment does not use a persistent volume. If you restart the pod all changes will be gone. Use a persistent volume if you are deploying Grafana for your project requirements. It will persist all the configs and data that Grafana uses.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      name: grafana
      labels:
        app: grafana
    spec:
      containers:
      - name: grafana
        image: grafana/grafana:latest
        ports:
        - name: grafana
          containerPort: 3000
        resources:
          limits:
            memory: "1Gi"
            cpu: "1000m"
          requests:
            memory: 500M
            cpu: "500m"
        volumeMounts:
          - mountPath: /var/lib/grafana
            name: grafana-storage
          - mountPath: /etc/grafana/provisioning/datasources
            name: grafana-datasources
            readOnly: false
      volumes:
        - name: grafana-storage
          emptyDir: {}
        - name: grafana-datasources
          configMap:
              defaultMode: 420
              name: grafana-datasources
Run the below command to deploy Grafana
kubectl create -f deployment.yaml -n monitoring

Check the pods status by running the below command:
kubectl get pods-n monitoring

Step 4: Create the Service
Below is the service yaml file to access Grafana over Load balancer URL. You can also expose it to NodePort based on your requirement
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
spec:
  selector:
    app: grafana
  type: LoadBalancer  
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
Run the below kubectl command to expose the Grafana URL to loadbalancer with service manifest
kubectl create -f service.yaml -n monitoring
Check the status of service by running below command
kubectl get svc -n monitoring

Validate the Load balancer status in AWS console

Now you will be able to access Grafana dashboard from Load Balancer URL
User: admin
Pass: admin

We can see, data source which we passed in ConfigMap is configured in Grafana data-source

Lets test the Grafana role configuration to check if Grafana can read the CloudWatch metrics.
We can see, data source is working with assume role ARN.

Lets, test by configuring a dashboard for EC2, There are many prebuilt Grafana dashboard available to use. One can import it and monitor the services or create their own custom dashboard depending on the use case.

You should see the dashboard immediately

Conclusion

In this blog post, I have shown you how to create the EKS cluster and nodes. Following this, I showed you how to deploy Grafana and CloudWatch data-source on Kubernetes. Hope this blog helped you in your similar use case.

Thank you for reading!

Comments

Popular posts from this blog

Connect to Linux EC2 Instance if Key pair is lost after Initial Launch

Start or Stop services in multiple Windows EC2 Instances using AWS Systems Manager

Concourse CI Installation and Configuration in Windows

Install SSM Agent in Amazon EC2 Instance

Deploy AWS infrastructure using Terraform and GitHub Actions

Automate Permission Boundary Attachment to IAM roles and Users

AWS Route 53 Inbound Resolver to resolve DNS for Multi Account Organization

Import Existing Resources using Terraform

Hosting AWS VPC Interface Endpoints in Shared Model