万字警告 - k8s入门,理应Pod先行!

你们好,欢迎来到小菜我的 solo 学堂。在这里,知识免费,不吝吸取!关注免费,不吝动手!
死鬼~看完记得给我来个三连哦!node

本文主要介绍 kubernetes中pod的使用nginx

若有须要,能够参考程序员

若有帮助,不忘 点赞算法

微信公众号已开启,小菜良记,没关注的同窗们记得关注哦!docker

上篇文章咱们说到如何搭建 k8s 集群,不知道看完的小伙伴有没有本身去尝试一下呢!shell

不要让贫穷扼杀了你学 k8s 的兴趣数据库

这篇咱们本着有始有终的原则,继续带你搞明白 k8s 中的pod ,成为别人家的程序员~centos

咱们老样子,先回顾下 k8s 中存在的几种组件:api

那咱们还得了解一下 k8s 中几种常见的资源:bash

  • Master: 集群控制节点,每一个集群都至少须要一个 master 节点负责集群的管控
  • Node: 工做负载节点,由 master 分配容器到这些 node 节点上,而后 node 节点上的docker 负责容器的运行
  • Pod: kubernetes的最小控制单元,容器都是运行在 pod 中的,一个pod中能够有 1 个或多个容器
  • Controller: 控制器,经过它来实现对 pod 的管理,好比启动 pod,中止 pod,伸缩 pod 的数量等等
  • Service: pod 对外服务的统一入口,能够维护同一类的多个 pod
  • Label: 标签,用于对 pod 进行分类,同一类的 pod 会拥有相同的标签
  • NameSpace: 命名空间,用来隔离 pod 的运行环境

这几个概念先初步有个了解便可,接下来即是对每一个概念展开说明的时候~那么,正片开始!

Kubernetes

1、资源管理

在 kubernetes 中,全部的内容都抽象为资源,用户须要经过操做资源来管理 kubernetes

关于对 资源管理 的理解,咱们须要了解如下几个概念:

  • kubernetes 本质上是一个集群系统,用户能够在集群中部署各类服务
  • kubernetes 最小管理单元是 pod 而不是容器,因此咱们须要将容器放在 pod 中运行,而 pod 通常是由 pod控制器 进行管理的
  • pod 提供服务后,咱们须要借助 service 这个资源来实现访问 pod 中的服务
  • pod 也支持数据的持久化

而后咱们经过下面图例梳理一下上面几个概念:

经过上面那张图咱们差很少就能够将 kubernetes 中的重点资源理解一遍了,大概明白每一个资源在集群中起到的做用。

咱们有三种方式能够对资源对象进行管理:

  • 命令式对象管理

直接使用命令来操做 kubernetes 资源。例如:

kubectl run nginx --image=nginx:1.19.0 -port=80
  • 命令式对象配置

经过命令配置和配置文件来操做 kubernetes 资源。例如:

kubectl create/patch -f nginx.yml
  • 声明式对象配置

经过 apply 命令和配置文件来操做 kubernetes 资源。例如:

kubectl apply -f nginx.yml

在 k8s 中咱们通常使用 YAML 格式的文件来建立符合咱们预期指望的 pod,这样的 YAML 文件称为资源清单。咱们也比较鼓励使用清单的方式来建立资源。

若是咱们使用 命令式对象管理,这种方式虽然比较简单,能够直接建立一个 pod 出来,可是只能操做活动对象,没法进行审计和跟踪。

命令式对象配置声明式对象配置 在咱们平常中在建立资源服务中是比较常常用到。

1)命令式对象管理

kubectl 这个是 kubernetes 集群的命令行工具,经过 kubectl 可以对集群自己进行管理,并可以在集群上进行容器化应用的安装部署。能够想象咱们接下来的操做绝大部分都须要借助这个命令工具的帮助。

咱们以前也已经使用过一次了:kubectl get nodes 。这个命令即是用来获取集群中各个节点状态的,那么不难想象,这个命令的语法:

