Как настроить стека регистрации Elasticsearch, Fluentd и Kibana (EFK) на Kubernetes

Вступление

При запуске нескольких служб и приложений в кластере Kubernetes централизованный стек ведения журналов на уровне кластера может помочь вам быстро отсортировать и проанализировать большой объем данных журнала, создаваемых вашими модулями. Одним из популярных централизованных решений для ведения журнала является стекElasticsearch,Fluentd иKibana (EFK).

Elasticsearch - это распределенная и масштабируемая поисковая система в реальном времени, которая позволяет выполнять полнотекстовый и структурированный поиск, а также выполнять аналитику. Он обычно используется для индексации и поиска в больших объемах данных журнала, но также может быть использован для поиска различных типов документов.

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

В этом руководстве мы будем использоватьFluentd для сбора, преобразования и отправки данных журнала в серверную часть Elasticsearch. Fluentd - это популярный сборщик данных с открытым исходным кодом, который мы настроим на наших узлах Kubernetes для привязки файлов журналов контейнера, фильтрации и преобразования данных журнала и доставки их в кластер Elasticsearch, где они будут проиндексированы и сохранены.

Мы начнем с настройки и запуска масштабируемого кластера Elasticsearch, а затем создадим Kibana Kubernetes Service and Deployment. В заключение, мы настроим Fluentd как DaemonSet, чтобы он работал на каждом рабочем узле Kubernetes.

Предпосылки

Прежде чем начать с этим руководством, убедитесь, что у вас есть следующее:

  • Кластер Kubernetes 1.10+ с включенным управлением доступом на основе ролей (RBAC)

    • Убедитесь, что в вашем кластере достаточно ресурсов для развертывания стека EFK, а если нет, то масштабируйте кластер, добавляя рабочие узлы. Мы будем развертывать 3-Pod кластер Elasticsearch (вы можете уменьшить его до 1, если необходимо), а также один Kibana Pod. Каждый рабочий узел также будет работать с модулем Fluentd. Кластер в этом руководстве состоит из 3 рабочих узлов и плоскости управляемого управления.

  • Инструмент командной строкиkubectl, установленный на вашем локальном компьютере, настроен для подключения к вашему кластеру. Вы можете узнать больше об установкеkubectlin the official documentation.

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

[[step-1 -—- Creating-a-namespace]] == Шаг 1. Создание пространства имен

Прежде чем мы развернем кластер Elasticsearch, мы сначала создадим пространство имен, в которое мы установим все наши инструменты ведения журналов. Kubernetes позволяет вам разделять объекты, работающие в вашем кластере, используя абстракцию «виртуального кластера», называемую Пространства имен. В этом руководстве мы создадим пространство именkube-logging, в которое мы установим компоненты стека EFK. Это пространство имен также позволит нам быстро очистить и удалить стек журналирования без потери функций для кластера Kubernetes.

Для начала сначала исследуйте существующие пространства имен в вашем кластере, используяkubectl:

kubectl get namespaces

Вы должны увидеть следующие три начальных пространства имен, которые предустановлены вместе с вашим кластером Kubernetes:

OutputNAME          STATUS    AGE
default       Active    5m
kube-system   Active    5m
kube-public   Active    5m

Пространство именdefault содержит объекты, созданные без указания пространства имен. Пространство именkube-system содержит объекты, созданные и используемые системой Kubernetes, напримерkube-dns,kube-proxy иkubernetes-dashboard. Рекомендуется содержать это пространство имен в чистоте и не загрязнять его прикладными и инструментальными нагрузками.

Пространство именkube-public - это еще одно автоматически созданное пространство имен, которое можно использовать для хранения объектов, которые вы хотите сделать доступными для чтения и доступа во всем кластере, даже для пользователей, не прошедших проверку подлинности.

Чтобы создать пространство именkube-logging, сначала откройте и отредактируйте файл с именемkube-logging.yaml с помощью вашего любимого редактора, такого как nano:

nano kube-logging.yaml

Внутри вашего редактора вставьте следующий объект пространства имен YAML:

kube-logging.yaml

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

Затем сохраните и закройте файл.

Здесь мы указываемkind объекта Kubernetes как объектNamespace. Чтобы узнать больше об объектахNamespace, обратитесь кNamespaces Walkthrough в официальной документации Kubernetes. Мы также указываем версию API Kubernetes, используемую для создания объекта (v1), и даем ейname,kube-logging.

