EFK - Kulichanin/speedtest GitHub Wiki

EFK Stack

Развертывание efk стака для логирования кластера kubernetes

Согласно оф. документации команда elastic предлагает Elastic Cloud on Kubernetes(ECK). Данный вариант предлагает максимальное эффективное управление изменениями кластера, как горизонтально так и вертикально

Подготовка кластера

Для установки необходимо скачать репозиторий cloud-on-k8s

git clone https://github.com/elastic/cloud-on-k8s.git

В виду локальных ограничений необходимо изменить репозиторий eck оператора cloud-on-k8s/deploy/eck-operator/values.yaml

/:20
image:
  # repository is the container image prefixed by the registry name.
  repository: elastic/eck-operator
  # pullPolicy is the container image pull policy.
  pullPolicy: IfNotPresent
  # tag is the container image tag. If not defined, defaults to chart appVersion.
  tag: "2.16.1"
  # fips specifies whether the operator will use a FIPS compliant container image for its own StatefulSet image.
  # This setting does not apply to Elastic Stack applications images.
  # Can be combined with config.ubiOnly.
  fips: false

/:204
containerRegistry: docker.io

Установка eck оператора

Установка происходить с помощью helm в namespace elastic-system

helm install elastic-operator cloud-on-k8s/deploy/eck-operator -n elastic-system --create-namespace

Определить namespace elastic-system по умолчанию для удобства

kubectl config set-context --current --namespace=elastic-system

Получение метрик из eck

Включите в ConfigMap настройку метрик.

cat <<EOF | kubectl apply -f -
kind: ConfigMap
apiVersion: v1
metadata:
  name: elastic-operator
  namespace: elastic-system
data:
  eck.yaml: |-
    log-verbosity: 0
    metrics-port: 8080
    metrics-host: 0.0.0.0
    container-registry: docker.io
    max-concurrent-reconciles: 3
    ca-cert-validity: 8760h
    ca-cert-rotate-before: 24h
    cert-validity: 8760h
    cert-rotate-before: 24h
    disable-config-watch: false
    exposed-node-labels: [topology.kubernetes.io/.*,failure-domain.beta.kubernetes.io/.*]
    set-default-security-context: auto-detect
    kube-client-timeout: 60s
    elasticsearch-client-timeout: 180s
    disable-telemetry: false
    distribution-channel: all-in-one
    validate-storage-class: true
    enable-webhook: true
    webhook-name: elastic-operator.elastic-system.k8s.elastic.co
    webhook-port: 9443
    operator-namespace: elastic-system
    enable-leader-election: true
    elasticsearch-observation-interval: 10s
    ubi-only: false
EOF

Исправьте StatefulSet, чтобы открыть порт метрик.

kubectl patch sts -n elastic-system elastic-operator --patch-file=/dev/stdin <<-EOF
spec:
  template:
    spec:
      containers:
        - name: manager
          ports:
          - containerPort: 9443
            name: https-webhook
            protocol: TCP
          - containerPort: 8080
            protocol: TCP
            name: metrics
EOF

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

cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: monitor-operator
  namespace: elastic-system
  labels:
    app.kubernetes.io/component: metrics
    release: kube-prometheus-stack
spec:
  podMetricsEndpoints:
    - port: metrics
      path: /metrics
      interval: 1m
      scrapeTimeout: 30s
  namespaceSelector:
    matchNames:
      - elastic-system
  selector:
    matchLabels:
      app.kubernetes.io/name: elastic-operator  
EOF

Установка elastic

Установка происходит через kubectl и обращение к новыму ресурсу Elasticsearch

Данный пример создает daemonset, который меняет max_map_count, после чего происходит установка кластера elasticsearch(1 ноды в режиме master и 2 ноды в режиме data). Также определен volumeClaimTemplates размером 1 гб и 5 гб в зависимости от роли.

elastic.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: max-map-count-setter
  labels:
    k8s-app: max-map-count-setter
spec:
  selector:
    matchLabels:
      name: max-map-count-setter
  template:
    metadata:
      labels:
        name: max-map-count-setter
    spec:
      initContainers:
        - name: max-map-count-setter
          image: docker.io/bash:5.2.21
          resources:
            limits:
              cpu: 100m
              memory: 32Mi
          securityContext:
            privileged: true
            runAsUser: 0
          command: ['/usr/local/bin/bash', '-e', '-c', 'echo 262144 > /proc/sys/vm/max_map_count']
      containers:
        - name: sleep
          image: docker.io/bash:5.2.21
          command: ['sleep', 'infinity']