kubectl [command] [TYPE] [NAME] [flags]
  • command:指定对资源执行的操做、例如:create、get、describe、delete...
  • TYPE: 指定资源类型。资源类型是大小写敏感的,开发者能以单数、复数和缩写的形式,例如:pod、pods、po
  • NAME: 指定资源的名称。名称也是大小写敏感的,若是省略名称,则会显示全部的资源,例如 :kubectl get pods
  • flags: 指定可选的参数。例如:-s 、-server、-o ...

k8s 支持的 command 有不少,咱们能够跟 docker 同样使用 kubectl --help 来获取帮助文档:

文档不少,固然有些是经常使用的,有些是不经常使用的,小菜在这里给大家简单分个类,下次有须要能够直接查看分类中的结果!

命令分类

一、 基础命令

名称 描述
create 经过文件名或标准输入建立资源
expose 将一个资源公开为一个新的 Service
run 在集群中运行一个特定的镜像
set 在对象上设置特定的功能
get 显示一个或多个资源
edit 使用默认的编辑器编辑一个资源
delete 经过文件名、标准输入、资源名称或标签
explain 获取文档参考资料

二、部署命令

名称 描述
rollout 管理资源的发布
rolling-update 对给定的控制器进行滚动更新
scale 扩容或缩容 pod 数量,可对 Deployment、ReplicaSet、RC或Job 操做
autoscale 建立一个自动选择扩容或缩容并设置 pod 数量

三、 集群管理命令

名称 描述
certificate 修改证书资源
cluster-info 显示集群信息
top 显示资源使用状况,须要运行 Heapster
cordon 标记节点不可调度
uncordon 标记节点可调度
drain 驱逐节点上的应用,准备下线维护
taint 修改节点的 taint 标记

四、故障\调试命令

名称 描述
describe 显示特定资源或资源组的详细信息
logs 在一个 pod 中打印容器日志,若是 pod 中只有多个容器,容器名称是可选的
attach 附加到一个运行的容器
exec 执行一个命令到容器中
port-forward 转发一个或多个本地端口到一个 pod
proxy 运行一个 proxy 到 kubernetes ApiServer
cp 拷贝文件或目录到容器中
auth 检查受权

六、高级命令

名称 描述
apply 经过文件名或标准输入对资源应用配置
patch 使用补丁修改、更新资源的字段
replace 经过文件名或标准输入替换一个资源
convert 不一样的API 版本之间转换配置文件

七、设置命令

名称 描述
label 更新资源上的标签
annotate 更新资源上的标签
completion 用于实现 kubectl 工具自动补全

八、其余命令

名称 描述
api-versions 打印受支持的 API 版本
config 修改 kubeconfig 文件(用于访问 API,好比配置认证信息)
help 获取全部命令帮助
plugin 运行一个命令行插件
version 打印客户端和服务版本信息

咱们经过一些简单的例子来简单的认识一下这个命令工具:

2)资源清单

无论是 命令式对象配置 仍是 声明式对象配置 咱们都须要借助 yaml 资源清单建立。

咱们先来看看一个 pod controller(控制器) 的yaml 文件中有哪些内容:

上面即是一个完整的 deployment 资源配置清单。内容不少,老样子咱们先混个眼熟,不是每一个 deployment 都须要这么多的配置,如下即是必须存在的字段属性介绍:

名称 类型 描述
version String 属于 k8s 哪个API 版本或组
kind String 资源类型,如pod、deployment、service
metadata Object 元数据对象,嵌套字段
metadata.name String 元数据对象的名字
spec Object 定义容器的规范,建立的容器应该有哪些特性
spec.container[] List 定义容器的列表
spec.container[].name String 容器的名称
spec.container[].image String 定义要用到镜像的名称

3)命令式对象配置

咱们结合以上必存的字段,能够简单写出一个 yaml (test.yaml) 文件:

而后咱们能够经过 命令式对象配置 的方式建立出一个 pod:

kubectl create -f test.yaml

4)声明式对象配置

声明式对象配置命令式对象配置 很类似,可是这种方式都是基于 apply 这一个命令来进行操做的。

咱们这边复用一下上面建立的 test.yaml 文件

kubectl apply -f test.yaml

这种方式不能说是鸡肋,它有它的特色,好比说咱们执行完上述命令后再执行一遍:

kubectl apply -f tset.yaml

