Finaliser la récupération de logs Nginx via la stack Elastic/ECK

Bonjour,

Je reviens vers vous pour une demande d'aide quant à la récolte de logs Nginx. Je me permets de poster en deux fois étant donnée la limitation sur le nombre de caractères.

La situation est la suivante :

  • Win10 PRO, Docker Desktop, WSL1/Ubuntu 18.04
  • un namespace avec :

Nginx :

apiVersion: v1
kind: Service
metadata:
  namespace: beats
  name: nginx
  labels:
    app: nginx-ns-beats
spec:
  type: LoadBalancer
  ports:
    - port: 80
      protocol: TCP
      targetPort: http
  selector:
    app: nginx-ns-beats

---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: beats
  name: nginx-ns-beats
spec:
  selector:
    matchLabels:
      app: nginx-ns-beats
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx-ns-beats
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - name: http
              containerPort: 80
          volumeMounts:
            - mountPath: "/var/log/nginx"
              name: nginx-data
      volumes:
        - name: nginx-data
          persistentVolumeClaim:
            claimName: nginx-data-pvc

Filebeat :

apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: beats
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    tags: ["nginx_test"]

    filebeat.autodiscover:
      providers:
        - type: kubernetes
          host: ${NODE_NAME}
          hints.enabled: true
          templates:
            - condition.contains:
                kubernetes.pod.name: nginx
              config:
                - module: nginx
                  enabled: true
                  log:
                    input:
                      type: container
                      paths:
                        volumes:
                          - name: nginx-data
                            persistentVolumeClaim:
                              claimName: nginx-data-pvc
    processors:
      - drop_event:
          when:
            or:
              - contains:
                  kubernetes.pod.name: "filebeat"
              - contains:
                  kubernetes.pod.name: "elasticsearch"
              - contains:
                  kubernetes.pod.name: "kibana"
              - contains:
                  kubernetes.pod.name: "logstash"
              - contains:
                  kubernetes.container.name: "dashboard"
              - contains:
                  kubernetes.container.name: "manager"
      - add_cloud_metadata:
      - add_host_metadata:

    output.logstash:
      hosts: ["logstash:5044"]

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: docker.elastic.co/beats/filebeat:7.8.0
          args: [
            "-c", "/etc/filebeat.yml",
            "-e",
          ]
          env:
            - name: ELASTICSEARCH_HOST
              value: elasticsearch-es-http
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value: elastic
            - name: ELASTICSEARCH_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: elastic
                  name: elasticsearch-es-elastic-user
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 100Mi
          volumeMounts:
            - name: config
              mountPath: /etc/filebeat.yml
              readOnly: true
              subPath: filebeat.yml
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
              readOnly: true
            - name: es-certs
              mountPath: /mnt/elastic/tls.crt
              readOnly: true
              subPath: tls.crt
      volumes:
        - name: config
          configMap:
            defaultMode: 0600
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        - name: data
          hostPath:
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
        - name: es-certs
          secret:
            secretName: elasticsearch-es-http-certs-public

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
  namespace: beats
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: beats
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  namespace: beats
  name: filebeat
  labels:
    k8s-app: filebeat
rules:
  - apiGroups: [""]
    resources:
      - namespaces
      - pods
    verbs:
      - get
      - watch
      - list

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat

Logstash :

---
apiVersion: v1
kind: Service
metadata:
  namespace: beats
  labels:
    app: logstash
  name: logstash
spec:
  ports:
    - name: "25826"
      port: 25826
      targetPort: 25826
    - name: "5044"
      port: 5044
      targetPort: 5044
  selector:
    app: logstash
status:
  loadBalancer: {}

---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: beats
  name: logstash-configmap
