Kubelet density test on scaling by nodes
Change-Id: I56e6765a61431e6613f3aad1c8a7a3212adc229f
@ -65,6 +65,34 @@ List of performance metrics
|
|||||||
+-------------------------+---------------------------------------------+
|
+-------------------------+---------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Test Case #2: Measure Kubelet capacity
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
The goal of this test is to investigate Kubelet capacity. For this, rerun
|
||||||
|
test case #1 for different number of nodes.
|
||||||
|
|
||||||
|
List of performance metrics
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. table:: list of test metrics to be collected during this test
|
||||||
|
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
| Parameter | Description |
|
||||||
|
+=========================+=============================================+
|
||||||
|
| POD_COUNT | Number of pods |
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
| NODE_COUNT | Number of nodes |
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
| POD_FIRST_REPORT | Time taken by pod to start and report |
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
| KUBECTL_RUN | Time for all pods to be reported as running |
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
| KUBECTL_TERMINATE | Time to terminate all pods |
|
||||||
|
+-------------------------+---------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
Reports
|
Reports
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 30 KiB |
@ -27,12 +27,18 @@ Node roles:
|
|||||||
- node3: minion+etcd
|
- node3: minion+etcd
|
||||||
- node4: minion
|
- node4: minion
|
||||||
|
|
||||||
Software versions:
|
Software versions (test case #1):
|
||||||
- OS: Ubuntu 16.04.1 LTS (Xenial Xerus)
|
- OS: Ubuntu 16.04.1 LTS (Xenial Xerus)
|
||||||
- Kernel: 4.4.0-47
|
- Kernel: 4.4.0-47
|
||||||
- Docker: 1.12.1
|
- Docker: 1.12.1
|
||||||
- Kubernetes: 1.4.3
|
- Kubernetes: 1.4.3
|
||||||
|
|
||||||
|
Software versions (test case #2):
|
||||||
|
- OS: Ubuntu 16.04.1 LTS (Xenial Xerus)
|
||||||
|
- Kernel: 4.4.0-36
|
||||||
|
- Docker: 1.13.1
|
||||||
|
- Kubernetes: 1.5.3
|
||||||
|
|
||||||
Reports
|
Reports
|
||||||
=======
|
=======
|
||||||
|
|
||||||
@ -176,6 +182,252 @@ System metrics from API nodes and minion are below
|
|||||||
Full `Kubernetes stats`_ are available online.
|
Full `Kubernetes stats`_ are available online.
|
||||||
|
|
||||||
|
|
||||||
|
Test Case #2: Measure Kubelet capacity
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Pod startup time is measured with help of
|
||||||
|
`MMM(MySQL/Master/Minions) testing suite`_. Original code was updated. We added
|
||||||
|
automatic creation of charts with pod's status, when pod startup (or down). To
|
||||||
|
schedule all pods on a single node the original replication controller for
|
||||||
|
minions is updated with scheduler hint. To do this add the following lines
|
||||||
|
into template's spec section:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: <node>
|
||||||
|
|
||||||
|
Pod status from Kubernetes point of view is retrieved from kubectl tool.
|
||||||
|
The process is automated with
|
||||||
|
:download:`kubectl_mon_v2.py <kubectl-mon/kubectl_mon_v2.py>`, which collects
|
||||||
|
information about pod's status and sends to database. Charts are created by
|
||||||
|
updated `MMM(MySQL/Master/Minions) testing suite`_.
|
||||||
|
|
||||||
|
Every measurement starts with empty namespace. Then Kubernetes replication
|
||||||
|
controller is created with specified number of pods. We collect pod's report
|
||||||
|
time and kubectl stats. The summary data is presented below.
|
||||||
|
|
||||||
|
.. list-table:: POD stats
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
*
|
||||||
|
- POD_COUNT
|
||||||
|
- NODE_COUNT
|
||||||
|
- POD_FIRST_REPORT, s
|
||||||
|
- KUBECTL_RUN, s
|
||||||
|
- KUBECTL_TERMINATE, s
|
||||||
|
*
|
||||||
|
- 50
|
||||||
|
- 50
|
||||||
|
- 197
|
||||||
|
- 290
|
||||||
|
- 289
|
||||||
|
*
|
||||||
|
- 100
|
||||||
|
- 50
|
||||||
|
- 415
|
||||||
|
- 597
|
||||||
|
- 577
|
||||||
|
*
|
||||||
|
- 200
|
||||||
|
- 50
|
||||||
|
- 952
|
||||||
|
- 1218
|
||||||
|
- 1154
|
||||||
|
*
|
||||||
|
- 50
|
||||||
|
- 100
|
||||||
|
- 381
|
||||||
|
- 425
|
||||||
|
- 536
|
||||||
|
*
|
||||||
|
- 100
|
||||||
|
- 100
|
||||||
|
- 788
|
||||||
|
- 2093 (with errors)
|
||||||
|
- 1076
|
||||||
|
*
|
||||||
|
- 200
|
||||||
|
- 100
|
||||||
|
- 2653
|
||||||
|
- 3838 (not finished)
|
||||||
|
- 3001 (not finished)
|
||||||
|
*
|
||||||
|
- 50
|
||||||
|
- 200
|
||||||
|
- 970
|
||||||
|
- 1256
|
||||||
|
- 1032
|
||||||
|
*
|
||||||
|
- 100
|
||||||
|
- 200
|
||||||
|
- 1632
|
||||||
|
- 3225
|
||||||
|
- 2248
|
||||||
|
*
|
||||||
|
- 200
|
||||||
|
- 200
|
||||||
|
- 7098 (6.5% lost)
|
||||||
|
- 8075 (not finished)
|
||||||
|
- ∞ (not finished)
|
||||||
|
*
|
||||||
|
- 50
|
||||||
|
- 400
|
||||||
|
- 1823
|
||||||
|
- 2667 (with errors)
|
||||||
|
- 2038
|
||||||
|
*
|
||||||
|
- 100
|
||||||
|
- 400
|
||||||
|
- 7582
|
||||||
|
- 8262 (with errors)
|
||||||
|
- 5200
|
||||||
|
*
|
||||||
|
- 400
|
||||||
|
- 50
|
||||||
|
- 9607
|
||||||
|
- ∞ (not finished)
|
||||||
|
- ∞ (not finished)
|
||||||
|
|
||||||
|
|
||||||
|
Detailed Stats
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Note: You can download these reports in HTML format
|
||||||
|
:download:`here <data/reports.tar.bz2>`
|
||||||
|
|
||||||
|
50 pods (~1 pod per core) on 50 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 50 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x50.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 50 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x50_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
100 pods (~2 pod per core) on 50 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 100 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x100.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 100 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x100_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
200 pods (~4 pod per core) on 50 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 200 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x200.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 200 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x200_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
50 pods (~1 pod per core) on 100 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 50 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x50.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 50 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x50_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
100 pods (~2 pod per core) on 100 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 100 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x100.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 100 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x100_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
200 pods (~4 pod per core) on 100 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 200 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x200.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 200 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 100x200_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
50 pods (~1 pod per core) on 200 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 50 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 200x50.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 50 pods on 100 nodes
|
||||||
|
|
||||||
|
.. image:: 200x50_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
100 pods (~2 pod per core) on 200 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 100 pods on 200 nodes
|
||||||
|
|
||||||
|
.. image:: 200x100.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 100 pods on 200 nodes
|
||||||
|
|
||||||
|
.. image:: 200x100_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
200 pods (~4 pod per core) on 200 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 200 pods on 200 nodes
|
||||||
|
|
||||||
|
Note: Docker service is frozen on 27 nodes
|
||||||
|
|
||||||
|
.. image:: 200x200.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 200 pods on 200 nodes
|
||||||
|
|
||||||
|
.. image:: 200x200_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
400 pods (~8 pod per core) on 50 nodes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Start replication controller with 400 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x400.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
|
Terminate replication controller with 400 pods on 50 nodes
|
||||||
|
|
||||||
|
.. image:: 50x400_term.png
|
||||||
|
:width: 100%
|
||||||
|
|
||||||
.. references:
|
.. references:
|
||||||
|
|
||||||
.. _Kargo: https://github.com/kubespray/kargo
|
.. _Kargo: https://github.com/kubespray/kargo
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/python
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
from requests.adapters import HTTPAdapter
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
KUBECTL_CMD = 'kubectl --namespace minions get pods -l k8s-app=minion'
|
||||||
|
TIMEOUT = 1200 # in seconds
|
||||||
|
|
||||||
|
|
||||||
|
class Monitor(object):
|
||||||
|
def __init__(self, **options):
|
||||||
|
self.options = options
|
||||||
|
|
||||||
|
def check_direction(self, n, l):
|
||||||
|
if self.direction == 'up':
|
||||||
|
if n > 0 and l == n + 1:
|
||||||
|
print 'Done.'
|
||||||
|
sys.exit(0)
|
||||||
|
if self.direction == 'down':
|
||||||
|
if l == 0:
|
||||||
|
print 'Done.'
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.direction = self.options.get('direction', 'up')
|
||||||
|
base_time = int(time.time() * 1000000000)
|
||||||
|
|
||||||
|
s = requests.Session()
|
||||||
|
s.mount('http://master.minions:8888', HTTPAdapter(max_retries=10))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = int(time.time() * 1000000000)
|
||||||
|
stdout = subprocess.Popen(KUBECTL_CMD, shell=True,
|
||||||
|
stdout=subprocess.PIPE).stdout.read()
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
for line in stdout.split('\n')[1:]:
|
||||||
|
if line:
|
||||||
|
tokens = re.split('\s+', line)
|
||||||
|
name = tokens[0]
|
||||||
|
status = tokens[2]
|
||||||
|
|
||||||
|
if status == 'Running':
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
url = "http://master.minions:8888/monitor?minion_time=%s&" \
|
||||||
|
"minion_name=%s&minion_status=%s&direction=%s" % (
|
||||||
|
start, name, status, self.direction)
|
||||||
|
|
||||||
|
s.get(url)
|
||||||
|
|
||||||
|
length_lines = len(stdout.split('\n')[1:])
|
||||||
|
self.check_direction(n, length_lines)
|
||||||
|
|
||||||
|
if (start - base_time) / 1000000000 > TIMEOUT:
|
||||||
|
print 'Timeout.(%d)' % TIMEOUT
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option('-d', '--direction', dest='direction', default='up')
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
|
Monitor(**vars(options)).run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|