невозможно развернуть стек EFK на кубернетах (с помощью kubespray)

Я пытаюсь развернуть стек EFK в производственном кластере kubernetes (установленном с помощью kubespray), у нас есть 3 узла, 1 мастер + 2 рабочих, мне нужно использовать elasticsearch в качестве набора состояний и использовать локальную папку на главном узле для хранения журналов (локальный хранилище для настойчивости), моя конфигурация:

kind: Namespace
apiVersion: v1
metadata:
  name: kube-logging

---
kind: Service
apiVersion: v1
metadata:
  name: elasticsearch
  namespace: kube-logging
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  clusterIP: None
  ports:
    - port: 9200
      name: rest
    - port: 9300
      name: inter-node
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
  namespace: kube-logging
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
  namespace: kube-logging
spec:
  storageClassName: local-storage
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  hostPath:
    path: /tmp/elastic
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: es-cluster
  namespace: kube-logging
spec:
  serviceName: elasticsearch
  replicas: 2
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
        resources:
            limits:
              cpu: 1000m
              memory: 2Gi
        ports:
        - containerPort: 9200
          name: rest
          protocol: TCP
        - containerPort: 9300
          name: inter-node
          protocol: TCP
        volumeMounts:
        - name: data
          mountPath: /usr/share/elasticsearch/data
        env:
          - name: cluster.name
            value: k8s-logs
          - name: node.name
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: discovery.seed_hosts
            value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
          - name: cluster.initial_master_nodes
            value: "es-cluster-0,es-cluster-1,es-cluster-2"
          - name: ES_JAVA_OPTS
            value: "-Xms512m -Xmx512m"
      initContainers:
      - name: fix-permissions
        image: busybox
        command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: data
          mountPath: /usr/share/elasticsearch/data
      - name: increase-vm-max-map
        image: busybox
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      - name: increase-fd-ulimit
        image: busybox
        command: ["sh", "-c", "ulimit -n 65536"]
        securityContext:
          privileged: true
  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: local-storage
      resources:
        requests:
          storage: 5Gi
---

так что это была моя конфигурация, но когда она применяется, один из двух модулей для Elasticsearch все еще находится в состоянии ожидания. когда я описал kubectl для этого модуля, я получил следующую ошибку: «1 узел (ы) не нашел доступных постоянных томов для привязки»

моя конфигурация верна? должен ли я использовать PV + storageclass + volumeClaimTemplates? заранее спасибо.

Это мои результаты:

    [root@node1 nex]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                            STORAGECLASS    REASON   AGE
my-pv   5Gi        RWO            Retain           Bound    kube-logging/data-es-cluster-0   local-storage            24m
[root@node1 nex]# kubectl get pvc
NAME                STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
data-es-cluster-0   Bound     my-pv    5Gi        RWO            local-storage   24m
data-es-cluster-1   Pending                                      local-storage   23m
[root@node1 nex]# kubectl describe pvc data-es-cluster-0
Name:          data-es-cluster-0
Namespace:     kube-logging
StorageClass:  local-storage
Status:        Bound
Volume:        my-pv
Labels:        app=elasticsearch
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      5Gi
Access Modes:  RWO
VolumeMode:    Filesystem
Mounted By:    es-cluster-0
Events:
  Type    Reason                Age   From                         Message
  ----    ------                ----  ----                         -------
  Normal  WaitForFirstConsumer  24m   persistentvolume-controller  waiting for first consumer to be created before binding
[root@node1 nex]# kubectl describe pvc data-es-cluster-1
Name:          data-es-cluster-1
Namespace:     kube-logging
StorageClass:  local-storage
Status:        Pending
Volume:
Labels:        app=elasticsearch
Annotations:   <none>
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode:    Filesystem
Mounted By:    es-cluster-1
Events:
  Type    Reason                Age                   From                         Message
  ----    ------                ----                  ----                         -------
  Normal  WaitForFirstConsumer  4m12s (x82 over 24m)  persistentvolume-controller  waiting for first consumer to be created before binding
[root@node1 nex]#

person abdel2020    schedule 08.06.2020    source источник
comment
поделиться выводом kubectl получить pvc, kubectl описать pvc pvcname   -  person Arghya Sadhu    schedule 08.06.2020
comment
привет @ArghyaSadhu, я отредактировал свой вопрос, добавив результаты по запросу, заранее спасибо.   -  person abdel2020    schedule 08.06.2020


Ответы (1)


моя конфигурация верна? должен ли я использовать PV + storageclass + volumeClaimTemplates? заранее спасибо.

Помимо того, что @Arghya Sadhu уже предложил в своем ответе, я хотел бы выделить еще одну вещь в вашей текущей настройке.