После того, как вы создали объектный файл пространства именkube-logging.yaml, создайте пространство имен, используяkubectl create с флагом имени файла-f:

kubectl create -f kube-logging.yaml

Вы должны увидеть следующий вывод:

Outputnamespace/kube-logging created

Затем вы можете подтвердить, что пространство имен было успешно создано:

kubectl get namespaces

На этом этапе вы должны увидеть новое пространство именkube-logging:

OutputNAME           STATUS    AGE
default        Active    23m
kube-logging   Active    1m
kube-public    Active    23m
kube-system    Active    23m

Теперь мы можем развернуть кластер Elasticsearch в этом изолированном пространстве имен журналирования.

[[step-2 -—- created-the-elasticsearch-statefulset]] == Шаг 2. Создание StatefulSet Elasticsearch

Теперь, когда мы создали пространство имен для размещения нашего стека журналирования, мы можем начать развертывание его различных компонентов. Сначала мы начнем с развертывания 3-узлового кластера Elasticsearch.

В этом руководстве мы используем 3 модуля Elasticsearch, чтобы избежать проблемы «расщепления мозга», возникающей в высокодоступных многоузловых кластерах. На высоком уровне «разделенный мозг» - это то, что возникает, когда один или несколько узлов не могут связываться с другими, и несколько «разделенных» мастеров избираются. С 3 узлами, если один временно отключается от кластера, два других узла могут выбрать нового мастера, и кластер может продолжить работу, пока последний узел пытается вернуться. Чтобы узнать больше, обратитесь кA new era for cluster coordination in Elasticsearch иVoting configurations.

Создание службы без головы

Для начала мы создадим автономную службу Kubernetes под названиемelasticsearch, которая будет определять домен DNS для трех модулей. Безголовый сервис не выполняет балансировку нагрузки и не имеет статического IP-адреса; чтобы узнать больше о безголовых сервисах, обратитесь к официальномуKubernetes documentation.

Откройте файл с именемelasticsearch_svc.yaml с помощью вашего любимого редактора:

nano elasticsearch_svc.yaml

Вставьте в следующий сервис Kubernetes YAML:

elasticsearch_svc.yaml

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

Затем сохраните и закройте файл.

Мы определяемService с именемelasticsearch в пространстве именkube-logging и даем ему меткуapp: elasticsearch. Затем мы устанавливаем для.spec.selector значениеapp: elasticsearch, чтобы служба выбирала модули с меткойapp: elasticsearch. Когда мы связываем наш Elasticsearch StatefulSet с этой Службой, Служба будет возвращать записи DNS A, которые указывают на модули Elasticsearch с меткойapp: elasticsearch.

Затем мы устанавливаемclusterIP: None, что делает сервис отключенным. Наконец, мы определяем порты9200 и9300, которые используются для взаимодействия с REST API и для связи между узлами соответственно.

Создайте сервис, используяkubectl:

kubectl create -f elasticsearch_svc.yaml

Вы должны увидеть следующий вывод:

Outputservice/elasticsearch created

Наконец, еще раз проверьте, что служба была успешно создана с помощьюkubectl get:

kubectl get services --namespace=kube-logging

Вы должны увидеть следующее:

OutputNAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None                 9200/TCP,9300/TCP   26s

Теперь, когда мы настроили наш безголовый сервис и стабильный домен.elasticsearch.kube-logging.svc.cluster.local для наших модулей, мы можем продолжить и создать StatefulSet.

Создание StatefulSet

Kubernetes StatefulSet позволяет назначать стабильные идентификаторы для модулей и предоставлять им стабильное, постоянное хранилище. Для Elasticsearch требуется стабильное хранилище для сохранения данных при изменении расписания Pod и перезапусках. Чтобы узнать больше о рабочей нагрузке StatefulSet, обратитесь к страницеStatefulsets в документации Kubernetes.

Откройте файл с именемelasticsearch_statefulset.yaml в своем любимом редакторе:

nano elasticsearch_statefulset.yaml

Мы будем перемещаться по определению объекта StatefulSet по частям, вставляя блоки в этот файл

Начните с вставки в следующем блоке:

elasticsearch_statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: es-cluster
  namespace: kube-logging
spec:
  serviceName: elasticsearch
  replicas: 3
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch

