nodeSelector(节点选择器)

nodeSelector : 用于将Pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。

作用:

  1. 约束Pod到特定的节点运行
  2. 完全匹配节点标签

应用场景:

  1. 专用节点:根据业务线将Node分组管理
  2. 配备特殊硬件:部分Node配有SSD硬盘、CPU

nodeSelector 是节点选择约束的最简单推荐形式。nodeSelector 是 PodSpec 的一个字段。 它包含键值对的映射。为了使 pod 可以在某个节点上运行,该节点的标签中 必须包含这里的每个键值对(它也可以具有其他标签)。 最常见的用法的是一对键值对。

让我们来看一个使用 nodeSelector 的例子。

步骤零:先决条件

本示例假设你已基本了解 Kubernetes 的 Pod 并且已经建立一个 Kubernetes 集群

步骤一:添加标签到节点

执行 kubectl get nodes 命令获取集群的节点名称。 选择一个你要增加标签的节点,然后执行 kubectl label nodes <node-name> <label-key>=<label-value> 命令将标签添加到你所选择的节点上。 例如,如果你的节点名称为 ‘kubernetes-foo-node-1.c.a-robinson.internal’ 并且想要的标签是 ‘disktype=ssd’,则可以执行 kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd 命令。

你可以通过重新运行 kubectl get nodes --show-labels, 查看节点当前具有了所指定的标签来验证它是否有效。 你也可以使用 kubectl describe node "nodename" 命令查看指定节点的标签完整列表。

步骤二:添加 nodeSelector 字段到 Pod 配置中

选择任何一个你想运行的 Pod 的配置文件,并且在其中添加一个 nodeSelector 部分。 例如,如果下面是我的 pod 配置:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx

然后像下面这样添加 nodeSelector:

[pods/pod-nginx.yaml ]

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

当你之后运行 kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml 命令, Pod 将会调度到将标签添加到的节点上。 你可以通过运行 kubectl get pods -o wide 并查看分配给 pod 的 “NODE” 来验证其是否有效

实例

准备如下

第一步:节点添加标签

例子:kubectl label nodes node2.example.com disktype=ssd

第二步:添加nodeSelector字段到Pod配置中

最后,验证:

例子:kubectl get nodes --show-labels

验证效果

//写入disktype=ssd
[root@master manifest]# vim test.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: b1
    image: busybox
    command: ["/bin/sh","-c","sleep 9000"]
    env:
    - name: xx
      valueFrom:
        fieldRef:
          fieldPath: status.podIPs
#标签选择
  nodeSelector:
    disktype: ssd
[root@master manifest]# kubectl create -f test.yaml 
pod/test created
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          8s
//标签选择到指定主机上面,不会变
[root@master manifest]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test   1/1     Running   0          58s   10.244.2.64   node2.example.com   <none>           <none>
//标签删除命令
kubectl label nodes node2.example.com disktype-

nodeAffinity(节点亲和性)

nodeAffinity:节点亲和性,与nodeSelector作用一样,但相比更灵活,满足更多条件,诸如:

  1. 匹配有更多的逻辑组合,不只是字符串的完全相等
  2. 调度分为软策略和硬策略,不只是字符串的完全相等
    硬(required):必须满足
    软(preferred): 尝试满足,但不保证
    操作符: In、Notln、Exists、DoesNotExist、Gt、Lt

节点亲和性概念上类似于 nodeSelector,它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点。

目前有两种类型的节点亲和性,分别为 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution。 你可以视它们为“硬需求”和“软需求”,意思是,前者指定了将 Pod 调度到一个节点上 必须满足的规则(就像 nodeSelector 但使用更具表现力的语法), 后者指定调度器将尝试执行但不能保证的偏好。 名称的“IgnoredDuringExecution”部分意味着,类似于 nodeSelector 的工作原理, 如果节点的标签在运行时发生变更,从而不再满足 Pod 上的亲和性规则,那么 Pod 将仍然继续在该节点上运行。 将来我们计划提供 requiredDuringSchedulingRequiredDuringExecution, 它将与 requiredDuringSchedulingIgnoredDuringExecution 完全相同, 只是它会将 Pod 从不再满足 Pod 的节点亲和性要求的节点上驱逐。

因此,requiredDuringSchedulingIgnoredDuringExecution 的示例将是 “仅将 Pod 运行在具有 Intel CPU 的节点上”,而preferredDuringSchedulingIgnoredDuringExecution 的示例为 “尝试将这组 Pod 运行在 XYZ 故障区域,如果这不可能的话,则允许一些 Pod 在其他地方运行”。