data:
  logstash.yml: |
    http.host: "0.0.0.0"
    path.config: /usr/share/logstash/pipeline
  logstash.conf: |
    input {
      beats {
        port => 5044
      }
    }
    filter {
          grok {
            match => { "message" => ["%{IPORHOST:[nginx][access][remote_ip]} - %{DATA:[nginx][access][user_name]} \[%{HTTPDATE:[nginx][access][time]}\] \"%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}\" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][body_sent][bytes]} \"%{DATA:[nginx][access][referrer]}\" \"%{DATA:[nginx][access][agent]}\""] }
            remove_field => "message"
          }
    }
    output {
      if "nginx_test" in [tags] {
        elasticsearch {
          index => "nginx_test-%{[@metadata][beat]}-%{+YYYY.MM.dd-H.m}"
          hosts => [ "${ES_HOSTS}" ]
          user => "${ES_USER}"
          password => "${ES_PASSWORD}"
          cacert => '/etc/logstash/certificates/ca.crt'
        }
      }
    }

---
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: logstash
  name: logstash
  namespace: beats
spec:
  containers:
    - image: docker.elastic.co/logstash/logstash:7.8.0
      name: logstash
      ports:
        - containerPort: 25826
        - containerPort: 5044
      env:
        - name: ES_HOSTS
          value: "https://elasticsearch-es-http:9200"
        - name: ES_USER
          value: "elastic"
        - name: ES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: elasticsearch-es-elastic-user
              key: elastic
      resources: {}
      volumeMounts:
        - name: config-volume
          mountPath: /usr/share/logstash/config
        - name: logstash-pipeline-volume
          mountPath: /usr/share/logstash/pipeline
        - name: cert-ca
          mountPath: "/etc/logstash/certificates"
          readOnly: true
  restartPolicy: OnFailure
  volumes:
    - name: config-volume
      configMap:
        name: logstash-configmap
        items:
          - key: logstash.yml
            path: logstash.yml
    - name: logstash-pipeline-volume
      configMap:
        name: logstash-configmap
        items:
          - key: logstash.conf
            path: logstash.conf
    - name: cert-ca
      secret:
        secretName: elasticsearch-es-http-certs-public
status: {}

Elasticsearch :

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch
  namespace: beats
spec:
  version: 7.8.0
  nodeSets:
    - name: elasticsearch
      count: 1
      config:
        node.store.allow_mmap: false
        node.master: true
        node.data: true
        node.ingest: true
        xpack.security.authc:
          anonymous:
            username: anonymous
            roles: superuser
            authz_exception: false
      podTemplate:
        metadata:
          labels:
            app: elasticsearch
        spec:
          initContainers:
            - name: sysctl
              securityContext:
                privileged: true
              command: ['sh', '-c', 'sysctl -w vm.max_map_count=262144']
          containers:
            - name: elasticsearch
              resources:
                requests:
                  memory: 4Gi
                  cpu: 0.5
                limits:
                  memory: 4Gi
                  cpu: 1
              env:
                - name: ES_JAVA_OPTS
                  value: "-Xms2g -Xmx2g"
      volumeClaimTemplates:
        - metadata:
            name: elasticsearch-data
          spec:
            storageClassName: es-data
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 5Gi

Kibana :

---
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: kibana
  namespace: beats
spec:
  version: 7.8.0
  count: 1
  elasticsearchRef:
    name: elasticsearch
  http:
    service:
      spec:
        type: LoadBalancer

2 Persistent Volumes pour Elasticsearch et les logs de Nginx :

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: es-data
  namespace: beats
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: es-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: es-data
  hostPath:
    path: /local/path/to/es-data

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  #storageClassName: nginx-data
  storageClassName: ""
  hostPath:
    path: /local/path/to/nginx-data

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-data-pvc
  namespace: beats
spec:
  #storageClassName: nginx-data
  storageClassName: ""
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  volumeName: nginx-data-pv

Suite de mon précédent message :

Pour générer des logs, je fais F5/Ctrl+F5 sur la page d'accueil Nginx.

Quand je démarre la stack, les pods sont en running et ready 1/1.

La commande curl -k -XGET https://localhost:9200/_cat/indices rend :

