可能是最实用的kubemark攻略

7,728 阅读5分钟

kubemark overview

Kubemark是K8s官方提供的一个对K8s集群进行性能测试的工具。它可以模拟出一个K8s cluster(Kubemark cluster),不受资源限制,从而能够测试的集群规模比真实集群大的多。这个cluster中master是真实的机器,所有的nodes是Hollow nodes。Hollow nodes执行的还是真实的K8s程序,只是不会调用Docker,因此测试会走一套K8s API调用的完整流程,但是不会真正创建pod。

Kubermark是在模拟的Kubemark cluster上跑E2E测试,从而获得集群的性能指标。Kubermark cluster的测试数据,虽然与真实集群的稍微有点误差,不过可以代表真实集群的数据,因此,可以借用Kubermark,直接在真实集群上跑E2E测试,从而对我们真实集群进行性能测试。

kubemark的架构图:

kubemark架构图

kubemark in practice

搭建方法

根据官方文档,k8s中的脚本只适用于GCE。

the steps below use gcloud for SSH and SCP to master, and should be easy to do outside of GCE

Kubemark当然可以在本地运行,于是我找到了这个文档,然而这个脚本存在缩进问题,与rbac权限问题,需要进行小小的修改。

为了搭建kubemark环境,我们需要两个集群,一个集群成为workers cluster,用来承载kubemark的虚拟节点(虚拟节点只是一个pod);一个作为masters cluster,用来承载kubemark的控制面。

事实上,如果只用一个集群也是可以的,但是daemonset资源会在虚拟的节点上创建,影响masters cluster的环境。所以最好的方式还是workers cluster选择一个容量较大的集群,而masters cluster用虚拟机搭一个最简单的集群,因为kubemark对workers cluster是没有影响的

所以最终的完整的搭建步骤如下:

编译kubemark镜像

由于k8s的编译比较耗费资源,且我测试了go 1.13在mac上交叉编译会失败,所以建议选择linux服务器进行编译。

# 进入k8s的目录
make WHAT='cmd/kubemark'
cp _output/bin/kubemark cluster/images/kubemark/
cd cluster/images/kubemark/
sudo make build
# 再打个tag上传就好

不打tag也可以,make的时候传入registry等环境变量是一样的。

要注意编译的版本要和masters cluster相同,不然运行起来之后kubelet会报错的。

准备masters和workers集群

准备完毕之后,准备好masters集群的Kubeconfig文件,在workers集群上执行

kubectl create ns kubemark
kubectl create configmap node-configmap -n kubemark --from-literal=content.type="test-cluster"
kubectl create secret generic kubeconfig --type=Opaque --namespace=kubemark --from-file=kubelet.kubeconfig=config --from-file=kubeproxy.kubeconfig=config

启动hollow-nodes

将下面的yaml文件命名为hollow-nodes-sts.yaml,这个脚本已经修复了RBAC问题与缩进问题,替换镜像名称之后可以直接食用。并且我无视了容器的错误日志,因为实在太多了,且错误原因是kubemark无法mock存储,并不是环境本身有问题。

apiVersion: v1
kind: Service
metadata:
  name: hollow-node
  namespace: kubemark
spec:
  clusterIP: None
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    name: hollow-node
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubemark
  namespace: kubemark
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: kubemark
rules:
- apiGroups: [""]
  resources: ["services", "pods", "nodes", "endpoints"]
  verbs: ["watch", "list", "get"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["*"]
- apiGroups: ["node.k8s.io"]
  resources: ["runtimeclasses"]
  verbs: ["watch", "list", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubemark
subjects:
- kind: ServiceAccount
  name: kubemark
  namespace: kubemark
roleRef:
  kind: ClusterRole
  name: kubemark
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: hollow-node
  namespace: kubemark
spec:
  podManagementPolicy: Parallel
  replicas: 150
  selector:
    matchLabels:
      name: hollow-node
  serviceName: hollow-node
  template:
    metadata:
      labels:
        name: hollow-node
    spec:
      serviceAccountName: kubemark
      initContainers:
      - name: init-inotify-limit
        image: busybox:latest
        command: ['sysctl', '-w', 'fs.inotify.max_user_instances=200']
        securityContext:
          privileged: true
      volumes:
      - name: kubeconfig-volume
        secret:
          secretName: kubeconfig
      - name: logs-volume
        hostPath:
          path: /var/log
      containers:
      - name: hollow-kubelet
        image: xxxxxxxxx
        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) --v=2 2>/dev/null
        volumeMounts:
        - name: kubeconfig-volume
          mountPath: /kubeconfig
          readOnly: true
        - name: logs-volume
          mountPath: /var/log
        resources:
          requests:
            cpu: 20m
            memory: 50M
        securityContext:
          privileged: true
      - name: hollow-proxy
        image: xxxxxxxx
        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 2>/dev/null
        volumeMounts:
        - name: kubeconfig-volume
          mountPath: /kubeconfig
          readOnly: true
        - name: logs-volume
          mountPath: /var/log
        resources:
          requests:
            cpu: 20m
            memory: 50M
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists

之后在workers集群上执行kubectl create -f hollow-nodes-sts.yaml即可。等待片刻后能看到起来了一堆一堆的pod

NAME              READY   STATUS    RESTARTS   AGE   IP               NODE                  NOMINATED NODE
hollow-node-0     2/2     Running   0          22m   xxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxx   <none>
hollow-node-1     2/2     Running   0          22m   xxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxx   <none>
hollow-node-10    2/2     Running   0          18m   xxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxx   <none>
hollow-node-100   2/2     Running   0          18m   xxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxx   <none>

切换到masters cluster上执行kubectl get nodes可以看到一堆一堆的假的节点了。

dive into kubemark

由于工作原因,我希望kubemark虚拟出的节点可以支持extended resources,所以阅读了kubemark的源码之后,我修改了kubemark的源码,使其支持GPU资源、RDMA资源等等的模拟。我向社区提出了这个issue,希望可以得到回复吧。如果你也有类似的需求,欢迎与我讨论。

再简单说一下Kubemark的源码。入口在cmd/kubemark/hollow-node.go中。可以分为两部分阅读,一部分是proxy,这部分使用了真实的proxy,而非mock的接口。另一部分是kubelet,这个都是mock的接口。

在kubelet中,和节点配置有关的代码都在pkg/kubelet/cm/container_manager_stub.go中,如果愿意,甚至可以用kubemark做一个仿真平台,节点的意外挂掉等等都是可以模拟出来的,然而这要这样还不如用matlab。