Skip to main content
Version: v1.4

Performance Test Setup for Karmada

Abstract

As Karmada is being implemented in more and more enterprises and organizations, scalability and scale of Karmada is gradually becoming new concerns for the community. In this article, we will introduce how to conduct large-scale testing for Karmada and how to monitor metrics from Karmada control plane.

Build large scale environment

Create member clusters using kind

Why kind

Kind is a tool for running local Kubernetes clusters using Docker containers. Kind was primarily designed for testing Kubernetes itself, so it play a good role in simulating member clusters.

Usage

Follow the kind installation guide.

Create 10 member clusters:

for ((i=1; i<=10; i ++)); do
kind create cluster --name member$i
done;

Simulate a large number of fake nodes using fake-kubelet

Why fake-kubelet

Compare to Kubemark

Kubemark is directly implemented with the code of kubelet, replacing the runtime part, except that it does not actually start the container, other behaviors are exactly the same as kubelet, mainly used for Kubernetes own e2e test, simulating a large number of nodes and pods will occupy the same memory as the real scene.

Fake-kubelet is a tool used to simulate any number of nodes and maintain pods on those nodes. It only does the minimum work of maintaining nodes and pods, so that it is very suitable for simulating a large number of nodes and pods for pressure testing on the control plane.

Usage

Deploy the fake-kubelet:

Note: Set container ENV GENERATE_REPLICAS in fake-kubelet deployment to set node replicas you want to create

export GENERATE_REPLICAS=your_replicas
curl https://raw.githubusercontent.com/wzshiming/fake-kubelet/master/deploy.yaml > fakekubelet.yml
# GENERATE_REPLICAS default value is 5
sed -i "s/5/$GENERATE_REPLICAS/g" fakekubelet.yml
kubectl apply -f fakekubelet.yml

kubectl get node You will find fake nodes.

> kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
fake-0 Ready agent 10s fake 10.88.0.136 <none> <unknown> <unknown> <unknown>
fake-1 Ready agent 10s fake 10.88.0.136 <none> <unknown> <unknown> <unknown>
fake-2 Ready agent 10s fake 10.88.0.136 <none> <unknown> <unknown> <unknown>
fake-3 Ready agent 10s fake 10.88.0.136 <none> <unknown> <unknown> <unknown>
fake-4 Ready agent 10s fake 10.88.0.136 <none> <unknown> <unknown> <unknown>

Deploy an sample deployment to test:

> kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: fake-pod
namespace: default
spec:
replicas: 4
selector:
matchLabels:
app: fake-pod
template:
metadata:
labels:
app: fake-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- fake-kubelet
tolerations: # A taints was added to an automatically created Node. You can remove taints of Node or add this tolerations
- key: "fake-kubelet/provider"
operator: "Exists"
effect: "NoSchedule"
# nodeName: fake-0 # Or direct scheduling to a fake node
containers:
- name: fake-pod
image: fake
EOF

kubectl get pod You will find that it has been started, although the image does not exist.

> kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fake-pod-78884479b7-52qcx 1/1 Running 0 6s 10.0.0.23 fake-4 <none> <none>
fake-pod-78884479b7-bd6nk 1/1 Running 0 6s 10.0.0.13 fake-2 <none> <none>
fake-pod-78884479b7-dqjtn 1/1 Running 0 6s 10.0.0.15 fake-2 <none> <none>
fake-pod-78884479b7-h2fv6 1/1 Running 0 6s 10.0.0.31 fake-0 <none> <none>

Distribute resources using ClusterLoader2

ClusterLoader2

ClusterLoader2 is an open source Kubernetes cluster testing tool. It tests against Kubernetes-defined SLIs/SLOs metrics to verify that clusters meet various quality of service standards. ClusterLoader2 is a tool oriented single cluster, it is complex to test karmada control plane meanwhile distribute resources to member clusters. Therefore, we just use the ClusterLoader2 to distribute resources to clusters managed by karmada.

Prepare a simple config

Let's prepare our config (config.yaml) to distribute resources. This config will:

  • Create 10 namespace

  • Create 20 deployments with 1000 pods inside that namespace

We will create file config.yaml that describes this test. First we need to start with defining test name:

name: test

ClusterLoader2 will create namespaces automatically, but we need to specify how many namespaces we want and whether delete the namespaces after distributing resources:

namespace:
number: 10
deleteAutomanagedNamespaces: false