能够发现是没什么改动的,可是若是咱们使用的是 create 来重复执行两遍呢?结果是报错

那么咱们不难猜出 apply 这个命令就是对 createpatch 这两个命令的结合:

  • 若是资源不存在,则执行建立 等同于 create
  • 若是资源存在,则执行更新 等同于 patch

2、实战入门

接下来的阶段即是咱们针对 k8sNameSpace 和 Pod 资源展开说明了,小伙伴们打起精神了哦!

image-20210414125544325

1)Namespace

Namespace(命名空间) 的做用即是用来实现多用户之间的资源那个李的,经过将集群内部的资源对象分配到不一样的 Namespace 中,造成逻辑上的分组,便于不一样分组在共享使用整个集群资源的同时被分别管理。默认状况下,kubernetes 集群中的全部 pod 都是能够互相访问的,可是有些时候咱们不想出现这种状况,那就能够借助于 namespace

在集群内部有个默认的Namespace - default ,咱们建立资源的时候若是不指定 namespace,那么就会将该资源分配到该 default 的命名空间之下。

[root@master test]# kubectl get namespace

建立 Namespace 的方式也很简单,经过如下指令即可建立:

[root@master test]# kubectl create namespace aaa-test

这样子,咱们就得到了一个名称为 aaa-test 的命名空间。或者咱们也能够经过 命令式对象配置 的方式建立,先准备一个 yaml 文件:

apiVersion: v1
kind: Namespace # yaml文件中大小写敏感
metadata:
  name:aaa-test  #命名空间的名称

而后执行kubectl create -f namespace.yml, 这样子咱们一样也能够得到一个名称为 aaa-test 的命名空间。

而后咱们就能够在资源建立的时候使用了:

而后执行 kubectl create -f nginx.yml,这样子咱们就能够获取到一个 pod 资源,只有经过指定命名空间才能查看到咱们的pod资源,这说明对其余用户是隔离的:

若是咱们想删除命名空间的话,可使用指令:kubectl delete -f namespace.ymlkubectl delete ns ns名称

注: 若是将命名空间删除,那么存在于该命名空间下的资源会所有被删除

2)Pod

Pod 是 k8s 中能够建立和管理的最小单元,是资源对象模型中由用户穿件或部署的最小资源对象模型,也是在 k8s 上运行容器化应用的资源对象。

在使用 docker 的时候,咱们清楚程序要运行就必须部署在容器中,而在 k8s 中,咱们容器必须存在与 pod 中,pod 就能够认为是容器的封装,一个 pod 能够存在一个或多个容器。

㈠ Pod 概念
① pod 特性

1. 资源共享

在一个pod 中,多个容器之间能够共享存储和网络,至关于一个逻辑意义上的主机。

2. 生命周期短暂

pod 是一个具备生命周期的组件,若是 pod 所在的节点发生故障,那么该节点上的pod 都会被调度到其余节点上,而调度后的pod是一个全新的 pod,与以前没有任何关系。

3. 平坦的网络

k8s 集群中的全部 pod 都在同一个网络地址空间中,也就是说每一个 pod 均可以经过其余 pod 的IP地址来实现访问

② pod 分类
  • 普通 pod

这种就是咱们平常中常常用到的。一旦被建立就会放入 etcd 中存储,接着就会被调度到任一节点上运行,当 Pod 里某个容器中止时,Kubernetes 会自动检测到这个问题而且从新启动这个 Pod 里某全部容器, 若是 Pod 所在的 Node 宕机,则会将这个 Node 上的全部 Pod 从新调度到其它节点上。

  • 静态 pod

静态pod是由 kubelet 激进型管理的仅存在于特定 node 节点上的,它们不能经过 API server 进行管理,没法与 controller 控制器 进行管理,而且 kubelet 也没法对其进行健康检测。

③ pod 声明周期

pod中有 5 中生命周期,咱们都须要了解一下~

