developing k6 perftest (#8581)
This commit is contained in:
parent
0ff500c23f
commit
bb1f9deafd
5 changed files with 264 additions and 1 deletions
67
.github/workflows/perftest.yaml
vendored
Normal file
67
.github/workflows/perftest.yaml
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
name: Performance Test
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
logLevel:
|
||||||
|
description: 'Log level'
|
||||||
|
required: true
|
||||||
|
default: 'warning'
|
||||||
|
tags:
|
||||||
|
description: 'K6 Load Test'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
k6_test_run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Install K6
|
||||||
|
run: |
|
||||||
|
wget https://github.com/grafana/k6/releases/download/v0.38.2/k6-v0.38.2-linux-amd64.tar.gz
|
||||||
|
tar -xvf k6-v0.38.2-linux-amd64.tar.gz k6-v0.38.2-linux-amd64/k6
|
||||||
|
mv k6-v0.38.2-linux-amd64/k6 .
|
||||||
|
./k6
|
||||||
|
|
||||||
|
- name: Make dev-env
|
||||||
|
run: |
|
||||||
|
mkdir $HOME/.kube
|
||||||
|
make dev-env
|
||||||
|
podName=`kubectl -n ingress-nginx get po | grep -i controller | awk '{print $1}'`
|
||||||
|
if [[ -z ${podName} ]] ; then
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
kubectl wait pod -n ingress-nginx --for condition=Ready $podName
|
||||||
|
kubectl get all -A
|
||||||
|
|
||||||
|
- name: Deploy workload
|
||||||
|
run: |
|
||||||
|
kubectl create deploy k6 --image kennethreitz/httpbin --port 80 && \
|
||||||
|
kubectl expose deploy k6 --port 80 && \
|
||||||
|
kubectl create ing k6 --class nginx \
|
||||||
|
--rule test.ingress-nginx-controller.ga/*=k6:80
|
||||||
|
podName=`kubectl get po | grep -i k6 | awk '{print $1}'`
|
||||||
|
if [[ -z ${podName} ]] ; then
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
kubectl wait pod --for condition=Ready $podName
|
||||||
|
kubectl get all,secrets,ing
|
||||||
|
|
||||||
|
- name: Tune OS
|
||||||
|
run : |
|
||||||
|
sudo sysctl -A 2>/dev/null | egrep -i "local_port_range|tw_reuse|tcp_timestamps"
|
||||||
|
sudo sh -c "ulimit"
|
||||||
|
sudo sysctl -w net.ipv4.ip_local_port_range="1024 65535"
|
||||||
|
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
|
||||||
|
sudo sysctl -w net.ipv4.tcp_timestamps=1
|
||||||
|
sudo sh -c "ulimit "
|
||||||
|
|
||||||
|
- name: Run smoke test
|
||||||
|
run: |
|
||||||
|
vmstat -at 5 | tee vmstat_report &
|
||||||
|
#./k6 login cloud -t $K6_TOKEN
|
||||||
|
#./k6 run -o cloud ./smoketest.js
|
||||||
|
./k6 run test/k6/smoketest.js
|
||||||
|
pkill vmstat
|
||||||
|
cat vmstat_report
|
|
@ -61,7 +61,7 @@ echo "[dev-env] building image"
|
||||||
make build image
|
make build image
|
||||||
docker tag "${REGISTRY}/controller:${TAG}" "${DEV_IMAGE}"
|
docker tag "${REGISTRY}/controller:${TAG}" "${DEV_IMAGE}"
|
||||||
|
|
||||||
export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6}
|
export K8S_VERSION=${K8S_VERSION:-v1.21.12@sha256:f316b33dd88f8196379f38feb80545ef3ed44d9197dca1bfd48bcb1583210207}
|
||||||
|
|
||||||
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
||||||
|
|
||||||
|
|
83
test/k6/README.md
Normal file
83
test/k6/README.md
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# Performance testing ingress-nginx-controller in GithubAction-CI
|
||||||
|
This README will evolve as the development of testing occurs.
|
||||||
|
|
||||||
|
## INFORMATION
|
||||||
|
### 1. No CPU/Memory for stress
|
||||||
|
- Github-Actions job runner is a 2core 7Gig VM so that limits what/how we test https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners
|
||||||
|
|
||||||
|
<img width="863" alt="image" src="https://user-images.githubusercontent.com/5085914/169713673-7daa56ed-dffe-4c49-8600-4e9a01754d37.png">
|
||||||
|
|
||||||
|
- Need to eventually get our own beefy runner, with enough cpu/memory to handle stress level load
|
||||||
|
|
||||||
|
### 2. Scale is work-in-progress
|
||||||
|
- We are grateful to have got a free account on K6.io, as part of their OSS Program. But it is limited to 600 tests per year.
|
||||||
|
|
||||||
|
### 3. No Testplans
|
||||||
|
- Testplan discussion and coding is needed for more practical real-world testing reports
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
|
||||||
|
### What
|
||||||
|
- An issue was created for performance tests, for the ingress-nginx-controller builds, https://github.com/kubernetes/ingress-nginx/issues/8033 .
|
||||||
|
|
||||||
|
### How
|
||||||
|
- A step by step guide to using https://k6.io with GithubActions is here https://k6.io/blog/load-testing-using-github-actions/
|
||||||
|
|
||||||
|
- The link above contains sample code
|
||||||
|
<img width="901" alt="image" src="https://user-images.githubusercontent.com/5085914/169714798-6ff62542-a591-4379-8f50-7678b6024936.png">
|
||||||
|
|
||||||
|
|
||||||
|
- Copy sample test code from website and edit to taste
|
||||||
|
<img width="646" alt="image" src="https://user-images.githubusercontent.com/5085914/169714937-1f6f2a86-36c0-4826-8e28-5e450d461353.png">
|
||||||
|
|
||||||
|
- The CI launches a ubuntu environment and uses `make dev-env` to create a kind cluster. The popular https://httpbin.org api docker image is used to create a workload
|
||||||
|
|
||||||
|
<img width="646" alt="image" src="https://user-images.githubusercontent.com/5085914/169714872-613ffd6a-36b5-4317-81fe-c39765a76649.png">
|
||||||
|
|
||||||
|
- We don't want the test to block CI so this syntax from Github-Actions creates a button to run the test
|
||||||
|
<img width="257" alt="image" src="https://user-images.githubusercontent.com/5085914/169715159-e7fbeada-fcb4-4c25-a65f-8be8547b7c19.png">
|
||||||
|
|
||||||
|
- The button looks like this (the `Run Workflow` dropdown at bottom right of screenshot)
|
||||||
|
<img width="1385" alt="image" src="https://user-images.githubusercontent.com/5085914/169715301-0752c5ed-9f84-4560-9a5e-c872c32041de.png">
|
||||||
|
|
||||||
|
<img width="1380" alt="image" src="https://user-images.githubusercontent.com/5085914/169715321-8e76ee6b-2a85-4ed2-ba4e-9d8410518c42.png">
|
||||||
|
|
||||||
|
|
||||||
|
### fqdn
|
||||||
|
- Obtained a freenom domain `ingress-nginx-controller.ga`
|
||||||
|
|
||||||
|
- The test uses a fqdn `test.ingress-nginx-controller.ga`
|
||||||
|
|
||||||
|
- The K6 api has configuration options for dns resolution of (above mentioned fqdn) to localhost/loopback/127.0.0.1 (`make dev-env` cluster)
|
||||||
|
<img width="445" alt="image" src="https://user-images.githubusercontent.com/5085914/169716036-213d43c1-4801-4b4f-aee6-1c11c7812e6d.png">
|
||||||
|
|
||||||
|
- Will need to discuss and decide on fqdn, as it relates to tls secret
|
||||||
|
|
||||||
|
### tls
|
||||||
|
- Procured a letsencrypt wildcard certificate for `*.ingress-nginx-controller.ga`
|
||||||
|
|
||||||
|
- base64 encoded hash of the cert + key is stored in the `Github Project Settings Secrets` as a variable
|
||||||
|
|
||||||
|
- The `GithubActions secrets` variables are decoded in the CI to create the TLS secret
|
||||||
|
|
||||||
|
<img width="1250" alt="image" src="https://user-images.githubusercontent.com/5085914/169716088-030b9f6f-cdb1-470b-b10c-ea4a0fb8199f.png">
|
||||||
|
|
||||||
|
|
||||||
|
### Visualization
|
||||||
|
- Plan is to run tests locally on a kind cluster, in the CI pipeline, but push results to K6-cloud
|
||||||
|
|
||||||
|
- Pushing and visualization on K6 cloud is as simple as executing `k6 run -o cloud test.js`
|
||||||
|
|
||||||
|
- Currently there is a personal account in trial period (50 tests or 1 year limit) bing used
|
||||||
|
|
||||||
|
- Pushing test-results from K6 tests on laptop, to K6-cloud personal trial account on K6-Cloud, to see what the graphs look like
|
||||||
|
|
||||||
|
<img width="954" alt="image" src="https://user-images.githubusercontent.com/5085914/169713896-2cc3b775-38d9-43c6-8792-2a43329a8cfb.png">
|
||||||
|
|
||||||
|
<img width="950" alt="image" src="https://user-images.githubusercontent.com/5085914/169713941-1671426d-9356-4c50-956b-b4003df4aa78.png">
|
||||||
|
|
||||||
|
- The cli result looks like this
|
||||||
|
<img width="835" alt="image" src="https://user-images.githubusercontent.com/5085914/169715209-68aa116a-020b-4f2d-8c8e-ec2c5f68b7b0.png">
|
||||||
|
|
||||||
|
- Before merging the PR, the testing is being done on personal Github project with exact same code as this PR here https://github.com/longwuyuan/k6-loadtest-example/runs/6545706269?check_suite_focus=true
|
||||||
|
|
49
test/k6/loadtest.js
Normal file
49
test/k6/loadtest.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// This is a loadtest under development
|
||||||
|
// Test here is spec'd to have 100virtual-users
|
||||||
|
// Other specs currently similar to smoktest
|
||||||
|
// But loadtest needs testplan that likely uses auth & data-transfer
|
||||||
|
|
||||||
|
import http from 'k6/http';
|
||||||
|
import { sleep } from 'k6';
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
hosts: {
|
||||||
|
'test.ingress-nginx-controller.ga:80': '127.0.0.1:80',
|
||||||
|
'test.ingress-nginx-controller.ga:443': '127.0.0.1:443',
|
||||||
|
},
|
||||||
|
duration: '1m',
|
||||||
|
vus: 100,
|
||||||
|
thresholds: {
|
||||||
|
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
|
||||||
|
http_req_duration: ['p(95)<500'], // 95 percent of response times must be below 500ms
|
||||||
|
http_req_duration: ['p(99)<1500'], // 99 percent of response times must be below 1500ms
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const params = {
|
||||||
|
headers: {'host': 'test.ingress-nginx-controller.ga'},
|
||||||
|
};
|
||||||
|
const req1 = {
|
||||||
|
method: 'GET',
|
||||||
|
url: 'http://test.ingress-nginx-controller.ga/ip',
|
||||||
|
};
|
||||||
|
const req2 = {
|
||||||
|
method: 'GET',
|
||||||
|
url: 'http://test.ingress-nginx-controller.ga/image/svg',
|
||||||
|
};
|
||||||
|
const req3 = {
|
||||||
|
params: {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
url: 'https://test.ingress-nginx-controller.ga/post',
|
||||||
|
body: {
|
||||||
|
hello: 'world!',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const res = http.batch([req1, req2, req3], params);
|
||||||
|
sleep(1);
|
||||||
|
}
|
64
test/k6/smoketest.js
Normal file
64
test/k6/smoketest.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// smotest.js edited after copy/pasting from https://k6.io docs
|
||||||
|
// Using this like loadtest because of limited cpu/memory/other
|
||||||
|
|
||||||
|
import http from 'k6/http';
|
||||||
|
import { sleep } from 'k6';
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
// testbed created with "make dev-env" requires this name resolution
|
||||||
|
// this does not set the host header
|
||||||
|
hosts: {
|
||||||
|
'test.ingress-nginx-controller.ga:80': '127.0.0.1:80',
|
||||||
|
'test.ingress-nginx-controller.ga:443': '127.0.0.1:443',
|
||||||
|
},
|
||||||
|
// below 3 lines documented at https://k6.io
|
||||||
|
duration: '1m',
|
||||||
|
vus: 50,
|
||||||
|
thresholds: {
|
||||||
|
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
|
||||||
|
http_req_duration: ['p(95)<500'], // 95 percent of response times must be below 500ms
|
||||||
|
http_req_duration: ['p(99)<1500'], // 99 percent of response times must be below 1500ms
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
// docs of k6 say this is how to adds host header
|
||||||
|
// needed as ingress is created with this host value
|
||||||
|
const params = {
|
||||||
|
headers: {'host': 'test.ingress-nginx-controller.ga'},
|
||||||
|
};
|
||||||
|
// httpbin.org documents these requests
|
||||||
|
const req1 = {
|
||||||
|
method: 'GET',
|
||||||
|
url: 'http://test.ingress-nginx-controller.ga/ip',
|
||||||
|
};
|
||||||
|
const req2 = {
|
||||||
|
method: 'GET',
|
||||||
|
url: 'http://test.ingress-nginx-controller.ga/image/svg',
|
||||||
|
};
|
||||||
|
const req3 = {
|
||||||
|
params: {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
url: 'https://test.ingress-nginx-controller.ga/post',
|
||||||
|
body: {
|
||||||
|
'key1': 'Hello World!',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const req4 = {
|
||||||
|
method: 'GET',
|
||||||
|
url: 'https://test.ingress-nginx-controller.ga/basic-auth/admin/admin',
|
||||||
|
params: {
|
||||||
|
headers: {
|
||||||
|
'accept': 'application/jsom',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(let i=0; i<20; i++){
|
||||||
|
const res = http.batch([req0, req1, req2, req3, req4], params);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue