Kubernetes Pod Предупреждение: 1 узел (ы) столкнулся с конфликтом узлов тома

Я пытаюсь настроить кластер kubernetes. У меня есть классы Persistent Volomue, Persistent Volume Claim и Storage, все они настроены и работают, но когда я хочу создать модуль из развертывания, модуль создается, но он зависает в состоянии ожидания. После описания я получаю только это предупреждение "1 узел (ы) имел конфликт сродства узла тома". Может кто-нибудь сказать мне, что мне не хватает в моей конфигурации тома?

apiVersion: v1
kind: PersistentVolume
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: mariadb-pv0
  name: mariadb-pv0
spec:
  volumeMode: Filesystem
  storageClassName: local-storage
  local:
    path: "/home/gtcontainer/applications/data/db/mariadb"
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 2Gi
  claimRef:
    namespace: default
    name: mariadb-claim0
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/cvl-gtv-42.corp.globaltelemetrics.eu
            operator: In
            values:
            - master

status: {}

18 ответов

Ошибка "конфликт сродства узла тома" возникает, когда постоянный том утверждает, что используемый модуль запланирован в разных зонах, а не в одной зоне, и поэтому фактический модуль не может быть запланирован, поскольку он не может подключиться к тому из другая зона. Чтобы проверить это, вы можете увидеть детали всех постоянных томов. Чтобы проверить это, сначала получите ваши PVC:

$ kubectl get pvc -n <namespace>

Затем получите сведения о постоянных томах (не утверждения о томах)

$  kubectl get pv

Найдите PV, которые соответствуют вашим PVC и опишите их

$  kubectl describe pv <pv1> <pv2>

Вы можете проверить Source.VolumeID для каждого из PV, скорее всего, это будут разные зоны доступности, поэтому ваш модуль выдаст ошибку привязки. Чтобы исправить это, создайте класс хранения для отдельной зоны и используйте этот класс хранения в своем PVC.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: region1storageclass
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  encrypted: "true" # if encryption required
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: failure-domain.beta.kubernetes.io/zone
    values:
    - eu-west-2b # this is the availability zone, will depend on your cloud provider
    # multi-az can be added, but that defeats the purpose in our scenario

0. Если вы не нашли решение в других ответах...

В нашем случае ошибка произошла в кластере AWS EKS, только что подготовленном с помощью Pulumi (см. полный исходный код здесь ). Эта ошибка сводила меня с ума, так как я ничего не менял, просто создал, как описано в документации Buildpacks Tekton:

      apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-source-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi

Я больше ничего не менял в конфигурации EKS по умолчанию, а также ничего не добавлял/не менял (на самом деле я даже не знал, как это сделать). Поскольку настройка EKS по умолчанию, кажется, полагается на 2 узла, я получил ошибку:

      0/2 nodes are available: 2 node(s) had volume node affinity conflict.

Прочитав ответ Сонака Роя, я впервые понял, что делать, но не знал, как это сделать . Итак, для заинтересованных людей вот все мои шаги по устранению ошибки :

1. Проверьте метки узлов EKS.

Как описано в разделе Statefull applications в этом посте два узла выделяются в других зонах доступности AWS в качестве постоянного тома (PV), который создается путем применения нашего PersistendVolumeClaimописано выше.

Чтобы проверить это, вам нужно изучить/описать свои узлы с помощью kubectl get nodes:

      $ kubectl get nodes
NAME                                             STATUS   ROLES    AGE     VERSION
ip-172-31-10-186.eu-central-1.compute.internal   Ready    <none>   2d16h   v1.21.5-eks-bc4871b
ip-172-31-20-83.eu-central-1.compute.internal    Ready    <none>   2d16h   v1.21.5-eks-bc4871b

а потом взгляните на Labelраздел с использованием kubectl describe node <node-name>:

      $ kubectl describe node ip-172-77-88-99.eu-central-1.compute.internal
