<commit_before>---
layout:     post
title:      "Kubernetes集群性能测试"
subtitle:   "Kubemark: Performance Test Tool for Your Kubernetes Cluster"
date:       2017-03-09
author:     "Robin"
header-img: "img/post-bg-2015.jpg"
catalog: true
tags:
    - Kubernetes
    - Kubemark
    - Performance
---

[Kubemark](https://github.com/kubernetes/community/blob/master/contributors/devel/kubemark-guide.md)是K8s官方提供的一个对K8s集群进行性能测试的工具。它可以模拟出一个K8s cluster（Kubemark cluster），不受资源限制，从而能够测试的集群规模比真实集群大的多。这个cluster中master是真实的机器，所有的nodes是Hollow nodes。Hollow nodes执行的还是真实的K8s程序，只是不会调用Docker，因此测试会走一套K8s API调用的完整流程，但是不会真正创建pod。

Kubermark是在模拟的Kubemark cluster上跑E2E测试，从而获得集群的性能指标。Kubermark cluster的测试数据，虽然与真实集群的稍微有点误差，不过可以代表真实集群的数据，具体数据见[Updates to Performance and Scalability in Kubernetes 1.3 -- 2,000 node 60,000 pod clusters](http://blog.kubernetes.io/2016/07/kubernetes-updates-to-performance-and-scalability-in-1.3.html)。因此，可以借用Kubermark，直接在真实集群上跑E2E测试，从而对我们真实集群进行性能测试。

## 测试设计

### 测试目标

- 集群容量上限：Node总数和Pod总数两个维度
- 性能瓶颈
- 服务延迟

### 服务质量目标（SLO）

- Node启动时间：4s
- 99%的Pod启动时间：5s
- 99%的API调用延时：1s

### 服务质量指标（SLI）

- 指标
  - Pod启动时间
  - API调用延时
- 定义
  - **集群容量**：集群中有N个Node，每个Node上30个Pod，集群容量为30 * N个Pod。
  - **集群负载**：集群中Pod总数量占集群容量百分比。通过调整Pod总数控制集群负载。
  - **百分位指标**：指标的分布性。以API调用延时指标为例，50% API调用延时为20ms，90% API调用延时为50ms。

### 测试的APIs

|Actions|              Resources              |
|-------|-------------------------------------|
|  PUT  | Nodes，Pods，Replication Controllers |
| POST  | Nodes，Pods，Replication Controllers |
| LIST  | Nodes，Pods，Replication Controllers |
|  GET  | Nodes，Pods，Replication Controllers |

### 数据统计

统计不同集群负载下，Pod启动时间和API调用延时这两个指标的分布性:
- 集群负载：10%， 25%，50%，90%，100%
- 指标分布性：10%， 50%，90%，99%

API调用延时统计数据表格示例：

|                 |  10%-full  |  25%-full  |  50%-full  |  90%-full  |  100%-full  |
|-----------------|------------|------------|------------|------------|-------------|
| 10th percentile |            |            |            |            |             |
| 50th percentile |            |            |            |            |             |
| 90th percentile |            |            |            |            |             |
| 99th percentile |            |            |            |            |             |

### Optional Benchmarks

- Kubemark

	K8s官方提供的Benchmark，K8s自身的CI中也是采用其进行测试：[ci-kubernetes-kubemark-500-gce](https://k8s-gubernator.appspot.com/builds/kubernetes-jenkins/logs/ci-kubernetes-kubemark-500-gce)，[google-kubemark](https://k8s-gubernator.appspot.com/builds/kubernetes-jenkins/logs/ci-kubernetes-kubemark-500-gce)。

- [Cloud Container Cluster Common Benchmark](https://github.com/allingeek/c4-bench)

	[Evaluating Container Platforms at Scale](https://medium.com/on-docker/evaluating-container-platforms-at-scale-5e7b44d93f2c#.b289jee06)中使用的Benchmark。

- [PerfKit Benchmarker](https://github.com/GoogleCloudPlatform/PerfKitBenchmarker)

	Google云平台提供的Benchmark，支持K8s。目前没有找到其在K8s测试的相关资料。

## Prepare Environment

### Kubernetes Cluster

根据自己的平台，参考[官方安装文档](https://kubernetes.io/docs/getting-started-guides/)，搭建Kubernetes Cluster。

### 安装依赖

```shell
$ yum install -y gcc.x86_64
```

### Go开发环境

1. 下载[go1.7.4.linux-amd64.tar.gz](https://storage.googleapis.com/golang/go1.7.4.linux-amd64.tar.gz)（保持与K8s构建用的Go版本一致）
2. 解压到/usr/local/go目录下
3. 设置GOROOT和GOPATH环境变量
	/etc/profile中添加：
	```shell
	$ export GOPATH=/root/gocode
	$ export PATH=$PATH:/opt/maven/latest/bin:$GOPATH/bin:/usr/local/go/bin
	```
	使变量生效：source /etc/profile

### Test Images

为了避免下载测试镜像，给Kubemark性能测试的结果带来误差，在运行Kubemark前，需要在所有K8s nodes上提前准备好这些镜像。Kubemark测试时使用的image都是GCR上面的，对于不能翻墙的Kubernetes Cluster，可以从[时速云Docker Registry](https://hub.tenxcloud.com/)下载相应的镜像到本地，然后重新标签为GCR的测试image。对于甚至不能连接外网的Kubernetes Cluster，可以通过一台可以连外网的机器从时速云Docker Registry下载所有镜像，然后上传到公司内部的Docker Registry，所有K8s nodes从公司Docker Registry上下载测试image，然后重新标签为GCR的测试image。

## Run Kubemark

> The version of Kubernetes source code is **`V1.5.3`**.
<commit_msg>update blog: update kubemark installation for v1.14.3<commit_after>---
layout:     post
title:      "Kubernetes集群性能测试"
subtitle:   "Kubemark: Performance Test Tool for Your Kubernetes Cluster"
date:       2017-03-09
author:     "Robin"
header-img: "img/post-bg-2015.jpg"
catalog: true
tags:
    - Kubernetes
    - Kubemark
    - Performance
---

[Kubemark](https://github.com/kubernetes/community/blob/master/contributors/devel/kubemark-guide.md)是K8s官方提供的一个对K8s集群进行性能测试的工具。它可以模拟出一个K8s cluster（Kubemark cluster），不受资源限制，从而能够测试的集群规模比真实集群大的多。这个cluster中master是真实的机器，所有的nodes是Hollow nodes。Hollow nodes执行的还是真实的K8s程序，只是不会调用Docker，因此测试会走一套K8s API调用的完整流程，但是不会真正创建pod。

Kubermark是在模拟的Kubemark cluster上跑E2E测试，从而获得集群的性能指标。Kubermark cluster的测试数据，虽然与真实集群的稍微有点误差，不过可以代表真实集群的数据，具体数据见[Updates to Performance and Scalability in Kubernetes 1.3 -- 2,000 node 60,000 pod clusters](http://blog.kubernetes.io/2016/07/kubernetes-updates-to-performance-and-scalability-in-1.3.html)。因此，可以借用Kubermark，直接在真实集群上跑E2E测试，从而对我们真实集群进行性能测试。

## 测试设计

### 测试目标

- 集群容量上限：Node总数和Pod总数两个维度
- 性能瓶颈
- 服务延迟

### 服务质量目标（SLO）

- Node启动时间：4s
- 99%的Pod启动时间：5s
- 99%的API调用延时：1s

### 服务质量指标（SLI）

- 指标
  - Pod启动时间
  - API调用延时
- 定义
  - **集群容量**：集群中有N个Node，每个Node上30个Pod，集群容量为30 * N个Pod。
  - **集群负载**：集群中Pod总数量占集群容量百分比。通过调整Pod总数控制集群负载。
  - **百分位指标**：指标的分布性。以API调用延时指标为例，50% API调用延时为20ms，90% API调用延时为50ms。

### 测试的APIs

|Actions|              Resources              |
|-------|-------------------------------------|
|  PUT  | Nodes，Pods，Replication Controllers |
| POST  | Nodes，Pods，Replication Controllers |
| LIST  | Nodes，Pods，Replication Controllers |
|  GET  | Nodes，Pods，Replication Controllers |

### 数据统计

统计不同集群负载下，Pod启动时间和API调用延时这两个指标的分布性:
- 集群负载：10%， 25%，50%，90%，100%
- 指标分布性：10%， 50%，90%，99%

API调用延时统计数据表格示例：

|                 |  10%-full  |  25%-full  |  50%-full  |  90%-full  |  100%-full  |
|-----------------|------------|------------|------------|------------|-------------|
| 10th percentile |            |            |            |            |             |
| 50th percentile |            |            |            |            |             |
| 90th percentile |            |            |            |            |             |
| 99th percentile |            |            |            |            |             |

### Optional Benchmarks

- Kubemark

	K8s官方提供的Benchmark，K8s自身的CI中也是采用其进行测试：[ci-kubernetes-kubemark-500-gce](https://k8s-gubernator.appspot.com/builds/kubernetes-jenkins/logs/ci-kubernetes-kubemark-500-gce)，[google-kubemark](https://k8s-gubernator.appspot.com/builds/kubernetes-jenkins/logs/ci-kubernetes-kubemark-500-gce)。

- [Cloud Container Cluster Common Benchmark](https://github.com/allingeek/c4-bench)

	[Evaluating Container Platforms at Scale](https://medium.com/on-docker/evaluating-container-platforms-at-scale-5e7b44d93f2c#.b289jee06)中使用的Benchmark。

- [PerfKit Benchmarker](https://github.com/GoogleCloudPlatform/PerfKitBenchmarker)

	Google云平台提供的Benchmark，支持K8s。目前没有找到其在K8s测试的相关资料。

## Prepare Environment

### Kubernetes Cluster

根据自己的平台，参考[官方安装文档](https://kubernetes.io/docs/getting-started-guides/)，搭建Kubernetes Cluster。

### 安装依赖

```shell
$ yum install -y gcc.x86_64
```

### Go开发环境

1. 下载[go1.7.4.linux-amd64.tar.gz](https://storage.googleapis.com/golang/go1.7.4.linux-amd64.tar.gz)（保持与K8s构建用的Go版本一致）
2. 解压到/usr/local/go目录下
3. 设置GOROOT和GOPATH环境变量
	/etc/profile中添加：
	```shell
	$ export GOPATH=/root/gocode
	$ export PATH=$PATH:/opt/maven/latest/bin:$GOPATH/bin:/usr/local/go/bin
	```
	使变量生效：source /etc/profile

### Test Images

为了避免下载测试镜像，给Kubemark性能测试的结果带来误差，在运行Kubemark前，需要在所有K8s nodes上提前准备好这些镜像。
Kubemark测试时使用的image都是GCR上面的，需要通过能翻墙的机器下载相应的镜像到本地，然后重新标签并上传到公司内部的Docker Registry。所有K8s nodes从公司Docker Registry上下载测试image，然后重新标签为GCR的测试image。

## Install Kubemark

> The version of Kubernetes source code is **`v1.14.3`**.

### Build Kubemark image

1. 构建二进制文件

	在 K8s 源码路径下构建 kubemark，生成的二进制文件在 `_output/bin` 目录下。

	```shell
	$ KUBE_BUILD_PLATFORMS=linux/amd64 make kubemark GOFLAGS=-v GOGCFLAGS="-N -l"
	```

2. 构建镜像

	将生成的 kubemark 二进制文件从 `_output/bin` 复制到 [cluster/images/kubemark](https://github.com/kubernetes/kubernetes/tree/v1.14.3/cluster/images/kubemark) 目录下。
	并在该目录下执行构建镜像命令，生成镜像：staging-k8s.gcr.io/kubemark:v1.14.3。

	```shell
	$ IMAGE_TAG=v1.14.3 make build
	```

### Create Hollow Nodes

1. 创建 kubemark namespace

	```shell
	$ kubectl create ns kubemark
	```

2. 创建 kubemark 需要的 configmap

	```shell
	$ kubectl create configmap node-configmap -n kubemark --from-literal=content.type="test-cluster"
	```

3. 创建 kubeconfig secret

	```shell
	$ kubectl create secret generic kubeconfig --type=Opaque --namespace=kubemark --from-file=kubelet.kubeconfig={kubeconfig_file_path} --from-file=kubeproxy.kubeconfig={kubeconfig_file_path}
	```

	> `kubeconfig_file_path` 为 kubeconfig 文件路径，一般为 `/root/.kube/config`。

4. 创建 hollow nodes

	通过如下的 deployment 创建 hollow nodes，通过修改 `replicas` 可以调整模拟节点的数量。

	```yaml
	apiVersion: apps/v1
	kind: Deployment
	metadata:
	name: hollow-node
	namespace: kubemark
	labels:
		name: hollow-node
	spec:
	replicas: 1
	selector:
		matchLabels:
		name: hollow-node
	template:
		metadata:
		labels:
			name: hollow-node
		spec:
		initContainers:
		- name: init-inotify-limit
			image: busybox
			command: ['sysctl', '-w', 'fs.inotify.max_user_instances=200']
			securityContext:
			privileged: true
		volumes:
		- name: kubeconfig-volume
			secret:
			secretName: kubeconfig
		containers:
		- name: hollow-kubelet
			image: supereagle/kubemark:v1.14.3
			imagePullPolicy: IfNotPresent
			ports:
			- containerPort: 4194
			- containerPort: 10250
			- containerPort: 10255
			env:
			- name: CONTENT_TYPE
			valueFrom:
				configMapKeyRef:
				name: node-configmap
				key: content.type
			- name: NODE_NAME
			valueFrom:
				fieldRef:
				fieldPath: metadata.name
			command:
			- /bin/sh
			- -c
			- /kubemark --morph=kubelet --name=$(NODE_NAME) --kubeconfig=/kubeconfig/kubelet.kubeconfig $(CONTENT_TYPE) --alsologtostderr --v=2
			volumeMounts:
			- name: kubeconfig-volume
			mountPath: /kubeconfig
			readOnly: true
			securityContext:
			privileged: true
		- name: hollow-proxy
			image: supereagle/kubemark:v1.14.3
			imagePullPolicy: IfNotPresent
			env:
			- name: CONTENT_TYPE
			valueFrom:
				configMapKeyRef:
				name: node-configmap
				key: content.type
			- name: NODE_NAME
			valueFrom:
				fieldRef:
				fieldPath: metadata.name
			command:
			- /bin/sh
			- -c
			- /kubemark --morph=proxy --name=$(NODE_NAME) --use-real-proxier=false --kubeconfig=/kubeconfig/kubeproxy.kubeconfig $(CONTENT_TYPE) --alsologtostderr --v=2
			volumeMounts:
			- name: kubeconfig-volume
			mountPath: /kubeconfig
			readOnly: true
	```

	> 如果 apiserver 的 `--admission-control` 中开启了 `PodSecurityPolicy`，需要先关闭 PSP admission，否则模拟节点的 pod 会因为 privileged 的安全问题创建失败。

## Run Kubemark(Deprecated)

> The version of Kubernetes source code is **`v1.5.3`**.

{'fraction_non_alphanumeric': 0.14823377103754393, 'fraction_numerical': 0.032457924912150916, 'mean_word_length': 3.2578740157480315, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 18, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3856212', 'n_tokens_mistral': 5365, 'n_tokens_neox': 5336, 'n_words': 578}