yellow open nginx_test-filebeat-2020.07.21-12.11 Jlg8-J1TQfCi0Iq8Bi2FXw 1 1  5  0  64.3kb  64.3kb
yellow open nginx_test-filebeat-2020.07.21-12.12 H4H-46yKTJ-1vjv_ripRjg 1 1 11  0 133.1kb 133.1kb
green  open .kibana_1                            FMNSvkHZTBqTO4pNYShTaA 1 0 11  5  39.8kb  39.8kb
green  open .apm-agent-configuration             LRc0-FzJQ3GoXxErGBAOMw 1 0  0  0    208b    208b
green  open .kibana-event-log-7.8.0-000001       dbBHLNumRnepRO3513MO-Q 1 0  1  0   5.3kb   5.3kb
green  open .security-7                          RflkD4NmTTuuJo6jqV25fQ 1 0 37 37   115kb   115kb
green  open .apm-custom-link                     ZlcinAjqQUWKz08w_uspZg 1 0  0  0    208b    208b
green  open .kibana_task_manager_1               Mhx-KOxlTnSBZkP4nv3lBA 1 0  5  0  56.9kb  56.9kb
green  open .async-search                        C-LvUFErSI6x_o5tF0_LIw 1 0  1  1   137kb   137kb

Dans Kibana, je récupère des choses mais pas celles souhaitées. Exemple :

@timestamp Jul 21, 2020 @ 14:10:10.069
@version 1
_id 7llIcXMBGmaWY3svJgAv
_index nginx_test-filebeat-2020.07.21-12.10
_score - 
_type _doc
agent.ephemeral_id 4e01b890-3542-4d3e-ac0c-862d8338239b
agent.hostname docker-desktop
agent.id 2cff26af-fe31-4b49-a0fc-ba7458a5bfa7
agent.name docker-desktop
agent.type filebeat
agent.version 7.8.0
ecs.version 1.5.0
host.architecture x86_64
host.containerized false
host.hostname docker-desktop
host.id 83a8f1f835d84a9a9bf5417cecaf0c8e
host.ip 192.168.65.3, fe80::50:ff:fe00:1, 172.17.0.1, 172.28.0.1, 10.1.0.1, [...]
host.mac 02:50:00:00:00:01, 02:42:2a:ec:18:e1, 02:42:bb:6a:a9:d7, [...]
host.name docker-desktop
host.os.codename Core
host.os.family redhat
host.os.kernel 4.19.76-linuxkit
host.os.name CentOS Linux
host.os.platform centos
host.os.version 7 (Core)
input.type container
kubernetes.container.image k8s.gcr.io/etcd:3.3.15-0
kubernetes.container.name etcd
kubernetes.labels.component etcd
kubernetes.labels.tier control-plane
kubernetes.namespace kube-system
kubernetes.node.name docker-desktop
kubernetes.pod.name etcd-docker-desktop
kubernetes.pod.uid 51a5bffe-64b3-460d-a5b4-6c234f7d3fa6
log.file.path /var/lib/docker/containers/[CONTAINER_ID]-json.log
log.offset 46,995
message WARNING: 2020/07/21 12:10:10 grpc: addrConn.createTransport failed to connect to {127.0.0.1:2379 0  <nil>}. Err :connection error: desc = "transport: authentication handshake failed: remote error: tls: bad certificate". Reconnecting...
stream stderr
tags nginx_test, beats_input_codec_plain_applied, _grokparsefailure

Les champs message, tags, log.file.path et kubernetes.namespace, notamment, me paraissent bizarres vues mes configurations.

Dans le filebeat.yaml :

  • j'ai ajouté un tag (pour aider au filtrage dans Logstash)
  • j'ai ajouté un processor drop_event histoire de commencer à filtrer les données non utiles pour moi dans l'immédiat
  • je demande à autodiscover de pointer sur le PV où sont persistés les logs de Nginx. D'ailleurs, j'ai un doute sur la pertinence du bloc :
paths:
  volumes:
    - name: nginx-data
      persistentVolumeClaim:
        claimName: nginx-data-pvc

