Можно ли назначить модуль StatefulSet указанному c узлу кластера Kubernetes? - PullRequest
2 голосов
/ 15 февраля 2020

У меня кластер из 5 узлов (1-мастер / 4-работник). Можно ли настроить StatefulSet, в котором я могу создать модуль (ы) для работы на данном узле, зная, что он имеет достаточную емкость, а Kubernetes Scheduler принимает это решение?

Допустим, мой StatefulSet создает 4 модуля (реплики). 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, он будет одинаковым для всех модулей, и все они будут запланированы на одном узле, соответствующем заражению.

Спасибо, J

Ответы [ 4 ]

0 голосов
/ 17 февраля 2020

Вы можете делегировать ответственность за планирование произвольных подмножеств модулей в свой собственный (-ые) планировщик (-и), который (-ые) выполняет (-ы) рядом с планировщиком 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: .

Пример:

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

В приведенном ниже фрагменте yaml состояния statefuset веб-сервера настроены podAntiAffinity и podAffinity. , Это сообщает планировщику, что все его реплики должны быть расположены вместе с модулями с меткой селектора app = store . Это также гарантирует, что каждая реплика веб-сервера не будет размещаться на одном узле.

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, чтобы на одном хосте не было двух экземпляров

Вы можете просто определить три реплики с указанием c pod и определите конкретный файл конфигурации pod, egg .: есть метка: nodeName , которая является самой простой формой ограничения выбора узла, но из-за его ограничений она обычно не используется. nodeName - это поле PodSpe c. Если он не пустой, планировщик игнорирует модуль, и кублет, запущенный на указанном узле, пытается запустить модуль. Таким образом, если имя узла указано в PodSpe c, оно имеет приоритет над вышеуказанными методами для выбора узла.

Вот пример файла конфигурации модуля, использующего поле nodeName:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: kube-worker-1

Дополнительная информация о планировщике: настраиваемый планировщик .

Посмотрите эту статью: assigining-pods-kubernetes .

0 голосов
/ 16 февраля 2020

Вы можете сделать это, используя nodeSelector и node affinity (взгляните на это руководство https://kubernetes.io/docs/concepts/configuration/assign-pod-node/), любой может быть использован для запуска модулей на указанных c узлах. Но если у узла есть проблемы (ограничения), то вам нужно добавить допуски для этих узлов (больше можно найти здесь https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/). Используя этот подход, вы можете указать список узлов, которые будут использоваться для планирования вашего модуля, подвох, если вы укажите для ex. 3 узла, и у вас есть 5 модулей, тогда вы не можете контролировать, сколько модулей будет работать на каждом из этих узлов. Они распределяются согласно кубе-расписанию. Еще один важный вариант использования: если вы хотите запустить один модуль в каждом из указанных узлов, вы можете создать набор демонов и выбрать узлы, используя nodeSelector.

0 голосов
/ 16 февраля 2020

Вы можете использовать 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"

Это приведет к развертыванию web-0 в worker1, web-1 в worker2, web-2 в worker3 и web-3 в worker4.

0 голосов
/ 16 февраля 2020

взгляните на это руководство https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ однако, то, что вы ищете, это директива nodeSelector, которая должна быть помещена в модуль c.

...