As Kubernetes has become the standard for deploying and managing containerized applications, testing has also adapted to this environment. Ensuring the reliability and performance of your application’s endpoints is crucial, especially in cloud-native deployments. A powerful combination to achieve this is using K6 for load and performance testing and Helm with its helm test hooks to integrate testing into the Kubernetes deployment lifecycle.
In this blog post, we’ll explore how you can use K6 for endpoint testing within Kubernetes using Helm’s test hooks. This setup allows you to test your application right after it has been deployed in your Kubernetes cluster, ensuring everything is running as expected before marking the deployment as successful.
What is K6?
K6 is an open-source, developer-centric load testing tool used to test the performance of APIs, web applications, and microservices. It is known for its simplicity and flexibility, allowing users to write performance tests in JavaScript. So in your tests you have a fully loaded programming language where one can also generate different payloads for requests.
What are Helm Test Hooks?
Helm is a package manager for Kubernetes that simplifies the deployment and management of applications. Helm provides test hooks which are essentially Kubernetes jobs that can be executed to verify that the application is functioning as expected after deployment.
Example
Step 1: Write K6 Test Script with your assumptions First, you need to create a K6 test script that defines the test for your application’s endpoints:
import http from 'k6/http';
import {check, fail, group, sleep} from 'k6';
export const options = {
vus: 1, // with 1 virtual user
duration: '5s', // running for 5 seconds
thresholds: {
// Set custom thresholds to determine failure
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
}
};
const BASE_URL = `${__ENV.INGRESS_HOST_URL}`
const headers = {
'apiKey': `${__ENV.KEY_TO_ACCESS_THE_API}`,
'Content-Type': 'application/json'
};
export default function () {
group('/your/first/endpoint', function () {
let res = http.get(`${BASE_URL}/path/to/your/first/endpoint`, {headers: headers});
let success = check(res, {
'status was 200': (r) => r.status === 200,
'one event was returned in array': (r) => r.json().events.length === 1,
});
if (!success) {
fail(`your/first/endpoint is not working`);
}
sleep(1)
})
group('/create', function () {
const twoRandomDateTimes = getTwoRandomDateTimes();
const payload = JSON.stringify({
startTime: twoRandomDateTimes.start,
endTime: twoRandomDateTimes.end,
startNumber: "123",
});
let res = http.post(`${BASE_URL}/path/to/your/second/endpoint`, payload, {headers: headers});
let success = check(res, {
'status was 200': (r) => r.status === 200,
'one id was returned': (r) => r.json().id !== "",
});
if (!success) {
fail(`your/second/endpoint is not working`);
}
sleep(1)
})
}
// omitted for the example. Returns a starting and end time on the same day
function getTwoRandomDateTimes() {
}
Step 2: Create a Helm Test Hook Next, integrate this K6 test script into your Helm chart using Helm’s test hook. Helm allows you to define Kubernetes jobs that will execute the tests. You can create a Job resource that runs the K6 test after the Helm deployment using the helm.sh/hook: test annotation.
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "server.fullname" . }}-smoke-test"
labels:
{{- include "server.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
template:
metadata:
labels:
{{- include "server.labels" . | nindent 8 }}
spec:
containers:
- name: k6
image: k6:latest
command: ['k6', 'run', '/scripts/test.js']
env:
- name: INGRESS_HOST_URL
valueFrom:
configMapKeyRef:
key: INGRESS_HOST_URL
name: app-config-map-with-ingress-url
- name: KEY_TO_ACCESS_THE_API
valueFrom:
secretKeyRef:
name: app-secret-with-api-key
key: API_KEY
volumeMounts:
- name: "{{ include "server.fullname" . }}-smoke-test-script"
mountPath: /scripts
restartPolicy: Never
volumes:
- name: "{{ include "server.fullname" . }}-smoke-test-script"
configMap:
name: "{{ include "server.fullname" . }}-smoke-test-script"
backoffLimit: 0
---
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ include "server.fullname" . }}-smoke-test-script"
labels:
{{- include "server.labels" . | nindent 4 }}
data:
test.js: |- {{ range .Files.Lines "tests/k6.js" }}
{{ . }}{{ end }}
I found the following file structure very suitable to run the tests also from the local machine.
CI/CD integration
This will trigger the Helm deployment, and after the deployment is complete, the K6 tests will be executed as part of the Helm test hook. You can monitor the output of the tests to ensure the endpoints are working correctly.
helm upgrade --install your-chart RELEASE_NAME --wait
helm test RELEASE_NAME
FluxCD (gitops)
If you using FluxCD, there is a neat option to enable automatically helm tests after a deployment. For more details check the documentaion
spec:
test:
enable: true
ignoreFailures: true
Conclusion
By combining K6 for testing with Helm’s test hooks, you can ensure that your Kubernetes-deployed applications are thoroughly tested before reaching production. This approach integrates reliability testing into your deployment process, catching issues early and improving the overall quality of your application. Testing your endpoints from an user perspective you are also making sure the ingress and the authentication layer is working as excepted.