Encore une fois, tous les containers sont en running : je n'ai aucune erreur d'exécution de la stack. Par contre, même sans faire de F5/Ctrl+F5, de nouveaux index sont générés toutes les minutes (cf. configuration de l'output Logstash)... :thinking:

Auriez-vous une idée pour que je puisse récupérer correctement les logs générés par Nginx, s'il-vous-plaît ? L'idée est de récupérer quelque chose comme ça dans le champ message :

127.0.0.1 - - [21/Jul/2020:12:01:54 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" "-"

Merci par avance pour l'aide que vous voudrez bien m'apporter. Je continue à creuser la question de mon côté.

Guillaume.

Salut, tu as visiblement une erreur dans le parsing de tes logs, le pattern grok que tu appliques aux logs semble ne pas correspondre au format. on peut le remarquer grace au tag "_grokparsefailure"

Après ça le champ message devrait apparaître

Il me semble qu'un pattern au format syslog ou nginx générique existe.

Salut grumo35 et merci pour ta réponse,

J'ai donc vérifié du côté du filtre Grok. C'est à priori le bon. Du moins, c'est celui que j'ai utilisé il y a quelques temps pour un déploiement de la stack Elastic avec Docker Compose : ce filtre avait l'air de bien fonctionner.
J'ai d'ailleurs modifié la configuration de Logstash avec un bloc filter vide et j'ai le même souci.

Pour apporter un peu plus d'informations, j'ai utilisé la commande :

kubectl -n beats logs po/FILEBEAT_POD_ID

J'ai récupéré quelque chose comme ça qui se répète plusieurs fois :

2020-07-22T15:12:21.718Z	ERROR	[autodiscover]	autodiscover/autodiscover.go:210	Auto discover config check failed for config '{
  "enabled": true,
  "log": {
    "input": {
      "paths": {
        "volumes": [
          {
            "name": "nginx-data-pv",
            "persistentVolumeClaim": {
              "claimName": "nginx-data-pvc"
            }
          }
        ]
      },
      "type": "container"
    }
  },
  "module": "nginx"
}', won't start runner: fileset nginx/log is configured but doesn't exist

Apparemment le souci vient de ce bloc de code dans filebeat.yaml :

templates:
            - condition.contains:
                kubernetes.pod.name: nginx
              config:
                - module: nginx
                  enabled: true
                  log:
                    input:
                      type: container
                      paths:
                        volumes:
                          - name: nginx-data-pv
                            persistentVolumeClaim:
                              claimName: nginx-data-pvc

La valeur que je donne au champ paths est de "l'improvisation" de ma part... ce ne serait pas surprenant que ça ne fonctionne pas. Le problème est que je ne vois pas comment faire autrement, pour que Filebeat aille récolter les access.log et error.log de Nginx... Si quelqu'un a une suggestion à ce niveau, je suis preneur.

Par ailleurs, comment est-ce que je peux faire pour "donner un signe distinctif" aux logs Nginx afin de pouvoir mieux les cibler avec Filebeat et surtout après avec Logstash ? Avec ce signe distinctif (tag ? autre ?), je pourrais demander à Filebeat puis Logstash de ne s'attarder que sur ces logs (pour le moment).

Merci à vous,

Guillaume.

Là c'est filebeat qui ne reconnaît pas les directives de type path comme il te le dit avec "no fileset"

Tu n'as pas moyen de lui indiquer des fichier de logs directement ?

Je verrais quelque chose comme ça

- module: nginx
  access:
    enabled: true
    var.paths: ["/path/to/log/nginx/access.log*"]
    tags: ["access"]
  error:
    enabled: true
    var.paths: ["/path/to/log/nginx/error.log*"]
    tags: ["error"]

Tu peux me montrer un document de sortie sans la directive filter ? Il ne devrait pas y avoir le même résultat si le Grok n'est pas fait.

Bonjour grumo35,

Je me suis mal exprimé dans mon précédent message. Quand je disais que :

J'ai d'ailleurs modifié la configuration de Logstash avec un bloc filter vide et j'ai le même souci.

... je voulais parler du souci pour récupérer les logs propres à Nginx. En effet, avec le bloc filter vide, je n'ai plus le tag relatif au problème de parsing avec le filtre Grok :

@timestamp Jul 23, 2020 @ 01:54:51.449
@version 1
_id GofzeHMBptiZIa3kpA9B
_index nginx_test-filebeat-2020.07.22-23.54
_score  - 
_type _doc
agent.ephemeral_id fbbc1daf-2c35-47c7-8181-4572b65a7dcb
agent.hostname docker-desktop
agent.id 2cff26af-fe31-4b49-a0fc-ba7458a5bfa7
agent.name docker-desktop
agent.type filebeat
agent.version 7.8.0
ecs.version 1.5.0
host.architecture x86_64
host.containerized false
host.hostname docker-desktop
host.id 83a8f1f835d84a9a9bf5417cecaf0c8e
host.ip 192.168.65.3, [...]
host.mac 02:50:00:00:00:01, [...]
host.name docker-desktop
host.os.codename Core
host.os.family redhat
host.os.kernel 4.19.76-linuxkit
host.os.name CentOS Linux
host.os.platform centos
host.os.version 7 (Core)
input.type container
kubernetes.container.image k8s.gcr.io/kube-apiserver:v1.16.5
kubernetes.container.name kube-apiserver
kubernetes.labels.component kube-apiserver
kubernetes.labels.tier control-plane
kubernetes.namespace kube-system
kubernetes.node.name docker-desktop
kubernetes.pod.name kube-apiserver-docker-desktop
kubernetes.pod.uid 9fb09a5c-36bd-4f5d-bd37-b7585050dc10
log.file.path /var/lib/docker/containers/2077d207f037061d07ccbe79ec2b2f1399cb42e670bb2ff55c3ca4b7910b86fb/2077d207f037061d07ccbe79ec2b2f1399cb42e670bb2ff55c3ca4b7910b86fb-json.log
log.offset 170,248
message I0722 23:54:51.449354       1 controller.go:107] OpenAPI AggregationController: Processing item v1alpha3.compose.docker.com
stream stderr
tags nginx_test, beats_input_codec_plain_applied

