服务发现
之前在核心篇总有相关介绍,主要是分为东西流量和南北流量,也就是service和ingress,那为什么又了service和ingress就能实现服务发下呢?请往下看。
service
外部,比如我们的kubectl来访问,首先都是进入apis-services的,如下图:
- master节点中,有一个service,api-service通过端口找到其中对应的service,然后找到对应的endpoint。
- endpoint里面维护了对应的ip,也维护了对应的端口,然后通过iptables最终转发到目标的机器上面。
- 找到目标的机器后,通过kube-proxy代理到具体的容器内部,然后实现跟容器内具体的交互。
也就是所有的容器都是通过service来实现互相的访问。
创建
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
ports:
- name: http # service 端口配置的名称
protocol: TCP # 端口绑定的协议,支持 TCP、UDP、SCTP,默认为 TCP
port: 80 # service 自己的端口
targetPort: 9527 # 目标 pod 的端口
- name: https
port: 443
protocol: TCP
targetPort: 443
selector: # 选中当前 service 匹配哪些 pod,对哪些 pod 的东西流量进行代理
app: nginx
kubectl create -f nginx-svc.yaml
创建后:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d13h
nginx-svc ClusterIP 10.108.186.61 <none> 80/TCP,443/TCP 26m
[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-86c57db685-p7gpz 1/1 Running 0 52m 10.244.169.130 k8s-node2 <none> <none>
使用一个临时的dns来访问
[root@k8s-master services]# kubectl run -it --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh
/ # wget 10.244.169.130
Connecting to 10.244.169.130 (10.244.169.130:80)
index.html 100% |*************************************************************| 615 0:00:00 ETA
/ # wget 10.244.169.130/index.html
反向代理外部域名
比如反向代理到博客首页:
apiVersion: v1
kind: Service
metadata:
labels:
app: boxiaoyang
name: boxiaoyang-domain
spec:
type: ExternalName
externalName: www.boxiaoyang.club
[root@k8s-master services]# kubectl create -f nginx-svn-external-blog.yaml
service/boxiaoyang-domain created
[root@k8s-master services]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
boxiaoyang-domain ExternalName <none> www.boxiaoyang.club <none> 11s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d14h
nginx NodePort 10.100.117.202 <none> 80:31000/TCP 73m
[root@k8s-master services]# kubectl run -it --image busybox:1.28.4 dns-test1 --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget boxiaoyang-domain
Connecting to boxiaoyang-domain (124.223.47.250:80)
index.html 100% |**********************| 35444 0:00:00 ETA
/ #
Ingress
官方介绍: ingress
刚刚都是通过内部访问的,比如起一个内部的busybox来访问内部的pod,但是外部的访问,还是得根据ingress来。
架构图如下:
有点像ingress代替了传统的nginx了。
安装 ingress-nginx
先安装helm,这个是k8s的资源包仓库,理解为linux的yum。
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
tar -zxvf helm-v3.2.3-linux-amd64.tar.gz
[root@k8s-master heml]# cd linux-amd64/
[root@k8s-master linux-amd64]# pwd
/var/heml/linux-amd64
[root@k8s-master linux-amd64]# cp helm /usr/local/bin/
添加仓库
[root@k8s-master linux-amd64]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
[root@k8s-master linux-amd64]# helm repo list
NAME URL
ingress-nginx https://kubernetes.github.io/ingress-nginx
[root@k8s-master linux-amd64]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.9.1 1.9.6 Ingress controller for K8s using NGINX a...
[root@k8s-master linux-amd64]#
下载安装包
helm pull ingress-nginx/ingress-nginx
# 将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz
# 解压后,进入解压完成的目录
cd ingress-nginx
# 修改 values.yaml
镜像地址:修改为国内镜像
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/nginx-ingress-controller
image: google_containers/kube-webhook-certgen
tag: v1.3.0
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
修改部署配置的 kind: DaemonSet
nodeSelector:
ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
将 admissionWebhooks.enabled 修改为 false
将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer
# 为 ingress 专门创建一个 namespace
kubectl create ns ingress-nginx
# 为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true
# 安装 ingress-nginx
helm install ingress-nginx ./ingress-nginx -n ingress-nginx
创建一个 ingress
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
多域名配置
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
- pathType: Exec # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
- host: api.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
配置和存储
配置
后台开发是有很多配置,为了防止硬编码,所以会在k8s中配置很多的配置信息。但是很多信息是不能放在容器里面的,因为修改起来很不方便,所以呢,我们要抽取出来。
ConfigMap
一般用于去存储 Pod 中应用所需的一些配置信息,或者环境变量,将配置于 Pod 分开,避免应为修改配置导致还需要重新构建 镜像与容器。 一般来说,有两种方式,一种是基于文件夹的方式,比如我们在test目录下面创建两个文件夹,然后使用过key=value的方式把值填写过去,如:
drwxr-xr-x 2 root root 4096 Jan 30 12:08 test
[root@k8s-master config]# cd test
[root@k8s-master test]# ll
total 8
-rw-r--r-- 1 root root 28 Jan 30 12:08 db.properties
-rw-r--r-- 1 root root 25 Jan 30 12:08 redis.properties
[root@k8s-master test]# cat db.properties
username=root
pawword=admin
然后通过指定文件夹的方式来创建configmap:
kubectl create cm test-config --from-file=文件路径
[root@k8s-master config]# kubectl create cm test-config --from-file=test/
configmap/test-config created
[root@k8s-master config]# kubectl get cm
NAME DATA AGE
test-config 2 7s
[root@k8s-master config]# kubectl describe cm test-config
Data
====
db.properties:
----
username=root
pawword=admin
redis.properties:
----
host:127.0.0.1
prot:6379
但是大部分的时候,是通过另外一种方式,就是指定某个文件的方式进行创建,因为有时候并非想把整个文件夹的文件全部放进去,而是指定放入某几个文件。 kubectl create cm calico-yaml --from-file=app.yaml
比如下面:
[root@k8s-master test]# cat app.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: calico-config
namespace: kube-system
[root@k8s-master test]# kubectl create cm calico-yaml --from-file=app.yaml
configmap/calico-yaml created
[root@k8s-master test]# kubectl get cm
NAME DATA AGE
calico-yaml 1 4s
test-config 2 130m
[root@k8s-master test]# kubectl describe cm calico-yaml
Name: calico-yaml
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
app.yaml:
----
kind: ConfigMap
apiVersion: v1
metadata:
name: calico-config
namespace: kube-system
还有一种方式,就是直接通过命令行的方式指定key和value
[root@k8s-master helm]# kubectl create configmap test-env-config --from-literal=JAVA_OPTS_TEST='-Xms512m -Xmx512m' --from-literal=APP_NAME=BLOG
configmap/test-env-config created
[root@k8s-master helm]# kubectl get cm
NAME DATA AGE
calico-yaml 1 14m
test-config 2 145m
test-env-config 2 5s
[root@k8s-master helm]# kubectl describe cm test-env-config
Name: test-env-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
APP_NAME:
----
BLOG
JAVA_OPTS_TEST:
----
-Xms512m -Xmx512m
Events: <none>
加载
那这些配置,如何加载到我们的容器里面呢?
举个例子,我们来创建一个pod,然后在pod里面引用相关配置:
[root@k8s-master test]# vim env-test-po.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env-cm
spec:
containers:
- name: env-test
image: alpine
command: ["/bin/sh" ,"-c","env;sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config
key: JAVA_OPTS_TEST
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config #用到了配置里文件
key: APP_NAME # key为appname的
restartPolicy: Never
基于yaml创建pod之后,然后等到启动起来后看日志可以发现:
[root@k8s-master test]# kubectl logs -f test-env-cm
...
HOSTNAME=test-env-cm
JAVA_VM_OPTS=-Xms512m -Xmx512m
APP=BLOG
...
secret加密数据配置
与 ConfigMap 类似,用于存储配置信息,但是主要用于存储敏感信息、需要加密的信息,Secret 可以提供数据加密、解密功能。
在创建 Secret 时,要注意如果要加密的字符中,包含了有特殊字符,需要使用转义符转移,例如 $ 转移后为 $,也可以对特殊字符使用单引号描述,这样就不需要转移例如 1$289*-! 转换为 '1$289*-!'
一般来说,用的较少。
[root@k8s-master test]# kubectl create secret generic orig-secret --from-literal=username=admin --from-literal=password=admin
secret/orig-secret created
[root@k8s-master test]# kubectl get secret
NAME TYPE DATA AGE
default-token-mnb9p kubernetes.io/service-account-token 3 3d18h
orig-secret Opaque 2 9s
[root@k8s-master test]# kubectl describe secret orig-secret
Name: orig-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 5 bytes
username: 5 bytes
配置热更新
我们通常会将项目的配置文件作为 configmap 然后挂载到 pod,那么如果更新 configmap 中的配置,会不会更新到 pod 中呢?
这得分成几种情况:
默认方式
会更新,更新周期是更新时间 + 缓存时间
subPath
不会更新
变量形式
如果 pod 中的一个变量是从 configmap 或 secret 中得到,同样也是不会更新的
对于 subPath 的方式,我们可以取消 subPath 的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后再利用软连接的形式,将该文件链接到目标位置
但是如果目标位置原本就有文件,可能无法创建软链接,此时可以基于前面讲过的 postStart 操作执行删除命令,将默认的吻技安删除即可
持久化存储
在k8s中,持久化存储有三种类型,Volumes、NFS挂载、PV和PVC这三种,都是比较常用的、
Volumes
类似于docker中的容器中,把node节点上挂载在pod容器里面去,即使pod消失,但是文件还在node上面。
我们先编写一个配置文件:
apiVersion: v1
kind: Pod
metadata:
name: test-volume-pd
spec:
containers:
- image: nginx
name: nginx-volume
volumeMounts:
- mountPath: /test-pd #挂载到容器的哪个目录
name: test-volume # 挂载哪个volume
volumes:
- name: test-volume
hostPath: # 与主机共享目录,加载主机中的指定目录到容器中
path: /data # 节点中的目录
type: DirectoryOrCreate # 检查类型,如果没有就创建
测试
使用kubectl get pod -o wide 发现创建的po落在了node1上面,去node1上查看并创建文件:
[root@k8s-node1 /]# cd /data
[root@k8s-node1 data]# ll
total 0
[root@k8s-node1 data]# touch index.html
去pod上查看发现存在,也就是确实挂载了。
[root@k8s-master volumes]# kubectl exec -it test-volume-pd -- sh
# cd /data
# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys test-pd tmp usr var
# cd test-pd
# ls
index.html
当然,还有一种方式就是pod里面多个容器之间进行共享,就是EmptyDir
EmptyDir 主要用于一个 Pod 中不同的 Container 共享数据使用的,由于只是在 Pod 内部使用,因此与其他 volume 比较大的区别是,当 Pod 如果被删除了,那么 emptyDir 也会被删除。
存储介质可以是任意类型,如 SSD、磁盘或网络存储。可以将 emptyDir.medium 设置为 Memory 让 k8s 使用 tmpfs(内存支持文件系统),速度比较快,但是重启 tmpfs 节点时,数据会被清除,且设置的大小会计入到 Container 的内存限制中。
NFS挂载
nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。 也就是不在本地,在一个局域网上面。
相当于把HostPath和EmptyDir结合了,即可永久存储,又可以容器内访问,但是效率没那么高,磁盘的效率已经很低了,再加一层网络。你可以用,但是不能频繁的读取上,比如mysql这些。你懂得。
# 安装 nfs 每个节点都做一次吧
yum install nfs-utils -y
# 启动 nfs
systemctl start nfs-server
# 查看 nfs 版本
cat /proc/fs/nfsd/versions
# 在磁盘大的节点上创建共享目录
mkdir -p /data/nfs
cd /data/nfs
mkdir rw
mkdir ro
# 设置共享目录 export
vim /etc/exports
/data/nfs/rw 192.168.113.0/24(rw,sync,no_subtree_check,no_root_squash)
/data/nfs/ro 192.168.113.0/24(ro,sync,no_subtree_check,no_root_squash)
# 重新加载
exportfs -f
systemctl reload nfs-server
# 到其他测试节点安装 nfs-utils 并加载测试
mkdir -p /mnt/nfs/rw
mount -t nfs 192.168.113.121:/data/nfs/rw /mnt/nfs/rw
PV和PVC
以上都是小菜,这两个才是真正的实现方案,也是最重要的。
持久卷(PersistentVolume,PV)
是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申领(PersistentVolumeClaim,PVC)
表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载)。
关联关系如下:
构建
创建PV
apiVersion: v1 kind: PersistentVolume metadata: name: pv0001 spec: capacity: storage: 5Gi # pv 的容量 volumeMode: Filesystem # 存储类型为文件系统 accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany - ReadWriteOnce # 可被单节点独写 persistentVolumeReclaimPolicy: Recycle # 回收策略 storageClassName: slow # 创建 PV 的存储类名,需要与 pvc 的相同 mountOptions: # 加载配置 - hard - nfsvers=4.1 nfs: # 连接到 nfs path: /data/nfs/rw/test-pv # 存储路径 server: 192.168.113.121 # nfs 服务地址
[root@k8s-master pv]# kubectl create -f pv-nfs.yaml persistentvolume/pv0001 created [root@k8s-master pv]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv0001 1Gi RWO Recycle Available slow 4s
有以下几种状态:
- Avaliable:空闲
- Bound:已经被PVC绑定
- Released:PVC被删除,资源已经回收,但是pv未被重新使用
- Failed:自动回收失败
创建PVC
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteOnce # 权限需要与对应的 pv 相同 volumeMode: Filesystem resources: requests: storage: 8Gi # 资源可以小于 pv 的,但是不能大于,如果大于就会匹配不到 pv storageClassName: slow # 名字需要与对应的 pv 相同 # selector: # 使用选择器选择对应的 pv # matchLabels: # release: "stable" # matchExpressions: # - {key: environment, operator: In, values: [dev]}
我们来看看是否绑定了
[root@k8s-master pv]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-pvc Bound pv0001 1Gi RWO slow 6s [root@k8s-master pv]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv0001 1Gi RWO Recycle Bound default/nfs-pvc slow 9m57s
把pod进行绑定
apiVersion: v1 kind: Pod metadata: name: test-pvc-pd spec: containers: - image: nginx name: nginx-volume volumeMounts: - mountPath: /usr/share/nginx/html #挂载到容器的哪个目录 name: test-volume # 挂载哪个volume volumes: - name: test-volume persistentVolumeClaim: # 关联PVC claimName: nfs-pvc # 要关联哪个PVC
高级调度
CornJob计划任务
和linux中的corntab类似,只不过放入了k8s中执行。
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
concurrencyPolicy: Allow # 并发调度策略:Allow 允许并发调度,Forbid:不允许并发执行,Replace:如果之前的任务还没执行完,就直接执行新的,放弃上一个任务
failedJobsHistoryLimit: 1 # 保留多少个失败的任务
successfulJobHistoryLimit: 3 # 保留多少个成功的任务
suspend: false # 是否挂起任务,若为 true 则该任务不会执行
# startingDeadlineSeconds: 30 # 间隔多长时间检测失败的任务并重新执行,时间不能小于 10
schedule: "* * * * *" # 调度策略
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
初始化容器InitContainer
在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。
相对于 postStart 来说,首先 InitController 能够保证一定在 EntryPoint 之前执行,而 postStart 不能,其次 postStart 更适合去执行一些命令操作,而 InitController 实际就是一个容器,可以在其他基础容器环境下执行更复杂的初始化功能。
在 pod 创建的模板中配置 initContainers 参数: spec: initContainers:
- image: nginx imagePullPolicy: IfNotPresent command: ["sh", "-c", "echo 'inited;' >> ~/.init"] name: init-test
污点和容忍
污点
我们知道,主节点是很重要的节点,负责调度从节点来实现对应的任务,是一个很重要的角色,所以它的资源应该是要更加充沛,而且不做很多事情来保障它的可用性,但是我们k8s分配任务的时候,是随机分配节点的,所以我们可以给master节点打上污点的标签,这样任务就不会部署过来。
污点:是标注在节点上的,当我们在一个节点上打上污点以后,k8s 会认为尽量不要将 pod 调度到该节点上,除非该 pod 上面表示可以容忍该污点,且一个节点可以打多个污点,此时则需要 pod 容忍所有污点才会被调度该节点。
分类
一般来说,我们有两种分类:
NoSchedule
如果不能容忍该污点,那么 Pod 就无法调度到该节点上,但是已经存在的节点不会被驱逐
NoExecute
如果 Pod 不能忍受这类污点,Pod 会马上被驱逐。
如果 Pod 能够忍受这类污点,但是在容忍度定义中没有指定 tolerationSeconds, 则 Pod 还会一直在这个节点上运行。
如果 Pod 能够忍受这类污点,而且指定了 tolerationSeconds, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。
操作
一般来说,我们可以如下创建污点:
# 为节点打上污点
kubectl taint node k8s-master key=value:NoSchedule
# 移除污点
kubectl taint node k8s-master key=value:NoSchedule-
# 查看污点
kubectl describe no k8s-master
容忍
当然,有些事情是必须要在放在master上面的,但是master有污点了怎么办?此时就可以给master配一个这个任务的容忍。
容忍:是标注在 pod 上的,当 pod 被调度时,如果没有配置容忍,则该 pod 不会被调度到有污点的节点上,只有该 pod 上标注了满足某个节点的所有污点,则会被调度到这些节点
类型
Equal
比较操作类型为 Equal,则意味着必须与污点值做匹配,key/value都必须相同,才表示能够容忍该污点
Exists
容忍与污点的比较只比较 key,不比较 value,不关心 value 是什么东西,只要 key 存在,就表示可以容忍。
配置
tolerations:
- key: "污点的 key"
value: "污点的 value"
offect: "NoSchedule" # 污点产生的影响
operator: "Equal" # 表是 value 与污点的 value 要相等,也可以设置为 Exists 表示存在 key 即可,此时可以不用配置 value
亲和力Affinity
这个和污点相反,污点的作用简单来说就是你不要来,而亲和力就是来吧亲爱的。如果说是反亲和力,那也有污点的作用,就是滚。
比如内存消耗比较大的任务,就可以分配到内存大一点的node上面,对于存储要求高的,就可以优先分配到ssd硬盘上面等等。