How to Setup Grafana Loki on Kubernetes & Query Logs

How to Setup Grafana Loki on Kubernetes & Query Logs

In this blog, we will look into a step-by-step guide to setup Grafana Loki on Kubernetes using Helm.

We will also look at setting up Promtail which is an agent for Loki to collect logs and setup Grafana for querying logs using Loki.

Grafana Loki is an open-source log aggregation system that supports large-scale log management. It is a widely adopted tool for organizations observability stack.

If you want to learn in detail about Grafana Loki's architecture, read the detailed Grafana Loki Architecture blog.

Pods that will be deployed for Loki are listed below:

  1. Loki (sts) - The Loki pod contains all its components, like ingester, distributor, etc.
    This pod is responsible for compressing the logs into chunks and storing them, whether it's configured for the local filesystem or the external object storage.
  2. Loki-canary (daemonset): This is a health check pod for Loki. It sends dummy logs to check Loki's performance, such as latency and success rates.
  3. Loki-chunks-cache (sts): This caches the log chunks that have been recently queried so that the same chunk can be queried faster next time.
  4. Loki-gateway (deployment): This is an Nginx Ingress pod that routes requests to the correct Loki components. It will be more helpful if you use it with Loki Micro Services.
  5. Loki-results (sts): This caches the results from previous queries for faster query if the same query is used next time.

Loki Workflow

A workflow overview of Loki is shown in the diagram below

Click to View in HD

Let me explain the diagram

  1. The diagram shows two types of workflow, one given in numbers and the other in letters. Let's see about numbers first.
  2. It starts with Promtail, a Loki log-collecting agent that collects logs from the /var/log/pods directory.
  3. The collected logs are sent to Loki-gateway, which routes them to the Loki pod.
  4. In this Loki setup, log ingestion, compression, and storage happen inside the same pod. Once it is done, it stores the compressed log chunks in the PV.
  5. The letter flow starts with a user query the logs through the Grafana dashboard.
  6. Grafana Sends the query requests to the Loki gateway and it routes the request to the Loki pod.
  7. After getting the query request, the Loki pod sends back the correct logs based on the query.
  8. The query results are then stored in the result cache, and the recently accessed chunk info is cached in the chunk cache.
  9. And there is canary, which sends dummy logs to Loki pod to check its health.

Setup Prerequisites

The following are the prerequisites for this setup.

  1. Kubernetes Cluster
  2. Kubectl
  3. Helm installed in your system

Steps to Setup Grafana Loki on Kubernetes

If you are ready with the prerequisites, follow the steps below to set up Loki on Kubernetes using Helm.

Step 1: Add Grafana repo

Add a Grafana repo to your system to download the helm chart and set up Loki. Run the following command to add the repo

helm repo add grafana https://grafana.github.io/helm-charts

Once the repo is added, run the following command to update the repo to make sure the repo is up-to-date

helm repo update

Now, list every repo with the word Loki using the command

helm search repo loki

You will get the list of repos with the word Loki as shown below

list repos with word loki

From these repos, we are going to use the grafana/loki Helm chart repo to deploy Loki.

Step 2: Customize the Loki Helm Values file

Before deploying, we need to update some configurations in the helm chart.

Use the below command to save the default values of the helm chart in a YAML file.

helm show values grafana/loki > loki.yaml

You can also use the custom values file that we created below.

loki:
  commonConfig:
    replication_factor: 1
  storage:
    type: 'filesystem'
    bucketNames:
      chunks: chunks
      ruler: ruler
      admin: admin
  schemaConfig:
    configs:
      - from: "2024-04-01"
        store: tsdb
        object_store: filesystem
        schema: v13
        index:
          prefix: loki_index_
          period: 24h
  storage_config:
    filesystem:
      directory: /tmp/loki/chunks
  pattern_ingester:
    enabled: true
  limits_config:
    allow_structured_metadata: true
    volume_enabled: true
  ruler:
    enable_api: true
  auth_enabled: false