В этом блоке мы определяем StatefulSet с именемes-cluster в пространстве именkube-logging. Затем мы связываем его с нашей ранее созданной службойelasticsearch, используя полеserviceName. Это гарантирует, что каждый Pod в StatefulSet будет доступен по следующему адресу DNS:es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local, где[0,1,2] соответствует назначенному Pod целочисленному порядковому номеру.

Мы указываем 3replicas (Pods) и устанавливаем селекторmatchLabels наapp: elasticseach, который затем отражаем в разделе.spec.template.metadata. Поля.spec.selector.matchLabels и.spec.template.metadata.labels должны совпадать.

Теперь мы можем перейти к спецификации объекта. Вставьте следующий блок YAML сразу под предыдущим блоком:

elasticsearch_statefulset.yaml

. . .
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
        resources:
            limits:
              cpu: 1000m
            requests:
              cpu: 100m
        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"

Здесь мы определяем стручки в StatefulSet. Назовем контейнерыelasticsearch и выберем образ Dockerdocker.elastic.co/elasticsearch/elasticsearch:7.2.0. На этом этапе вы можете изменить этот тег изображения, чтобы он соответствовал вашему собственному внутреннему образу Elasticsearch или другой версии. Обратите внимание, что для целей этого руководства был протестирован только Elasticsearch7.2.0.

Затем мы используем полеresources, чтобы указать, что контейнеру требуется как минимум 0,1 виртуального ЦП, гарантированно для него, и что он может разорвать до 1 виртуального ЦП (что ограничивает использование ресурсов модуля при выполнении начального большого захвата или при пике нагрузки ). Вы должны изменить эти значения в зависимости от ожидаемой нагрузки и доступных ресурсов. Чтобы узнать больше о запросах ресурсов и ограничениях, обратитесь к официальномуKubernetes Documentation.

Затем мы открываем и называем порты9200 и9300 для REST API и межузловой связи соответственно. Мы указываемvolumeMount с именемdata, который будет монтировать PersistentVolume с именемdata в контейнер по пути/usr/share/elasticsearch/data. Мы определим VolumeClaims для этого StatefulSet в более позднем блоке YAML.

Наконец, мы устанавливаем некоторые переменные окружения в контейнере:

  • cluster.name: имя кластера Elasticsearch, которое в этом руководстве -k8s-logs.

  • node.name: имя узла, которое мы установили в поле.metadata.name с помощьюvalueFrom. Это будет преобразовано вes-cluster-[0,1,2], в зависимости от назначенного порядкового номера узла.

  • discovery.seed_hosts: в этом поле задается список узлов кластера, отвечающих требованиям главного, которые будут запускать процесс обнаружения узлов. В этом руководстве, благодаря настроенному ранее безголовому сервису, наши поды имеют домены в формеes-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local, поэтому мы устанавливаем эту переменную соответствующим образом. Используя локальное пространство имен Kubernetes DNS, мы можем сократить это доes-cluster-[0,1,2].elasticsearch. Чтобы узнать больше об обнаружении Elasticsearch, обратитесь к официальномуElasticsearch documentation.

  • cluster.initial_master_nodes: в этом поле также указывается список основных узлов, которые будут участвовать в процессе выбора главного. Обратите внимание, что для этого поля вы должны идентифицировать узлы по ихnode.name, а не по именам хостов.

  • ES_JAVA_OPTS: здесь мы устанавливаем это значение-Xms512m -Xmx512m, которое указывает JVM использовать минимальный и максимальный размер кучи 512 МБ. Вы должны настроить эти параметры в зависимости от доступности ресурсов вашего кластера и потребностей. Чтобы узнать больше, обратитесь кSetting the heap size.

Следующий блок, который мы вставим, выглядит следующим образом:

elasticsearch_statefulset.yaml

. . .
      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

В этом блоке мы определяем несколько контейнеров инициализации, которые запускаются перед основным контейнером приложенияelasticsearch. Эти начальные контейнеры запускаются до конца в порядке их определения. Чтобы узнать больше о Init-контейнерах, обратитесь к официальномуKubernetes Documentation.

Первый, названныйfix-permissions, запускает командуchown, чтобы изменить владельца и группу каталога данных Elasticsearch на1000:1000, UID пользователя Elasticsearch. По умолчанию Kubernetes монтирует каталог данных какroot, что делает его недоступным для Elasticsearch. Чтобы узнать больше об этом шаге, обратитесь к разделу Elasticsearch «https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults[Notes для производственного использования и значений по умолчанию]».

