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  }