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
`
}
Copy link

ghost commented Feb 5, 2024

Hi @javaducky (Paul),

We are testing GRPC call using k6 . For that we need to port-forward a particular service before we can call GRPC method.(Currently we are doing it manually.)
Is port-forwarding is yet not available in xk6 Kubernetes?
Are you guys planning to introduce this capability any time sooner ? :)

Thanks in advance.

Regards,
SaifAli Sanadi

@javaducky
Copy link
Author

Hi @saifaliZeals! Port forwarding is not supported at the moment. I'm no longer with Grafana, so doubtful I'd be able to look into this further. I'd recommend opening an issue with grafana/xk6-kubernetes to put this feature on their radar.

Copy link

ghost commented Feb 27, 2024

Thanks @javaducky (Paul) for responding back to my message.
Sure i will raise issue with Grafana for above request.
Its sad to hear that you are no longer with Grafana and we won't be able to see you again on k6 Office Hours , I really enjoyed those sessions.

All the best with your new journey, Cheers.

@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