Второй, названныйincrease-vm-max-map, запускает команду для увеличения ограничений операционной системы на счетчики mmap, которые по умолчанию могут быть слишком низкими, что приводит к ошибкам нехватки памяти. Чтобы узнать больше об этом шаге, обратитесь к официальномуElasticsearch documentation.

Следующий запускаемый контейнер Init -increase-fd-ulimit, который запускает командуulimit, чтобы увеличить максимальное количество дескрипторов открытых файлов. Чтобы узнать больше об этом шаге, обратитесь к «https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults[Notes for Production Use and Defaults]» официальной документации Elasticsearch.

[.note] #Note: В ElasticsearchNotes for Production Use также упоминается отключение подкачки по соображениям производительности. В зависимости от вашей установки или поставщика Kubernetes подкачка может быть уже отключена. Чтобы проверить это, откройтеexec в работающем контейнере и запуститеcat /proc/swaps, чтобы вывести список активных устройств подкачки. Если там ничего не видно, своп отключен.
#

Теперь, когда мы определили наш основной контейнер приложения и контейнеры инициализации, которые запускаются перед ним для настройки ОС контейнера, мы можем добавить последний фрагмент в наш файл определения объекта StatefulSet:volumeClaimTemplates.

Вставьте следующий блокvolumeClaimTemplate:

elasticsearch_statefulset.yaml

. . .
  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: do-block-storage
      resources:
        requests:
          storage: 100Gi

