1. Pod 简单介绍

  • Pod 是最小的调度单位,Pod 里面包含的是容器

  • Pod 中可以有一个容器,也可以有多个容器

  • Pod 是最终对外提供服务的

  • 所有的资源都是以命名空间进行隔离的

2. Pod 的创建

2.1 通过命令的方式创建

命令:kubectl run ,完整的命令为:

Copy to Clipboard

其中,常用的命令选项有:

  • --image :必须,pod 的镜像

  • --env :可选,表示传入容器的环境变量

  • --port :可选,表示使用的port端口

  • --dry-run

    • client: 仅仅打印输出,但并不实际创建 pod,检查 yaml 文件的格式是否正确

    • server: 实际创建

  • --overrides :可选, 表示覆盖的 pod 的json文件,例如:--overrides='{ "apiVersion": "v1", "spec": { ... } }'

  • --image-pull-policy 可选,镜像下载策略:

    • Always: 不管本地有没有镜像,都要去下载

    • IfNotPresent: 如果本地有,则优先使用本地镜像,如果没有镜像,就去下载

    • Never:从不去下载镜像

  • --command :可选,表示执行的命令

  • --labels :可选,添加 标签

示例:

Copy to Clipboard

2.2 以 yaml 文件的方式创建

可以通过 dry-run 和 -o yaml 生成一个简单的模板,例如:

Copy to Clipboard

注意:

  • yaml 缩进是两个空格

  • 以驼峰格式命名并且 key 的首字母小写,value 的首字母大写

  • apiVersion 不同的资源使用不通的 apiVersion,可以使用此命令查看所有的 apiVersion: kubectl api-version

  • 如果不知道 yaml 中的属性,可以使用此命令查看:kubectl explain pod

  • 如果查看 pod 下的具体某个属性下的具体属性,可以使用:kubectl explain pod.spec.containers

示例:

Copy to Clipboard

Notes:

  • command 就是代替容器的默认 执行命令

  • command 与 args 相同含义,可以用 args 替换

    • 一般,如果要设置命令,就填写在配置文件的 command 字段下,如果要设置命令的参数,就填写在配置文件的 args 字段下。

3. Pod 的常用命令

  1. 查看 Pod 分配在了哪个节点上

    • kubectl get pods -o wide

Copy to Clipboard
  1. 查看 pod 的属性

    • kubectl describe pod nginx

Copy to Clipboard
  1. 在 pod 中执行 shell 命令

    • kubectl exec nginx -- shell 命令

    • 注意: 如果 pod 中有多个容器,想默认 exec 进入到 第一个容器,称为主容器,后面的称为 sidecar

    • 如果想进入指定容器,可以使用 -c 选项 kubectl exec nginx -c 容器名 -- shell 命令

Copy to Clipboard
  1. 以 伪终端的形式 进入到 pod 中执行 shell 命令

    • kubectl exec -it nginx -- /bin/bash

    • 进入指定的容器: kubectl exec -it nginx -c 容器名 -- /bin/bash

Copy to Clipboard
  1. 拷贝文件到 pod 中,或者从 pod 中拷贝文件出来

    • kubectl cp 本机文件名 Pod名:Pod目录 -> 从本机拷贝到容器

    • kubectl cp Pod名:Pod文件目录 本机目录 -> 从容器拷贝到本地

Copy to Clipboard
  1. 查看 pod 的 log 输出

    • kubectl logs pod名

Copy to Clipboard

4. Pod 的删除

  1. kubectl delete pod nginx -> 直接删除某个pod

  2. kubectl delete -f nginx.yaml -> 从创建的 yaml 文件 直接删除所有指定的资源

优雅的删除Pod:

  • kubectl 删除 pod 其实是发送一个 SIGTERM 信号给容器,让容器关闭进程

  • k8s 里默认设置了 30s 的时间等待容器 关闭进程,也就是等待 30s 后,在删除容器,如果容器中的进程 30s 内没有关闭,则会强制关闭

  • 如果在 30s 内,容器已经关闭进程,则会直接删除容器,可以通过容器的 lifecycle 来控制容器的关闭

操作:

  • 可以通过 kubectl delete 命令后加上 –grace-period 选项,会延迟一定时长才进行删除,缺省未设定的情况下会等待30s中之后删除。例如:
