Categorygithub.com/chinthanep-asml/xk6-kubernetes
repositorypackage
0.0.7
Repository: https://github.com/chinthanep-asml/xk6-kubernetes.git
Documentation: pkg.go.dev

# Packages

No description provided by the author

# README

Go Reference Version Badge Build Status

xk6-kubernetes

A k6 extension for interacting with Kubernetes clusters while testing.

Build

To build a custom k6 binary with this extension, first ensure you have the prerequisites:

  1. Download xk6:

    go install go.k6.io/xk6/cmd/xk6@latest
    
  2. Build the k6 binary:

    xk6 build --with github.com/grafana/xk6-kubernetes
    

    The xk6 build command creates a k6 binary that includes the xk6-kubernetes extension in your local folder. This k6 binary can now run a k6 test using xk6-kubernetes APIs.

Development

To make development a little smoother, use the Makefile in the root folder. The default target will format your code, run tests, and create a k6 binary with your local code rather than from GitHub.

git clone [email protected]:grafana/xk6-kubernetes.git
cd xk6-kubernetes
make

Using the k6 binary with xk6-kubernetes, run the k6 test as usual:

./k6 run k8s-test-script.js

Usage

The API assumes a kubeconfig configuration is available at any of the following default locations:

  • at the location pointed by the KUBECONFIG environment variable
  • at $HOME/.kube

API

Generic API

This API offers methods for creating, retrieving, listing and deleting resources of any of the supported kinds.

MethodParametersDescription
applymanifest stringcreates a Kubernetes resource given a YAML manifest or updates it if already exists
createspec objectcreates a Kubernetes resource given its specification
deletekindremoves the named resource
name
namespace
getkindreturns the named resource
name
namespace
listkindreturns a collection of resources of a given kind
namespace
updatespec objectupdates an existing resource

The kinds of resources currently supported are:

  • ConfigMap
  • Deployment
  • Ingress
  • Job
  • Namespace
  • Node
  • PersistentVolume
  • PersistentVolumeClaim
  • Pod
  • Secret
  • Service
  • StatefulSet

Examples

Creating a pod using a specification

import { Kubernetes } from 'k6/x/kubernetes';

const podSpec = {
    apiVersion: "v1",
    kind:       "Pod",
    metadata: {
        name:      "busybox",
        namespace: "testns"
    },
    spec: {
        containers: [
            {
                name:    "busybox",
                image:   "busybox",
                command: ["sh", "-c", "sleep 30"]
            }
        ]
    }
}

export default function () {
  const kubernetes = new Kubernetes();

  kubernetes.create(pod)

  const pods = kubernetes.list("Pod", "testns");

  console.log(`${pods.length} Pods found:`);
  pods.map(function(pod) {
    console.log(`  ${pod.metadata.name}`)
  });
}

Creating a job using a YAML manifest

import { Kubernetes } from 'k6/x/kubernetes';

const manifest = `
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox
  namespace: testns
spec:
  template:
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["sleep", "300"]
    restartPolicy: Never
`

export default function () {
  const kubernetes = new Kubernetes();

  kubernetes.apply(manifest)

  const jobs = kubernetes.list("Job", "testns");

  console.log(`${jobs.length} Jobs found:`);
  pods.map(function(job) {
    console.log(`  ${job.metadata.name}`)
  });
}

Helpers

The xk6-kubernetes extension offers helpers to facilitate common tasks when setting up a tests. All helper functions work in a namespace to facilitate the development of tests segregated by namespace. The helpers are accessed using the following method:

MethodParametersDescription
helpersnamespacereturns helpers that operate in the given namespace. If none is specified, "default" is used

The methods above return an object that implements the following helper functions:

MethodParametersDescription
getExternalIPservicereturns the external IP of a service if any is assigned before timeout expires
timeout in seconds
waitPodRunningpod namewaits until the pod is in 'Running' state or the timeout expires. Returns a boolean indicating of the pod was ready or not. Throws an error if the pod is Failed.
timeout in seconds
waitServiceReadyservice namewaits until the given service has at least one endpoint ready or the timeout expires
timeout in seconds

Examples

Creating a pod in a random namespace and wait until it is running

import { Kubernetes } from 'k6/x/kubernetes';

let podSpec = {
    apiVersion: "v1",
    kind:       "Pod",
    metadata: {
        name:      "busybox",
        namespace:  "default"
    },
    spec: {
        containers: [
            {
                name:    "busybox",
                image:   "busybox",
                command: ["sh", "-c", "sleep 30"]
            }
        ]
    }
}

export default function () {
  const kubernetes = new Kubernetes();

  // create pod
  kubernetes.create(pod)

  // get helpers for test namespace
  const helpers = kubernetes.helpers()

  // wait for pod to be running
  const timeout = 10
  if (!helpers.waitPodRunning(pod.metadata.name, timeout)) {
      console.log(`"pod ${pod.metadata.name} not ready after ${timeout} seconds`)
  }
}

Resource kind helpers

This API offers a helper for each kind of Kubernetes resources supported (Pods, Deployments, Secrets, et cetera). For each one, an interface for creating, getting, listing and deleting objects is offered.

⚠️ This interface is deprecated and will be removed soon

Migrate to the usage of the generic resources API.

(Deprecated) Create a client: new Kubernetes(config)

Creates a Kubernetes client to interact with the Kubernetes cluster.

Config optionsTypeDescriptionDefault
config_pathStringThe path to the kubeconfig file~/.kube/config
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({
    // config_path: "/path/to/kube/config"
  })
}

(Deprecated) Client.config_maps