---
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 8.17.1
  image: elastic/elasticsearch:8.17.1
  nodeSets:
  - name: master-nodes
    count: 1
    config:
      node.roles: ["master"]
    volumeClaimTemplates:
      - metadata:
          name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
          storageClassName: nfs-sc  
    podTemplate:
      spec:
        # This init container ensures that the max_map_count setting has been applied before starting Elasticsearch.
        # This is not required, but is encouraged when using the previous Daemonset to set max_map_count.
        # Do not use this if setting config.node.store.allow_mmap: false
        initContainers:
        - name: max-map-count-check
          command: ['sh', '-c', "while true; do mmc=$(cat /proc/sys/vm/max_map_count); if [ ${mmc} -eq 262144 ]; then exit 0; fi; sleep 1; done"]
  - name: data
    count: 2
    config:
      node.roles: ["data"]
    volumeClaimTemplates:
      - metadata:
          name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 5Gi
          storageClassName: nfs-sc

Применим файл

kubectl apply -f elastic.yml

Проверка работы elastic

Получим пароль из соответствующего секрета

kubectl get secrets elastic-cluster-es-elastic-user -o json | jq -r .data.elastic | base64 -d

Прокинем порт для работы обращение через localhost

kubectl port-forward service/elastic-cluster-es-http 9200

В отдельном окне обратимся к сервису

curl https://localhost:9200 -u elastic:PASSWORD -k

Получение метрик из нод кластера

На основе Elasticsearch Exporter добавим в манифест создания Elasticsearch класстера под для сбора метрик.

Согласно документации определим securityContext для запуска пода с версией elasticsearch 8.17.1

Для других версий необходимо ознакомиться с документацией!

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 8.17.1
  image: elastic/elasticsearch:8.17.1
  nodeSets:
  - name: default
    count: 1
    volumeClaimTemplates:
      - metadata:
          name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
          storageClassName: nfs-sc  
    podTemplate:
      spec:
        # In versions of Elasticsearch before 8.0.0, the Elastisearch container is run as root and its entrypoint is responsible to run the Elasticsearch process with the elasticsearch user (defined with ID 1000). 
        securityContext:
          runAsUser: 1000
        containers:
          - name: metrics
            image: quay.io/prometheuscommunity/elasticsearch-exporter:latest
            imagePullPolicy: IfNotPresent
            command: ["elasticsearch_exporter",
                      "--es.uri=https://127.0.0.1:9200",
                      "--es.ssl-skip-verify",
                      "--es.timeout=120s"]
            env:
              - name: ES_USERNAME
                value: elastic
              - name: ES_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: elastic-cluster-es-elastic-user
                    key: elastic
            ports:
              - containerPort: 9114
                name: metrics

Пароль для подключения берем из секрета, который создает eck при создании кластера

Изменим стандаратный service/elastic-cluster-es-http, чтобы открыть порт метрик. Это можно сделать добавив в манифест для создания кластера Elasticsearch

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 8.17.1
  image: elastic/elasticsearch:8.17.1
  nodeSets:
  - name: default
    count: 1
    volumeClaimTemplates:
      - metadata:
          name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
          storageClassName: nfs-sc  
    podTemplate:
      spec:
        # In versions of Elasticsearch before 8.0.0, the Elastisearch container is run as root and its entrypoint is responsible to run the Elasticsearch process with the elasticsearch user (defined with ID 1000). 
        # In the background, ECK uses an initContainer to make sure that the data volume is writable for the elasticsearch user. https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-security-context.html
        securityContext:  
          runAsUser: 1000
        containers:
          - name: elasticsearch
            env:
              - name: ES_JAVA_OPTS
                value: "-Xms1g -Xmx1g"
          - name: metrics
            image: quay.io/prometheuscommunity/elasticsearch-exporter:latest
            imagePullPolicy: IfNotPresent
            command: ["elasticsearch_exporter",
                      "--es.uri=https://127.0.0.1:9200",
                      "--es.ssl-skip-verify",
                      "--es.timeout=120s"]
            env:
              - name: ES_USERNAME
                value: elastic
              - name: ES_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: elastic-cluster-es-elastic-user
                    key: elastic
            ports:
              - containerPort: 9114
                name: metrics