Next, we need to specify TuningSets. TuningSet describes how actions are executed. The qps means 1/qps s per action interval. In order to distribute resources slowly to relieve the pressure on the apiserver, the qps of Uniformtinyqps is set to 0.1, which means that after distributing a deployment, we wait 10s before continuing to distribute the next deployment.

tuningSets:
- name: Uniformtinyqps
qpsLoad:
qps: 0.1
- name: Uniform1qps
qpsLoad:
qps: 1

Finally, we will create a phase that creates deployment and propagation policy. We need to specify in which namespaces we want the deployment and propagation policy to be created, how many of these deployments per namespace. Also, we will need to specify template for our deployment and propagation policy , which we will do later. For now, let's assume that this template allows us to specify numbers of replicas in deployment and propagation policy.

steps:
- name: Create deployment
phases:
- namespaceRange:
min: 1
max: 10
replicasPerNamespace: 20
tuningSet: Uniformtinyqps
objectBundle:
- basename: test-deployment
objectTemplatePath: "deployment.yaml"
templateFillMap:
Replicas: 1000
- namespaceRange:
min: 1
max: 10
replicasPerNamespace: 1
tuningSet: Uniform1qps
objectBundle:
- basename: test-policy
objectTemplatePath: "policy.yaml"
templateFillMap:
Replicas: 1

The whole config.yaml will look like this:

name: test

namespace:
number: 10
deleteAutomanagedNamespaces: false

tuningSets:
- name: Uniformtinyqps
qpsLoad:
qps: 0.1
- name: Uniform1qps
qpsLoad:
qps: 1

steps:
- name: Create deployment
phases:
- namespaceRange:
min: 1
max: 10
replicasPerNamespace: 20
tuningSet: Uniformtinyqps
objectBundle:
- basename: test-deployment
objectTemplatePath: "deployment.yaml"
templateFillMap:
Replicas: 1000
- namespaceRange:
min: 1
max: 10
replicasPerNamespace: 1
tuningSet: Uniform1qps
objectBundle:
- basename: test-policy
objectTemplatePath: "policy.yaml"

Now, we need to specify deployment and propagation template. ClusterLoader2 by default adds parameter Name that you can use in your template. In our config, we also passed Replicas parameter. So our template for deployment and propagation policy will look like following:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Name}}
labels:
group: test-deployment
spec:
replicas: {{.Replicas}}
selector:
matchLabels:
app: fake-pod
template:
metadata:
labels:
app: fake-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- fake-kubelet
tolerations: # A taints was added to an automatically created Node. You can remove taints of Node or add this tolerations
- key: "fake-kubelet/provider"
operator: "Exists"
effect: "NoSchedule"
containers:
- image: fake-pod
name: {{.Name}}
# policy.yaml
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: test
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
placement:
replicaScheduling:
replicaDivisionPreference: Weighted
replicaSchedulingType: Divided

Start Distributing

To distributing resources, run:

export KARMADA_APISERVERCONFIG=your_config
export KARMADA_APISERVERIP=your_ip
cd clusterloader2/
go run cmd/clusterloader.go --testconfig=config.yaml --provider=local --kubeconfig=$KARMADA_APISERVERCONFIG --v=2 --k8s-clients-number=1 --skip-cluster-verification=true --masterip=$KARMADA_APISERVERIP --enable-exec-service=false

The meaning of args above shows as following:

  • k8s-clients-number: the number of karmada apiserver client number.
  • skip-cluster-verification: whether to skip the cluster verification, which expects at least one schedulable node in the cluster.
  • enable-exec-service: whether to enable exec service that allows executing arbitrary commands from a pod running in the cluster.

Since the resources of member cluster cannot be accessed in karmada control plane, we have to turn off enable-exec-service and cluster-verification.

Note: If the deleteAutomanagedNamespaces parameter in config file is set to true, when the whole distribution of resources is complete, the resources will be immediately deleted.

Monitor Karmada control plane using Prometheus and Grafana

Deploy Prometheus and Grafana

Follow the Prometheus and Grafana Deploy Guide

Create Grafana DashBoards to observe Karmada control plane metrics

Here's an example to monitor the mutating api call latency for works and resourcebindings of the karmada apiserver through grafana. Monitor the metrics you want by modifying the Query statement.

Create a dashboard

Follow the Grafana support For Prometheus document.

Modify Query Statement

Enter the following Prometheus expression into the Query field.

histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb!="WATCH|GET|LIST", resource~="works|resourcebindings"}[5m])) by (resource, verb, le))

The gragh will show as follow:

grafana-dashboard