Skip to content

Latest commit

 

History

History
284 lines (254 loc) · 11.2 KB

调度.md

File metadata and controls

284 lines (254 loc) · 11.2 KB

认证要求

  • Scheduling 调度 5%
    • 使用label选择器来调度pods
    • 理解Daemonset的角色
    • 理解resource limit 会如何影响pod 调度
    • 理解如何运行多个调度器, 以及如何配置pod使用它们
    • 不使用调度器, 手动调度一个pod
    • 查看和显示调度事件events
    • 知道如何配置kubernetes scheduler

使用label选择器来调度pods

  1. 查看节点信息
kubectl get nodes

输出如下:

NAME      STATUS    AGE     VERSION
 worker0   Ready     1d      v1.6.0+fff5156
 worker1   Ready     1d      v1.6.0+fff5156
 worker2   Ready     1d      v1.6.0+fff5156
  1. 选择一个节点, 并给这个节点打上label
kubectl label nodes <your-node-name> disktype=ssd
  1. 验证节点上是否有成功打上对应label
kubectl get nodes --show-labels

输出结果类似于

 NAME      STATUS    AGE     VERSION            LABELS
 worker0   Ready     1d      v1.6.0+fff5156     ...,disktype=ssd,kubernetes.io/hostname=worker0
 worker1   Ready     1d      v1.6.0+fff5156     ...,kubernetes.io/hostname=worker1
 worker2   Ready     1d      v1.6.0+fff5156     ...,kubernetes.io/hostname=worker2
  1. 创建一个pod, 调度到这个node上 在pod的配置里, 要指定nodeSelector, 比如disktype=ssd。 这意味着pod启动后会调度到打上了disktype=ssd标签的node上
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
  1. 验证pod启动后是否调度到指定节点上
kubectl get pods --output=wide

输出类似于

AME     READY     STATUS    RESTARTS   AGE    IP           NODE
 nginx    1/1       Running   0          13s    10.200.0.4   worker0

参考 Assign Pods to Nodes

理解Daemonset的角色

什么是daemonset以其使用场景

daemonset会在每一个节点上运行一个pod的副本,当有node加入集群时,会自动在新节点上启动pod副本, 当node被移出节点时, 上面的pod副本会被自动删除。 使用场景:

  • 运行storage进程,如 glusterd, ceph等
  • 进行日志收集进程fluentd, logstash , filebeat等
  • 监控进程,比如prometheus node exporter, collectd, datadog agent, new relic agent, ganglia gmond等

创建一个daemonset

apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      containers:
      - name: fluentd-elasticsearch
        image: gcr.io/google-containers/fluentd-elasticsearch:1.20
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

如果只想调度到某些主机上, 可以指定nodeSelector的值。

Daemon Pods如何调度

通常情况下pod要运行的机器是由scheduler来选择的的。但是DaemonSet controller创建的pod要运行的机器是已经被选择好的(pod在创建的时候.spec.nodeName字段就指定了, 因此会被scheduler忽略)

因此:

  • unschedulable字段对daemonset controller创建的pod不起作用,当你尝试kubectl drain <node_name> 时, 驱赶不了daemonset创建的pod
  • 即使scheduler没有起来, daemonset创建的pod也可以正常调度,因为它的调度不依赖scheduler

但是如果node被标记为以下的两种状态: node.alpha.kubernetes.io/notReady node.alpha.kubernetes.io/unreachable

daemon pods就不会调度到上面。

如何和daemonset的pod通信

  • 使用hostPort
  • 创建headless service(指定pod 的选择器标签),使用dns解析得到一堆endpoint
  • 创建service(指定pod 的选择器标签), 用service 的cluster ip或者域名进行连接

如何更新一个daemonset

node的label改变时,daemonset会自动将pod启动在新匹配上的节点,或者把pod移除出不匹配的节点

当你用kubectl删除daemonset时,指定参数--cascade=false, 这时daemonset会被删除, 但是pod会被保留, 重新使用新的模板创建daemonset, 新的daemonset会识别和匹配到已经存在于node上的pods, 但是不会修改和删除它们, 你需要手动执行删除这些pod, 才能让新的pod能够创建。

值得注意的是, 在kubernetes 1.6版本之后, daemonset可以执行滚动更新了。 具体操作可以参考https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/

daemonset的几种替代方案

  • init, upstartd, 和systemd

但是daemonset的好处在于 可以像k8s上的应用一样, 监控和记录日志 可以像k8s上的应用一样使用模板进行编排,比如Pod Template,并使用k8s的工具, 比如kubectl 在未来版本中, 可以和node的升级工作流和daemonset创建的pod进行整合 可以通过资源限制, 更好和应用的容器做隔离 可以方便的进行滚动升级 安装部署方便, 而且有新的节点移入移除时,进程的添加和删除都是自动执行的

  • bare pods