Name:               ip-172-77-88-99.eu-central-1.compute.internal
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=t2.medium
                    beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/region=eu-central-1
                    failure-domain.beta.kubernetes.io/zone=eu-central-1b
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=ip-172-77-88-99.eu-central-1.compute.internal
                    kubernetes.io/os=linux
                    node.kubernetes.io/instance-type=t2.medium
                    topology.kubernetes.io/region=eu-central-1
                    topology.kubernetes.io/zone=eu-central-1b
Annotations:        node.alpha.kubernetes.io/ttl: 0
...

В моем случае узел ip-172-77-88-99.eu-central-1.compute.internalимеет failure-domain.beta.kubernetes.io/regionопределяется как eu-central-1и аз с до .

А другой узел определяет az :

      $ kubectl describe nodes ip-172-31-10-186.eu-central-1.compute.internal
Name:               ip-172-31-10-186.eu-central-1.compute.internal
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=t2.medium
                    beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/region=eu-central-1
                    failure-domain.beta.kubernetes.io/zone=eu-central-1a
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=ip-172-31-10-186.eu-central-1.compute.internal
                    kubernetes.io/os=linux
                    node.kubernetes.io/instance-type=t2.medium
                    topology.kubernetes.io/region=eu-central-1
                    topology.kubernetes.io/zone=eu-central-1a
Annotations:        node.alpha.kubernetes.io/ttl: 0
...

2. Проверьте topology.kubernetes.ioполе

Теперь мы должны проверить автоматически предоставленный после того, как мы вручную применили наш файл . Использовать kubectl get pv:

      $ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                           STORAGECLASS   REASON   AGE
pvc-93650993-6154-4bd0-bd1c-6260e7df49d3   1Gi        RWO            Delete           Bound    default/buildpacks-source-pvc   gp2                     21d

с последующим kubectl describe pv <pv-name>

      $ kubectl describe pv pvc-93650993-6154-4bd0-bd1c-6260e7df49d3
Name:              pvc-93650993-6154-4bd0-bd1c-6260e7df49d3
Labels:            topology.kubernetes.io/region=eu-central-1
                   topology.kubernetes.io/zone=eu-central-1c
Annotations:       kubernetes.io/createdby: aws-ebs-dynamic-provisioner
...

Был настроен с меткой topology.kubernetes.io/zoneв az, из-за чего наши поды жалуются, что не находят своего тома — ведь они находятся в совершенно другом az!

3. Добавить в

Как указано в документации Kubernetes, одним из решений проблемы является добавление конфигурации в файл . Если вы уже подготовили кластер EKS, как я, вам нужно получить уже определенный с помощью

      kubectl get storageclasses gp2 -o yaml

Сохраните его в файл с именем и добавьте раздел, соответствующий вашему узлу. failure-domain.beta.kubernetes.ioтакие ярлыки:

      allowedTopologies:
- matchLabelExpressions:
  - key: failure-domain.beta.kubernetes.io/zone
    values:
    - eu-central-1a
    - eu-central-1b

The allowedTopologiesконфигурация определяет, что failure-domain.beta.kubernetes.io/zoneпринадлежащий PersistentVolumeдолжен быть либо в eu-central-1aили же eu-central-1b- нет eu-central-1c!

Полный storage-class.ymlвыглядит так:

      apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2
parameters:
  fsType: ext4
  type: gp2
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: failure-domain.beta.kubernetes.io/zone
    values:
    - eu-central-1a
    - eu-central-1b

Примените расширенную конфигурацию к своему кластеру EKS с помощью

      kubectl apply -f storage-class.yml

4. Удалите, добавьте к нему и повторно примените его

Чтобы все снова заработало, нам нужно удалить первый.

Чтобы сопоставить с нашим ранее определить StorageClassнам нужно добавить storageClassName: gp2к определению PersistendVolumeClaim в нашем pvc.yml:

      apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-source-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  storageClassName: gp2

Наконец, повторно примените PersistentVolumeClaimс kubectl apply -f pvc.yml. Это должно устранить ошибку.

