github.com/cilium/cilium@v1.16.2/pkg/k8s/informer/benchmarks/informer_benchmarks_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package benchmarks 5 6 import ( 7 "context" 8 "encoding/json" 9 "os" 10 "reflect" 11 "strconv" 12 "sync" 13 "testing" 14 15 "github.com/stretchr/testify/require" 16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/watch" 19 "k8s.io/client-go/tools/cache" 20 21 "github.com/cilium/cilium/pkg/annotation" 22 slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 23 24 "github.com/cilium/cilium/pkg/k8s/informer" 25 ) 26 27 var nodeSampleJSON = `{ 28 "apiVersion": "v1", 29 "kind": "Node", 30 "metadata": { 31 "annotations": { 32 "container.googleapis.com/instance_id": "111111111111111111", 33 "network.cilium.io/ipv4-cilium-host": "10.0.0.1", 34 "network.cilium.io/ipv4-health-ip": "10.0.0.1", 35 "network.cilium.io/ipv4-pod-cidr": "10.0.0.1/27", 36 "node.alpha.kubernetes.io/ttl": "30", 37 "volumes.kubernetes.io/controller-managed-attach-detach": "true" 38 }, 39 "creationTimestamp": "2019-03-07T13:35:02Z", 40 "labels": { 41 "kubernetes.io/arch": "amd64", 42 "beta.kubernetes.io/fluentd-ds-ready": "true", 43 "node.kubernetes.io/instance-type": "foo", 44 "kubernetes.io/os": "linux", 45 "cloud.google.com/gke-nodepool": "default-pool", 46 "cloud.google.com/gke-os-distribution": "cos", 47 "disktype": "ssd", 48 "failure-domain.beta.kubernetes.io/region": "earth", // Remove after support for 1.17 is dropped 49 "failure-domain.beta.kubernetes.io/zone": "earth", // Remove after support for 1.17 is dropped 50 "topology.kubernetes.io/region": "earth", 51 "topology.kubernetes.io/zone": "earth", 52 "kubernetes.io/hostname": "super-node" 53 }, 54 "name": "super-node", 55 "resourceVersion": "0", 56 "selfLink": "/api/v1/nodes/super-node", 57 "uid": "cf66ea66-40dd-11e9-bcdf-4201ac100009" 58 }, 59 "spec": { 60 "podCIDR": "10.0.0.1/16", 61 "providerID": "gce://universe/earth/super-node" 62 }, 63 "status": { 64 "addresses": [ 65 { 66 "address": "10.0.0.1", 67 "type": "InternalIP" 68 }, 69 { 70 "address": "", 71 "type": "ExternalIP" 72 }, 73 { 74 "address": "super-node.c.earth.internal", 75 "type": "InternalDNS" 76 }, 77 { 78 "address": "super-node.c.earth.internal", 79 "type": "Hostname" 80 } 81 ], 82 "allocatable": { 83 "attachable-volumes-gce-pd": "0", 84 "cpu": "0m", 85 "ephemeral-storage": "0", 86 "hugepages-2Mi": "0", 87 "memory": "0", 88 "pods": "0" 89 }, 90 "capacity": { 91 "attachable-volumes-gce-pd": "16", 92 "cpu": "4", 93 "ephemeral-storage": "26615568Ki", 94 "hugepages-2Mi": "0", 95 "memory": "8173944Ki", 96 "pods": "16" 97 }, 98 "conditions": [ 99 { 100 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 101 "lastTransitionTime": "2019-03-07T13:40:03Z", 102 "message": "kubelet is functioning properly", 103 "reason": "FrequentKubeletRestart", 104 "status": "False", 105 "type": "FrequentKubeletRestart" 106 }, 107 { 108 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 109 "lastTransitionTime": "2019-03-07T13:40:04Z", 110 "message": "docker is functioning properly", 111 "reason": "FrequentDockerRestart", 112 "status": "False", 113 "type": "FrequentDockerRestart" 114 }, 115 { 116 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 117 "lastTransitionTime": "2019-03-07T13:40:05Z", 118 "message": "containerd is functioning properly", 119 "reason": "FrequentContainerdRestart", 120 "status": "False", 121 "type": "FrequentContainerdRestart" 122 }, 123 { 124 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 125 "lastTransitionTime": "2019-03-07T13:40:03Z", 126 "message": "docker overlay2 is functioning properly", 127 "reason": "CorruptDockerOverlay2", 128 "status": "False", 129 "type": "CorruptDockerOverlay2" 130 }, 131 { 132 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 133 "lastTransitionTime": "2019-03-07T13:35:01Z", 134 "message": "kernel has no deadlock", 135 "reason": "KernelHasNoDeadlock", 136 "status": "False", 137 "type": "KernelDeadlock" 138 }, 139 { 140 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 141 "lastTransitionTime": "2019-03-07T13:35:01Z", 142 "message": "Filesystem is not read-only", 143 "reason": "FilesystemIsNotReadOnly", 144 "status": "False", 145 "type": "ReadonlyFilesystem" 146 }, 147 { 148 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 149 "lastTransitionTime": "2019-03-07T13:40:03Z", 150 "message": "node is functioning properly", 151 "reason": "UnregisterNetDevice", 152 "status": "False", 153 "type": "FrequentUnregisterNetDevice" 154 }, 155 { 156 "lastHeartbeatTime": "2019-03-15T10:44:54Z", 157 "lastTransitionTime": "2019-03-15T10:44:54Z", 158 "message": "NodeController create implicit route", 159 "reason": "RouteCreated", 160 "status": "False", 161 "type": "NetworkUnavailable" 162 }, 163 { 164 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 165 "lastTransitionTime": "2019-03-07T13:35:02Z", 166 "message": "kubelet has sufficient disk space available", 167 "reason": "KubeletHasSufficientDisk", 168 "status": "False", 169 "type": "OutOfDisk" 170 }, 171 { 172 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 173 "lastTransitionTime": "2019-03-07T13:35:02Z", 174 "message": "kubelet has sufficient memory available", 175 "reason": "KubeletHasSufficientMemory", 176 "status": "False", 177 "type": "MemoryPressure" 178 }, 179 { 180 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 181 "lastTransitionTime": "2019-03-07T13:35:02Z", 182 "message": "kubelet has no disk pressure", 183 "reason": "KubeletHasNoDiskPressure", 184 "status": "False", 185 "type": "DiskPressure" 186 }, 187 { 188 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 189 "lastTransitionTime": "2019-03-07T13:35:02Z", 190 "message": "kubelet has sufficient PID available", 191 "reason": "KubeletHasSufficientPID", 192 "status": "False", 193 "type": "PIDPressure" 194 }, 195 { 196 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 197 "lastTransitionTime": "2019-03-07T13:36:12Z", 198 "message": "kubelet is posting ready status. AppArmor enabled", 199 "reason": "KubeletReady", 200 "status": "True", 201 "type": "Ready" 202 } 203 ], 204 "daemonEndpoints": { 205 "kubeletEndpoint": { 206 "Port": 10250 207 } 208 }, 209 "images": [ 210 { 211 "names": [ 212 "quay.io/cilium/cilium-dev@sha256:53e005e8ae3649412cfb5b5538916bc6c9f66c408ee6a76273e964a285cb28aa", 213 "quay.io/cilium/cilium-dev:scale-test-2019-03-13" 214 ], 215 "sizeBytes": 618888533 216 }, 217 { 218 "names": [ 219 "quay.io/cilium/cilium@sha256:9f41fc120b2c8cf5006220bcea7ee17c573cb13f0d32b0578ea83690f6412b6e", 220 "quay.io/cilium/cilium:latest" 221 ], 222 "sizeBytes": 618884013 223 }, 224 { 225 "names": [ 226 "quay.io/cilium/cilium-dev@sha256:41b2bc225d90a52cbf04f030fd4e4bb8235e00262e08643963dd887090d17b96", 227 "quay.io/cilium/cilium-dev:scale-test-2019-03-12" 228 ], 229 "sizeBytes": 618855547 230 }, 231 { 232 "names": [ 233 "cilium/cilium@sha256:bb8a0507c1850f856d7c3e1ab27fa8246d666dcf5bab9040ced3d6513e730b02", 234 "cilium/cilium:latest" 235 ], 236 "sizeBytes": 618841491 237 }, 238 { 239 "names": [ 240 "cilium/cilium@sha256:2d0ea8c2eee882c7005d5645f349f58bca57fcd8e2e682a517c400ccd045f9c2" 241 ], 242 "sizeBytes": 618821939 243 }, 244 { 245 "names": [ 246 "cilium/cilium-dev@sha256:c55141a813d30123c34372b87d75c3b8ff4eaf955ff0531f93ec2a8fbd2d6dff", 247 "cilium/cilium-dev:tgraf-scale-fixes2" 248 ], 249 "sizeBytes": 618670939 250 }, 251 { 252 "names": [ 253 "registry.k8s.io/node-problem-detector@sha256:f95cab985c26b2f46e9bd43283e0bfa88860c14e0fb0649266babe8b65e9eb2b", 254 "registry.k8s.io/node-problem-detector:v0.4.1" 255 ], 256 "sizeBytes": 286572743 257 }, 258 { 259 "names": [ 260 "grafana/grafana@sha256:b5098a06dc59d28b11120eab01d8d0147b526a175aa606f9978934b6b2224138", 261 "grafana/grafana:6.0.0" 262 ], 263 "sizeBytes": 256099268 264 }, 265 { 266 "names": [ 267 "quay.io/coreos/etcd-operator@sha256:3633b6d103e9efc2798e4214c8ee6d9b78f262eca65f085d76f5b4aee77e1e95", 268 "quay.io/coreos/etcd-operator:v0.9.3" 269 ], 270 "sizeBytes": 150833530 271 }, 272 { 273 "names": [ 274 "registry.k8s.io/fluentd-elasticsearch@sha256:a54e7a450c0bdd19f49f56e487427a08c50f99ea8f8846179acf7d4182ce1fc0", 275 "registry.k8s.io/fluentd-elasticsearch:v2.2.0" 276 ], 277 "sizeBytes": 138313727 278 }, 279 { 280 "names": [ 281 "registry.k8s.io/fluentd-gcp-scaler@sha256:457a13df66534b94bab627c4c2dc2df0ee5153a5d0f0afd27502bd46bd8da81d", 282 "registry.k8s.io/fluentd-gcp-scaler:0.5" 283 ], 284 "sizeBytes": 103488147 285 }, 286 { 287 "names": [ 288 "registry.k8s.io/kubernetes-dashboard-amd64@sha256:dc4026c1b595435ef5527ca598e1e9c4343076926d7d62b365c44831395adbd0", 289 "registry.k8s.io/kubernetes-dashboard-amd64:v1.8.3" 290 ], 291 "sizeBytes": 102319441 292 }, 293 { 294 "names": [ 295 "gcr.io/google_containers/kube-proxy:v1.12.5-gke.10", 296 "registry.k8s.io/kube-proxy:v1.12.5-gke.10" 297 ], 298 "sizeBytes": 101370340 299 }, 300 { 301 "names": [ 302 "registry.k8s.io/event-exporter@sha256:7f9cd7cb04d6959b0aa960727d04fa86759008048c785397b7b0d9dff0007516", 303 "registry.k8s.io/event-exporter:v0.2.3" 304 ], 305 "sizeBytes": 94171943 306 }, 307 { 308 "names": [ 309 "gcr.io/google-containers/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662", 310 "registry.k8s.io/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662", 311 "gcr.io/google-containers/prometheus-to-sd:v0.3.1", 312 "registry.k8s.io/prometheus-to-sd:v0.3.1" 313 ], 314 "sizeBytes": 88077694 315 }, 316 { 317 "names": [ 318 "registry.k8s.io/heapster-amd64@sha256:9fae0af136ce0cf4f88393b3670f7139ffc464692060c374d2ae748e13144521", 319 "registry.k8s.io/heapster-amd64:v1.6.0-beta.1" 320 ], 321 "sizeBytes": 76016169 322 }, 323 { 324 "names": [ 325 "registry.k8s.io/ingress-gce-glbc-amd64@sha256:14f14351a03038b238232e60850a9cfa0dffbed0590321ef84216a432accc1ca", 326 "registry.k8s.io/ingress-gce-glbc-amd64:v1.2.3" 327 ], 328 "sizeBytes": 71797285 329 }, 330 { 331 "names": [ 332 "quay.io/cilium/cilium-dev@sha256:d8bb81b46f9e10e40ca106bc6a9ac0f3365e5310bbb5bfba1f52d1d8c8b64740", 333 "quay.io/cilium/cilium-dev:vetcd-v3.3.11-hf1-aanm" 334 ], 335 "sizeBytes": 64108258 336 }, 337 { 338 "names": [ 339 "registry.k8s.io/kube-addon-manager@sha256:d53486c3a0b49ebee019932878dc44232735d5622a51dbbdcec7124199020d09", 340 "registry.k8s.io/kube-addon-manager:v8.7" 341 ], 342 "sizeBytes": 63322109 343 }, 344 { 345 "names": [ 346 "registry.k8s.io/cpvpa-amd64@sha256:cfe7b0a11c9c8e18c87b1eb34fef9a7cbb8480a8da11fc2657f78dbf4739f869", 347 "registry.k8s.io/cpvpa-amd64:v0.6.0" 348 ], 349 "sizeBytes": 51785854 350 }, 351 { 352 "names": [ 353 "registry.k8s.io/k8s-dns-kube-dns-amd64@sha256:618a82fa66cf0c75e4753369a6999032372be7308866fc9afb381789b1e5ad52", 354 "registry.k8s.io/k8s-dns-kube-dns@sha256:c54a527a4ba8f1bc15e4796b09bf5d69313c7f42af9911dc437e056c0264a2fe", 355 "registry.k8s.io/k8s-dns-kube-dns-amd64:1.14.13", 356 "registry.k8s.io/k8s-dns-kube-dns:1.14.13" 357 ], 358 "sizeBytes": 51157394 359 }, 360 { 361 "names": [ 362 "registry.k8s.io/cluster-proportional-autoscaler-amd64@sha256:36359630278b119e7dd78f5437be1c667080108fa59ecba1b81cda3610dcf4d7", 363 "registry.k8s.io/cluster-proportional-autoscaler-amd64:1.2.0" 364 ], 365 "sizeBytes": 50258329 366 }, 367 { 368 "names": [ 369 "registry.k8s.io/cluster-proportional-autoscaler-amd64@sha256:003f98d9f411ddfa6ff6d539196355e03ddd69fa4ed38c7ffb8fec6f729afe2d", 370 "registry.k8s.io/cluster-proportional-autoscaler-amd64:1.1.2-r2" 371 ], 372 "sizeBytes": 49648481 373 }, 374 { 375 "names": [ 376 "registry.k8s.io/ip-masq-agent-amd64@sha256:1ffda57d87901bc01324c82ceb2145fe6a0448d3f0dd9cb65aa76a867cd62103", 377 "registry.k8s.io/ip-masq-agent-amd64:v2.1.1" 378 ], 379 "sizeBytes": 49612505 380 }, 381 { 382 "names": [ 383 "quay.io/cilium/operator-dev@sha256:ab697ec83f8e3da7e64630c67252a5cf2ac4017ce2414c6c1d5476e165a844c6", 384 "quay.io/cilium/operator-dev:scale-test-2019-03-12" 385 ], 386 "sizeBytes": 48754920 387 } 388 ], 389 "nodeInfo": { 390 "architecture": "amd64", 391 "bootID": "999999999999999999999999999", 392 "containerRuntimeVersion": "docker://17.3.2", 393 "kernelVersion": "4.14.91+", 394 "kubeProxyVersion": "v1.12.5", 395 "kubeletVersion": "v1.12.5", 396 "machineID": "999999999999999999999999999", 397 "operatingSystem": "linux", 398 "osImage": "Container-Optimized OS from Google", 399 "systemUUID": "999999999999999999999999999" 400 } 401 } 402 } 403 ` 404 405 func benchmarkInformer(ctx context.Context, nCycles int, newInformer bool, b *testing.B) { 406 n := slim_corev1.Node{} 407 err := json.Unmarshal([]byte(nodeSampleJSON), &n) 408 n.ResourceVersion = "1" 409 require.NoError(b, err) 410 w := watch.NewFakeWithChanSize(nCycles, false) 411 wg := sync.WaitGroup{} 412 413 lw := &cache.ListWatch{ 414 ListFunc: func(_ metav1.ListOptions) (runtime.Object, error) { 415 return &slim_corev1.NodeList{ 416 Items: []slim_corev1.Node{n}, 417 }, nil 418 }, 419 WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) { 420 return w, nil 421 }, 422 } 423 424 if newInformer { 425 _, controller := informer.NewInformer( 426 lw, 427 &slim_corev1.Node{}, 428 0, 429 cache.ResourceEventHandlerFuncs{ 430 AddFunc: func(obj interface{}) {}, 431 UpdateFunc: func(oldObj, newObj interface{}) { 432 if oldK8sNP := informer.CastInformerEvent[slim_corev1.Node](oldObj); oldK8sNP != nil { 433 if newK8sNP := informer.CastInformerEvent[slim_corev1.Node](newObj); newK8sNP != nil { 434 if reflect.DeepEqual(oldK8sNP, newK8sNP) { 435 return 436 } 437 } 438 } 439 }, 440 DeleteFunc: func(obj interface{}) { 441 k8sNP := informer.CastInformerEvent[slim_corev1.Node](obj) 442 if k8sNP == nil { 443 deletedObj, ok := obj.(cache.DeletedFinalStateUnknown) 444 if !ok { 445 return 446 } 447 // Delete was not observed by the watcher but is 448 // removed from kube-apiserver. This is the last 449 // known state and the object no longer exists. 450 k8sNP = informer.CastInformerEvent[slim_corev1.Node](deletedObj.Obj) 451 if k8sNP == nil { 452 return 453 } 454 } 455 wg.Done() 456 }, 457 }, 458 nil, 459 ) 460 go controller.Run(ctx.Done()) 461 } else { 462 _, controller := cache.NewInformer( 463 lw, 464 &slim_corev1.Node{}, 465 0, 466 cache.ResourceEventHandlerFuncs{ 467 AddFunc: func(obj interface{}) {}, 468 UpdateFunc: func(oldObj, newObj interface{}) { 469 if oldK8sNP := OldCopyObjToV1Node(oldObj); oldK8sNP != nil { 470 if newK8sNP := OldCopyObjToV1Node(newObj); newK8sNP != nil { 471 if OldEqualV1Node(oldK8sNP, newK8sNP) { 472 return 473 } 474 } 475 } 476 }, 477 DeleteFunc: func(obj interface{}) { 478 k8sNP := OldCopyObjToV1Node(obj) 479 if k8sNP == nil { 480 deletedObj, ok := obj.(cache.DeletedFinalStateUnknown) 481 if !ok { 482 return 483 } 484 // Delete was not observed by the watcher but is 485 // removed from kube-apiserver. This is the last 486 // known state and the object no longer exists. 487 k8sNP = OldCopyObjToV1Node(deletedObj.Obj) 488 if k8sNP == nil { 489 return 490 } 491 } 492 wg.Done() 493 }, 494 }, 495 ) 496 go controller.Run(ctx.Done()) 497 } 498 499 wg.Add(1) 500 b.ResetTimer() 501 for i := 2; i <= nCycles; i++ { 502 n.ResourceVersion = strconv.Itoa(i) 503 w.Action(watch.Modified, &n) 504 } 505 w.Action(watch.Deleted, &n) 506 wg.Wait() 507 b.StopTimer() 508 } 509 510 func OldEqualV1Node(node1, node2 *slim_corev1.Node) bool { 511 // The only information we care about the node is it's annotations, in 512 // particularly the CiliumHostIP annotation. 513 return node1.GetObjectMeta().GetName() == node2.GetObjectMeta().GetName() && 514 node1.GetAnnotations()[annotation.CiliumHostIP] == node2.GetAnnotations()[annotation.CiliumHostIP] 515 } 516 517 func OldCopyObjToV1Node(obj interface{}) *slim_corev1.Node { 518 node, ok := obj.(*slim_corev1.Node) 519 if !ok { 520 return nil 521 } 522 return node.DeepCopy() 523 } 524 525 func Benchmark_Informer(b *testing.B) { 526 nCycles, err := strconv.Atoi(os.Getenv("CYCLES")) 527 if err != nil { 528 nCycles = b.N 529 } 530 531 benchmarkInformer(context.Background(), nCycles, true, b) 532 } 533 534 func Benchmark_K8sInformer(b *testing.B) { 535 nCycles, err := strconv.Atoi(os.Getenv("CYCLES")) 536 if err != nil { 537 nCycles = b.N 538 } 539 540 benchmarkInformer(context.Background(), nCycles, false, b) 541 }