状态名称 描述
Pending API Server已经建立了 pod,但 pod 中的一个或多个容器的镜像尚未建立,包括镜像下载过程
Running Pod 内全部容器都已建立,且至少一个容器处于运行状态,正在启动状态或正在重启状态
Completed Pod 内全部容器均成功执行退出,且不会再重启
Failed Pod 内全部容器都已退出,但至少一个容器退出失败
Unknown 因为某种缘由没法获取 Pod 状态,例如网络不通
④ pod重启策略
策略名称 描述
Always 当容器失效时,有 kubelet 自动重启该容器
OnFailure 当容器中止运行且退出码不为0时,由 kubelet 自动重启该容器
Never 不论容器运行状态如何,kubelet 都不会重启该容器
⑤ pod 资源配置

以前在 docker 咱们有进行测试没有对 docker 资源进行限额的时候,运行一个 elasticSearch 镜像的时候服务器直接卡死。那么在 docker 能作到资源限额,k8s 中天然也能够。

Kubernetes 中能够设置限额的计算资源有 CPUMemory 两种。Kubernetes 咱们想要进行配额限定须要设定两个参数:RequestLimits

  • Request:表示该资源最小的申请量,系统必须知足要求
  • Limits:表示该资源最大容许使用量,不能超出这个量,当容器试图使用超过这个量的资源时,就会被 Kubernetes kill 掉并重启

上面表示一个 nginx 容器最少须要 0.25个CPU和 64 MB内存,最多只能使用 0.5个CPU和 128 MB内存。

㈡ pod 基操

如下是一份 pod 的完整资源清单:

这份清单大部分看起来会比较陌生,可是有部分关键属性咱们在上面已经讲过了,当咱们实际要用的时候若是记不起那么多咱们可使用指令 kubectl explain pod.xxx 的方式来查看每一个属性的含义,例如

① 简单建立

咱们若是想要建立一个 pod ,只须要简单准备一份 test.yml 文件便可:

而后经过 命令式对象配置 的指令 kubectl create -f test.yml 就能够获取到一个含有 nginx 和 centos 容器的pod。而后咱们经过指令kubectl get pod -n cbuc-test 查看当前 pod 的状态。

docker 能够用 docker exec -it 进入容器,k8s 也是相似此命令:

kubectl exec -it pod名称 -c 容器名称 -n 命名空间 bash

经过以上命令就能够进入到咱们的pod中

若是 pod 中只有一个容器,-c 能够不用指定容器名称

② 属性说明

上面咱们已经成功的建立了一个 pod,可是这只是一个简单的 pod 配置,咱们能够针对该 yaml 文件进行扩展~

1. imagePullPolicy

这个属性用来设置镜像拉取策略,在 k8s 中支持三种镜像拉取策略:

  • Always: 老是从远程仓库拉取镜像
  • IfNotPresent: 本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
  • Never: 只使用本地镜像,从不去远程仓库拉取,本地若是不存在就会报错

注意:

若是镜像号为指定版本号,则默认策略为 :IfNotPresent

若是镜像号为 latest ,则默认策略为: Always

2. command

command 是用于在 pod 中的容器初始化完毕以后运行一个命令。

咱们在上面建立了一个 centos的pod,而后在pod初始化完成后,便会执行 command 中的命令,咱们能够经过 kubectl exec -it pod名称 -n 命名空间 bash 而后进入pod中查看 /mnt/test.txt

或者咱们能够在pod外部执行命令:

kubectl exec pod名称 -n 命名空间 -c 容器名称 -- shell命令

3. args

咱们上面说到的 command 已经能够完成启动命令和传递参数的功能,可是咱们 k8s 中还提供了一个 args 选项,用于传递参数。k8s 中使用 command 和 args 两个参数能够实现覆盖 Dockerfile 中的 ENTRYPOINE 的功能。

注意:

  1. 若是 command 和 args 均没有写,那么是使用 Dockerfile 的配置
  2. 若是 command 写了,args 没有写,那么 Dockerfile 默认的配置会被忽略,执行输入的 command
  3. 若是 command 没写,args 写了, 那么 Dockerfile 中配置的 ENTRYPOINT 的命令会被执行,使用当前 args 的参数
  4. 若是 command 和 arg 都写了,那么 Dockerfile 的配置就会被忽略,执行 command 命令加上 args 参数

4. env

用于在 pod 中的容器设置环境变量

进入pod查看:

