热门搜索:iPhone 7 iOS 10 iPad Pro

Kubernetes应用安排策略实践

CSDN云计算 2017-12-06

【摘要】Kubernetes是Google开源的Docker容器集群治理系统,为容器化的应用提供资源调度、安排运行、服务发现、扩容缩容等整一套功能。在应用安排这块,类似于别的系统,Kubernetes也提供了一些操纵容器安排的方式,本文主要通过实践的方式介绍一下kubernetes的应用在安排时的安排策略。

几个概念:

Pod:是Kubernetes最基本的安排调度单元,能够包含container,逻辑上表示某种应用的一个实例。比如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们能够创建包含三个container的pod。

node: 是 Kubernetes的worker节点,通常也称作为Minion node。除了运行一些kubernetes的组件以外(kubelet, kube-proxy等),还承担着运行容器服务的重任。

ReplicationController:是pod的复制抽象,用于解决pod的扩容缩容问题。通常,分布式应用为了性能或高可用性的考虑,需要复制多份资源,并且依据负载情况动态伸缩。通过ReplicationController,我们能够指定一个应用需要几份复制,Kubernetes将为每份复制创建一个pod,并且保证实际运行pod数量总是与该复制数量相等(例如,当前某个pod宕机时,主动创建新的pod来替换)

情况介绍:

为了演示kubernetes应用安排策略,准备了7台机器(1个kubernetes master节点和6个kubernetes worker节点),如下图所示。

Kubernetes应用安排策略实践(图一)

其中:

1) kubernetes master: hchenk8s1(ubuntu 16.04 LTS) 2) etcd: hchenk8s1(能够和kubernetes master不在一个节点上面) 3) worker nodes: hchenk8s2 - hchenk8s7(总共6台机器, 操作系统为ubuntu 16.04 LTS)

当前nodeAffinity撑腰requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution这两种类型。从字面意义就能看到,类型一的要求要比类型二的苛刻的多,对付类型一来说,更像是上面介绍的nodeSelector的高级版,而对付类型二来说,在创建pod的时刻会依据各种调度条件对可调度的机器进行排序,并且不会像类型一那样,因为资源不够或者一些别的原因而创建失败,退而求其次来去选择别的的机器继续创建。

盼望结果:

以nginx应用为例,准备一个容器应用安排的kubernetes的deployment文件。

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 1  template:    metadata:      labels:        app: nginx        image: nginx_1_8_1    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:1.8.1        imagePullPolicy: Always        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 1000m            memory: 1024Mi      nodeSelector:        kubernetes.io/hostname: 9.111.254.218

在yaml文件中加入nodeSelector, 其中key和value分别为label的name和value.

首先为集群中的机器添加lable来标示机器的内核版本信息:

root@hchenk8s1:~# kc get nodes --show-labels -l worker=trueNAME            STATUS    AGE       LABELS9.111.254.208   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group1,kernel-version=0310,kubernetes.io/hostname=9.111.254.208,worker=true9.111.254.209   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group1,kernel-version=0404,kubernetes.io/hostname=9.111.254.209,worker=true9.111.254.212   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group2,kubernetes.io/hostname=9.111.254.212,worker=true9.111.254.213   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group2,kubernetes.io/hostname=9.111.254.213,worker=true9.111.254.214   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group3,kubernetes.io/hostname=9.111.254.214,worker=true9.111.254.218   Ready     6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group3,kubernetes.io/hostname=9.111.254.218,worker=true

从上面的输出能够看到,9.111.254.208的kernel-version为0310,9.111.254.209的kernel-version为0404.

准备需要创建服务所需要的yaml文件:

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 1  template:    metadata:      labels:        app: nginx        image: nginx_1_8_1    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:1.8.1        imagePullPolicy: IfNotPresent        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 1000m            memory: 1024Mi      nodeSelector:        storage_type: aufs        application_type: web

从上面的yaml文件能够看到,nodeSelector里面定义了两个条件,分别是storage_type和application_type, 应用只有创建在两个条件同时满足的节点上面。

为了测验nodeSelector多条件撑腰的测验,我们对6个worker分别进行标志:

