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

gstyhher  于 12个月前  发布在  Kubernetes
关注(0)|答案(6)|浏览(107)

我有一个5节点的集群(1-master/4-worker)。是否可以配置一个StatefulSet,让我可以在一个给定的节点上运行一个pod,知道它有足够的容量,而不是让Kubernetes来做这个决定?
比如说,我的StatefulSet创建了4个pod(副本:4)作为myapp-0,myapp-1,myapp-2和myapp-3。现在我需要的是:
myapp-0 pod-- get scheduled over-> worker-1
myapp-1 pod-- get scheduled over-> worker-2
myapp-2 pod-- get scheduled over-> worker-3
myapp-3 pod-- get scheduled over---> worker-4
请让我知道它是否可以以某种方式实现?因为如果我向StatefulSet的pod添加toleration,它将对所有pod都是相同的,并且所有pod都将在匹配污点的单个节点上进行调度。
谢了J

798qvoo8

798qvoo81#

您可以将调度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

字符串
然后,只需在StatefulSet配置文件的规范部分下添加schedulerName: your-scheduler行。
你也可以使用pod affinity:。
示例如下:

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


下面的webserver 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


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

node-1              node-2           node-3
webserver-1     webserver-2          webserver-3
cache-1             cache-2          cache-3


上面的示例使用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


更多关于调度程序的信息:custom-scheduler
看看这篇文章:assigining-pods-kubernetes

aoyhnmkz

aoyhnmkz2#

您可以使用以下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'

字符串
上面的ModRule将监控名为myapp-*的pod的创建,并在部署它们之前将nodeAffinity部分注入到它们的资源清单中。这将指示调度程序将pod调度到标签为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
...


部署上述ModRule后,创建StatefulSet将触发其Pod的创建,该Pod将被ModRule拦截。ModRule将使用Pod的名称动态注入nodeAffinity部分。
如果稍后StatefulSet被删除,再次部署它将导致Pod被调度在与之前相同的节点上。

im9ewurl

im9ewurl3#

您可以使用nodeSelectornode affinity来完成此操作(看看这个指南https://kubernetes.io/docs/concepts/configuration/assign-pod-node/),任何人都可以用来在特定的节点上运行pod。但是如果节点有污点,(限制),则需要为这些节点添加容差(更多内容可以在https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/中找到)。使用这种方法,您可以指定用于pod调度的节点列表,问题是如果你指定了ex. 3个节点,而你有5个pod,那么你就无法控制每个节点上会运行多少个pod。它们会按照kube-schedular进行分发。另一个相关的用例:如果你想在每个指定的节点上运行一个pod,你可以创建一个daemonset,然后使用nodewords选择节点。

tvmytwxo

tvmytwxo4#

看看这个指南https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/然而,你正在寻找的是nodeSelector指令,应该放在pod规范中。

x8diyxa7

x8diyxa75#

您可以使用podAntiAffinity将副本分发到不同的节点。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 4
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: "kubernetes.io/hostname"

字符串
这将在worker 1中部署web-0,在worker 2中部署web-1,在worker 3中部署web-2,在worker 4中部署web-3。

kknvjkwl

kknvjkwl6#

带manifest选项的statefulset:

podManagementPolicy: OrderedReady

字符串

nodeAffinity:                                                                                                     
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 100
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - node1
  - weight: 60
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - node2
  - weight: 20
    preference:
      matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - node3


为我做了一个工作。希望它能帮助任何人。对于更多的工作者/节点添加更多的权重

相关问题