节点亲和性通过 PodSpec 的 affinity 字段下的 nodeAffinity 字段进行指定。

下面是一个使用节点亲和性的 Pod 的实例:

[pods/pod-with-node-affinity.yaml ]

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0

此节点亲和性规则表示,Pod 只能放置在具有标签键 kubernetes.io/e2e-az-name 且标签值为 e2e-az1e2e-az2 的节点上。 另外,在满足这些标准的节点中,具有标签键为 another-node-label-key 且标签值为 another-node-label-value 的节点应该优先使用。

你可以在上面的例子中看到 In 操作符的使用。新的节点亲和性语法支持下面的操作符: InNotInExistsDoesNotExistGtLt。 你可以使用 NotInDoesNotExist 来实现节点反亲和性行为,或者使用 节点污点 将 Pod 从特定节点中驱逐。

如果你同时指定了 nodeSelectornodeAffinity两者必须都要满足, 才能将 Pod 调度到候选节点上。

如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,则 如果其中一个 nodeSelectorTerms 满足的话,pod将可以调度到节点上。

如果你指定了多个与 nodeSelectorTerms 关联的 matchExpressions,则 只有当所有 matchExpressions 满足的话,Pod 才会可以调度到节点上。

如果你修改或删除了 pod 所调度到的节点的标签,Pod 不会被删除。 换句话说,亲和性选择只在 Pod 调度期间有效。

preferredDuringSchedulingIgnoredDuringExecution 中的 weight 字段值的 范围是 1-100。 对于每个符合所有调度要求(资源请求、RequiredDuringScheduling 亲和性表达式等) 的节点,调度器将遍历该字段的元素来计算总和,并且如果节点匹配对应的 MatchExpressions,则添加“权重”到总和。 然后将这个评调度方案中设置节点亲和性

实例

//#节点亲和性required必需满足
[root@master manifest]# vim test.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: b1
    image: busybox
    command: ["/bin/sh","-c","sleep 9000"]
    env:
    - name: xx
      valueFrom:
        fieldRef:
          fieldPath: status.podIPs
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
[root@master manifest]# kubectl create -f test.yaml 
pod/test created
//只在有标签的时候执行
[root@master manifest]# kubectl apply -f test.yaml 
pod/test created
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   0/1     Pending   0          13s
//添加标签查看效果
[root@master manifest]# kubectl label nodes node2.example.com disktype=ssd
node/node2.example.com labeled
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          103s

//#节点亲和性required必需满足preferrede 第二个条件满足
[root@master ~]# kubectl label nodes node2.example.com disktype=sata
node/node2.example.com labeled
//node1不创建
[root@master manifest]# vim test.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: b1
    image: busybox
    command: ["/bin/sh","-c","sleep 9000"]
    env:
    - name: xx
      valueFrom:
        fieldRef:
          fieldPath: status.podIPs
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 3
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd 
//没有满足
[root@master manifest]# kubectl apply -f test.yaml 
pod/test created
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   0/1     Pending   0          8s
//标签添加
[root@master manifest]# kubectl label nodes node2.example.com disktype=ssd --overwrite
node/node2.example.com labeled
[root@master manifest]# kubectl label nodes node1.example.com disktype=ssd --overwrite
node/node1.example.com labeled
[root@master ~]# kubectl label nodes node2.example.com app=httpd --overwrite
node/node2.example.com labeled
//配置
[root@master manifest]# vim test.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: b1
    image: busybox
    command: ["/bin/sh","-c","sleep 9000"]
    env:
    - name: xx
      valueFrom:
        fieldRef:
          fieldPath: status.podIPs
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 3
        preference:
          matchExpressions:
          - key: app
            operator: In
            values:
            - httpd

//二个条件达到,运行到node2
[root@master manifest]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test   1/1     Running   0          13s   10.244.2.68   node2.example.com   <none>           <none>

taint and tolratins(污点和容忍度)

Taints: 避免Pod调度到特定Node上

Tolerations:允许Pod调度到特有Taints的Node上

应用场景:

  1. 专用节点:根据业务线将Node分组管理,希望在默认情况下不调度该污点,只有配置了污点容忍才允许分配
  2. 配备特殊硬件:部分Node配有SSD硬盘、CPU、希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配到
  3. 基于Taint的驱逐

节点亲和性Pod 的一种属性,它使 Pod 被吸引到一类特定的节点 (这可能出于一种偏好,也可能是硬性要求)。 污点(Taint)则相反——它使节点能够排斥一类特定的 Pod。