5. ports

ports 在 k8s 的属性类型是 Object,咱们能够经过 kubectl explain pod.spec.containers.ports 查看该对象下的属性:

咱们从图中能够发现该对象由5个属性:

  • containerPort: 容器要监听的端口(0~65536)
  • hostIP: 要将外部端口绑定到主机IP(通常省略)
  • hostPort: 容器要在主机上公开的端口,若是设置,主机上只能运行容器的一个副本(通常省略)
  • name: 端口名称,若是指定,必须保证name 在pod中是惟一的
  • protocol: 端口协议,必须是 UDP、TCP或 SCTP,默认为 TCP

咱们简单看个 nginx 的例子:

建立方式能够选择 3 中建立方式任意一种,而后建立完成后咱们能够经过 podIp+containerPort 来访问到 nginx 资源

6. resources

容器中运行的程序须要占用必定的资源(CPU和内存),在运行的时候若是不对某个容器的资源进行限制,那么它可能会耗尽服务器的大量资源,防止这种状况的发生,k8s 中提供了 resource 属性,对资源进行限制。这个属性下有两个子选项:

  • limits: 用于限制运行容器的最大占用资源,当容器占用资源超过 limit 时会被终止,并进行重启
  • requests: 用于设置容器须要的最小资源,若是环境资源不够,容器将会没法启动

看个使用例子:

  • cpu: core数,能够为整数或小数
  • memory: 内存大小,可使用 Gi, Mi, G,M 等形式
㈢ pod 扩展
① 生命周期

任何事物的建立过程都有属于它本身的生命周期,而 pod 对象从建立到销毁,这段的时间范围便称为 pod 的生命周期。生命周期通常包含下面几个过程:

运行初始化容器 (init container) 过程

运行主容器 (main container)

2.1 容器启动后钩子(post start),容器终止前钩子(pre stop)

2.2 容器存活性检测(liveness probe),就绪性检测(readiness probe)

pod 终止过程

在整个生命周期中,pod 也会相应的出现 5 中状态,以下:

  • 挂起(Pending): apiServer 已经建立 pod 资源对象,但它还没有被调度完成或者仍处于下载镜像的过程当中
  • 运行中(Running): pod 已经被调度至某节点,而且所用容器都已经被 kubelet 建立完成
  • 成功(Succeeded): pod 中的全部容器都已经成功终止而且不会被重启
  • 失败(Failed): 全部容器都已经终止,但至少有一个容器终止失败,即容器返回了非 0 值的退出状态
  • 未知(UnKnown): apiServer 没法获取到 pod 对象的状态信息,一般是由于网络通讯失败致使的

    ⑴ pod 的建立过程

kubernetes 启动后,不管是 master 节点 亦或者 node 节点,都会将自身的信息存储到 etcd 数据库中

  1. 用户经过 kubectl 或其余 api 客户端提交须要建立的 pod 信息给 apiServer
  2. apiServer 接收到信息后会生成 pod 对象信息,并存入 etcd 数据库中,返回确认消息给客户端
  3. apiServer 开始反映 etcd 中 pod 对象的变化,其余组件会使用 watch 机制来跟踪检查 apiServer 上的变更
  4. scheduler 发现若是有新的 pod 对象须要建立,便会为 pod 分配主机并将结果回送至 apiServer
  5. node 节点上的 kubectl 发现有 pod 调度过来,会尝试调用 docker 启动容器,并将结果返回给 apiServer
  6. apiServer 将接收到的 pod 状态信息存入 etcd

⑵ pod 的终止过程

  1. 用户首先向 apiServer 发送删除 pod 对象的命令
  2. apiServer 中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod 会被视为 dead 状态,并将 pod 标记为 terminating 状态
  3. kubelet 在监控到 pod 对象转为 terminating 状态的同时启动 pod 关闭过程
  4. 端点控制器监控到 pod 对象的关闭行为时将其从全部匹配到此端点的 service 资源的端点列表中移除
  5. 若是当前 pod 对象定义了 preStop 钩子处理器,则在其标记为 terminating 后即会以同步的方式启动执行
  6. pod 对象中的容器进程接收到中止信号,并中止容器
  7. 宽限期结束后,若是 pod 中还存在仍在运行的进程,那么 pod 对象就会收到当即终止的信号
  8. kubelet 请求 apiServer 将此 pod 资源的宽限期设置为 0 从而完成删除操做。