http:
    service:
      metadata:
       labels:
         service: "elastic-cluster-es-http"
      spec:
        ports:
          - name: https
            port: 9200
            protocol: TCP
            targetPort: 9200 
          - name: metrics
            port: 9114
            protocol: TCP
            targetPort: 9114

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

cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: monitor-cluster
  namespace: elastic-system
  labels:
    app.kubernetes.io/component: metrics
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      service: "elastic-cluster-es-http"
  endpoints:
  - interval: 5s
    targetPort: metrics
    path: /metrics
EOF

Изменения в ресурсах JMV

Согласно документации вы можете настроить Pod, созданные для каждого приложения стека Elastic, изменив соответствующее podTemplate.

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 8.17.2
  nodeSets:
  - name: default
    count: 1
    podTemplate:
      spec:
        containers:
          - name: elasticsearch
            env:
              - name: ES_JAVA_OPTS
                value: "-Xms4g -Xmx4g"

Установка kibana

Установка происходит через kubectl и обращение к новыму ресурсу Elasticsearch

Пример создания kibana c типом service LoadBalancer

apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 8.17.1
  image: kibana:8.17.1
  count: 1
  elasticsearchRef:
    name: elastic-cluster
    namespace: elastic-system

Настройка HTTPS сертификатов

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

apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 8.17.1
  image: kibana:8.17.1
  count: 1
  elasticsearchRef:
    name: elastic-cluster
    namespace: elastic-system
  http:
    service:
      spec:
        type: LoadBalancer
  tls:
    selfSignedCertificate:
      subjectAltNames:
      - ip: 1.2.3.4
      - dns: kibana.example.com

Согласно документации нет четкого подход к доступу через ingress, поэтому можно просто отключить автоматическую генерацию ssl

apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: kibana-sample
spec:
  version: 8.17.2
  count: 1
  elasticsearchRef:
    name: "elasticsearch-sample"
  http:
    tls:
      selfSignedCertificate:
        disabled: true

Установка fluent-bit

Подготовка к установке

Для установки необходимо скачать репозиторий c помощью helm

helm repo add fluent https://fluent.github.io/helm-charts
helm repo update
helm pull fluent/fluent-bit --untar

Изменить данные в файле ./fluent-bit/values.yaml для подлючения к кластеру elasticsearch

Добавим tolerations, чтобы запуск происходил на всех нодах с помощью daemonset

:/295
tolerations:
  - key: node-role.kubernetes.io/control-plane
    operator: Exists
    effect: NoSchedule
  - key: node-role.kubernetes.io/master
    operator: Exists
    effect: NoSchedule 

:/315

env:
  - name: ELASTICSEARCH_PASSWORD
    valueFrom:
      secretKeyRef:
        name: elastic-cluster-es-elastic-user
        key: elastic

:/359

extraVolumes:
  - name: elastic-certs
    secret:
      secretName: elastic-cluster-es-http-certs-internal
      items:
        - key: ca.crt
          path: certs/es.ca
        - key: tls.crt
          path: certs/es.crt
        - key: tls.key
          path: certs/es.key

extraVolumeMounts:
  - name: elastic-certs
    mountPath: "/opt/"
    readOnly: true

:/419

  outputs: |
    [OUTPUT]
        Name es
        Match kube.*
        Host elastic-cluster-es-http  
        Logstash_Format On
        Logstash_Prefix kube
        Retry_Limit False
        Suppress_Type_Name On
        Buffer_Size 1Mb
        http_user elastic
        http_passwd ${ELASTICSEARCH_PASSWORD}
        tls on
        tls.debug 4
        tls.verify on
        tls.ca_file /opt/certs/es.ca
        tls.crt_file /opt/certs/es.crt
        tls.key_file /opt/certs/es.key

    [OUTPUT]
        Name es
        Match host.*
        Host elastic-cluster-es-http
        Logstash_Format On
        Logstash_Prefix node
        Retry_Limit False
        Suppress_Type_Name On
        Buffer_Size 1Mb
        http_user elastic
        http_passwd ${ELASTICSEARCH_PASSWORD}
        tls on
        tls.debug 4
        tls.verify on
        tls.ca_file /opt/certs/es.ca
        tls.crt_file /opt/certs/es.crt 
        tls.key_file /opt/certs/es.key 

Установка

Установка с корректной конфигурацией

helm install fluent-bit -n elastic-system ./fluent-bit/ -f fluent-bit/values.yaml

После успешного развертывания можем зайти в kibana и убедиться в получение данных