容忍度(Toleration)是应用于 Pod 上的,允许(但并不要求)Pod 调度到带有与之匹配的污点的节点上。

污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod,是不会被该节点接受的。

概念

您可以使用命令 kubectl taint 给节点增加一个污点。比如,

kubectl taint nodes node1 key1=value1:NoSchedule

给节点 node1 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 node1 这个节点。

若要移除上述命令所添加的污点,你可以执行:

kubectl taint nodes node1 key1=value1:NoSchedule-

您可以在 PodSpec 中定义 Pod 的容忍度。 下面两个容忍度均与上面例子中使用 kubectl taint 命令创建的污点相匹配, 因此如果一个 Pod 拥有其中的任何一个容忍度都能够被分配到 node1

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoSchedule"

这里是一个使用了容忍度的 Pod:

[pods/pod-with-toleration.yaml ]

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  tolerations:
  - key: "example-key"
    operator: "Exists"
    effect: "NoSchedule"

operator 的默认值是 Equal

一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:

  • 如果 operatorExists (此时容忍度不能指定 value),或者
  • 如果 operatorEqual ,则它们的 value 应该相等

说明:

存在两种特殊情况:

如果一个容忍度的 key 为空且 operator 为 Exists, 表示这个容忍度与任意的 key 、value 和 effect 都匹配,即这个容忍度能容忍任意 taint。

如果 effect 为空,则可以与所有键名 key1 的效果相匹配。

上述例子中 effect 使用的值为 NoSchedule,您也可以使用另外一个值 PreferNoSchedule。 这是“优化”或“软”版本的 NoSchedule —— 系统会 尽量 避免将 Pod 调度到存在其不能容忍污点的节点上, 但这不是强制的。effect 的值还可以设置为 NoExecute,下文会详细描述这个值。

您可以给一个节点添加多个污点,也可以给一个 Pod 添加多个容忍度设置。 Kubernetes 处理多个污点和容忍度的过程就像一个过滤器:从一个节点的所有污点开始遍历, 过滤掉那些 Pod 中存在与之相匹配的容忍度的污点。余下未被过滤的污点的 effect 值决定了 Pod 是否会被分配到该节点,特别是以下情况:

  • 如果未被过滤的污点中存在至少一个 effect 值为 NoSchedule 的污点, 则 Kubernetes 不会将 Pod 分配到该节点。
  • 如果未被过滤的污点中不存在 effect 值为 NoSchedule 的污点, 但是存在 effect 值为 PreferNoSchedule 的污点, 则 Kubernetes 会 尝试不将 Pod 分配到该节点。
  • 如果未被过滤的污点中存在至少一个 effect 值为 NoExecute 的污点, 则 Kubernetes 不会将 Pod 分配到该节点(如果 Pod 还未在节点上运行), 或者将 Pod 从该节点驱逐(如果 Pod 已经在节点上运行)。

例如,假设您给一个节点添加了如下污点

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule

假定有一个 Pod,它有两个容忍度:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

在这种情况下,上述 Pod 不会被分配到上述节点,因为其没有容忍度和第三个污点相匹配。 但是如果在给节点添加上述污点之前,该 Pod 已经在上述节点运行, 那么它还可以继续运行在该节点上,因为第三个污点是三个污点中唯一不能被这个 Pod 容忍的。

通常情况下,如果给一个节点添加了一个 effect 值为 NoExecute 的污点, 则任何不能忍受这个污点的 Pod 都会马上被驱逐, 任何可以忍受这个污点的 Pod 都不会被驱逐。 但是,如果 Pod 存在一个 effect 值为 NoExecute 的容忍度指定了可选属性 tolerationSeconds 的值,则表示在给节点添加了上述污点之后, Pod 还能继续在节点上运行的时间。例如,

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

个 effect 值为 NoExecute 的容忍度指定了可选属性 tolerationSeconds 的值,则表示在给节点添加了上述污点之后, Pod 还能继续在节点上运行的时间。例如,

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

这表示如果这个 Pod 正在运行,同时一个匹配的污点被添加到其所在的节点, 那么 Pod 还将继续在节点上运行 3600 秒,然后被驱逐。 如果在此之前上述污点被删除了,则 Pod 不会被驱逐。

Mstart上的污点

[root@master manifest]# kubectl describe node master.example.com
..........以上多行省略
Taints:             node-role.kubernetes.io/master:NoSchedule //拒绝调度
..........以下多行省略

实例

NoSchedule: 一定不能调度

PreferNoSchedule: 尽量不要调度

NoExecute: 不仅不调度还驱除,已有pod