⑶ 初始化容器

初始化容器,看名字也大体可以猜到初始化容器是在 pod 主容器启动以前要运行的容器,主要是作一些主容器的前置工做。

特征:

  • 初始化容器必须运行完成直至结束,若是运行失败便会进行重启直至成功
  • 初始化容器必须按照顺序执行,只有前一个成功后,后一个才能执行

这里简单看一个使用例子:

咱们在初始化容器中定义了一个 centos 容器,只有 ping 通对应的地址才会启动成功,已知当前网络能通 192.168.108.101

能够看到,在初始化容器成功启动的状况下,咱们的 nginx 容器也能运行成功,可是若是咱们把 ping 的地址改一下,就会致使初始化容器启动失败,那么正常容器也是会启动失败的:

⑷ 钩子函数

不知道你对钩子函数这个词是否有一些了解~ 钩子函数可以感知自身生命周期中的事件,在相应的时刻到来时就会运行用户指定的程序代码。

k8s 提供了两个钩子函数,分别是启动以后中止以前

  • post start:容器建立以后执行。若是失败了会重启容器
  • pre stop: 容器终止以前执行。执行完成以后容器将成功终止,在其完成以前会阻塞删除容器的操做

那么钩子函数有了,咱们该如何定义这个函数呢?在 k8s 中钩子函数支持使用三种方式定义动做:

  • exec 命令

在容器中执行一次命令,若是命令执行的退出码为0,则认为程序正常,不然反之。

  • tcpSocket

将会尝试访问一个用户容器的端口,若是可以创建这条链接,则认为程序正常,不然不正常

  • httpGet

调用容器内Web应用的URL,若是返回的状态码在200和399之间,则认为程序正常,不然不正常

② 容器探测

容器探测是用来检测容器中的应用实例是否正常工做,是保障业务可用性的一种传统机制。若是通过探测,实例的状态不符合预期结果,那么 k8s 就会把这个实例删除。在 k8s 中也支持了两种探针来实现容器探测:

  • liveness probes: 存活性探针,用于检测应用实例当前是否处于正常运行状态,若是不是,k8s 会重启容器
  • readiness probe: 就绪性探针,用于检测应用实例当前是否能够接受请求,若是不能,k8s不会转发流量

注意:

livenessProbe 决定了容器是否须要重启

readinessProbe 决定了是否将请求转发给容器

这两种探针支持的检测方式与上面生命周期检测的方式同样:

  • exec 命令

  • TCPSocket

  • httpGet

③ 重启策略

容器探测 检测出容器有问题后, k8s 就会对容器所在的 pod 进行重启,而这些重启的定义即是由 pod 自身的重启策略决定的,pod 的重启策略有以下3种:

  • Always: 容器失效时,自动重启该容器(默认值)
  • OnFailure: 容器终止运行且退出码不为0时重启
  • Never: 不论状态为什么,都不重启该容器

首次须要重启的容器会当即进行重启,若是随后还须要重启,那么kubectl 便会延迟一段时间后才进行,反复重启的操做延迟时长为 10s,20s,30s,40s,80s,160s和300s,其中300s是最大的延迟时长

㈣ pod 调度

上面说到过默认状况下,pod 在哪一个 Node 节点上运行是由 Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。可是在实际的使用场景中咱们有时候想要控制某些pod到达某些节点上,而针对于这种需求,k8s 固然也是能够知足的~ 在 k8s 中它提供了 4 中调度方式:

  • 自动调度:scheduler 组件计算运行在哪一个node节点上
  • 定向调度: 由用户自定义,须要用到 NodeNameNodeSelector 属性
  • 亲和性调度: 由用户自定义,须要用到 NodeAffinity、PodAffinity、PodAntiAffinity 属性
  • 污点容忍调度: 由用户自定义,须要用到 Taints、Toleration属性
① 定向调度