Sinon, j'ai essayé avec la modification que tu me proposes. Mon bloc providers ressemble donc maintenant à ça :

providers:
        - type: kubernetes
          host: ${NODE_NAME}
          hints.enabled: true
          templates:
            - condition.contains:
                kubernetes.pod.name: nginx
              config:
                - module: nginx
                  access:
                    enabled: true
                    var.paths: ["/c/path/to/nginx-data/persistent/volume/access.log*"]
                    tags: ["access"]
                  error:
                    enabled: true
                    var.paths: ["/c/path/to/nginx-data/persistent/volume/error.log*"]
                    tags: ["error"]

Je ne retrouve pas les logs Nginx dans Kibana. Tout est bien taggué nginx_test, mais je ne retrouve pas les tags error ni access (les tags que tu as mentionnés dans le bloc module: nginx plus haut) :

Capturetag

Par ailleurs, pour le champ kubernetes.namespace, je n'ai rien d'autre que kube-system... aucune trace de mon namespace beats. :thinking:

Capturetag2

Si ça peut aider...

Bonjour,

Après pas mal de tâtonnements, je parviens à récupérer des "données" en provenance du namespace beats. Dans Kibana, beats apparaît bien dans le champ kubernetes.namespace :

Capture_ns1

Seulement, ces données ne sont pas les logs générés suite aux clics sur F5 ou Ctrl+F5 sur la page Welcome to Nginx. Par exemple, je récupère ce genre de choses dans le champ message :

message {"type": "server", "timestamp": "2020-07-27T09:02:07,494Z", "level": "INFO", "component": "o.e.c.m.MetadataMappingService", "cluster.name": "elasticsearch", "node.name": "elasticsearch-es-elasticsearch-0", "message": "[nginx_test-filebeat-2020.07.27-9.2/GP7KCMwhRiSVsfxHMK2Tyw] create_mapping [_doc]", "cluster.uuid": "kbIEppuhQlKGRvwQKpBE6w", "node.id": "hJlfaS_4T1qa4CFy_6GkCQ" }

Là, on est sur une information qui concerne Elasticsearch a priori, mais ce n'est pas une structure de log type Nginx.
En fait, je ne récupère aucune donnée tagguée access ou error. Le souci doit donc provenir de la configuration du bloc template de l'autodiscover dans filebeat.yaml (voir ci-dessous), mais je ne vois pas où peut être le problème. Le tag nginx_test passe bien.

Voici la version à jour de mon fichier :