Есть несколько вещей, которые могут вызвать эту ошибку:

  1. Узел не помечен правильно. У меня была эта проблема в AWS, когда у моего рабочего узла не было соответствующих меток (хотя у мастера они были), например:

    failure-domain.beta.kubernetes.io/region=us-east-2

    failure-domain.beta.kubernetes.io/zone=us-east-2c

    После исправления узла с метками ошибка "1 узел (ы) имела конфликт сродства узла тома" исчезла, поэтому PV, PVC с модулем были успешно развернуты. Значение этих меток зависит от поставщика облачных услуг. По сути, именно облачный провайдер (с параметром -cloud-provider, определенным в cube-controller, API-server, kubelet) устанавливает эти метки. Если соответствующие метки не установлены, проверьте правильность интеграции с CloudProvider. Я использовал kubeadm, поэтому его сложно установить, но с другими инструментами, например, kops, он работает сразу.

  2. Исходя из определения PV и использования поля nodeAffinity, вы пытаетесь использовать локальный том (см. Ссылку на описание локального тома, официальные документы), а затем убедитесь, что вы установили "Поле NodeAffinity" таким образом (это работало в моем дело на AWS):

    nodeAffinity:

         required:
          nodeSelectorTerms:
           - matchExpressions:
             - key: kubernetes.io/hostname
               operator: In
               values:
               - my-node  # it must be the name of your node(kubectl get nodes)
    

Так что после создания ресурса и запуска описать его там он будет выглядеть так:

         Required Terms:  
                    Term 0:  kubernetes.io/hostname in [your node name]
  1. Определение StorageClass (названное local-storage, которое здесь не публикуется) должно быть создано с VolumeBindingMode, установленным в WaitForFirstConsumer, чтобы локальное хранилище работало должным образом. Обратитесь к примеру здесь, локальное описание класса хранения, официальный документ, чтобы понять причину этого.

В AWS EKS вы также можете столкнуться с этой проблемой, если забудете установить надстройку EKS aws-ebs-csi-driver перед обновлением кластера Kubernetes с версии 1.22 до версии 1.23.

Вы также можете установить дополнение после обновления (хотя и с некоторыми перерывами в обслуживании).

Обязательно ознакомьтесь с часто задаваемыми вопросами по AWS: https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi-migration-faq.html .

"1 узел (ы) имел объем сродство узла конфликт" ошибка создается с помощью планировщика, поскольку он не может планировать свой стручок узла, который согласуется сpersistenvolume.spec.nodeAffinity в вашем PersistentVolume (PV).

Другими словами, вы говорите в своем PV, что под, использующий этот PV, должен быть запланирован узел с меткой kubernetes.io/cvl-gtv-42.corp.globaltelemetrics.eu = master, но по какой-то причине это невозможно.

Могут быть разные причины, по которым ваш модуль не может быть назначен на такой узел:

  • У пода есть сходства узлов, подов и т. Д., Которые конфликтуют с целевым узлом.
  • Целевой узел испорчен
  • Целевой узел достиг предельного количества пакетов на узел.
  • Нет узла с данной меткой

Место для начала поиска причины - определение узла и модуля.

После некоторого расследования, вызывающего головную боль, необходимо проверить несколько вещей:

Лазурь:

  • В вашем кластере выбрано более одной зоны? (зона 1, 2, 3)
  • У вашего класса хранения по умолчанию есть правильный поставщик хранилища?(ZRS Zone-Redundant-Storage)

Если не:

  • измените класс хранения, чтобы использовать правильный поставщик
  • создать резервную копию данных PV
  • остановить развертывание, использующее PVC (установить для реплик значение 0)
  • удалите PVC и убедитесь, что соответствующий PV удален.
  • повторно применить yaml конфигурации PVC (без ссылки на старое имя класса хранения)
  • запустите развертывание, использующее PVC (установите для реплик значение 1)
  • вручную импортировать резервные данные