咱们能够利用 nodeName 或者 nodeSelector 来标记 pod 须要调度到指望的 node 节点上。这里的标记是强制性,无论 node 节点有没有宕机,都会往这个节点上面调度,所以若是node节点宕机的话,就会致使 pod 运行失败。

  • NodeName

这个属性用于强制约束将 Pod 调度到指定名称的 node节点上,这种方式,其实就是直接跳过 scheduler 的调度逻辑。

上面已经准备了一个 pod 的yaml文件,咱们建立看下是否可以调度到咱们想要的节点上

能够看到 pod 节点已经成功的调度到名称为 node02 的节点上了

  • NodeSelector

这个属性是用于将 pod 调度到添加了指定标签上的 node 节点上(k8s 中资源能够打标签,咱们同样能够对 node 节点打标签)。它是经过 k8s 的 label-selector 机制实现的,就是说在 pod 建立以前,会由 scheduler 的使用 MatchNodeSelector 的调度策略进行 label 匹配,找出目标 node,而后将 pod 调度到目标节点,该匹配规则也是属于强制约束。

测试:

首先对 node 节点打上标签:

kubectl label nodes node02 app=node-dev

查看是否打成功:

而后准备一份 pod yaml文件:

而后咱们建立后查看:

② 亲和度调度

上面介绍的定向调度是属于强制性约束,若是没有知足的node节点供运行的话,pod 就是启动失败,这样子就很大地限制了它的使用场景。因此咱们接下来介绍的 亲和度调度 (Affinity) 即是用来解决这种问题的。

它是经过配置的形式,实现优先选择知足条件的 Node 进行调度,若是有就调度到对应节点,若是没有,也能够调度到不知足条件的节点上,这样可使调度更加灵活

Affinity分为三大类:

  • nodeAffinity(node亲和性)

node为目标,解决 pod 能够调度到哪些 node 的问题

这个属性中又存在 requiredDuringSchedulingIgnoredDuringExecution (硬限制)preferredDuringSchedulingIgnoredDuringExecution (软限制) 两种

Ⅰ、requiredDuringSchedulingIgnoredDuringExecution (硬限制)

这个限制和上面说到的定向调度有点像,只选择知足条件的 node 节点进行调度,使用例子以下:

上面咱们建立了一个 pod,会在标签 keyapp,且valuenode-pro 或 node-test 的节点上选择,可是并不存在具有这个标签的节点,所以这个pod 一直处于挂起的状态~

咱们上面看到了一个新的属性 matchExpressions,这个是用来编写关系表达式的,具体使用方法以下:

- matchExpressions:
  - key: app # 匹配存在标签的key为 app 的节点
    operator: Exists
  - key: app # 匹配标签的key为 app ,且value是"xxx"或"yyy"的节点
    operator: In
    values: ["xxx","yyy"]
  - key: app # 匹配标签的key为 app, 且value大于"xxx"的节点
    operator: Gt
    values: "xxx"

Ⅱ、 preferredDuringSchedulingIgnoredDuringExecution (软限制)

上面已经了解到了 硬限制 的使用,软限制 的使用以下,咱们直接来看 yaml 文件:

这边能够看到虽然不存在知足条件的node,可是也是能够成功运行pod 的,只是调度到了不知足条件的 node 上!

咱们来总结一下硬限制和软限制的用法:

  • podAffinity(pod 亲和性)

以 pod 为目标,解决pod能够和哪些已存在的pod部署在同一个拓扑域中的问题。

podAffinity 一样也存在 硬限制 和 软限制 ,咱们接下来直接看下如何配置:

image-20210423130432962

上面即是 podAffinity 硬限制的yaml文件,除了眼熟的属性以外,咱们还看到了一个新的属性 topologyKey,那么这个属性是用来干吗的呢?

topologyKey 用于指定调度时做用域:

  • 若是值为 kubernetes.io/hostname ,说明是以 node 节点为区分范围
  • 若是值为 kubernetes.io/os, 则以 node 节点的操做系统来区分

了解完硬限制的编写,软限制也是与上面 node亲和度的用法类似,这里再也不赘诉~

  • podAntiAffinity(pod反亲和性)

以pod 为目标,解决pod不能和哪些已存在的pod部署在同一个拓扑域中的问题。

