背景
客户有一个java应用比较耗内存,在kubernetes上对cpu和内存进行了限制,但效果不大好,应用经常被kill掉,由于该应用属于核心应用,后面就解除限制,在jvm上对堆内存进行了限制,因为没有配置kubernetes资源请求限制,kubernetes在调度上就无法灵活调度,经常将多个副本调度到同一节点,多个大内存应用运行在同一个节点,内存很容易就被耗尽导致jvm gc频繁,频繁的gc又导致了服务器cpu负载过大,最终应用挂掉无法访问。如果kubernetes能将应用多个副本调度到不同节点那么至少能保证一个节点挂掉,其他节点应用还可以继续服务。
方案
- DaemonSet
首先想到的是DaemonSet,DaemonSet能保证应用跑在不同的节点,但DaemonSet应用场景一般是作为守护进程或者日志收集,并且每个节点都会部署一个副本,这并不是我们想要的结果,因此不考虑DaemonSet。
- nodeAffinity
节点亲和性(nodeAffinity)可以通过条件让kubernetes将应用调度到指定节点上,在我们期望的场景中是kubernetes能够将应用调度到不同节点,这个通过节点的标签无法构建表达式。nodeAffinity适合需要将应用调度到明确的节点上。
- podAntiAffinity
和节点亲和性只能通过节点标签来指定节点不同的是,pod的亲和性可以通过运行在该node上的pod标签进行节点选择,那么假设所有应用都带有app标签,值为app的名称,那么我们可以这么表达不希望调度到节点上有pod标签和我一样的节点
,用podAntiAffinity表达如下
affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: app operator: NotIn values: - nginx topologyKey: kubernetes.io/hostname
一个完整的nginx示例
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment-1 labels: app: nginx spec: replicas: 9 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 0 maxUnavailable: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 80 - containerPort: 443 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: app operator: NotIn values: - nginx topologyKey: kubernetes.io/hostname weight: 100
亲和性还有软亲和(preferredDuringSchedulingIgnoredDuringExecution)和硬亲和(requiredDuringSchedulingIgnoredDuringExecution)之分,硬亲和必须满足条件才进行调度,比如上面的nginx配置了硬亲和不在同一节点上运行,假设副本数超过了节点数,那么超过的副本将不满足条件,超过的副本状态会变为Unavaliable
,如果是软亲和,kubernetes会尽量满足条件,如果不满足也会调度到其他节点上,如果是硬亲和建议副本数不要超过节点数
no comment untill now