Если вас устраивает тот факт, что ваш Elasticsearch Pods будет запланирован только на одном конкретном узле (в вашем случае на главном узле), вы все равно можете использовать локальный тип тома. Однако не путайте его с hostPath. Я заметил в вашем PV определении, что вы использовали hostPath ключ, так что есть вероятность, что вы не полностью осведомлены о различиях между этими двумя концепциями. Хотя они очень похожи, тип local имеет большие возможности и некоторые неоспоримые преимущества. более hostPath.

Как вы можете прочитать в документации:

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

Это означает, что помимо определенного каталога вы также можете смонтировать локальный диск или раздел (/dev/sdb, /dev/sdb5 и т. Д.). Это может быть, например, раздел LVM со строго определенной емкостью. Имейте в виду, что когда дело доходит до монтирования локального каталога, вы не можете обеспечить объем, который может быть фактически использован, поэтому даже если вы определите, скажем, 5Gi, журналы могут быть записаны в ваш локальный каталог, даже если это значение превышено. Но это не относится к logical volume, поскольку вы можете определить его емкость и убедиться, что он не будет использовать больше дискового пространства, чем вы ему предоставили.

Второе отличие состоит в том, что:

По сравнению с hostPath томами, local тома можно использовать надежным и переносимым образом без ручного планирования Pod'ов для узлов, поскольку система знает об ограничениях узла тома, глядя на сходство узлов в PersistentVolume.

В данном случае это PersistentVolume, где вы определяете свою привязку к узлу, поэтому любой Pod (он может Pod управляться вашим StatefulSet), который впоследствии использует local-storage класс хранения, и соответствующий PersistenVolume будет автоматически запланирован справа узел.

Как вы можете прочитать далее, nodeAffinity на самом деле является обязательным полем в таких PV:

PersistentVolume nodeAffinity требуется при использовании локальных томов. Это позволяет планировщику Kubernetes правильно планировать поды с использованием локальных томов для правильного узла.

Насколько я понимаю, ваш кластер Kubernetes настроен локально / локально. В этом случае NFS может быть правильным выбором.

Если вы использовали какую-то облачную среду, вы можете использовать постоянное хранилище, предлагаемое вашим конкретным облачным провайдером, например. GCEPersistentDisk или AWSElasticBlockStore. Полный список типов постоянных томов, которые в настоящее время поддерживаются кубернетами, вы можете найти на здесь.

Итак, еще раз: если вас беспокоит избыточность на уровне узлов в вашем StatefulSet и вы хотите, чтобы ваш 2 Elasticsearch Pods всегда планировался на разных узлах, как уже предлагал @Arghya Sadhu, используйте NFS или другое нелокальное хранилище.

Однако, если вас не беспокоит избыточность на уровне узлов и вы полностью согласны с тем, что оба ваших Elasticsearch Pods работают на одном узле (главный узел в вашем случае), пожалуйста, следуйте за мной: )

Как справедливо заметил @Arghya Sadhu:

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

Хотя между PV и PVC всегда есть соответствие один-к-одному, это не означает, что вы не можете использовать один PVC во многих модулях.

Обратите внимание, что в вашем StatefulSet примере вы использовали volumeClaimTemplates, что в основном означает, что каждый раз, когда создается новый Pod, управляемый вашим StatefulSet, на основе этого шаблона также создается новый соответствующий PersistentVolumeClaim. Итак, если у вас, например, 10Gi PersistentVolume, независимо от того, запрашиваете ли вы в своей заявке все 10Gi или только половину, только первый PVC будет успешно привязан к вашему PV.

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

Первое, что нам нужно, это класс хранилища. Он очень похож на тот, что в вашем примере:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Первое различие между этой установкой и вашей - в определении PV. Вместо hostPath мы используем здесь локальный том:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /var/tmp/test ### path on your master node
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - your-master-node-name

Обратите внимание, что помимо определения local пути, мы также определили nodeAffinity правило, которое гарантирует, что все Pods, которые получают этот конкретный PV, будут автоматически запланированы на нашем главном узле.

Затем мы вручную применили PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 10Gi
  storageClassName: local-storage

Этот PVC теперь может использоваться всеми (в вашем примере 2) Pods под управлением StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 2 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: mypd
          mountPath: /usr/share/nginx/html
      volumes:
      - name: mypd
        persistentVolumeClaim:
          claimName: myclaim

Обратите внимание, что в приведенном выше примере мы больше не используем volumeClaimTemplates, а только один PersistentVolumeClaim, который может использоваться всеми нашими модулями. Поды по-прежнему уникальны, поскольку ими управляет StatefulSet, но вместо уникального PVCs они используют общий. Благодаря такому подходу оба Pods могут одновременно записывать журналы на один том.

В моем примере я использовал сервер nginx, чтобы сделать репликацию максимально простой для всех, кто хочет быстро ее опробовать, но я считаю, что вы можете легко настроить ее в соответствии со своими потребностями.

person mario    schedule 09.06.2020