这个使用就是和上面基本一致了,就是和 podAffinity 要求反着来就是了,属性名换个就完事了~

这个yaml文件表明的含义即是选择不和标签带有 app=test01app=test02 的pod "共处一室"。一样存在硬限制和软限制的配置

亲和性反亲和性 的使用场景

亲和性: 若是两个应用交互频繁,那就有必要利用亲和性让两个应用尽量的靠近,能够减小由于网络通讯而带来的性能损耗

反亲和性: 当应用采用多副本部署的时候,有必要采用反亲和性让各个应用实例打散分布在各个 node 上,这样能够提升服务的高可用性

③ 污点(Taint)

咱们先来看下目前 pod 存在于每一个节点的状况,

是否发现了一个问题,那就是 pod 基本都分布在了 node 节点上,而 master 节点却没有运行任何pod。而这个缘由即是和咱们要讲到的污点 有关系了!

咱们前面说到的调度都是站在 pod 的角度,让 pod 选择 node 进行运行,而污点很好的进行了反转。让node节点决定让哪些pod能够调度过来!

Node 能够设置 污点 ,设置上 污点 以后,就会和 pod 之间造成了一种排斥关系。这种关系存在的意义即是能够拒绝 pod 调度进来,也能够将已经存在的 pod 驱逐出去。

污点格式: key=value:effect

keyvalue 是污点的标签,而 effect 则是用来描述污点的做用,支持三种功能定义:

  • PreferNoSchedule

    k8s将尽可能避免把 Pod 调度到具备该污点的 node 节点上,除非没有其余节点能够调度。(尽可能不要来,除非没办法)

  • NoScheduler

    k8s 将不会把 Pod 调度到具备该污点的 node 节点上,但不会影响当前 Node 上已经存在的 pod。(新的不要来,在这的就别动了)

  • NoExecute

    k8s 将不会把 Pod 调度到具备该污点的 node 节点上,同时也会将 Node 上已经存在的 Pod 驱逐。(新的不要来,在这的赶忙走)

设置污点命令以下:

# 设置污点
kubectl taint nodes node01 key=value:effect

# 去除污点
kubectl taint nodes node01 key:effect-

# 去除全部污点
kubectl taint nodes node01 key-

而 k8s中的 master节点之因此没有运行任何pod,那即是由于 master 节点上已经存在了污点:

④ 容忍(Toleration)

上面说到若是 node 节点存在污点,那么pod就会没法调度。那若是 pod 有时候就是想 "厚着脸皮",哪怕你存在污点,也不嫌弃的想要调度进去有没有办法解决呢?

k8s 也是想到了这种状况的存在,所以便有了一个 容忍 的属性!

污点就是拒绝,容忍就是忽略,Node 经过污点来拒绝 pod 调度上去,pod 经过容忍忽略拒绝

咱们先给 node01 打上 NoExecute 的污点,而后咱们再给 pod 添加容忍,看下是否可以成功调度上去

pod yaml:

经过添加容忍后,咱们能够发现pod 在 node01 的节点上成功运行了,说明容忍成功~

容忍的配置信息以下:

tolerations:
- key         # 对应着要容忍的污点的键,空意味着匹配全部的键
  value        # 对应着要容忍的污点值
  operator    # key-value 的运算符,支持 Equal 和 Exists(默认)
  effect    # 对应污点的effect,空意味着匹配全部的影响
  tolerationSeconds  # 容忍时间,当 effect 为NoExecute 时生效,表示 pod 在Node上的停留时间

END

关于 k8s 中 pod 的介绍到这里就结束啦~我的以为仍是挺详细的,若是可以认真看下来,相信对 pod 已经有足够了解了。可是你认为 k8s 到这里就结束了吗?那确定不会的,碍于篇幅,因此其余资源组件留到下一节介绍~请动动小手,点点关注不迷路。路漫漫,小菜与你一同求索!

今天的你多努力一点,明天的你就能少说一句求人的话!

我是小菜,一个和你一块儿学习的男人。 💋

微信公众号已开启,小菜良记,没关注的同窗们记得关注哦!

相关文章
相关标签/搜索