filebeat.yaml :

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: beats
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    tags: ["nginx_test"]
    filebeat.autodiscover:
      providers:
        - type: kubernetes
          host: ${NODE_NAME}
          hints.enabled: true
          add_resource_metadata:
            namespace:
              enabled: true
          templates:
            - condition.and:
              - contains:
                  kubernetes.image.name: nginx
              - contains:
                  kubernetes.namespace: beats
              config:
                - module: nginx
                  access:
                    enabled: true
                    var.paths: ["/c/PATH/TO/nginx-data/access.log"]
                    subPath: access.log
                    tags: ["access"]
                  error:
                    enabled: true
                    var.paths: ["/c/PATH/TO/nginx-data/error.log"]
                    subPath: error.log
                    tags: ["error"]
    processors:

      - add_cloud_metadata:
      - add_host_metadata: ~

    output.logstash:
      hosts: ["logstash:5044"]

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: docker.elastic.co/beats/filebeat:7.8.0
          args: [
            "-c", "/etc/filebeat.yml",
            "-e",
          ]
          env:
            - name: ELASTICSEARCH_HOST
              value: elasticsearch-es-http
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value: elastic
            - name: ELASTICSEARCH_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: elastic
                  name: elasticsearch-es-elastic-user
            - name: NODE_NAME
              # value: elasticsearch-es-elasticsearch-0
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 100Mi
          volumeMounts:
            - name: config
              mountPath: /etc/filebeat.yml
              subPath: filebeat.yml
              readOnly: true
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
              readOnly: true
            #- name: es-certs
              #mountPath: /mnt/elastic/tls.crt
              #readOnly: true
              #subPath: tls.crt
      volumes:
        - name: config
          configMap:
            defaultMode: 0600
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        - name: data
          hostPath:
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
        #- name: es-certs
          #secret:
            #secretName: elasticsearch-es-http-certs-public

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: beats
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: filebeat
  labels:
    k8s-app: filebeat
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources:
      - namespaces
      - pods
    verbs:
      - get
      - watch
      - list

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat

---

nginx.yaml :

---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  namespace: beats
  labels:
    app: my-nginx
spec:
  externalTrafficPolicy: Local
  type: LoadBalancer
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: my-nginx

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: beats
spec:
  selector:
    matchLabels:
      app: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx
          ports:
          - containerPort: 80
          volumeMounts:
            - mountPath: "/var/log/nginx"
              name: nginx-data
      volumes:
        - name: nginx-data
          persistentVolumeClaim:
            claimName: nginx-data-pvc

Pour info (je ne sais pas si ça a un lien), je récupère à plusieurs reprises, des erreurs comme celle-ci dans le kubectl logs de Filebeat :

2020-07-27T12:48:44.375Z	ERROR	fileset/factory.go:103	Error creating input: Can only start an input when all related states are finished: {Id:1191429-2049 Finished:false Fileinfo:0xc0036b2410 Source:/var/lib/docker/containers/859c1546dbfc0ad0f906f8a0eff65782e385ac30b2eaaf3fd7c9aa09aab75643/859c1546dbfc0ad0f906f8a0eff65782e385ac30b2eaaf3fd7c9aa09aab75643-json.log Offset:827351 Timestamp:2020-07-27 12:48:33.492611289 +0000 UTC m=+11145.518057280 TTL:-1ns Type:container Meta:map[] FileStateOS:1191429-2049}
2020-07-27T12:48:44.376Z	ERROR	[autodiscover]	autodiscover/autodiscover.go:210	Auto discover config check failed for config '{
  "log": {
    "enabled": true,
    "input": {
      "paths": [
        "/var/lib/docker/containers/859c1546dbfc0ad0f906f8a0eff65782e385ac30b2eaaf3fd7c9aa09aab75643/*-json.log"
      ],
      "stream": "all",
      "type": "container"
    }
  },
  "module": "kibana"
}', won't start runner: Can only start an input when all related states are finished: {Id:1191429-2049 Finished:false Fileinfo:0xc0036b2410 Source:/var/lib/docker/containers/859c1546dbfc0ad0f906f8a0eff65782e385ac30b2eaaf3fd7c9aa09aab75643/859c1546dbfc0ad0f906f8a0eff65782e385ac30b2eaaf3fd7c9aa09aab75643-json.log Offset:827351 Timestamp:2020-07-27 12:48:33.492611289 +0000 UTC m=+11145.518057280 TTL:-1ns Type:container Meta:map[] FileStateOS:1191429-2049}