Пример класса хранилища для AKS:

      allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: zone-redundant-storage
parameters:
  skuname: StandardSSD_ZRS
provisioner: disk.csi.azure.com
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

ГКЭ:

  • В вашем кластере выбрано более одной зоны? (Зона А, В, С)
  • Есть ли в вашем классе хранения по умолчанию параметр типа репликации? (тип репликации: региональный-PD)

Если не:

  • измените класс хранения, чтобы использовать правильные параметры
  • создать резервную копию данных PV
  • остановить развертывание, использующее PVC (установить для реплик значение 0)
  • удалите PVC и убедитесь, что соответствующий PV удален.
  • повторно применить yaml конфигурации PVC (без ссылки на старое имя класса хранения)
  • запустите развертывание, использующее PVC (установите для реплик значение 1)
  • вручную импортировать резервные данные

Пример класса хранилища для GKE:

      kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard-regional-pd-storage
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-standard
  replication-type: regional-pd
volumeBindingMode: WaitForFirstConsumer

После этого PV будет иметь избыточность в выбранных зонах, что позволит модулю получать доступ к PV с других узлов в разных зонах.

У меня это произошло на GKE после обновления до k8s v1.25. В моем случае ничего из вышеперечисленного не сработало, поэтому я решил клонировать том, чтобы не потерять данные.

Этот пост побудил меня включить CSI-драйвер постоянного диска Compute Engine , который после включения решил мою проблему.

Отличный ответ Сонака Роя. У меня был такой же случай, когда PV создавался в другой зоне по сравнению с узлом, который должен был его использовать. Решение, которое я применил, было основано на ответе Сонака, только в моем случае было достаточно указать класс хранилища без списка "allowedTopologies", например:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cloud-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
volumeBindingMode: WaitForFirstConsumer

Убедитесь, что узел kubernetes имеет требуемую метку. Вы можете проверить метки узлов, используя:


Один из узлов должен показать вам имя постоянного тома , с которым связан ваш модуль .


Этапы проверки:

  1. Опишите ваш постоянный том:
      kubectl describe pv postgres-br-proxy-pv-0

Выход:

      ...
Node Affinity:
  Required Terms:
    Term 0:        postgres-br-proxy in [postgres-br-proxy-pv-0]
...
  1. Показать метки узлов:
      kubectl get nodes --show-labels

Выход:

      NAME    STATUS   ROLES    AGE   VERSION   LABELS
node3   Ready    <none>   19d   v1.17.6   postgres-br-proxy=postgres-br-proxy-pv-0

Если вы не получаете постоянную метку тома на узле , который использует ваш модуль, модуль не будет запланирован.

В моем случае основная причина заключалась в том, что постоянный том находится в us-west-2c, а новые рабочие узлы перезапускаются в us-west-2a и us-west-2b. Решение состоит в том, чтобы либо иметь больше рабочих узлов, чтобы они находились в большем количестве зон, либо удалить / расширить привязку узлов для приложения, чтобы большее количество рабочих узлов соответствовало требованиям для привязки к постоянному тому.

Другой случай от GCP GKE. Предположим, вы используете региональный кластер и создали два PVC. Оба были созданы в разных зонах (вы не заметили).

На следующем шаге вы пытаетесь запустить модуль, в котором оба PVC будут установлены в один модуль. Вы должны запланировать этот модуль для определенного узла в определенной зоне, но поскольку ваши тома находятся в разных зонах, k8s не сможет запланировать это, и вы получите следующую проблему.

Например - два простых PVC в региональном кластере (узлы в разных зонах):

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: disk-a
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: disk-b
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Следующий простой модуль:

apiVersion: v1
kind: Pod
metadata:
  name: debug
spec:
  containers:
    - name: debug
      image: pnowy/docker-tools:latest
      command: [ "sleep" ]
      args: [ "infinity" ]
      volumeMounts:
        - name: disk-a
          mountPath: /disk-a
        - name: disk-b
          mountPath: /disk-b
  volumes:
    - name: disk-a
      persistentVolumeClaim:
        claimName: disk-a
    - name: disk-b
      persistentVolumeClaim:
        claimName: disk-b