//node1添加污点
[root@master manifest]#  kubectl taint nodes node1.example.com disktype:NoSchedule
node/node1.example.com tainted

[root@master manifest]# ls
deploy.yaml  test.yaml
[root@master manifest]# kubectl get pods
No resources found in default namespace.
[root@master manifest]# kubectl apply -f test.yaml 
pod/test created
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          3s
//显示结果都不会到污点主机,因为没有容忍
[root@master manifest]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test   1/1     Running   0          10s   10.244.2.69   node2.example.com   <none>           <none>
//删除
[root@master manifest]#  kubectl taint nodes node1.example.com disktype-
node/node1.example.com untainted
[root@master manifest]# kubectl describe node node1.example.com
....以上多行显示
Taints:             <none>
.....以下多行显示

//配置yaml文件 IfNotPresent污点
[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             <none>
[root@master manifest]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test   1/1     Running   0          27s   10.244.2.70   node2.example.com   <none>           <none>
[root@master manifest]# vim nginx.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
 //一定会跑到node1上面去
[root@master manifest]# kubectl apply -f nginx.yaml 
deployment.apps/web created
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE    IP            NODE                NOMINATED NODE   READINESS GATES
test                   1/1     Running   0          5m5s   10.244.2.70   node2.example.com   <none>           <none>
web-7cf7d6dbc8-88cph   1/1     Running   0          11s    10.244.1.50   node1.example.com   <none>           <none>

[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             <none>
[root@master manifest]# kubectl  taint node node1.example.com node1:NoSchedule
node/node1.example.com tainted
[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             node1:NoSchedule
//IfNotPresent不可被调度,不是驱赶,所以没有改变
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE     IP            NODE                NOMINATED NODE   READINESS GATES
test                   1/1     Running   0          9m27s   10.244.2.70   node2.example.com   <none>           <none>
web-7cf7d6dbc8-88cph   1/1     Running   0          4m33s   10.244.1.50   node1.example.com   <none>           <none>
//删除后,node1就没有任何pod
[root@master manifest]# kubectl delete -f nginx.yaml
[root@master manifest]# kubectl apply -f nginx.yaml 
deployment.apps/web created
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test                   1/1     Running   0          15m   10.244.2.70   node2.example.com   <none>           <none>
web-7cf7d6dbc8-lsrk2   1/1     Running   0          7s    10.244.2.72   node2.example.com   <none>           <none>
//污点改为NoSchedule会驱除本来的pod
[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             node1:NoSchedule
[root@master manifest]# kubectl taint nodes node1.example.com node1-
node/node1.example.com untainted
[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             <none>
[root@master manifest]# kubectl taint nodes node1.example.com node1:NoExecute
node/node1.example.com tainted
[root@master manifest]# kubectl  describe node node1.example.com |grep taint -i
Taints:             node1:NoExecute
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE     IP            NODE                NOMINATED NODE   READINESS GATES
test                   1/1     Running   0          19m     10.244.2.70   node2.example.com   <none>           <none>
web-7cf7d6dbc8-lsrk2   1/1     Running   0          4m10s   10.244.2.72   node2.example.com   <none>           <none>

//tolerations容忍
[root@master manifest]# vim nginx.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
      tolerations:
      - key: node1
        effect: NoExecute
[root@master manifest]# kubectl apply -f nginx.yaml 
deployment.apps/web configured
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS        RESTARTS   AGE     IP            NODE                NOMINATED NODE   READINESS GATES
test                   1/1     Running       0          23m     10.244.2.70   node2.example.com   <none>           <none>
web-7cf7d6dbc8-lsrk2   0/1     Terminating   0          8m16s   10.244.2.72   node2.example.com   <none>           <none>
web-bbb4f7c98-zdnhz    1/1     Running       0          8s      10.244.1.51   node1.example.com   <none>           <none>

nodeName(指定节点)

实例

[root@master manifest]# kubectl apply -f nginx.yaml 
deployment.apps/web created
[root@master manifest]# vim nginx.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
      nodeName: node1.example.com
[root@master manifest]# kubectl get pods -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
web-d7dc966d8-6tbls   1/1     Running   0          6s    10.244.1.52   node1.example.com   <none>           <none>

[root@master manifest]# vim nginx.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
      nodeName: node2.example.com
[root@master manifest]# kubectl apply -f nginx.yaml 
deployment.apps/web configured
[root@master manifest]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
web-7c76cb5bc5-fxsrv   1/1     Running   0          8s    10.244.2.73   node2.example.com   <none>           <none>