Par contre, il n'y a aucune trace du path du PV pour Nginx...

A nouveau, si jamais vous avez des idées pour résoudre ce problème, merci par avance.

Guillaume.

Je n'ai malheureusement pas l'experience sur ce type de problème avec une infrastructure comme la votre Kubernetes m'est totallement étranger.

J'espère que vous trouverez des réponses, essayez toujuors de traduire vote message sur le forum anglais.
Bon courage !

Merci grumo35. J'ai en effet posté sur le forum anglais d'elastic.co... mais ça ne se bouscule pas pour y répondre... vacances obligent peut-être.

Je continue à prospecter.

Bonne continuation !

Bonjour,

Je reviens vers vous avec un peu de nouveau. Après modification du fichier filebeat.yaml, je parviens à récupérer les fichiers access.log et error.log dans le container filebeat (j'ai ajouté un volume et un mountVolume dans le fichier de configuration, voir plus bas).

  • Le souci est que ces fichiers restent désespérément vides malgré des F5/Ctrl+F5 sur la page d'accueil Welcome to nginx.

  • Par ailleurs, j'ai modifié volontairement à la main, le fichier access.log dans le conteneur filebeat (j'y ai écrit une chaîne de caractères quelconque) via une commande kubectl exec -ti... Ce qui me surprend, c'est que cette chaîne de caractères se retrouve à nouveau malgré la suppression du conteneur et le redémarrage de toute la stack ! Y a un truc qui m'échappe : cela veut dire que les fichiers access.log et error.log ont donc été récupérés la 1ère fois à partir du volume nginx-data, mais qu'ils ont été persistés depuis... mais je ne vois pas où. En tout cas, ces fichiers ne sont