Copy to Clipboard
  • 也可以通过在配置文件中加入,spec 下的 terminationGracePeriodSeconds 属性,来配置该等待时间,默认 30s

    • 也就是在选项中使用 –grace-period 镭射纸,在 yaml 文件中使用 terminationGracePeriodSeconds 属性设置。

5. Pod 的生命周期

Pod 的生命周期,有两个 hook,分别是:

  • postStart:

    • 表示当容器启动起来后,就运行的一些操作

    • postStart 这个进程,和主进程是同时进行的,也就是异步的。

  • preStop:

    • 表示当容器关闭之前,运行的一些操作

    • 如果 preStop 没有完成,Pod 是不会被删除的

使用方法:

  • 在 yaml文件中添加 lifecycle

  • 属性位置: pod.spec.containers.lifecycle

  • postStart 和 preStop 下又有三种方法,分别是

    • exec:执行命令

    • httpGet:使用发送http消息来访问某个地址

    • tcpSocket:使用发送tcp消息来访问某个地址

示例:

Copy to Clipboard

6. Pod 的端口暴露

例如:

Copy to Clipboard

说明:

  • targetPort : 这个是容器中监听的端口,也就是 9376

  • hostPort : 这个是将容器的端口映射到物理机的端口,也就是将容器的 9376 映射到物理机的 80 端口(与服务中的 port 相同)

7. Pod 的重启策略

在yaml文件中的 pod.spec.restartPolicy 字段,有三种情况:

  • Always : Pod 里的进程执行完了,不管正常或者异常,都回重新执行

  • OnFailure : pod 里的进程执行完了,如果异常退出,则会重新执行,如果正确退出,则不会重启

  • Never : 完全不会重启

8. init 初始化容器

初始化容器的步骤:

  • 一个容器 A 依赖其他容器,可以为 A 设置多个依赖容器 A1,A2,A3

  • A1, A2, A3 要按照顺序启动,A1没有启动启动起来的话,A2, A3是不会启动的,直到所有的容器全部启动完毕,主容器 A 才会启动。

  • 这里可以把 A1,A2,A3 设置为初始化容器

注意:

初始化容器失败,则会一直重启,后续的初始化容器不会执行,Pod 不会创建。 只有所有的初始化容器执行完毕,才会创建普通容器,Pod 才会创建。

使用方法:

  • pod.spec.initContainers 属性,来定义初始化容器

  • 注意:容器中可以修改本机的内核属性的,但是必须设置

Copy to Clipboard

示例:

Copy to Clipboard

初始化容器的规则

  1. 它们总是运行到完成。

  2. 每个都必须在下一个启动之前成功完成

  3. 如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动

  4. Init 容器支持应用容器的全部字段和特性,但不支持 Readiness Probe,因为它们必须在 Pod 就绪之前运行完成。

  5. 如果为一个 Pod 指定了多个 Init 容器,那些容器会按顺序一次运行一个。 每个 Init 容器必须运行成功,下一个才能够运行。

  6. 因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 特别地,被写到 EmptyDirs 中文件的代码,应该对输出文件可能已经存在做好准备。

  7. 在 Pod 上使用 activeDeadlineSeconds,在容器上使用 livenessProbe,这样能够避免 Init 容器一直失败。 这就为 Init 容器活跃设置了一个期限。

    1. activeDeadlineSeconds 标志失败 Pod 的重试最大时间,超过这个时间不会继续重试

  8. 在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误。

  9. 对 Init 容器 spec 的修改,被限制在容器 image 字段中。 更改 Init 容器的 image 字段,等价于重启该 Pod。

9. 静态 Pod

静态 Pod 介绍:

  • 静态 Pod 是直接由特定节点上的 kubelet 进程来管理,不通过主控节点上的 API 服务器。

  • 静态 Pod 不关联任何 replication controller,它由 kubelet 进程自己来监控,当 Pod 崩溃时重启该 Pod 。

  • 对于静态 Pod 没有健康检查。静态 Pod 始终绑定在某一个 kubelet,并且始终运行在同一个节点上。

