Docker logging using filebeat

I’ve been looking for a good solution for viewing my docker container logs via Kibana and Elasticsearch while at the same time maintaining the possibility of accessing the logs from the docker community edition engine itself that sadly lacks an option to use multiple logging outputs for a specific container.

Before I got to using filebeat as a nice solution to this problem, I was using fluentd from inside a docker container on the same host. This forced me to change the docker logging type to fluentd, after which I could no longer access the logs using the docker logs command. To circumvent this shortcoming in practice I would end up disabling filebeat for that container and then restart it. That made me look for a better solution.

So, how to set filebeat up for ingesting logs from docker containers? I presume you already have elasticsearch and kibana running somewhere. If not, I’ve got an easy-to-run docker-compose.yml example that helps you run a 3-node elasticsearch cluster with Kibana to easily experiment with those two locally, for a start.

Now for running filebeat, I run it from a container itself and provide it with access to the docker socket. Probably not the best choice for a secure production environment, but very easy and effective. This is the docker-compose file with filebeat added to it:

    services:
      filebeat:
        image: myregistry.azurecr.io/filebeat:latest
        container_name: filebeat
        hostname: mydockerhost
        restart: unless-stopped
        environment:
          - ELASTICSEARCH_HOSTS=elasticsearch1:9200,elasticsearch2:9200
        labels:
          co.elastic.logs/enabled: "false"
        volumes:
          - type: bind
            source: /var/run/docker.sock
            target: /var/run/docker.sock
          - type: bind
            source: /var/lib/docker
            target: /var/lib/docker
        logging:
          driver: "json-file"
          options:
            max-size: "10m"
            max-file: "2"

With regards to co.elastic.logs/enabled: "false" in the docker-compose.yml file for the filebeat container above, this is to exempt this container from including its own container logfiles from being ingested. I also set the hostname directive for the filebeat service so logs end up in elastic search with a reference to the actual docker hostname they where run on.

And this is the Dockerfile for building the above customized filebeat container. It uses the official filebeat docker image provided by Elastic.co:

  FROM docker.elastic.co/beats/filebeat:7.9.1
  COPY filebeat.docker.yml /usr/share/filebeat/filebeat.yml
  USER root
  RUN chown root:filebeat /usr/share/filebeat/filebeat.yml
  RUN chmod go-w /usr/share/filebeat/filebeat.yml

And this is my filebeat.docker.yml that is copied into the container:

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

  filebeat.autodiscover:
    providers:
      - type: docker
        hints.enabled: true

  processors:
  - add_cloud_metadata: ~

  output.elasticsearch:
    hosts: '${ELASTICSEARCH_HOSTS:elasticsearch:9200}'

  setup.ilm:
    setup.ilm.enabled: auto
    setup.ilm.rollover_alias: "filebeat"
    setup.ilm.pattern: "{now/d}-000001"

This configuration is somewhat tailored to my specific needs, but in general I only replace the default filebeat configuration with the autodiscover module module and have it send logs directly to the elasticsearch cluster. I’ve added ${ELASTICSEARCH_HOSTS:elasticsearch:9200} as a means to override the elasticsearch location(s). Besides, I let filebeat manage the filebeat-* indices via an Index Lifecycle Management (ILM) policy, which has been working well for me.

The above code blocks are also contained in a just run and it worksexample on github.

What springs to my mind is that messages from some processes in some containers could be further processed. Filebeat can help with this in all kinds of ways, which is documented with the autodiscover module.

Kibana showing container logs (from kibana)

Now with elasticsearch, kibana and filebeat instances ingesting the logs for docker containers on the same host as the filebeat container, I can not only easily access unprocessed (raw) container log output using Kibana (via http://localhost:5601 (after you create an Index Pattern for filebeat-* for it), but also look at the container logs via the default docker logging to file mechanism (eg. docker logs -f <container_name>). Hooray!