В этом блоке мы определяемvolumeClaimTemplates StatefulSet. Kubernetes будет использовать это для создания PersistentVolumes для модулей. В блоке выше мы называем егоdata (этоname, на который мы ссылаемся в меткеvolumeMount+`s defined previously), and give it the same `+app: elasticsearch как на наш StatefulSet.

Затем мы указываем его режим доступа какReadWriteOnce, что означает, что он может быть установлен как чтение-запись только одним узлом. В этом руководстве мы определяем класс хранилища какdo-block-storage, поскольку мы используем кластер DigitalOcean Kubernetes для демонстрационных целей. Вы должны изменить это значение в зависимости от того, где вы используете свой кластер Kubernetes. Чтобы узнать больше, обратитесь к документацииPersistent Volume.

Наконец, мы указываем, что мы хотим, чтобы каждый PersistentVolume был размером 100 ГБ. Вы должны отрегулировать это значение в зависимости от ваших производственных потребностей.

Полная спецификация StatefulSet должна выглядеть примерно так:

elasticsearch_statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: es-cluster
  namespace: kube-logging
spec:
  serviceName: elasticsearch
  replicas: 3
  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
            requests:
              cpu: 100m
        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: do-block-storage
      resources:
        requests:
          storage: 100Gi

Когда вы будете удовлетворены конфигурацией Elasticsearch, сохраните и закройте файл.

Теперь разверните StatefulSet, используяkubectl:

kubectl create -f elasticsearch_statefulset.yaml

Вы должны увидеть следующий вывод:

Outputstatefulset.apps/es-cluster created

Вы можете отслеживать StatefulSet по мере его развертывания, используяkubectl rollout status:

kubectl rollout status sts/es-cluster --namespace=kube-logging

По мере развертывания кластера вы должны увидеть следующий вывод:

OutputWaiting for 3 pods to be ready...
Waiting for 2 pods to be ready...
Waiting for 1 pods to be ready...
partitioned roll out complete: 3 new pods have been updated...

После развертывания всех модулей вы можете убедиться, что ваш кластер Elasticsearch работает правильно, выполнив запрос к REST API.

Для этого сначала перенаправьте локальный порт9200 на порт9200 на одном из узлов Elasticsearch (es-cluster-0), используяkubectl port-forward:

kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging

Затем в отдельном окне терминала выполните запросcurl к REST API:

curl http://localhost:9200/_cluster/state?pretty

Вы должны увидеть следующий вывод:

Output{
  "cluster_name" : "k8s-logs",
  "compressed_size_in_bytes" : 348,
  "cluster_uuid" : "QD06dK7CQgids-GQZooNVw",
  "version" : 3,
  "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg",
  "master_node" : "IdM5B7cUQWqFgIHXBp0JDg",
  "blocks" : { },
  "nodes" : {
    "u7DoTpMmSCixOoictzHItA" : {
      "name" : "es-cluster-1",
      "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg",
      "transport_address" : "10.244.8.2:9300",
      "attributes" : { }
    },
    "IdM5B7cUQWqFgIHXBp0JDg" : {
      "name" : "es-cluster-0",
      "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ",
      "transport_address" : "10.244.44.3:9300",
      "attributes" : { }
    },
    "R8E7xcSUSbGbgrhAdyAKmQ" : {
      "name" : "es-cluster-2",
      "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA",
      "transport_address" : "10.244.40.4:9300",
      "attributes" : { }
    }
  },
...

Это указывает на то, что наш кластер Elasticsearchk8s-logs успешно создан с 3 узлами:es-cluster-0,es-cluster-1 иes-cluster-2. Текущий главный узел -es-cluster-0.

Теперь, когда ваш кластер Elasticsearch запущен и работает, вы можете перейти к настройке для него внешнего интерфейса Kibana.

[[step-3 -—- created-the-kibana-deployment-and-service]] == Шаг 3 - Создание развертывания и обслуживания Kibana

Чтобы запустить Kibana в Kubernetes, мы создадим сервис под названиемkibana и Deployment, состоящее из одной реплики Pod. Вы можете масштабировать количество реплик в зависимости от производственных потребностей и, при необходимости, указать типLoadBalancer для Службы, чтобы загружать запросы балансировки между модулями развертывания.

На этот раз мы создадим Сервис и Развертывание в одном файле. Откройте файл с именемkibana.yaml в своем любимом редакторе:

nano kibana.yaml

Вставьте в следующую сервисную спецификацию:

kibana.yaml

apiVersion: v1
kind: Service
metadata:
  name: kibana
  namespace: kube-logging
  labels:
    app: kibana
spec:
  ports:
  - port: 5601
  selector:
    app: kibana
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  namespace: kube-logging
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: docker.elastic.co/kibana/kibana:7.2.0
        resources:
          limits:
            cpu: 1000m
          requests:
            cpu: 100m
        env:
          - name: ELASTICSEARCH_URL
            value: http://elasticsearch:9200
        ports:
        - containerPort: 5601

Затем сохраните и закройте файл.

В этой спецификации мы определили службу с именемkibana в пространстве именkube-logging и присвоили ей меткуapp: kibana.

Мы также указали, что он должен быть доступен через порт5601, и использовать меткуapp: kibana для выбора целевых модулей службы.

В спецификацииDeployment мы определяем развертывание под названиемkibana и указываем, что нам нужна 1 реплика Pod.

Мы используем изображениеdocker.elastic.co/kibana/kibana:7.2.0. На этом этапе вы можете заменить свой собственный личный или общедоступный образ Kibana для использования.

Мы указываем, что мы хотели бы по крайней мере 0,1 vCPU, гарантируемой Pod, разрыва до предела 1 vCPU. Вы можете изменить эти параметры в зависимости от ожидаемой нагрузки и доступных ресурсов.

Затем мы используем переменную средыELASTICSEARCH_URL, чтобы установить конечную точку и порт для кластера Elasticsearch. При использовании Kubernetes DNS эта конечная точка соответствует имени службыelasticsearch. Этот домен будет преобразован в список IP-адресов для 3 модулей Elasticsearch. Чтобы узнать больше о Kubernetes DNS, обратитесь кDNS for Services and Pods.

Наконец, мы устанавливаем порт контейнера Kibana на5601, на который службаkibana будет пересылать запросы.

Когда вы будете удовлетворены конфигурацией Kibana, вы можете развернуть Сервис и Развертывание, используяkubectl:

kubectl create -f kibana.yaml

Вы должны увидеть следующий вывод:

Outputservice/kibana created
deployment.apps/kibana created

Вы можете проверить успешность развертывания, выполнив следующую команду:

kubectl rollout status deployment/kibana --namespace=kube-logging

Вы должны увидеть следующий вывод:

Outputdeployment "kibana" successfully rolled out

Чтобы получить доступ к интерфейсу Kibana, мы еще раз перенаправим локальный порт узлу Kubernetes, на котором работает Kibana. Возьмите детали Kibana Pod, используяkubectl get:

kubectl get pods --namespace=kube-logging
OutputNAME                      READY     STATUS    RESTARTS   AGE
es-cluster-0              1/1       Running   0          55m
es-cluster-1              1/1       Running   0          54m
es-cluster-2              1/1       Running   0          54m
kibana-6c9fb4b5b7-plbg2   1/1       Running   0          4m27s

Здесь мы видим, что наш Kibana Pod называетсяkibana-6c9fb4b5b7-plbg2.

Перенаправить локальный порт5601 на порт5601 на этом поде:

kubectl port-forward kibana-6c9fb4b5b7-plbg2 5601:5601 --namespace=kube-logging

Вы должны увидеть следующий вывод:

OutputForwarding from 127.0.0.1:5601 -> 5601
Forwarding from [::1]:5601 -> 5601

Теперь в вашем веб-браузере перейдите по следующему URL:

http://localhost:5601

Если вы видите следующую страницу приветствия Kibana, вы успешно развернули Kibana в своем кластере Kubernetes:

Kibana Welcome Screen

Теперь вы можете перейти к развертыванию последнего компонента стека EFK: сборщика журналов Fluentd.

[[step-4 -—- Creating-the-fluentd-daemonset]] == Шаг 4 - Создание Fluentd DaemonSet

В этом руководстве мы настроим Fluentd как DaemonSet, тип рабочей нагрузки Kubernetes, который запускает копию данного Pod на каждом узле в кластере Kubernetes. Используя этот контроллер DaemonSet, мы развернем модуль регистрации Fluentd на каждом узле нашего кластера. Чтобы узнать больше об этой архитектуре ведения журналов, обратитесь к официальному Kubernetes «https://kubernetes.io/docs/concepts/cluster-administration/logging/#using-a-node-logging-agent[Using агент регистрации узлов]» Docs.

В Kubernetes контейнерные приложения, которые регистрируются вstdout иstderr, получают свои потоки журналов и перенаправляют их в файлы JSON на узлах. Модуль Fluentd Pod будет отслеживать эти файлы журнала, фильтровать события журнала, преобразовывать данные журнала и отправлять их в серверную часть ведения журнала Elasticsearch, которую мы развернули вStep 2.

В дополнение к журналам контейнеров агент Fluentd будет привязывать журналы системных компонентов Kubernetes, такие как журналы kubelet, kube-proxy и Docker. Чтобы увидеть полный список источников, отслеживаемых агентом ведения журнала Fluentd, обратитесь к файлуkubernetes.conf, который используется для настройки агента ведения журнала. Чтобы узнать больше о регистрации в кластерах Kubernetes, обратитесь к официальному представителю «https://kubernetes.io/docs/concepts/cluster-administration/logging/#logging-at-the-node-level[Logging на уровне узла]» от официального Кубернетская документация.

Начните с открытия файла с именемfluentd.yaml в вашем любимом текстовом редакторе:

nano fluentd.yaml

Еще раз, мы вставим определения объектов Kubernetes блок за блоком, предоставляя контекст по мере продвижения. В этом руководстве мы используемFluentd DaemonSet spec, предоставленные разработчиками Fluentd. Еще один полезный ресурс, предоставляемый специалистами по сопровождению Fluentd, - этоKuberentes Fluentd.

Сначала вставьте следующее определение ServiceAccount:

fluentd.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    app: fluentd

Здесь мы создаем учетную запись службы с именемfluentd, которую модули Fluentd будут использовать для доступа к Kubernetes API. Мы создаем его в пространстве именkube-logging и снова присваиваем ему меткуapp: fluentd. Чтобы узнать больше об учетных записях служб в Kubernetes, обратитесь кConfigure Service Accounts for Pods в официальной документации Kubernetes.

Затем вставьте следующий блокClusterRole:

fluentd.yaml

. . .
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd
  labels:
    app: fluentd
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch

Здесь мы определяем ClusterRole с именемfluentd, которому мы предоставляем разрешенияget,list иwatch для объектовpods иnamespaces. ClusterRoles позволяют вам предоставлять доступ к кластерным ресурсам Kubernetes, таким как Nodes. Чтобы узнать больше о ролевом контроле доступа и ролях кластера, обратитесь кUsing RBAC Authorization из официальной документации Kubernetes.

Теперь вставьте следующий блокClusterRoleBinding:

fluentd.yaml

. . .
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: kube-logging

В этом блоке мы определяемClusterRoleBinding с именемfluentd, который связывает роль кластераfluentd с учетной записью службыfluentd. Это предоставляет ServiceAccountfluentd разрешения, перечисленные в роли кластераfluentd.

С этого момента мы можем начать вставку в текущую спецификацию DaemonSet:

fluentd.yaml

. . .
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    app: fluentd

Здесь мы определяем DaemonSet с именемfluentd в пространстве именkube-logging и даем ему меткуapp: fluentd.

Далее вставьте в следующий раздел:

fluentd.yaml

. . .
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      serviceAccount: fluentd
      serviceAccountName: fluentd
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch.kube-logging.svc.cluster.local"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          - name: FLUENTD_SYSTEMD_CONF
            value: disable

Здесь мы сопоставляем меткуapp: fluentd, определенную в.metadata.labels, а затем назначаем DaemonSet учетную запись службыfluentd. Мы также выбираемapp: fluentd в качестве модулей, управляемых этим DaemonSet.

Затем мы определяем допускNoSchedule, чтобы соответствовать эквивалентному заражению на главных узлах Kubernetes. Это гарантирует, что DaemonSet также будет распространен среди мастеров Kubernetes. Если вы не хотите запускать Fluentd Pod на своих мастер-узлах, снимите этот допуск. Чтобы узнать больше о пороках и допусках в Kubernetes, обратитесь к «https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/[Taints and Tolerations]» в официальных документах Kubernetes.

Затем мы начинаем определение контейнера Pod, который мы называемfluentd.

Мы используемofficial v1.4.2 Debian image, предоставленные разработчиками Fluentd. Если вы хотите использовать собственное частное или общедоступное изображение Fluentd или использовать другую версию изображения, измените тегimage в спецификации контейнера. Dockerfile и содержимое этого образа доступны вfluentd-kubernetes-daemonset Github repo Fluentd.

Далее мы настраиваем Fluentd, используя некоторые переменные окружения:

  • FLUENT_ELASTICSEARCH_HOST: мы установили это на адрес службы без заголовка Elasticsearch, определенный ранее:elasticsearch.kube-logging.svc.cluster.local. Это разрешит список IP-адресов для 3 модулей Elasticsearch. Фактически хост Elasticsearch, скорее всего, будет первым IP-адресом, возвращенным в этом списке. Чтобы распределить журналы по кластеру, вам необходимо изменить конфигурацию для плагина вывода Fluentd Elasticsearch. Чтобы узнать больше об этом плагине, обратитесь кElasticsearch Output Plugin.

  • FLUENT_ELASTICSEARCH_PORT: мы установили это для порта Elasticsearch, который мы настроили ранее,9200.

  • FLUENT_ELASTICSEARCH_SCHEME: мы устанавливаем это наhttp.

  • FLUENTD_SYSTEMD_CONF: мы установили это значение наdisable, чтобы подавить вывод, связанный с тем, чтоsystemd не настроен в контейнере.

Наконец, вставьте в следующий раздел:

fluentd.yaml

. . .
        resources:
          limits:
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

Здесь мы указываем ограничение памяти в 512 МБ на модуле FluentD Pod и гарантируем его 0,1 В ЦП и 200 МБ памяти. Вы можете настроить эти ограничения ресурсов и запросы в зависимости от ожидаемого объема журнала и доступных ресурсов.

Затем мы монтируем пути к хосту/var/log и/var/lib/docker/containers в контейнер, используяvarlog иvarlibdockercontainersvolumeMounts. Этиvolumes определены в конце блока.

Последний параметр, который мы определяем в этом блоке, -terminationGracePeriodSeconds, который дает Fluentd 30 секунд для корректного завершения работы после получения сигналаSIGTERM. Через 30 секунд контейнеры отправляют сигналSIGKILL. Значение по умолчанию дляterminationGracePeriodSeconds - 30 с, поэтому в большинстве случаев этот параметр можно опустить. Чтобы узнать больше о грациозном прекращении рабочих нагрузок Kubernetes, ознакомьтесь с «https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-terminating-with-grace[Kubernetes Лучшие практики: прекращение с благодати]».

Вся спецификация Fluentd должна выглядеть примерно так:

fluentd.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    app: fluentd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd
  labels:
    app: fluentd
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: kube-logging
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    app: fluentd
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      serviceAccount: fluentd
      serviceAccountName: fluentd
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch.kube-logging.svc.cluster.local"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          - name: FLUENTD_SYSTEMD_CONF
            value: disable
        resources:
          limits:
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

Когда вы закончите настройку Fluentd DaemonSet, сохраните и закройте файл.

Теперь разверните DaemonSet, используяkubectl:

kubectl create -f fluentd.yaml

Вы должны увидеть следующий вывод:

Outputserviceaccount/fluentd created
clusterrole.rbac.authorization.k8s.io/fluentd created
clusterrolebinding.rbac.authorization.k8s.io/fluentd created
daemonset.extensions/fluentd created

Убедитесь, что ваш DaemonSet успешно развернут, используяkubectl:

kubectl get ds --namespace=kube-logging

Вы должны увидеть следующий вывод статуса:

OutputNAME      DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
fluentd   3         3         3         3            3                     58s

Это означает, что запущено 3fluentd модулей, что соответствует количеству узлов в нашем кластере Kubernetes.

Теперь мы можем проверить Kibana, чтобы убедиться, что данные журнала правильно собираются и отправляются в Elasticsearch.

Покаkubectl port-forward все еще открыт, перейдите кhttp://localhost:5601.

НажмитеDiscover в левом меню навигации:

Kibana Discover

Вы должны увидеть следующее окно конфигурации:

Kibana Index Pattern Configuration

Это позволяет вам определять индексы Elasticsearch, которые вы хотели бы изучить в Кибане. Чтобы узнать больше, обратитесь кDefining your index patterns в официальной документации Kibana. На данный момент мы просто воспользуемся шаблоном подстановкиlogstash-* для сбора всех данных журнала в нашем кластере Elasticsearch. Введитеlogstash-* в текстовое поле и щелкнитеNext step.

Затем вы попадете на следующую страницу:

Kibana Index Pattern Settings

Это позволяет вам настроить, какое поле Kibana будет использовать для фильтрации данных журнала по времени. В раскрывающемся списке выберите поле@timestamp и нажмитеCreate index pattern.

Теперь нажмитеDiscover в левом меню навигации.

Вы должны увидеть график гистограммы и некоторые последние записи в журнале:

Kibana Incoming Logs

На этом этапе вы успешно настроили и развернули стек EFK в своем кластере Kubernetes. Чтобы узнать, как использовать Kibana для анализа данных журнала, обратитесь кKibana User Guide.

В следующем дополнительном разделе мы развернем простой счетчик Pod, который печатает числа на стандартный вывод, и найдем его логи в Kibana.

[[step-5-optional -—- testing-container-logging]] == Шаг 5 (необязательно) - Тестирование ведения журнала контейнера

Чтобы продемонстрировать базовый вариант использования Kibana для изучения последних журналов для данного модуля, мы развернем модуль минимального счетчика, который печатает последовательные числа в стандартный вывод.

Давайте начнем с создания Pod. Откройте файл с именемcounter.yaml в своем любимом редакторе:

nano counter.yaml

Затем вставьте в следующие спецификации Pod:

counter.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

Сохраните и закройте файл.

Это минимальный Pod под названиемcounter, который запускает циклwhile, последовательно печатая числа.

Разверните подcounter, используяkubectl:

kubectl create -f counter.yaml

После того, как Pod был создан и запущен, вернитесь на панель управления Kibana.

На страницеDiscover в строке поиска введитеkubernetes.pod_name:counter. Это фильтрует данные журнала для модулей с именемcounter.

Затем вы должны увидеть список записей журнала для модуляcounter:

Counter Logs in Kibana

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

Заключение

В этом руководстве мы продемонстрировали, как настроить и настроить Elasticsearch, Fluentd и Kibana в кластере Kubernetes. Мы использовали минимальную архитектуру ведения журнала, которая состоит из одного модуля агента ведения журнала, работающего на каждом рабочем узле Kubernetes.

Перед развертыванием этого стека журналирования в производственном кластере Kubernetes лучше всего настроить требования к ресурсам и ограничения, как указано в этом руководстве. Вы также можете настроитьX-Pack для включения встроенных функций мониторинга и безопасности.

Архитектура ведения журнала, которую мы здесь использовали, состоит из 3 модулей Elasticsearch, одного модуля Kibana (без балансировки нагрузки) и набора модулей Fluentd, развернутых как DaemonSet. Вы можете масштабировать эту настройку в зависимости от вашего производственного варианта использования. Чтобы узнать больше о масштабировании стека Elasticsearch и Kibana, обратитесь кScaling Elasticsearch.

В Kubernetes также предусмотрены более сложные архитектуры агентов журналирования, которые могут лучше соответствовать вашему варианту использования. Чтобы узнать больше, обратитесь кLogging Architecture из документации Kubernetes.

Related