方法:

  • 在 node 节点上,找到 kubelet 的配置选项, –pod-manifest-path 选项,该选项指定的是 静态 Pod 的 yaml 文件存放的地址,步骤:

    • systemctl status kubelet -> 查看 kubelet 的配置文件地址

    • 修改配置文件,在 Environment 中添加 --pod-manifest-path=静态pod目录

    • systemctl daemon-reload

    • systemctl restart kubelet

    • 在指定的目录下创建 Pod 的 yaml 文件,则 kubelet 会自动创建该 Pod ,可以在 master 上查看,但是不由 master 管理,

    • 直接修改该 yaml 文件,保存后,会自动重建

10. Pod 的调度

当创建一个 Pod 时,scheduler 会根据自己的算法来决定 Pod 在那个节点上运行。

调度的三个对象有:

  1. 带调度的 Pod 列表

    • 也就是新创建的所有的 Pod 列表

  2. 可用的 node 列表

    • 也就是可以将 Pod 创建在哪些 node 节点的列表

  3. 调度算法

    • 主机过滤(label 过滤)

    • 主机打分

调度过程

  • 主机过滤算法,是去除掉一些不符合要求的节点,然后剩下的节点都符合主机过滤算法的要求。

  • 主机过滤后,将所有的可用的 node 节点通过主机打分算法,每个节点根据 cpu 使用率、mem 使用率等等参数打分,最终 Pod 会调度在分值高的节点上。

10.1 查看和指定 node 节点的标签

  1. 查看 node 节点的标签

    • kubectl get nodes --show-labels

Copy to Clipboard
  1. 为某个 node 节点添加标签

    • kubectl label nodes node名称 标签名=标签值 -> 给某个 node 添加标签

    • kubectl label node --all 标签名=标签值 -> 为所有 node 添加标签

    • kubectl label nodes node名称 标签名=标签值 --overwrite -> 修改标签

Copy to Clipboard
  1. 为某个 node 节点删除标签,(短横线)

    • kubectl label nodes 节点名 标签名-

Copy to Clipboard

10.2 将 Pod 调度到指定的 node节点(标签选择)

方法:

  • 在 node节点上可以定义一些 label,例如在 node1 指定 disktype 为 ssd 的标签

  • 在定义 Pod 的 yaml 文件中,添加 nodeSelector 选择在指定 label 的 node 节点上调度 Pod ,位置在 pod.spec.nodeSelector

    • 如果有多个node满足指定的标签,那就会在打分高的node上调度

    • 如果没有node满足指定的标签,那就会报错

示例:

Copy to Clipboard

10.3 将 Pod 调度到指定的 node节点(主机亲和性)

节点亲和通过 pod.spec 的 affinity 字段指定,有三种分别是

  • nodeAffinity

  • podAffinity

  • podAntiAffinity

注意

  • 两种类型(node 亲和性与 Pod 亲和性)的相同点在于后半部分: IgnoredDuringExecution。
  • 也就是说,如果某一个 Pod 所在的 Node 的 label 发生了变化,导致一些已经运行在该 Node 上的 Pod 不符合运行条件,那么这些 Pod 也不会受到影响。

10.3.1 nodeAffinity(node 亲和性)

指定 node 的亲和性,也就是对 node 进行匹配和计算,有两个node 亲和性策略:

  • requiredDuringSchedulingIgnoredDuringExecution : 硬策略

    • 指定了将 Pod 调度到一个节点上必须满足的规则

  • preferredDuringSchedulingIgnoredDuringExecution : 软策略

    • 指定调度器将尝试执行但不能保证的偏好

affinity.nodeAffinity 下路径以及说明:

  • requiredDuringSchedulingIgnoredDuringExecution : 硬策略

    • nodeSelectorTerms : 必填,node选择的具体策略,列表

      • matchExpressions : 通过标签进行匹配

      • matchFields : 通过 node 其他 filed 匹配

  • preferredDuringSchedulingIgnoredDuringExecution : 软策略

    • weight : 设置该条件的权重,1-100

    • preference :

      • matchExpressions : 通过标签进行匹配

      • matchFields : 通过node 其他 filed 匹配