Наконец, в результате может случиться так, что k8s не сможет запланировать pod, потому что тома находятся в разных зонах.

Почти та же проблема, описанная здесь... https://github.com/kubernetes/kubernetes/issues/61620

"Если вы используете локальные тома, и узел выходит из строя, ваш модуль не может быть перенесен на другой узел. Он должен быть запланирован на тот же узел. Это предостережение об использовании локального хранилища, ваш модуль навсегда привязан к одному конкретному узел."

Скорее всего, вы просто сократили количество узлов в кластере кубернетов, и некоторые «регионы» больше не доступны ...

Кое-что стоит упомянуть ... если ваш модуль будет находиться в другой зоне, чем постоянный том, тогда:

  • время доступа к вашему диску значительно снизится (ваше локальное постоянное хранилище больше не является локальным - даже с гипербыстрыми оптоволоконными соединениями Amazon / Google он все еще проходит через центры обработки данных)
  • вы будете платить за «межрегиональную сеть» (в вашем счете AWS это что-то, что входит в «EC2-other», и только после детализации счета Aws вы можете это заметить)

В моем случае я работал сDocker DesktopнаWindows, и мой пример использовал толькоdocker-desktopзначение как имя узла. поэтому настройка очень важна.

я добавилminikubeпоскольку я использовал один узел. их может быть больше, если будут добавлены дополнительные узлы, напримерminikube-m02.

      spec:
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - minikube

kubectl get nodeдолжно быть достаточно, чтобы указать имена узлов.

Одной из причин этого является то, что у вас есть определение, подобное приведенному ниже (Kafka Zookeeper в этом примере), которое использует несколько pvc для одного контейнера. Если они попадут на разные узлы, вы получите что-то вроде следующего: ..volume node affinity conflict. Решение здесь состоит в том, чтобы использовать одно определение ПВХ и использовать subPathна volumeMount.

Проблема

            ...
      volumeMounts:
        - mountPath: /data
          name: kafka-zoo-data
        - mountPath: /datalog
          name: kafka-zoo-datalog
  restartPolicy: Always
  volumes:
    - name: kafka-zoo-data
      persistentVolumeClaim:
        claimName: "zookeeper-data"
    - name: kafka-zoo-datalog
      persistentVolumeClaim:
        claimName: "zookeeper-datalog"

Решено

            ...
      volumeMounts:
        - mountPath: /data
          subPath: data
          name: kafka-zoo-data
        - mountPath: /datalog
          subPath: datalog
          name: kafka-zoo-data
  restartPolicy: Always
  volumes:
    - name: kafka-zoo-data
      persistentVolumeClaim:
        claimName: "zookeeper-data"

Другая причина возникновения этой ошибки — наличие нескольких узлов, использующих taints. В некоторых выпусках компонент DaemonSet драйвера EBS CSI по умолчанию не допускает всех испорченных данных; если вы пытаетесь запланировать Pod на узел с taint и из-за этого taint он не имеетPod работает, вы получаете эту ошибку.

Я запускал кластер k8s на AWS. В моем случае PV описывался как

      │ Node Affinity:                                                                           │
│   Required Terms:                                                                        │
│     Term 0:        topology.kubernetes.io/zone in [ap-southeast-1a]                      │
│                    topology.kubernetes.io/region in [ap-southeast-1]

Но когда я добавил

      topology.ebs.csi.aws.com/zone=ap-southeast-1a
topology.ebs.csi.aws.com/region=ap-southeast-1

как метки к моему узлу, контейнер начал создаваться. Должен работать для вас, если вы работаете на AWS.

Мой случай был posthog (самообслуживание)

В моем случае я просто удалилсвязанный с конфликтома затем воссоздал стручок.

Другие вопросы по тегам