minio:
  enabled: false
      
deploymentMode: SingleBinary

singleBinary:
  replicas: 1
  persistence:
    storageClass: gp2
    accessModes:
      - ReadWriteOnce
    size: 20Gi

  resources:
    requests:
      cpu: "1"
      memory: "2Gi"
    limits:
      cpu: "2"
      memory: "4Gi"

sidecar:
  image:
    repository: kiwigrid/k8s-sidecar
    tag: 1.30.0
  resources:
    requests:
      cpu: 50m
      memory: 50Mi
    limits:
      cpu: 100m
      memory: 100Mi

backend:
  replicas: 0
read:
  replicas: 0
write:
  replicas: 0

chunksCache:
  allocatedMemory: 500

In this, we are using the pods filesystem as storage for logs, which is a temporary storage.

For the production environment, configure external storage like AWS S3, Azure Blob Storage, etc.

deploymentMode: SingleBinary

singleBinary:
  replicas: 1
  persistence:
    storageClass: gp2
    accessModes:
      - ReadWriteOnce
    size: 20Gi
Note: By specifying the deployment mode as SingleBinary, we are deploying Loki as monolithic.

It is a single binary deployment, which means all its components, such as the ingester, distributor, etc, run as a single pod.

The persistence volume configuration is also set with 20GB the storage, you can modify it as per your requirements.

Change the storageClass name if your storageClass name is different.

Then, we configured the resource limit and requested the Loki and sidecar containers.

chunksCache:
  allocatedMemory: 1024

We have also set the allocatedMemory for chunksCache pod to 1GB, by default it allocates 8GB for the pod, and it results in the chunksCache pod in the pending state with the following error.

Warning  FailedScheduling  96s (x2 over 97s)  default-scheduler  0/2 nodes are available: 2 Insufficient memory. preemption: 0/2 nodes are available: 2 No preemption victims found for incoming pod.

If you have more resources on your cluster, you can remove the above chunksCache allocatedMemory block from the values file.

Since Loki is deployed as a StatefulSet, the logs will be saved on the same persistent volume even if the Loki pod is deleted and deployed again.

Following are the images used in this Helm chart.

  1. grafana/loki
  2. nginxinc/nginx-unprivileged
  3. grafana/loki-canary
  4. grafana/loki-helm-test
  5. memcached
  6. prom/memcached-exporter
  7. kiwigrid/k8s-sidecar
Note: Setting up Loki as MicroService or Scalable mode is not so different from setting up Monolithic Loki, you just have to change the deployment mode in values file and increase the replicas of each Loki components.

Step 3: Deploy Loki

Once the values file is set, deploy the Loki Helm chart with the values file using the following command.

helm install loki grafana/loki -n loki --create-namespace -f loki.yaml

This creates a namespace loki and deploys the pods.

Once the above command completes running, run the following command to check if the Loki pods are deployed.

kubectl get po -n loki

You will get the following output.

pods deployed for loki monolithic mode

If every pod is running, move on to the next step.

Step4: Customize Promtail Helm Values file

The next step is to deploy Promtail, which is a log collecting agent for Loki.

Note: Promtail is now depricated and its currently on LTS, it will only get support until March 2, 2026

Download the Promtail values file using the following command, if you need to make any changes.

helm show values grafana/promtail > promtail.yaml

You can also use our custom values file.

image:
  registry: docker.io
  repository: grafana/promtail
  tag: 3.4.2

# Resource configuration
resources:
  limits:
    cpu: 200m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

# Configuration
config:
  clients:
    - url: http://loki-gateway/loki/api/v1/push

We have added resource request and limit for promtail pods.

config:
  clients:
    - url: http://loki-gateway/loki/api/v1/push

The above block specifies the loki gateway endpoint, where the logs must be sent.

By default the URL will be http://loki-gateway/loki/api/v1/push.

If you disabled Loki gateway, the URL will be changed, which will be Loki’s service URL http://loki:3100/loki/api/v1/push.