root@hchenk8s1:~# kubectl label node 9.111.254.208 storage_type=overlay application_type=webnode9.111.254.208" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.209 storage_type=overlay application_type=dbnode9.111.254.209" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.212 storage_type=aufs application_type=webnode9.111.254.212" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.213 storage_type=aufs application_type=dbnode9.111.254.213" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.214 storage_type=devicemapper application_type=webnode9.111.254.214" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.218 storage_type=devicemapper application_type=dbnode9.111.254.218" labeled

标志后, 集群结构如下图所示。 Kubernetes应用安排策略实践(图二)

首先,对集群中的worker node添加label来标识组信息。

root@hchenk8s1:~# kubectl label node 9.111.254.208 group=group1node9.111.254.208" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.209 group=group1node9.111.254.209" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.212 group=group2node9.111.254.212" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.213 group=group2node9.111.254.213" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.214 group=group3node9.111.254.214" labeledroot@hchenk8s1:~# kubectl label node 9.111.254.218 group=group3node9.111.254.218" labeled

标识完后的worker node信息如下图所示。

盼望结果:

场景3:

下面准备一个用来测验的yaml文件:

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 4  template:    metadata:      labels:        app: nginx      annotations:        scheduler.alpha.kubernetes.io/affinity: >          {            "nodeAffinity": {              "requiredDuringSchedulingIgnoredDuringExecution": {                "nodeSelectorTerms": [                  {                    "matchExpressions": [                      {                        "key":group",                        "operator":In",                        "values": ["group1",group2"]                      }                    ]                  }                ]              }            }          }    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:latest        imagePullPolicy: IfNotPresent        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 500m            memory: 512Mi

下面开头创建容器服务。

root@hchenk8s1:~# kc create -f nginx_nodeaffinity.yamldeploymentnginx" createdroot@hchenk8s1:~# kc get pods -o wideNAME                     READY     STATUS    RESTARTS   AGE       IP            NODEnginx-3792017226-5cn0s   1/1       Running   0          1m        10.1.36.194   9.111.254.213nginx-3792017226-ljq9h   1/1       Running   0          1m        10.1.56.66    9.111.254.208nginx-3792017226-qfbvs   1/1       Running   0          1m        10.1.64.66    9.111.254.212nginx-3792017226-tdm23   1/1       Running   0          1m        10.1.183.3    9.111.254.209

从测验结果能够看到,4个副本分别安排在了group1和group2上的机器。

下面开头创建应用

root@hchenk8s1:~# kubectl create -f nginx_exist.yamldeploymentnginx" createdroot@hchenk8s1:~# kubectl get pods -o wideNAME                     READY     STATUS    RESTARTS   AGE       IP            NODEnginx-3031338627-7bbfc   1/1       Running   0          7s        10.1.183.17   9.111.254.209nginx-3031338627-cd1jz   1/1       Running   0          7s        10.1.56.80    9.111.254.208nginx-3031338627-wslpb   1/1       Running   0          7s        10.1.183.16   9.111.254.209nginx-3031338627-zgrxn   1/1       Running   0          7s        10.1.56.79    9.111.254.208

从测验结果能够看到,4个副本分别安排在了有network label的机器上面。

下面通过应用安排来测验nodeSelector的多条件选择:

从这个参数就能看出来,这种策略的调度工具是node,也就是上面说的kubernetes的worker,说的更明白一点是,用户在创建应用的时刻,能够通过nodeSelector来指定某个、或者某组具有某些属性的worker node来创建这些容器服务。这里既然提到了需要依据worker node的某些属性来创建这些容器服务,那就不得不介绍一下worker node的label.

首先先察看当前kubernetes cluster的worker node的情况。

root@hchenk8s1:~# kubectl get nodesNAME                 STATUS                                    AGE9.111.254.207   Ready,SchedulingDisabled   1d9.111.254.208   Ready                                       1d9.111.254.209   Ready                                       1d9.111.254.212   Ready                                       1d9.111.254.213   Ready                                       1d9.111.254.214   Ready                                       1d9.111.254.218   Ready                                       1d

从输出能够看到当前测验集群中有6台worker node和一个不可调度的master节点。

在kubernetes集群中,kubelet会上报一些机器属性比如hostname, os, arch等信息记载在nodes的label里面。下面先察看一下这些label.

root@hchenk8s1:~# kubectl get nodes --show-labelsNAME            STATUS                     AGE       LABELS9.111.254.207   Ready,SchedulingDisabled   1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2079.111.254.208   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2089.111.254.209   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2099.111.254.212   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2129.111.254.213   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2139.111.254.214   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.2149.111.254.218   Ready                      1d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=9.111.254.218

从输出结果能够看到,每个node都有3个label分别是beta.kubernetes.io/arch,beta.kubernetes.io/os,kubernetes.io/hostname。下面通过hostname作为应用安排的选择策略来安排应用到9.111.254.218机器上面。

集群中的6个worker node分别属于3个差别的组,这里分别命名为group1, group2, group3. 需要安排一个nignx应用,并且有4个副本,要求nignx应用安排在除了group3以外的别的group上面。

下面准备一个nginx的yaml文件,用来创建nginx服务:

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 4  template:    metadata:      labels:        app: nginx      annotations:        scheduler.alpha.kubernetes.io/affinity: >          {            "nodeAffinity": {              "requiredDuringSchedulingIgnoredDuringExecution": {                "nodeSelectorTerms": [                  {                    "matchExpressions": [                      {                        "key":kernel-version",                        "operator":Gt",                        "values": ["0320"]                      }                    ]                  }                ]              }            }          }    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:latest        imagePullPolicy: IfNotPresent        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 200m            memory: 256Mi

上面的文件表示的策略是盼望创建服务到kernel-version大于0320的机器上面。

Exists: 和In比较类似,凡是有某个标签的机器都会被选择出来。使用Exists的operator的话,values里面就不克写东西了。

Label: 标签的意义,使用在worker node上面顾名思义就是用来对worker node进行一些标志的。比如说worker node的cpu架构(ppc64, x86, etc)或者分组信息啊什么的。nodeSelector就是通过这些标签来选择应用到底要在哪些机器上去安排。

准备需要创建服务所需要的yaml文件:

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 1  template:    metadata:      labels:        app: nginx        image: nginx_1_8_1    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:1.8.1        imagePullPolicy: IfNotPresent        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 1000m            memory: 1024Mi      nodeSelector:        storage_type: btrfs        application_type: web

下面开头创建容器服务。

root@hchenk8s1:~# kubectl create -f nginx.yamldeploymentnginx" createdroot@hchenk8s1:~# kubectl get deploymentNAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEnginx     1         1         1            0           58sroot@hchenk8s1:~# kubectl  get pods -o wideNAME                    READY     STATUS    RESTARTS   AGE       IP        NODEnginx-155862529-m5pr1   0/1       Pending   0          1m        <none>root@hchenk8s1:~# kubectl describe pods nginx-155862529-m5pr1Name:       nginx-155862529-m5pr1Namespace:  defaultNode:       /Labels:     app=nginx        pod-template-hash=155862529Status:     PendingIP:Controllers:    ReplicaSet/nginx-155862529Containers:  nginx:    Image:  nginx:latest    Port:   80/TCP    Limits:      cpu:  1      memory:   1Gi    Requests:      cpu:  1      memory:   1Gi    Volume Mounts:      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5rj87 (ro)    Environment Variables:  <none>Conditions:  Type      Status  PodScheduled  FalseVolumes:  default-token-5rj87:    Type:   Secret (a volume populated by a Secret)    SecretName: default-token-5rj87QoS Class:  GuaranteedTolerations:    <none>Events:  FirstSeen LastSeen    Count   From            SubObjectPath   Type        Reason          Message  --------- --------    -----   ----            -------------   --------    ------          -------  1m        27s     8   {default-scheduler }            Warning     FailedScheduling    pod (nginx-155862529-m5pr1) failed to fit in any nodefit failure summary on nodes : MatchNodeSelector (6)

从输出能够看到,pod创建失败了,原因是没有找到适合的机器去安排。

总结一下:nodeSelector通过label选择机制,提供了比较简单直观的pod安排策略,从一些方面实现了节点的亲和/反亲和的策略。虽然现在依旧存在在kubernetes中,不外相信这个功能会慢慢被接下来要提到的node Affinity和inter-pod affinity取而代之。

2. NodeAffinity

NodeAffinity是kubernetes 1.2的时刻集成进来的,概念上类似于上面介绍的nodeSelector, 通过对node label的选择来安排你的pod的。

下面开头创建容器服务。

root@hchenk8s1:~# kubectl create -f nginx.yamldeploymentnginx" createdroot@hchenk8s1:~# kubectl get deploymentNAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEnginx     1         1         1            1           46sroot@hchenk8s1:~# kubectl  get pods -o wideNAME                     READY     STATUS    RESTARTS   AGE       IP            NODEnginx-2704164239-lr0gj   1/1       Running   0          1m        10.1.58.235   9.111.254.212

从输出能够看到,nginx服务已经选择机器9.111.254.212去安排应用。

上面的例子中用了In的operator,matchExpressions的operator大约有一下几种:

下面设计一个场景还试一下:

完了就开头情况搭建,这里就不演示了,情况搭建局部网上很多。可供参考的比较多。

进入主题

当前,kubernetes提供了3中应用安排策略,下面一一进行介绍:

1. nodeSelector:

nodeSelector是kubernetes提供的最简单的一种应用安排策略,通过一种key=value的方式来安排用户的应用。

nginx web服务安排在节点9.111.254.212上面

盼望结果:

盼望结果:

创建一个nginx web服务,选择worker node上面,storage_type标志为啊btrfs的节点:

场景2:

程序:

在这两种类型中,ignoredDuringExecution的意义是在node在运行期间如果label发生了变化,之间通过这些类型安排的pod不会因为node label的变化而去重新安排来满足已经定义好的亲和/反亲和的策略。不外社区计划会针对这些case提供requiredDuringSchedulingRequiredDuringExecution的类型来应对因为node label变化,定义的亲和/反亲和的策略发生变化的问题,当然,pod可能就需要重新安排来适应已经发生的变化。

nginx的应用能安排在group1和group2里的worker node。

场景2:

程序:

程序:

场景1:

程序:

场景1:

Lt: less than的意义,表示凡是某个value小于设定的值的机器则会被选择出来。

下面就开头见证奇迹了。

当然,nodeSelector自身能够撑腰多个选择条件,当创建应用的时刻,nodeSelector里面的条件都满足的机器会被选择出来用来安排pod.

先说说nodeAffinity的类型:

通过kubectl创建应用容器服务。

root@hchenk8s1:~# kubectl  create -f nginx.yamldeploymentnginx" createdroot@hchenk8s1:~# kubectl get deploymentNAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEnginx     1         1         1            1           9mroot@hchenk8s1:~# kubectl  get pods -o wideNAME                     READY     STATUS    RESTARTS   AGE       IP            NODEnginx-1245594662-sjjp9   1/1       Running   0          1m        10.1.20.130   9.111.254.218

从输出能够看到, nginx的容器服务已经安排到了刚刚指定的机器上面。

集群中的6个worker node,其中的2台有kernel-version标签,用来记载机器的内核版本。通过deployment创建一个nginx应用,并且nginx应用有4个副本,通过nodeAffinity选择内核版本范围来进行应用安排。

集群中的6个worker node,其中的2台标志了network的标签,而别的的4台没有network标签。通过deployment创建一个nginx应用,并且nginx应用有4个副本,通过nodeAffinity选择有network标签的机器进行应用安排。

In: 凡是满足values里面条件的机器都会被选择出来。以上面的例子为例,凡是满足group=group1或者group=group2的机器都会被选择出来。

Kubernetes应用安排策略实践(图三)

盼望nginx的应用安排在kerver-version大于0320的机器上面。

创建一个nginx web服务,选择worker node上面,storage_type标志为啊aufs的节点:

程序:

NotIn: 和In相反,凡是满足values里面条件的机器都会被剔除出去。如果以上面的例子为例,operator换成NotIn, 那么group=group1以及group=group2的机器就会被剔除出去,而group=group3的机器则会被选择出来。

盼望结果:

下面我们通过nodeSelector来安排应用,并且应用需要安排在指定的机器上面。

nginx web选择不到适合的机器安排应用。

DoesNotExist: 和Exists相反,凡是不具备某个标签的机器则会被选择出来。和Exists的Operator一样,values里面也不克写东西了。

首先,对集群中的worker node添加label来标识组信息,通过命令能够察看当前集群中的worker node的label信息。

root@hchenk8s1:~# kubectl get nodes --show-labelsNAME            STATUS                     AGE       LABELS9.111.254.208   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group1,kubernetes.io/hostname=9.111.254.208,network=calico9.111.254.209   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group1,kubernetes.io/hostname=9.111.254.209,network=calico9.111.254.212   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group2,kubernetes.io/hostname=9.111.254.2129.111.254.213   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group2,kubernetes.io/hostname=9.111.254.2139.111.254.214   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group3,kubernetes.io/hostname=9.111.254.2149.111.254.218   Ready                      6d        beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,group=group3,kubernetes.io/hostname=9.111.254.218

准备创建nginx应用的deployment

kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: nginxspec:  replicas: 4  template:    metadata:      labels:        app: nginx      annotations:        scheduler.alpha.kubernetes.io/affinity: >          {            "nodeAffinity": {              "requiredDuringSchedulingIgnoredDuringExecution": {                "nodeSelectorTerms": [                  {                    "matchExpressions": [                      {                        "key":network",                        "operator":Exists"                      }                    ]                  }                ]              }            }          }    spec:      hostNetwork: false      containers:      - name: nginx        image: nginx:latest        imagePullPolicy: IfNotPresent        ports:        - protocol: TCP          containerPort: 80        resources:          limits:            cpu: 500m            memory: 512Mi

从上面的yaml文件能够看到,matchExpression里面定义了nodeAffinity的选择条件,从上面的例子能够看到,nginx应用盼望能创建在有network label的机器上。

下面2个例子分别看看别的几个operator的使用以及测验结果。

Gt: greater than的意义,表示凡是某个value大于设定的值的机器则会被选择出来。

nginx的应用能安排在有network的标签的机器上面。

下面开头创建;

root@hchenk8s1:~# kubectl create -f nginx_gt.yamldeploymentnginx" createdroot@hchenk8s1:~# kubectl get pods -o wideNAME                     READY     STATUS    RESTARTS   AGE       IP            NODEnginx-4087060041-2x9lw   1/1       Running   0          4s        10.1.183.26   9.111.254.209nginx-4087060041-4x1dd   1/1       Running   0          4s        10.1.183.23   9.111.254.209nginx-4087060041-bgt0z   1/1       Running   0          4s        10.1.183.24   9.111.254.209nginx-4087060041-brgb3   1/1       Running   0          4s        10.1.183.25   9.111.254.209

从测验结果能够看到,4个副本都创建在了kernel-version为0404的机器上。

3. Inter-pod affinity/anti-affinity

Inter-pod affinity/anti-affinity是kubernetes 1.4开头撑腰的,pod的安排策略不再单单的只是通过node label的选择,而是能够从pod层面通过pod的 label来安排自己的应用,简单点说就是你能够通过inter-pod affinity/anti-affinity来决议自己的容器应用靠近或者远离具有某些label的容器应用。

和nodeAffinity一样,inter-pod affinity/anti-affinity也有requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution两种类型,分别表示”hard”和”soft”两种需求。

篇幅限制,想察看原文,请点击左下角“阅读原文

作者简介:陈晖,供职于西安IBM, 主要从事云计算方面工作,涉及Openstack, Mesos, kubernetes等开源项目,在资源治理 ,资源调度等方面有比较丰盛的经验 。

关键字:

特约作者

推举阅读 ^o^

微信扫一扫
分享到朋友圈

prve

SRWebSocket源码浅析(上)

上一篇

next

大数据计算框架Hadoop, Spark和MPI

下一篇

条评论