matchExpressionsmatchFields 下的属性有:

  • key : label 或 field 的 key 名称,必填

  • operator : 匹配的方法,有一下几种情况:

    • In:label 的值在某个列表中

    • NotIn:label 的值不在某个列表中

    • Gt:label 的值大于某个值

    • Lt:label 的值小于某个值

    • Exists:某个 label 存在

    • DoesNotExist:某个 label 不存在

  • values : 列表,通过上面 operator 方法,匹配下面的值

示例:

  1. 创建一个 deployment ,并且有在 node 亲和性 nodeAffinity 上有硬策略和软策略

  2. 在 node-1 上 有标签 disktype=ssd

  3. 硬策略是:kubernetes.io/hostname 必须是 node-1 和 node-2

  4. 软策略是: 优先选择 disktype=ssd 标签的 node

  5. 结果应该是,优先在 node-1 上创建

Copy to Clipboard

创建 deployment,查看结果, 可以看到优先在 node-1 上创建

Copy to Clipboard

10.3.2 podAffinity 和 podAntiAffinity (Pod 亲和性)

Pod 的亲和性,也就是 基于 Pod 的 label 制定调度策略,而不是 Node 的 label。也就是 Pod 的调度,考虑其他 Pod 的label 和 field 来调度。

Pod 和 Pod 之间的亲和,例如将应用的前端和后端部署在一起,从而减少访问延迟。

用法与 nodeAffinity 相同

10.4 调度,警戒线 cordon

如果把某个节点设置了cordon(警戒线),则这个节点会被为不可调度,在创建新的 Pod 的时候,是不会在调度到这个 node 节点上的。

使用方法:

  • 将某个节点设置为 cordon:

    • kubectl cordon k8s-node-1

  • 将某个节点,取消 cordon:

    • kubectl uncordon k8s-node-1

设置完后,该节点就会变成不可调度状态,如下所示

Copy to Clipboard

将某个 node 节点设置了警戒线后,在调度 Pod 的时候,就会不在该节点上。但不会影响 已经在该节点上构建好的 Pod

10.5 调度,node 驱逐:drain

如果 node 需要升级或者排错,这时候就需要将该 node 上的所有 Pod 安全的驱逐到其他 node 上,这就是 drain 的作用,用于节点的维护。

如果一个节点被设置为 drain,则此节点不再被调度 Pod ,且此节点上已经运行的 Pod 会被驱逐(evicted)到其他节点

方法:

  • 将节点设为 drain

    • kubectl drain $NODENAME --ignore-daemonsets

    • 可以看到该节点上的 pod 都为 evicted

    • 选项 –ignore-daemonsets 表示Ignore DaemonSet-managed pods.

Copy to Clipboard
  • 将节点取消 不可调度状态,使用 uncordon

    • kubectl uncordon k8s-node-1

10.6 调度: node 的污点 taint 及 Pod 的容忍性 tolerations

1. 问题: kubeadm 安装的 kubernetes 集群中,master 节点为什么不能调度 Pod ?

  • 回答:master 节点,被打上了污点 taint,为不可调度,因此 Pod 不往 master 节点上调度。而 worker 节点是没有污点的,因此可以调度 Pod 。

Copy to Clipboard

2. node 添加污点的方法:

  • kubectl taint node keyName=valueName:NoSchedule

  • 一般 key=value:NoSchedule 后加上 NoSchedule 表示该节点有污点不可调度

  • node 节点加上污点后,如果 Pod 不设置能够容忍 tolerations ,那么 Pod 不会往该 node 上调度。

Copy to Clipboard

3. 将 Pod 添加容忍性 tolerations

  • Pod 的容忍性 tolerations ,表示 Pod 可以容忍调度在有指定污点(taint)的 node 节点上

  • 在 Pod 的 yaml 文件中,添加 tolerations 的属性,位置为:pod.spec.tolerations

  • tolerations 下的定义方法,类似 matchExpressions 的定义方法,也是通过,key、operator、value、effect

  • effect 就表示 定义 taint 时,keyName:valueName:NoSchedule value 冒号后面的值

Copy to Clipboard

4. 删除节点的污点

  • kubectl taint node <nodeName> keyNmae-

  • 取消的方法,类似取消 label 的方法,在 key 的后面加 减号 –

Copy to Clipboard