MethodDescription
applycreates the Kubernetes resource given a YAML configurationapply-configmap.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named ConfigMap
getreturns the named ConfigMapsget-configmap.js
listreturns a collection of ConfigMapslist-configmaps.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});

  const nameSpace = "default";
  const name = "config-map-name";
  kubernetesClient.config_maps.apply(getConfigMapYaml(name), nameSpace);
}

(Deprecated) Client.deployments

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-deployment-service-ingress.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named Deployment
getreturns the named Deploymentget-configmap.js
listreturns a collection of Deploymentslist-configmaps.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});

  const nameSpace = "default";
  const name = "deployment-name";
  const app = 'app-label';

  kubernetesClient.deployments.apply(getDeploymentYaml(name, app), nameSpace);
}

(Deprecated) Client.ingresses

MethodDescription
applycreates the Kubernetes resource given a YAML configurationapply-deployment-service-ingress.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named Ingress
getreturns the named Ingressget-ingress.js
listreturns a collection of Ingresseslist-ingresses.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});

  const nameSpace = "default";
  const name = "deployment-name";
  const url = 'ingress-url.com';

  kubernetesClient.ingresses.apply(getIngressYaml(name, url), nameSpace);
}

(Deprecated) Client.jobs

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-job.js
createcreates the Kubernetes resource given an object configurationcreate-job.js, create-job-wait.js, create-job-by-nodename.js, create-job-autodelete.js
deleteremoves the named Job
getreturns the named Jobsget-job.js
listreturns a collection of Jobslist-jobs.js
waitwait for all Jobs to completewait-job.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const namespace = "default"
  const jobName = "new-job"
  const image = "perl"
  const command = ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]

  kubernetesClient.jobs.create({
    namespace: namespace,
    name: jobName,
    image: image,
    command: command
  })

  const completed = kubernetesClient.jobs.wait({
    namespace: namespace,
    name: jobName,
    timeout: "30s"
  })
  const jobStatus = completed? "completed": "not completed"
}

(Deprecated) Client.namespaces

MethodDescription
applycreates the Kubernetes resource given a YAML configurationapply-namespace.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named Namespaces
getreturns the named Namespaceget-namespace.js
listreturns a collection of Namespaceslist-namespaces.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const name = "namespace-name";

  kubernetesClient.namespaces.apply(getNamespaceYaml(name));
}

(Deprecated) Client.nodes

MethodDescriptionExample
listreturns a collection of Nodes comprising the clusterlist-nodes.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const nodes = kubernetesClient.nodes.list()
}

(Deprecated) Client.persistent_volumes

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-get-delete-pv.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named persistent volumeapply-get-delete-pv.js
getreturns the named persistent volume instanceapply-get-delete-pv.js
listreturns a collection of persistent volumenslist-pv.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});

  const name = "example-pv";
  kubernetesClient.persistent_volumes.apply(getPVYaml(name, "1Gi", "local-storage"));
}

(Deprecated) Client.persistent_volumes_claims

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-get-delete-pvc.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named persistent volume claimapply-get-delete-pvc.js
getreturns the named persistent volume claimapply-get-delete-pvc.js
listreturns a collection of persistent volumen claimslist-pvc.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});

    const name = "example-pvc";
    const nameSpace = "default";

    kubernetes.persistent_volume_claims.apply(getPVCYaml(name, "1Gi", "nfs-csi"), nameSpace);
}

(Deprecated) Client.pods

MethodDescriptionExample
createruns a podcreate-pod.js, create-pod-wait.js
deleteremoves the named Pod
getreturns the named Podget-pod.js
listreturns a collection of Podslist-pods.js
waitwait for the Pod to be in a given statuswait-pod.js
execexecutes a non-interactive commandexec-command.js
addEphemeralContaineradds an ephemeral container to a running podadd-ephemeral.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const namespace = "default"
  const podName = "new-pod"
  const image = "busybox"
  const command = ["sh",  "-c", "sleep 5"]

  kubernetesClient.pods.create({
    namespace: namespace,
    name: podName,
    image: image,
    command: command
  });
 
  const options = {
    namespace: namespace,
    name: podName,
    status: "Succeeded",
    timeout: "10s"
  }
  if (kubernetesClient.pods.wait(options)) {
    console.log(podName + " pod completed successfully")
  } else {
    throw podName + " is not completed"
  }
}

(Deprecated) Client.secrets

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-secret.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named secret
getreturns the named secretget-secret.js
listreturns a collection of secretslist-secrets.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const secrets = kubernetesClient.secrets.list()
}

(Deprecated) Client.services

MethodDescriptionExample
applycreates the Kubernetes resource given a YAML configurationapply-deployment-service-ingress.js
createcreates the Kubernetes resource given an object configuration
deleteremoves the named service
getreturns the named serviceget-service.js
listreturns a collection of serviceslist-services.js
import { Kubernetes } from 'k6/x/kubernetes';

export default function () {
  const kubernetesClient = new Kubernetes({});
  const svcs = kubernetesClient.services.list()
}

If things go wrong

Are you using the custom binary?

An easy mistake--which happens often--is to forget that xk6 is generating a new executable. You may be accustomed to simply running k6 from the command-line which probably isn't your new build. Make sure to use ./k6 after building your extended version otherwise you can expect to see an error similar to:

ERRO[0000] The moduleSpecifier "k8s-test-script.js" couldn't be found on local disk. Make sure that you've specified the right path to the file. If you're running k6 using the Docker image make sure you have mounted the local directory (-v /local/path/:/inside/docker/path) containing your script and modules so that they're accessible by k6 from inside of the container, see https://k6.io/docs/using-k6/modules#using-local-modules-with-docker. Additionally it was tried to be loaded as remote module by prepending "https://" to it, which also didn't work. Remote resolution error: "Get "https://k8s-test-script.js": dial tcp: lookup k8s-test-script.js: no such host"