This URL will only work if both Loki and Promtail are deployed in the same namespace, if both are in different namespaces, the URL will be http://loki.loki.svc.cluster.local:3100/loki/api/v1/push.

Following are the images used in this Helm chart.

  1. grafana/promtail
  2. jimmidyson/configmap-reload

Step 5: Install Promtail

Once the values file is set, deploy the Promtail application with the values file using the following command.

helm install promtail grafana/promtail -n loki -f promtail.yaml

Run the following command to check if the promtail pods are deployed.

kubectl get po -n loki

You will get the following output.

checking if promtail pods are deployed

You can see the Promtail pods are deployed as Daemonset.

If you want to migrate from Promtail to Grafana Alloy, which is an OpenTelemetry collector, refer to the official documentation.

Step 6: Customize Grafana Helm Values file

The next step is to deploy Grafana, which we will use to query Loki and visualize it.

Download the Grafana values file using the following command, if you need to make any changes.

You can also use our custom values file.

image:
  repository: grafana/grafana
  tag: latest
  pullPolicy: IfNotPresent

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
    - name: Loki
      type: loki
      url: http://loki-gateway.loki.svc.cluster.local
      access: proxy
      isDefault: false
      editable: true

service:
  type: NodePort
  port: 80

You can see we have added Loki as a datasource for Grafana, so we don't have to configure it manually after logging in to Grafana.

Also set the Grafana service Nodeport to access the UI using the node IP and nodeport.

Exposing service as NodePort is not recommended for production environment, user Load Balancers or Ingress to expose the application.

Following are the images used in this Helm chart.

  1. grafana/grafana
  2. bats/bats
  3. curlimages/curl
  4. library/busybox
  5. kiwigrid/k8s-sidecar

Step 7: Install Grafana

Once the values file is set, deploy Grafana with the values file using the following command.

helm install grafana grafana/grafana -n grafana --create-namespace -f g.yaml

This command will create a namespace grafana if not present and deploy the Grafana pod in it.

Run the following command to check if the Grafana pod is deployed.

kubectl get po -n grafana

You will get the following output.

checking if grafana pod is up and running

Since we have exposed the Grafana service as NodePort, we can access the Grafana dashboard using the node IP and node port assigned to your service.

Step 8: Log in to Grafana UI

Access your Grafana on the browser using the node IP and node port, you will get the following window.

Login to Grafana using the username and password

Login to Grafana using the username and password. Your default username will be admin and to get the password run the following command

kubectl get secret --namespace grafana grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

This command will show your password for Grafana. Use the password to log in to Grafana.

Once you log in, you can see the home screen of Grafana, press the three lines at the top left corner, you can see the menu, then go to Connections > Data sources as shown in the below image.

Grafana UI

In the Data sources you can see Loki has been configured as default.

Add adding loki as data source on grafana

Now, check if you are getting logs.

Go to Explore by pressing the Explore button.

To query logs select a Label and Value, Loki will collect every log in your Kubernetes cluster and label it according to container, pod, namespace, and other objects of Kubernetes.

Filtering the logs using loki

After selecting a Label and Value, press the Live button at the top right corner to query logs.

You can also set a time to query logs. For example, if you set the time to 5s it queries logs every 5s.

Filtering the logs using loki

After pressing the Live button, scroll down to view the logs from the Label and Value you select.

Filtering the logs using loki

Conclusion

I believe this helped you to set up the Loki on Kubernetes using Helm. We also learned how to query logs using Loki from the Grafana dashboard.

You can use our Configure S3 for Loki blog to add S3 as log storage for Loki.

If you want more detailed information about Grafana setup, you can use our guide on setting up Grafana on Kubernetes.

About the author
Aswin Vijayan

Aswin Vijayan

Aswin Vijayan: DevOps engineer passionate about open-source tools and automation. Committed to continuous learning to master his field. Enjoys reading and exploring new technologies in free time.

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to DevOpsCube – Easy DevOps, SRE Guides & Reviews.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.