是否可以将 StatefulSet 的 pod 分配给 Kubernetes 集群的特定节点?

Jar*_*aws 5 kubernetes kubernetes-statefulset kubernetes-pod

我有一个 5 节点集群(1-master/4-worker)。是否可以配置一个 StatefulSet,在那里我可以让一个 pod(s) 在给定节点上运行,因为它知道它有足够的容量而不是 Kubernetes 调度程序做出这个决定?

假设,我的 StatefulSet 创建了 4 个 pod(副本:4)作为 myapp-0、myapp-1、myapp-2 和 myapp-3。现在我要找的是:

myapp-0 pod--被安排结束---> worker-1

myapp-1 pod--被调度结束---> worker-2

myapp-2 pod--被调度结束---> worker-3

myapp-3 pod--被调度结束---> worker-4

请让我知道它是否可以以某种方式实现?因为如果我向 StatefulSet 的 Pod 添加一个容忍度,它对所有 Pod 都是相同的,并且所有这些 Pod 都将在与污点匹配的单个节点上进行调度。

谢谢,J

Mal*_*ata 5

您可以将调度任意 Pod 子集的责任委派给您自己的自定义调度程序,这些调度程序与默认 Kubernetes 调度程序一起运行,或代替默认 Kubernetes 调度程序运行。

您可以编写自己的自定义调度程序。自定义调度程序可以用任何语言编写,可以根据需要简单或复杂。下面是一个用 Bash 编写的自定义调度程序的非常简单的例子,它随机分配一个节点。请注意,您需要将它与 kubectl 代理一起运行才能工作。

SERVER='localhost:8001'

while true;

do

    for PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName == "my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"')

;

    do

        NODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"'))


        NUMNODES=${#NODES[@]}

        CHOSEN=${NODES[$[$RANDOM % $NUMNODES]]}

        curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1", "kind": "Binding", "metadata": {"name": "'$PODNAME'"}, "target": {"apiVersion": "v1", "kind"

: "Node", "name": "'$CHOSEN'"}}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/

        echo "Assigned $PODNAME to $CHOSEN"

    done

    sleep 1

done
Run Code Online (Sandbox Code Playgroud)

然后只是在规范部分下的 StatefulSet 配置文件中,您将不得不添加schedulerName: your-scheduler行。

您还可以使用pod 关联: .

例子:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cache
spec:
  selector:
    matchLabels:
      app: store
  replicas: 3
  template:
    metadata:
      labels:
        app: store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis:3.2-alpine
Run Code Online (Sandbox Code Playgroud)

网络服务器 statefuset 的以下 yaml 片段配置了 podAntiAffinity 和 podAffinity。这会通知调度程序它的所有副本都将与具有选择器标签app=store 的pod 位于同一位置。这也将确保每个 Web 服务器副本不会位于单个节点上。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: web-store
  replicas: 3
  template:
    metadata:
      labels:
        app: web-store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-store
            topologyKey: "kubernetes.io/hostname"
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: web-app
        image: nginx:1.12-alpine
Run Code Online (Sandbox Code Playgroud)

如果我们创建上述两个部署,我们的三节点集群应该如下所示。

node-1              node-2           node-3
webserver-1     webserver-2          webserver-3
cache-1             cache-2          cache-3
Run Code Online (Sandbox Code Playgroud)

上面的例子使用 PodAntiAffinity 规则和 topologyKey:"kubernetes.io/hostname"来部署 redis 集群,以便没有两个实例位于同一主机上

您可以简单地定义特定 pod 的三个副本并定义特定的 pod 配置文件 egg.:有标签:nodeName,这是节点选择约束的最简单形式,但由于其局限性,通常不使用它。nodeName 是 PodSpec 的一个字段。如果它不为空,调度程序会忽略 pod,运行在命名节点上的 kubelet 会尝试运行 pod。因此,如果 PodSpec 中提供了 nodeName,则它优先于上述节点选择方法。

以下是使用 nodeName 字段的 pod 配置文件示例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: kube-worker-1
Run Code Online (Sandbox Code Playgroud)

有关调度程序的更多信息:custom-scheduler

看看这篇文章:assigining-pods-kubernetes


vas*_*lvk 5

您可以使用以下KubeMod ModRule:

apiVersion: api.kubemod.io/v1beta1
kind: ModRule
metadata:
  name: statefulset-pod-node-affinity
spec:
  type: Patch

  match:
    # Select pods named myapp-xxx.
    - select: '$.kind'
      matchValue: Pod
    - select: '$.metadata.name'
      matchRegex: myapp-.*

  patch:
    # Patch the selected pods such that their node affinity matches nodes that contain a label with the name of the pod.
    - op: add
      path: /spec/affinity/nodeAffinity/requiredDuringSchedulingIgnoredDuringExecution
      value: |-
        nodeSelectorTerms:
          - matchExpressions:
            - key: accept-pod/{{ .Target.metadata.name }}
              operator: In
              values:
                - 'true'
Run Code Online (Sandbox Code Playgroud)

上面的 ModRule 将监视名为 pod 的创建,并在部署之前myapp-*将一个部分注入到其资源清单中。nodeAffinity这将指示调度程序将 pod 调度到标签设置为 的accept-pod/<pod-name>节点true

然后,您可以通过向节点添加标签来将未来的 pod 分配给节点:

kubectl label node worker-1 accept-pod/myapp-0=true
kubectl label node worker-2 accept-pod/myapp-1=true
kubectl label node worker-3 accept-pod/myapp-2=true
...
Run Code Online (Sandbox Code Playgroud)

上述ModRule部署后,创建StatefulSet会触发其Pod的创建,这些Pod会被ModRule拦截。ModRule 将nodeAffinity使用 pod 的名称动态注入该部分。

如果稍后删除 StatefulSet,再次部署它会导致 pod 被调度到与之前相同的节点上。


cpe*_*z08 0

请查看此指南https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ 但是,您要查找的是nodeSelector应放置在 pod 规范中的指令。