Вступление
При запуске нескольких служб и приложений в кластере 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
, установленный на вашем локальном компьютере, настроен для подключения к вашему кластеру. Вы можете узнать больше об установкеkubectl
in 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:
Теперь вы можете перейти к развертыванию последнего компонента стека 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
иvarlibdockercontainers
volumeMounts
. Эти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 в левом меню навигации:
Вы должны увидеть следующее окно конфигурации:
Это позволяет вам определять индексы Elasticsearch, которые вы хотели бы изучить в Кибане. Чтобы узнать больше, обратитесь кDefining your index patterns в официальной документации Kibana. На данный момент мы просто воспользуемся шаблоном подстановкиlogstash-*
для сбора всех данных журнала в нашем кластере Elasticsearch. Введитеlogstash-*
в текстовое поле и щелкнитеNext step.
Затем вы попадете на следующую страницу:
Это позволяет вам настроить, какое поле Kibana будет использовать для фильтрации данных журнала по времени. В раскрывающемся списке выберите поле@timestamp и нажмитеCreate index pattern.
Теперь нажмитеDiscover в левом меню навигации.
Вы должны увидеть график гистограммы и некоторые последние записи в журнале:
На этом этапе вы успешно настроили и развернули стек 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
:
Вы можете нажать на любую из записей журнала, чтобы увидеть дополнительные метаданные, такие как имя контейнера, узел Kubernetes, пространство имен и многое другое.
Заключение
В этом руководстве мы продемонстрировали, как настроить и настроить Elasticsearch, Fluentd и Kibana в кластере Kubernetes. Мы использовали минимальную архитектуру ведения журнала, которая состоит из одного модуля агента ведения журнала, работающего на каждом рабочем узле Kubernetes.
Перед развертыванием этого стека журналирования в производственном кластере Kubernetes лучше всего настроить требования к ресурсам и ограничения, как указано в этом руководстве. Вы также можете настроитьX-Pack для включения встроенных функций мониторинга и безопасности.
Архитектура ведения журнала, которую мы здесь использовали, состоит из 3 модулей Elasticsearch, одного модуля Kibana (без балансировки нагрузки) и набора модулей Fluentd, развернутых как DaemonSet. Вы можете масштабировать эту настройку в зависимости от вашего производственного варианта использования. Чтобы узнать больше о масштабировании стека Elasticsearch и Kibana, обратитесь кScaling Elasticsearch.
В Kubernetes также предусмотрены более сложные архитектуры агентов журналирования, которые могут лучше соответствовать вашему варианту использования. Чтобы узнать больше, обратитесь кLogging Architecture из документации Kubernetes.