在pod中指定特定的节点运行。 daemonset的方式优于这种方式, 它会自动替换和删除有故障主机上的pod, 或者处于维护中(比如内核升级)的节点上的pod

  • static pods

static pod不能被 kubectl和其它的kubernetes 的api client。 static pods 有可能在未来的版本中被废弃。

  • Deployments

deployment更适合有滚动升级, 扩缩容需求的无状态服务 daemonset适合那些需要运行在所有或特定主机上的服务, 或者需要先于其它pod启动的服务

理解resource limit 会如何影响pod 调度

理解如何运行多个调度器, 以及如何配置pod使用它们

  1. 打包自定义的scheduler镜像
  2. 为你的scheduler制作deployment
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  labels:
    component: scheduler
    tier: control-plane
  name: my-scheduler
  namespace: kube-system
spec:
  replicas: 1
  template:
    metadata:
      labels:
        component: scheduler
        tier: control-plane
        version: second
    spec:
      containers:
      - command:
        - /usr/local/bin/kube-scheduler
        - --address=0.0.0.0
        - --leader-elect=false
        - --scheduler-name=my-scheduler
        image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10251
          initialDelaySeconds: 15
        name: kube-second-scheduler
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10251
        resources:
          requests:
            cpu: '0.1'
        securityContext:
          privileged: false
        volumeMounts: []
      hostNetwork: false
      hostPID: false
      volumes: []

这个scheduler pod启动的时候, 要指定--scheduler-name, 这个名称是要唯一的。另外其它pod要指定调度器的时候用的是这里指定的调度器名称。 3. 在集群中运行scheduler

kubectl create -f my-scheduler.yaml

如果要让多个调度器之间进行选主操作, 要修改pod yaml里的启动参数, 增加如下参数

  • --leader-elect=true
  • --lock-object-namespace=lock-object-namespace
  • --lock-object-name=lock-object-name

如果你开启了RBAC, 要更新你的cluster role - system:kube-scheduler. 在resourceNames:那一行,加上你的调度器名称

  1. pod启动时指定调度器
apiVersion: v1
kind: Pod
metadata:
  name: annotation-second-scheduler
  labels:
    name: multischeduler-example
spec:
  schedulerName: my-scheduler
  containers:
  - name: pod-with-second-annotation-container
    image: gcr.io/google_containers/pause:2.0

spec.schedulerName指定的调度器的名称要和 scheduler的启动参数--scheduler-name里指定的名称一致,才能正常调度。

  1. 验证pod有没有被期望的调度器调度
kubectl get events

从events可以看出调度行为

参考 Configure Multiple Schedulers

不使用调度器, 手动调度一个pod

使用static pod可以实现手动调度一个pod。

static pod的特点总结如下:

  1. 不通过apiserver watch, 由本机的kubelet进程执行watch,并拉起
  2. 只在本机进行调度
  3. 没有健康检查
  4. 不被controller manager调度
  5. 因为apiserver里有pod的镜像信息, 通过apiserver还是可以看到pod的信息

如何创建?

方法一: kubelet启动时要指定参数kubelet --pod-manifest-path=,这里的the directory要放置static pod的编排文件的目录。 把static pod的编排文件放到此目录下, kubelet可以监听到变化, 并根据编排文件创建pod。

方法二: 指定--manifest-url=, kubelet会从这个URL下载编排文件, 并创建pod

如何删除?

当我们直接用kubectl的命令kubectl delete pod删除一个静态pod时, 我们会发现static pod过一段时间又会被kubelet拉起。

要完全删除一个static pod, 可以移除把该static pod的编排文件, 从--pod-manifest-path=所指定的目录里移除即可。

使用场景?

因为static pod有一个特性是我们的应用的docker 容器被删除,或者pod被kubectl误删了之后, static pod还能被kubelet进程拉起。通过这种方式保证了应用的可用性。 有点相当于systemd的功能, 但比systemd好的一点是, static pod的镜像信息会在apiserver中注册。 这样的话, 我们就可以统一对部署信息进行可视化管理。 另外static调度了的是容器, 无需拷贝二进制文件到主机上, 应用封装在镜像里也保证了环境的一致性, 无论是应用的编排文件还是应用的镜像都方便进行版本管理和分发。

实际生产中, static pod可以用来部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver等进程。

当我们要部署一个有状态的应用, 有几种方式:

  1. 使用statefulset
  2. 给主机打上label,只允许主机在这几台主机上调度
  3. 通过挂载ceph盘来存储有状态数据(要求master和node节点上都要安装rbd工具)
  4. 使用static pod ,但是这种方式适合那些无滚动升级需求, 无扩缩容需求,不频繁进行升级的应用

查看和显示调度事件events

知道如何配置kubernetes scheduler

参考文献