How to load test with the k6 charm

To load test something with the k6 charm, you should:

  1. write a load test;
  2. deploy the k6-k8s charm;
  3. set the script and environment;
  4. run the test!

Let’s explore each step in more detail.

Writing a load test

Explaining how to write load tests is out of the scope for this document, but let’s take a look at a simple load test for Loki.

// Load test for pushing logs to Loki
import loki from 'k6/x/loki';
import sleep from 'k6';
// import http from 'k6/http'; // Arbitrary HTTP requests

export const options = {
   vus: 1000, // Virtual Users that are pushing logs
   duration: "30m", // Total duration of the test
}

export default function () {
   const conf = loki.Config(`http://fake@10.1.15.133:3100`);  // 'fake' is the default tenant for Loki
   const client = loki.Client(conf);
   
   const streams = 4 // How many log streams per client
   const minSize = 1024  // log line minimum size: 1kb
   const maxSize = 2048  // log line maximum size: 2kb
   const thinkTime = randInt(1, 3)  // Waiting time in-between log pushes
   
   const res = client.pushParameterized(streams, minSize, maxSize) // Push the logs
   sleep(thinkTime)
};

function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
};

When executed, k6 will spin up a total of 1000 virtual users. Each of them will open 4 log streams with Loki, sending between 1kb and 2kb of data every 1–3 seconds.

Can I make the script configurable?

Yes, by using template literals, Javascript's version of f-strings:


   ...
   const conf = loki.Config(`http://fake@${__ENV.LOKI_IP}:3100`);
   ...
You can then pass the environment variables you need to k6 via:

LOKI_IP="$(juju status --format=json | jq '.applications.loki.address')"
juju config k6 environment=LOKI_IP=$LOKI_IP

To learn more about k6 and how to write load test scripts, check out grafana/k6-learn or my blog post summarizing the key points I learned from it.

Deploying the charms

The k6 charm uses Prometheus and Loki to store the results of its tests, and Grafana to display them: deploy all of them and cross-relate them.

Manual commands

# Deploy the charms
∮ juju deploy k6-k8s k6
∮ juju deploy prometheus-k8s prometheus
∮ juju deploy loki-k8s loki
∮ juju deploy grafana-k8s grafana
# Add the relations
∮ juju relate k6 prometheus  # send metrics
∮ juju relate k6 loki  # send logs
∮ juju relate k6 grafana  # send dashboards
∮ juju relate prometheus:grafana-source grafana
∮ juju relate loki:grafana-source grafana
Juju bundle (ready to go!)

bundle: kubernetes
applications:
  grafana:
    charm: grafana-k8s
    channel: latest/edge
    revision: 143
    base: ubuntu@20.04/stable
    resources:
      grafana-image: 71
      litestream-image: 46
    scale: 1
    constraints: arch=amd64
    storage:
      database: kubernetes,1,1024M
    trust: true
  k6:
    charm: local:k6-k8s-11
    base: ubuntu@24.04/stable
    scale: 1
    constraints: arch=amd64
  loki:
    charm: loki-k8s
    channel: latest/edge
    revision: 191
    base: ubuntu@20.04/stable
    resources:
      loki-image: 100
      node-exporter-image: 3
    scale: 1
    constraints: arch=amd64
    storage:
      active-index-directory: kubernetes,1,1024M
      loki-chunks: kubernetes,1,1024M
    trust: true
  prometheus:
    charm: prometheus-k8s
    channel: latest/edge
    revision: 237
    base: ubuntu@20.04/stable
    resources:
      prometheus-image: 151
    scale: 1
    constraints: arch=amd64
    storage:
      database: kubernetes,1,1024M
    trust: true
relations:
- - k6:send-remote-write
  - prometheus:receive-remote-write
- - loki:grafana-source
  - grafana:grafana-source
- - prometheus:grafana-source
  - grafana:grafana-source
- - k6:logging
  - loki:logging

Easy as that!

Configuring the script and environment

Now you need to configure the k6 charm with the load test you want to run, and the environment variables you want to pass to it. There are two ways of doing so:

  • adding a charmed load test;
  • side-loading a test via juju config.

Adding a charmed load test

The k6 charm offers a k6_test library, which can be used by charms to send load tests (and their environment) over relation data.

After saving your k6 script in tests/load (by default), simply add the following to your charm.py file:

from charms.k6_k8s.v0.k6_tests import K6TestsProvider

def __init__(self, *args):
    ...
    env = {"LOKI_IP": self.external_url}
    self.k6_tests = K6TestsProvider(self, environment=env)
    self.k6_tests.reconcile()  # read the tests into relation data
    ...

Don’t forget to add the relation in charmcraft.yaml:

provides:
  send-k6-tests:  # default name
    interface: k6_tests

You can now relate your charm to k6 and the tests will be sent over!

Side-loading a test

You can easily do that via juju config:

∮ juju config k6 load-test=@loki-test.js 
∮ juju config k6 environment=LOKI_IP=10.1.15.133

Now we’re ready to run the tests!

Running the test

You can interact with the k6 charm (and the load test) via Juju actions:

∮ juju run k6/leader start  # runs the side-loaded test
∮ juju run k6/leader start app=loki test=test.js  # runs a test from a charm

The test progress can be observed in the juju status, and the metrics and logs can be inspected live in Prometheus and Loki, or directly via the Grafana dashboard.

(insert beautiful Grafana dashboard image once we have it)

Congratulations, you’ve load tested Loki! :tada:

1 Like