filebeat.yaml :

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: beats
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-

    tags: ["nginx_test"]

    filebeat.config:
      modules:
        path: ${path.config}/modules.d/*.yml
        reload.enabled: false

    filebeat.autodiscover:

      providers:
        - type: kubernetes
          host: ${NODE_NAME}
          hints.enabled: true

          templates:
            - conditions.and:
                - contains:
                    kubernetes.container.image: nginx
                - contains:
                    kubernetes.namespace: beats
              config:
                - module: nginx
                  access:
                    enabled: true
                    var.paths: ["/usr/share/filebeat/nginxlogs"]
                    subPath: access.log
                    tags: ["access"]
                  error:
                    enabled: true
                    var.paths: ["/usr/share/filebeat/nginxlogs"]
                    subPath: error.log
                    tags: ["error"]

    processors:
      - add_cloud_metadata:
      - add_kubernetes_metadata:
          in_cluster: true
      - add_host_metadata:
      - add_docker_metadata:

    filebeat.registry.path: /usr/share/filebeat/data/registry

    output.logstash:
      hosts: ["logstash:5044"]

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: docker.elastic.co/beats/filebeat:7.8.0
          args: [
            "-c", "/etc/filebeat.yml",
            "-e",
          ]
          env:
            - name: ELASTICSEARCH_HOST
              value: elasticsearch-es-http
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value: elastic
            - name: ELASTICSEARCH_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: elastic
                  name: elasticsearch-es-elastic-user
            - name: NODE_NAME
              # value: elasticsearch-es-elasticsearch-0
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 100Mi
          volumeMounts:
            - name: config
              #mountPath: /usr/share/filebeat/filebeat.yml
              mountPath: /etc/filebeat.yml
              subPath: filebeat.yml
              readOnly: true
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
              readOnly: true
            - name: es-certs
              mountPath: /mnt/elastic/tls.crt
              readOnly: true
              subPath: tls.crt
            - name: nginxlogs
              mountPath: /usr/share/filebeat/nginxlogs
              readOnly: false
      volumes:
        - name: config
          configMap:
            defaultMode: 0600
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        - name: data
          hostPath:
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
        - name: es-certs
          secret:
            secretName: elasticsearch-es-http-certs-public
        - name: nginxlogs
          hostPath:
            path: /c/path/to/nginx-data/persistent/volume/nginx-data

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: beats
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io

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

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat
---

Et pour rappel, le fichier des volumes :

volume.yaml :

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: es-data
  namespace: beats
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nginx-data
  namespace: beats
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: es-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: es-data
  hostPath:
    path: /c/path/to/nginx-data/persistent/volume/es-data

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  #storageClassName: nginx-data
  storageClassName: ""
  hostPath:
    path: /c/path/to/nginx-data/persistent/volume/nginx-data

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-data-pvc
  namespace: beats
spec:
  #storageClassName: nginx-data
  storageClassName: ""
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  volumeName: nginx-data-pv

SI quelqu'un a une aide à m'apporter par rapport à ces nouveaux éléments : comment faire pour que les fichiers access.log et error.log du conteneur filebeat contiennent les mêmes lignes de log que dans le PV nginx-data ?

Merci par avance,

Guillaume

Bonjour,

Je reviens ici poster la version "au point" du fichier filebeat.yaml, si cela peut servir à quelqu'un. J'ai résolu mon souci d'accès aux données des fichiers access.log et error.log... au final, c'était dû à une inattention de ma part quant à l'écriture d'un path pour un des volumes utilisés.

filebeat.yaml

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: beats
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-

    tags: ["nginx_test"]

    filebeat.config:
      modules:
        path: ${path.config}/modules.d/*.yml
        reload.enabled: false

    filebeat.autodiscover:

      providers:
        - type: kubernetes
          host: ${NODE_NAME}
          hints.enabled: true

          templates:
            - conditions.and:
                - contains.kubernetes.container.image: nginx
                - equals.kubernetes.namespace: beats
              config:
                - module: nginx
                  access:
                    enabled: true
                    var.paths: ["/usr/share/filebeat/nginxlogs/access.log"]
                  error:
                    enabled: true
                    var.paths: ["/usr/share/filebeat/nginxlogs/error.log"]

    processors:
      - add_cloud_metadata:
      - add_kubernetes_metadata:
          in_cluster: true
      - add_host_metadata:
      - add_docker_metadata:


    output.logstash:
      hosts: ["logstash:5044"]

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: docker.elastic.co/beats/filebeat:7.8.0
          args: [
            "-c", "/etc/filebeat.yml",
            "-e",
          ]
          env:
            - name: ELASTICSEARCH_HOST
              value: elasticsearch-es-http
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value: elastic
            - name: ELASTICSEARCH_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: elastic
                  name: elasticsearch-es-elastic-user
            - name: NODE_NAME
              # value: elasticsearch-es-elasticsearch-0
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 100Mi
          volumeMounts:
            - name: config
              #mountPath: /usr/share/filebeat/filebeat.yml
              mountPath: /etc/filebeat.yml
              subPath: filebeat.yml
              readOnly: true
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
              readOnly: true
            - name: es-certs
              mountPath: /mnt/elastic/tls.crt
              readOnly: true
              subPath: tls.crt
            - name: nginxlogs
              mountPath: /usr/share/filebeat/nginxlogs

      volumes:
        - name: config
          configMap:
            defaultMode: 0600
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        - name: data
          hostPath:
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
        - name: es-certs
          secret:
            secretName: elasticsearch-es-http-certs-public
        - name: nginxlogs
          hostPath:
            path: /c/path/to/nginx-data/persistent/volume/nginx-data

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: beats
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io

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

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: beats
  labels:
    k8s-app: filebeat

volume.yaml :

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: es-data
  namespace: beats
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nginx-data
  namespace: beats
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: es-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: es-data
  hostPath:
    path: /c/path/to/es-data/persistent/volume/es-data

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-data-pv
  namespace: beats
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: ""
  hostPath:
    path: /c/path/to/nginx-data/persistent/volume/nginx-data

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-data-pvc
  namespace: beats
spec:
  storageClassName: ""
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  volumeName: nginx-data-pv

Pour info, le champ tags dans la configuration du module nginx, ne fonctionne pas... ou du moins pas comme j'ai pu l'essayer plus haut. Ceci n'est pas très important au final, le filtrage ou manipulation des données dans Logstash ensuite, pouvant se faire sur le champ fileset.name par exemple (if [fileset][name] == "access"...).

Merci encore à grumo35 pour ses réponses.

Guillaume.