Skip to content

Instantly share code, notes, and snippets.

@javaducky
Last active February 28, 2024 12:37
Show Gist options
  • Save javaducky/6fea70d3352834683b2c4f3ce3d1234a to your computer and use it in GitHub Desktop.
Save javaducky/6fea70d3352834683b2c4f3ce3d1234a to your computer and use it in GitHub Desktop.
k6 and Kubernetes experimentation

Experimenting with k6 and Kubernetes

Prerequisite...you MUST have a running installation of Docker!

For this experiment, we will:

  • install a local Kubernetes cluster running in Docker
  • optionally install some tooling to give us visibility into the cluster
  • build a custom k6 binary having xk6-kubernetes
  • run some simple scripts to test our local cluster

Setup your Kubernetes cluster

To run our Kubernetes cluster, we'll use the k3d project. Follow the instructions there for installation.

I personally used Homebrew to install, i.e. brew install k3d

Once installed, we'll create our cluster using the following command:

k3d cluster create local-kube-cluster \
 --api-port 6550 \
 -p "8081:80@loadbalancer" \
 --agents 3 \
 --k3s-arg '--kube-apiserver-arg=feature-gates=EphemeralContainers=true@server:*'

After this command completes, you will have a local Kubernetes cluster running, having multiple nodes...just like a real cluster.

Setup some tooling (optional)

You can setup some tools to make life easier and provide visibility into the cluster. For me, a light-weight option is the k9s utility. This provides a text-based user interface from the command-line for the Kube cluster. Other options exist, like Lens, Octant, among others I'm sure.

For myself once again, I used Homebrew, i.e. brew install derailed/k9s/k9s.

Build k6 with Kubernetes Extension

In order to create k6 test scripts which incorporate the ability to interact with Kubernetes resources, we'll need to compile and extended version of k6] using xk6.

Prerequisite: You will need to have a Go(lang) development environment setup locally to compile the extended version!

# Install xk6 into your local toolset
go install go.k6.io/xk6/cmd/xk6@latest

# Build an new k6 binary with k8s support
#   (command provided by the "bundle builder" at https://k6.io/docs/extensions/bundle-builder/)
xk6 build v0.38.3 --with github.com/grafana/xk6-kubernetes

Play

Now you should be set to use the Kubernetes client within your test scripts! k8s-playground.js can get you started!

🚀 Happy testing!

import { sleep } from 'k6';
import http from 'k6/http';
import { Kubernetes } from 'k6/x/kubernetes';
const kubernetes = new Kubernetes({
// config_path: "/path/to/kube/config", ~/.kube/config by default
})
const namespace = "k6-testing"
export const options = {
vus: 10,
duration: '10s',
thresholds: {
'http_reqs{expected_response:true}': ['rate>10'],
},
};
export function setup() {
// Verify or create namespace for testing
if (!getNamespaceNames(kubernetes).includes(namespace)) {
kubernetes.namespaces.create({
name: namespace
})
console.log(`+ Created namespace: ` + namespace)
}
// Deploy httpbin into the namespace.
if (!getDeploymentNames(kubernetes, namespace).includes("httpbin")) {
kubernetes.deployments.apply(getDeploymentYaml(3), namespace)
console.log(`+ Created deployment: httpbin in ` + namespace)
kubernetes.services.apply(getServiceYaml(), namespace)
console.log(`+ Created service: httpbin in ` + namespace)
// Port-forward is not yet available within the client, so we'll need to setup a port-forward manually.
// `kubectl port-forward -n <your-namespace> deployment/httpbin 63367:80`
// View http://localhost:63367 in a browser once deployed.
console.log(`!!! Execute the following from your command-line (requires kubectl):`)
console.log(`kubectl port-forward -n ` + namespace + ` deployment/httpbin 63367:80`)
}
}
export default function () {
http.get('http://localhost:63367/get');
sleep(1);
}
function getNamespaceNames(kubernetes) {
return kubernetes.namespaces.list().map(function(ns){
return ns.name
})
}
function getPodNames(kubernetes, namespace) {
return kubernetes.pods.list(namespace).map(function(pod){
return pod.name
})
}
function getDeploymentNames(kubernetes, namespace) {
return kubernetes.deployments.list(namespace).map(function(deploy){
return deploy.name
})
}
function getDeploymentYaml(replicas) {
return `apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: ` + replicas + `
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- image: kennethreitz/httpbin:latest
name: httpbin
ports:
- containerPort: 80
`
}
function getServiceYaml() {
return `apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: httpbin
`
}
@javaducky
Copy link
Author

@saifaliZeals Thank you so much for those kind words! It is truly appreciated and I will definitely miss my days with k6 and Grafana. 🙇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment