我正在参加「掘金·启航计划」
📣 大家好,我是Zhan,一名个人练习时长一年半的大二后台练习生🏀
📣 这篇文章是 Kubernetes 第三篇笔记📙
📣 如果有不对的地方,欢迎各位指正🙏🏼
📣 与君同舟渡,达岸各自归🌊
🔔 引语
在上篇文章 【云原生 • Kubernetes】(二) Kubernetes 的组件与架构 - 掘金 (juejin.cn) 中,我们介绍了 Kubernetes 的 控制平面组件、Node 结点、插件,也知道了 Pod 是 Kubernetes 的最小调度单元,而我们使用 Container 正是运行在 Pod 中,在本文 Kubernetes 终于和我们之前所了解的 Docker 这类 Container 联系起来了,关于 Pod 我们将在本文详细去了解:
- 什么是 Pod
- Pod 基本操作
- Pod 的 Labels
- Pod 的 生命周期
- Container 特性
- Pod 的资源限制
- Pod 中 Init 容器
- 结点亲和性分配 Pod
1 什么是 Pod
1.1 简介
Pod 是 Kubernetes 中可以创建、管理的最小的可以部署的计量单元。Pod 翻译为 豌豆荚,类似于豌豆荚中有很多的豌豆,Pod 管理一组(一个 | 多个)容器,这些容器共用存储、网络、以及怎么运行这组容器的声明。Pod 中的内容总是并置的,并且一并调度,在共享的上下文中运行。
1.2 Pod 怎样管理多个容器?
Pod 中的容器被自动安排到集群中的一台物理机或者虚拟机上,一同被调度。容器之间可以共享资源和负载、彼此通信、协调何时以何种方式终止自身
例如:你可能有一个 Pod,有两个 容器 共享存储,也就是共享卷:
- 其中一个容器为共享卷提供 Web 服务支持,也就是读(下图中的
WebServer); - 另一个容器负责从远端更新这些文件(下图中的
FilePuller拉取数据卷的数据) - 也就是一个
Pod中是可以运行多个协同工作的容器的
1.3 如何使用 Pod?
Pod 是 Kubernetes 中最小的一个调度单元,我们通常不直接创建 Pod ,而是通过诸如
Deployment或者Job这类的控制器来创建Pod,不过在下面的学习中,我们会直接创建 Pod 去演示 Pod 的基本操作,如果需要跟踪 Pod 的状态,可以考虑StatefulSet资源。因为,如果直接使用 Pod 其实只是对 Container 做了一个共享资源和网络,而做不到其他的事情,也就是说 Pod 是把 Container 做了一层包装,实现了容器之间的共享资源和网络
Kubernetes 集群中的 Pod 主要有两种用法:
- 运行单个容器的 Pod,在这种情况下,可以把 Pod 看做单个容器的包装器,而且 Kubernetes 直接管理 Pod,而不是容器
- 运行多个协同工作的容器的 Pod。Pod 可以封装多个紧密耦合并且需要共享资源的共处容器,把这些容器和存储打包成为一个可以管理的实体,其实就是上面那幅图。
说明:
- 将多个并置、同管的容器组织到一个 Pod 中是一种相对高级的使用场景,也就是上述的运行多个协同工作的容器
- 一个 Pod 可以看做一个应用程序的单实例,如果想跑多个实例,就需要跑多个 Pod,当然,跑多个 Pod 通常是通过控制器来做
2 Pod 基本操作
2.1 查看 Pod
# 查看指定命名空间的 Pod
kubectl get po|pod|pods -n 命名空间
# 查看所有的 Pod
kubectl get po|pod|pods -A
# 查看 Pod 的输出情况(具体情况)
kubectl get po|pod|pods -o wide
# 监视 Pod 的变化
kubectl get po|pod|pods -w
# 查看默认的命名空间的 Pod
kubectl get po|pod|pods
# 查看指定 Pod 的相信信息
kubectl describe pod pod名称
2.2 创建 Pod
Pod 可以直接通过命令进行创建:
pod: kubectl run nginx(Pod 名称) --image=nginx:1.19这种创建方式的缺点也很明显,这个命令执行了一次之后就使用不了了,而我们可以把它当做一个模版记录下来,也就是下面提供的通过配置文件的方式进行创建:
# nginx-pod.yml
apiVersion: v1
kind: Pod
metaData:
name: nginx
spec:
containers:
- name: nginx
- image: nginx:1.19
- ports:
- containerPord: 80
然后通过下面的两个命令其中一个进行创建
kubectl create -f nginx-pod.yml
kubectl apply -f nginx-pod.yml
注意:
- create 仅仅是不存在时创建,如果已经存在则会报错!
- apply 不存在则创建,存在则更新配置,推荐使用 apply
2.3 删除 pod
# 根据 Pod 的名称进行删除
kubectl delete pod pod名称
# 根据 配置文件 进行删除,因为配置文件中也有 Pod 的名称
kubectl delete -f pod.yml
2.4 进入 Pod 中容器
# 默认进入 Pod 中的第一个容器
kubectl exec -it nginx(Pod名称) --(固定写死) bash(执行命令)
# 指定进入 Pod 的某个容器
kubectl exec -it nginx(Pod名称) -c 容器名称 --(固定写死) bash(执行命令)
2.5 查看 Pod 日志
# 查看 Pod 中所有容器的日志
kubectl logs -f nginx(pod 名称)
# 查看 Pod 中指定容器的日志
kubectl logs -f nginx(pod 名称) -c 容器名称
2.6 查看 Pod 的描述信息
kubectl describe pod nginx(pod 名称)
3 Pod 运行多个容器
3.1 创建 Pod
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
# 容器一:Nginx:1.19
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 容器二:Redis:5.0.10
- name: redis
image: redis:5.0.10
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
kubectl apply -f my-pod.yml
3.2 查看指定容器日志
kubectl logs -f mypod -c nginx(容器名称)
kubectl logs -f mypod -c redis(容器名称)
3.3 进入容器
kubectl exec -it mypod -c nginx -- sh
kubectl exec -it mypod -c redis -- sh
4 Pod 的 Labels
标签(Labels)是附加到 Kubernetes 对象(比如 Pod)上的键值对,用于指定对用户有意义且相关的对象的标识属性标签作用:给 K8s 对象起别名,有了别名可以过滤和筛选
例如:给在杭州的服务器和在广州的服务器加上地区的标识,这样我们就可以根据地区去筛选出 Pod,并对 Pod 做一个合理的调配
4.1 语法
标签由键值对组成,对于值有以下约束:
- 必须为 63 个字符或更少(可以为空)
- 除非标签值为空,否则要以数字或者字符开头和结尾
- 包含破折号(
-),下划线(_),点(.)
4.2 标签基本操作
# 查看标签
kubectl get pods --show-labels
# 给指定的 Pod 动态添加 标签键值对
kubectl label pod mypod env=prod
# 重写指定 Pod 标签的 键值对
kubectl label --overwrite pod mypod env=test
# 删除标签 `-`表示删除标签
kubectl label pod mypod env-
# 根据标签进行筛选:
# 1. 查看 key=value 的标签
kubectl get pod -l env=test
# 2. 查看键值对中有 key 的标签
kubectl get pod -l env
# 3. 查看键值对中没有 key 的标签
kubectl get pod -l '!env'
# 4. 查看键值对的值为某些值其中的标签
kubectl get pod -l 'env in (test,prod)'
# 5. 查看键值对的值不为某些值其中的标签
kubectl get pod -l 'env not in (test, prod)'
5 Pod 的生命周期
Pod 遵循预定义的生命周期:
- 起始于
Pending阶段,该阶段存在至少一个容器未创建 - 如果此时至少一个主要容器正常启动,则进入
Running阶段 - 之后,如果有容器有失败状态结束则变为
Failed,否则进入Succeeded阶段。
5.1 生命周期
之前,在【云原生 • Kubernetes】(二) Kubernetes 的组件与架构 中我们讲到
Node 结点是运行Pod的,一个 Pod 被创建、同时赋予一个唯一的 ID(UID),并被调度到 Node 结点,并在终止或者删除之前一直运行在这个结点上如果节点死掉了,调度到这个节点上的 Pod 也会被计划在给定时限结束后删除。
也就是说 Pod 自身不具备自愈能力,会因为节点的失效而被删除,同样也会因为节点资源耗尽或者节点维护而无法存活,不过 Kubernetes 会使用 控制器 来保证 Pod 的自愈能力自愈能力并不代表会重新调度到另外的节点,因为任意给定的 Pod 是不会重新被调度到另外的节点的,只能做到创建一个新的,属性完全相同,但是 UID 不同的 Pod 调度到另外一个节点
说明:如果有组件在声明时表示与 Pod 的生命周期相同,那么在 Pod 存在期间它会一直存在,但是 Pod 因为任何原因删除、或者被相同的 Pod 替代的时候,这个对象会被删除并重建
5.2 Pod 阶段
| 阶段 | 描述 |
|---|---|
Pending(悬停) | Pod 已经被 Kubernetes 接受,但是有一个或者多个容器没有创建,该阶段存于 等待 Pod 被调度到某个节点的时间 以及 通过网络下载镜像 的时间 |
Running(运行中) | Pod 已经被调度到某个节点,所有容器都被创建了,并且至少有一个容器存在于运行状态 |
Succeeded(成功) | Pod 所有容器都成功运行 |
Failed(失败) | Pod 所有容器都已经终止,并且至少有一个容器是非正常退出 |
Unknown(未知) | 因为某些原因无法获得 Pod 的状态,一般是因为 Pod 与主机通信失败 |
说明:
当一个 Pod 被删除的时候,此时它的状态会变为
Terminating,但是这个状态并不是 Pod 的阶段之一,Pod 被赋予一个可以体面终止的期限,默认为 30 秒,也可以强制关闭这个容器:kubectl delete pod <pod_name> --force --grace-period=0如果某节点死掉,或者与其他的节点失联,该节点上的所有
Pod都会变为Failed
6 Container 特性
6.1 容器生命周期
Kubernetes会跟踪Pod每个容器的状态,并且可以根据 容器生命周期回调 来在容器生命周期中特定的时间点触发事件。其实就是 Kubernetes 在容器的生命周期中增加了几个 钩子函数
一旦调度器给 Pod 分配了节点,那么kubelet就会通过 容器运行时(Container Runtime)为 Pod 创建容器,而容器有三种状态:
-
Waiting (等待)如果容器不存在
Running或Terminated状态,它就处在Waiting状态,在这个状态,容器仍然在运行完成启动所需要的操作,例如从镜像仓库拉取镜像、向容器应用Secret数据 -
Running (运行中)该状态表明容器正在执行状态,并没有问题发生,而如果配置了
postStart回调,就会在转为Running状态之前完成这个回调,例如在开始Java应用程序服务之前确定MySQL服务是否开启了 -
Terminated (已终止)表明容器已经开始执行或者正常结束、失败,如果配置了
preStop回调,就会在终止之前,也就是进入Terminated状态之前执行该回调
6.2 容器生命周期回调 / 事件 / 钩子
回调使容器能够了解其管理生命周期中的事件,并在执行相应的生命周期回调时 运行在处理程序中实现的代码,有两个回调暴露给容器:
-
PostStart :
这个回调在容器被创建之后立即执行,但是不能保证回调在容器入口点之前执行,没有参数传递给处理程序,也就是无法确定容器执行的顺序和这个事件执行的顺序。
这里可能就无法完成在Java应用程序服务开始之前确定MySQL服务是否开启,但是这个可以通过
Init容器来实现,Init 容器我们后面会讲到 -
PreStop :
在容器因 API 请求或者管理事件而被终止,那么在这之前,此回调会被调用。而停止 Pod 是有一个时间限制的,不管
PreStop是否执行结束 -
使用容器生命周期回调实例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: mypod
spec:
containers:
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
# 写入 start.txt
command: ["/bin/sh", "-c", "echo postStart >> /start.txt"]
preStop:
exec:
# 写入 stop.txt 并睡眠 5s
command: ["/bin/sh", "-c", "echo preStop >> /stop.txt && sleep 5"]
ports:
- containerPort: 80
6.3 容器重启策略
Pod 中的 spec 包含一个 restartPolicy字段,它表示容器重启的策略,其可能取值包括Always(总是重启)、OnFailure(容器异常退出时重启)、Never(永不重启)
它是包含于spec中,而不是container中,这是因为我们之前讲到,Kubernetes 的最小操作单元为 Pod,Pod 中的所有容器有同一套声明规则
说明:Pod 的重启策略也并不是一失败就立马重启,当 Pod 中的容器退出时,kubelet 会按照 指数回退 方式计算重启的延时(10s,20s,40s……),其最长延时为五分钟,一旦某容器执行了 10 分钟并且没有出现问题,kubelet 会对该容器的重启回退计时器执行 重置操作。
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.0.19
imagePullPolicy: IfNotPresent
restartPolicy: Always # OnFailure Never
6.4 自定义容器启动命令
和 Docker 一样,K8s 也可以通过 command、args 来修改 容器启动时默认执行命令 以及 传递相关的参数
一般使用 command 修改启动命令,使用 args 为启动命令传递参数
apiVersion: v1
kind: Pod
metadata:
name: redis
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5.0.10
imagePullPolicy: IfNotPresent
command: ["redis-server"]
# 开启 AOF
args: ["--appendonly yes"]
restartPolicy: Always
6.5 容器探针
probe 是由 Kubelet 对容器执行的定期诊断,要执行诊断,Kubelet 既可以在容器内执行代码,也可以发出一个网络请求。可以理解为定期对容器进行健康检查
探针类型
针对运行中的容器,kubelet可以选择是否执行以下三种探针,以及如何对探测结果作出反应:
livenessProbe指示容器是否正在运行。如果存活态探测失败,则 Kubelet 就会杀死容器,并且容器将根据重启策略决定未来的操作。readinessProbe指示容器是否准备好为请求提供服务。如果就绪态探测失败,则 端点控制器 会与 Pod 匹配的端点列表中删除该 Pod 的 IP地址。startupProbe 1.7+指示容器中的应用是否已经启动。如果提供了启动探针,其他所有探针都会被禁用,直到这个探针成功为止,同样的,如果启动探针失败,Kubelet 会杀死容器
探针机制
使用探针来检查容器有以下四种机制来进行检测容器:
-
exec通过执行一个 Shell 命令来判断,即在容器执行指定命令,如果命令退出时返回 0 则表示成功
-
grpc使用 gRPC 执行一个远程调用,目标应该实现 gRPC 健康检查,如果相应的状态是”SERVING“,则认为诊断成功
-
httpGet对容器的 IP地址 上指定端口和路径执行 HTTP
GET请求,如果相应的状态码大于等于 200 且小于 400 则诊断认为是成功的 -
tcpSocket对容器的 IP地址 上的指定端口执行 TCP 检查,如果端口能够正常通信则认为是成功的
探针结果
每次探测、每种探针、每种机制的结果都是以下三种:
Success(成功) 容器通过了诊断Failure(失败) 容器未通过诊断Unknown(未知) 诊断失败,因此不会采取任何行动
探针参数
# 容器开始多少秒之后开始探针
initialDelaySeconds: 5
# 检测间隔时间
periodSeconds: 4
# 默认检测超时时间
timeoutSeconds: 1
# 默认失败次数为 3 次,达到 3 次后重启 Pod
failureThreshold: 3
# 默认成功次数为 1 次,1次检测成功代表成功
successThreshold: 1
使用探针
- exec
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
ports:
- containerPort: 80
args:
- /bin/sh
- -c
- sleep 7 && nginx -g "daemon off;"
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
# 查看 Nginx 是否有启动成功
command:
- ls
- /var/run/nginx.pid
initialDelaySeconds: 5
periodSeconds: 4
timeoutSeconds: 1
failureThreshold: 3
successThreshold: 1
restartPolicy: Always
说明:
- 如果睡眠 7s,第一次检测发现失败,但是第二次检测发现成功,只有 3次失败 才回重启
- 如果睡眠 30s,会超过三次检测失败,K8s 就会杀死容器重新启动,反复循环这个过程
- tcpSocket
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
ports:
- containerPort: 80
args:
- /bin/sh
- -c
- sleep 7 && nginx -g "daemon off;"
imagePullPolicy: IfNotPresent
livenessProbe:
# 查看 Nginx 的 80 端口是否能够正常通信
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 4
timeoutSeconds: 1
failureThreshold: 3
successThreshold: 1
restartPolicy: Always
- httpGet
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
ports:
- containerPort: 80
args:
- /bin/sh
- -c
- sleep 7 && nginx -g "daemon off;"
imagePullPolicy: IfNotPresent
livenessProbe:
# 请求主页 index.html 查看是否能够正常返回 200
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 5
periodSeconds: 4
timeoutSeconds: 1
failureThreshold: 3
successThreshold: 1
restartPolicy: Always
- gRPC
官网参考地址:配置存活、就绪和启动探针 | Kubernetes
6.6 资源限制
如果不对容器进行内存限制和CPU限制,容器可以无限制的使用当前结点的资源,这样如果某个容器使用率过高就会对其他的容器造成影响
在 Kubernetes 中对于容器资源限制主要有两方面的限制:
内存资源限制:分为内存请求和内存限制,我们保证容器拥有它请求数量的内存,但不能使用超过限制数量的内存CPU 资源限制:同样分为 request(请求) 和 limit(限制)。容器使用的 CPU 不能超过所配置的限制,如果系统有空闲的 CPU 时间,则可以保证给容器分配器请求数量的 CPU 资源
请求 request memory cpu : 可以使用的基础资源
限制 limit memory cpu : 可以使用的最大资源 如果超过最大资源之后 容器会被
1 metrics-server
Kubernetes Metrics Server(Kubernetes 指标服务器),它是一个可扩展的、高效的容器资源度量源。Metrics Server 用于监控每个 Node 和 Pod 的负载,从 Kubelets 收集资源指标,并通过 Metrics API 在 Kubernetes apiserver 中公开,这样我们就可以通过 kubectl top 访问
- 查看 Metrics-server 是否正在运行,可以键入以下指令:
# 查看所有的资源指标 API
kubectl get apiservices
- 如果资源指标 API 可用,则输出会包含一个对
metrics.k8s.io的引用
NAME
v1betal.metrics.k8s.io
- 安装 metrics-server ,使用 github 上的源
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
- 查看容器正在使用内存情况:
kubectl top pod pod名称
2 指定内存请求和限制
为容器指定内存请求,直接在配置文件中添加resources:limits,这里要简单提一下内存的单位:内存的基本单位是字节(byte),可以使用E P T G M K Ei Pi Ti Gi Mi Ki
apiVersion: v1
kind: Pod
metadata:
name: nginx-memory
labels:
app: nginx-memory
spec:
containers:
- name: nginx-memory
image: nginx:1.19
imagePullPolicy: IfNotPresent
resources:
requests:
memory: 100M
limits:
memory: 200M
restartPolicy: Always
查看容器内存使用情况(包括容器内存的请求和限制):
kubectl get pod pod名称 --output=yaml
-
内存请求和限制的目的通过给集群中的容器配置内存请求和限制,可以有效利用集群节点上可用的内存资源,通过将 Pod 的内存请求保持在较低的水平,可以更好的安排 Pod 调度,而限制大于请求的好处是:
- Pod 可以进行一些突发活动,从而更好的利用可用内存
- Pod 可以在突发活动期间,可使用的内存被限制为合理的数量
-
如果没有指定内存限制如果没有指定内存限制,则自动遵循以下情况之一:
- 容器无限制的使用内存,会使用节点所有的可用内存,进而可能导致 OOM Killer
- 如果运行的容器所在的命名空间有默认的内存限制,则会被自动分配默认限制
-
如果只指定了内存限制,没有指定内存请求Kubernetes 会自动设置与限制相同数值的请求值,这在 内存限制 和 CPU限制 中都是这样的
3 指定 CPU 请求和限制
CPU 请求和限制和 内存请求和限制 差不多,唯一的区别就是,CPU 在超出 limit限制 后不会 Kill,而会继续运行,它的使用也和内存类似:
apiVersion: v1
kind: Pod
metadata:
name: nginx-memory
labels:
app: nginx-memory
spec:
containers:
- name: nginx-memory
image: nginx:1.19
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
limits:
cpu: 200m
restartPolicy: Always
值得一提的是 CPU 的单位:小数值是可以用的,一个请求 0.5 CPU 的容器只会保证获得请求 1个CPU 容器的 CPU 的一半,可以使用 m 表示毫,例如 100m CPU 与 0.1 CPU 相同。
7 Pod 中 init 容器
Pod 中可能管理很多的容器,不同于 Nginx、Redis 这种应用容器,Init 容器在所有应用容器启动之前运行,因此 Init 容器 中可以包括一些应用镜像中不存在的实用工具和安装脚本 例如:现在有一个 Java 应用程序,那么就可以在 Init 容器中去验证 MySQL 服务是否开启,并可以执行一些 SQL 脚本
7.1 init 容器特点
- 它们总是运行到完成,也就是说,如果 Pod 的 Init 容器失败,Kubelet 会不断的重启 Init 容器直至成功为止。如果
restartPolicy = never,那么 Init 容器失败会把Pod状态设置为失败 - 一个 Pod 中可以拥有多个 Init 容器,每个 Init 容器都必须在下一个启动之前完成
- Init 容器不支持
lifecycle livenessProbe readinessProbe startupProbe - Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷、安全设置
7.2 使用 Init 容器
在 Pod 的规约中用来描述应用容器的 containers 数组平行的位置指定 Init 容器
apiVersion: v1
kind: Pod
metadata:
name: init
labels:
app: init
spec:
containers:
- name: init
image: busybox:1.28
command: ["sh", "-c", "echo The app is running! && sleep 3600"]
imagePullPolicy: IfNotPresent
initContainers:
- name: init-service
image: busybox:1.28
command: ["sh", "-c", "echo init-service is running! && sleep 5"]
- name: init-db
image: busybox:1.28
command: [ "sh", "-c", "echo init-db is running! && sleep 5" ]
restartPolicy: Always
- 查看启动详情:
8 节点亲和性分配 Pod
如果一个 Web 服务放在一个 Pod,而 日志服务 也放在一个 Pod,最好就是能够把两个 Pod 放在一个节点,这样就可以减少一些节点之间的通信,也就是说在某些特定的场景下,我们更希望能够指定某些 Pod 在哪个结点上:
我们可以约束一个 Pod 以便 限制 它只在特定的节点上运行,或者优先在特定的节点上运行,有以下四种方法可以选择 Kubernetes 对指定 Pod 的调度:
- 与节点标签匹配的 nodeSelector 推荐
- 亲和性和反亲和性
- nodeName
- Pod 拓扑分布约束
8.1 给节点添加标签
# 选择一个节点,给它添加一个标签
kubectl label nodes k8s-node1(节点名称) disk=ssd
# 查看节点的标签
kubectl get pods --show-labels
8.2 根据选择节点标签指派 pod 到指定节点 [nodeSelector]
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
restartPolicy: Always
# 选择节点为标签为 ssd 的节点
# 我们可以给 CPU 处理快的节点加上 cpu=fast cpu=slow 类似的节点
# 这样就可以在给 Pod 选择节点的时候加上 cpu=fast
nodeSelector:
disk: ssd
8.3 根据节点名称指派 pod 到指定节点 [nodeName]
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
restartPolicy: Always
# 根据节点的名称指派 pod 到 指定节点
# 这种方式并不推荐使用
# 如果找不到 nodeName 会处于一个 Pending 的状态,直至有对应名字的节点被创建
nodeName: k8s-node1
8.4 根据亲和性和反亲和性指派 pod 到指定结点
说明
nodeSelector提供了一种最简单的方法来把 Pod 约束到有指定标签的 节点 上,而亲和性和反亲和性扩展了你可以定义的约束类型,具体好处有以下三点:
- 亲和性、反亲和性的语言表达能力更强。对于 nodeSelector 和 nodeName 只能选择存在的标签,而亲和性和反亲和性提供对选择逻辑更强的控制能力
- 可以表明某些规则是
软需求或者偏好,这样对于不存在的标签和结点名称,仍然可以调度 Pod - 可以使用节点上运行的其他 Pod 标签来实施调度约束,让处于同一个网络域的 Pod 放在一起
亲和性功能有两种亲和性:
节点亲和性:它的功能类似于nodeSelector,但是它能够写表达式和指定软规则,也就是说它能够表达的逻辑更强Pod 亲和性:它可以做到和节点上的 Pod 去计算亲和性,如果 node1 节点上的 Pod 与当前要调度的 Pod 并不亲和,那么就可能会调度到 node2 节点上去
节点亲和性概念上类似于nodeSelector ,它也是根据节点上的标签来约束 Pod 调度到哪些节点上,节点亲和性有两种实现:
requiredDuringSchedulingIgnoredDuringExecution:它设置的规则是和 nodeSelector 一样,必须满足才能执行调度,但是它的语法表达能力更强preferredDuringSchedulingIgnoredDuringExecution:它设置的是弱规则,即调度器会尝试去寻找满足对应规则的节点,如果没找到,Pod 不会处于 Pending 状态,调度器仍然会调度该 Pod 注意:在上述类型中,IgnoredDuringExecution意味着如果节点标签在 Kubernetes 中调度 Pod 后发生了变更, Pod 会继续运行
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
# 亲和性设置
affinity:
# 节点亲和性
nodeAffinity:
# 必须满足的标签
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
restartPolicy: Always
注意:你可以使用In、NotIn、Exists、DoesNotExist、Gt、Lt 作为 operator 这个操作符,用于实现亲和性和反亲和性,其实这里就能看得出来,相比于 nodeSelector ,亲和性和反亲和性的逻辑表达能力更强
8.5 节点亲和性权重
当使用
preferredDuringSchedulingIgnoredDuringExecution的时候就会涉及到权重weight,它的取值在 1 - 100 之间,权重越高,在选择的时候优先选择
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
# 亲和性设置
affinity:
# 节点亲和性
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: cpu
operator: In
values:
- fast
weight: 80
- preference:
matchExpressions:
- key: disk
operator: In
values:
- ssd
weight: 50
containers:
- name: nginx
image: nginx:1.19
imagePullPolicy: IfNotPresent
restartPolicy: Always
说明: 这里就会优先选择 cpu=fast 的节点,然后如果没有再选择 disk=ssd 的节点,因为前者的权重相较于后者更高
8.6 pod 间亲和性和反亲和性及权重
与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution例如,可以使用requiredDuringSchedulingIgnoredDuringExecution亲和性来告诉调度器,将两个服务器的 Pod 放在同一个云提供商可用区内,因为他们之间的通信比较频繁。使用preferredDuringSchedulingIgnoredDuringExecution反亲和性来把同一个服务的多个 Pod 放在不同的云提供商可用区中。
要使用 Pod 间亲和性,要使用 Pod 规约中的 spec.affinity.podAffinity 字段:
apiVersion: v1
kind: Pod
metadata:
name: redis
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5.0.10
imagePullPolicy: IfNotPresent
restartPolicy: Always
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: BeiJing
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
说明:这里出现了topologyKey 这个约束,这个约束就是我们在调度 Pod 到节点的时候,该节点的标签需要有 BeiJing 这个 Key,我们可以把所有北京的节点都加上这个 Key,杭州的节点都加上 HangZhou,这样我们就可以使用节点的亲和性让 Pod 调度到我们想要的地区的节点上
🍁 友链
- 【云原生 • Kubernetes】(一) 初识 Kubernetes - 掘金 (juejin.cn)
- 【云原生 • Kubernetes】(二) Kubernetes 的组件与架构 - 掘金 (juejin.cn)
- 【编程不良人】kubernetes (k8s) 实战教程,每周一章更完为止!_哔哩哔哩_bilibili
✒ 写在最后
都看到这里啦~,给个点赞再走呗~,也欢迎各位大佬指正以及补充,在评论区一起交流,共同进步!也欢迎加微信一起交流:Goldfish7710。