カテゴリー
Linux

Docker ロギング・ドライバを使ってコンテナログを ELK スタックで利用する

はじめに

Docker Compose でミニマムに ELK スタックに入門する記録 – oki2a24 の続きです。

前回までは、 Nginx コンテナの、 Nginx のログ、 /var/log/nginx/access.log などのログファイルを、ディレクトリ共有することで Logstash もアクセス可能にし、読み取る、というやり方でやってきました。

今回は、ログファイルをファイルに書き込むのではなく標準出力にして (変更するというよりも、標準出力がデフォルト) 、そうするとログは Nginx コンテナのログとして出力されますので、これを Logstash で扱う、ということをやっていきます。

無事できたので、ワクワクしています♪

ポイント

  • Docker のロギング・ドライバ gelf を使用する。これは Graylog Extendef ログ・フォーマット(GELF)ロギング・ドライバといい、ログ・メッセージを Graylog のエンドポイントや Logstash に記録する。
  • ログを出力するコンテナ (Logstash 用にログを出力したコンテナ) の logging オプションで設定する。
    • driver: gelfoptions:gelf-address: udp://localhost:12201 、 の 2 つが最低必要。
    • gelf-address: udp://<Logstash サーバのアドレス>:<Logstash サーバのポート> というフォーマット。 Docker Compose で同じマシンのコンテナを指定したい場合、アドレスは localhost と指定する。たとえば services で logstash と定義しても、 gelf-address: udp://logstash:12201 では動かない。
  • Logstash コンテナ
    • Docker Compose で、 ports: で "12201:12201/udp" を追加し、送られてくるログを受け入られるようにしておく。
    • 設定ファイル (logstash.conf など) の input では、 gelf を指定し、 type => dockerport => 12201 と設定する。

コード

前回 から変更した所は、コメントにしています。

docker-compose.yml

version: "3"

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      discovery.type: "single-node"
    volumes:
      - "es_data:/usr/share/elasticsearch/data"

  kibana:
    image: docker.elastic.co/kibana/kibana-oss:7.0.0
    ports:
      - "5601:5601"
    environment:
      ELASTICSEARCH_URL: "http://elasticsearch:9200"
    depends_on:
      - elasticsearch

  logstash:
    image: docker.elastic.co/logstash/logstash-oss:7.0.0
    ports:
      - "12201:12201/udp"
    volumes:
      - "./data/logstash/pipeline:/usr/share/logstash/pipeline"
    #  - "./data/nginx/log:/var/log/nginx"
    depends_on:
      - elasticsearch

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    #volumes:
    #  - "./data/nginx/log:/var/log/nginx"
    logging:
      driver: gelf
      options:
        gelf-address: udp://localhost:12201
        tag: "docker.{{.Name}}"
    depends_on:
      - logstash

volumes:
  es_data:
    driver: local

data/logstash/pipeline/logstash.conf

input {
  #file {
  #  path => "/var/log/nginx/access.log"
  #  start_position => beginning
  #}
  gelf {
    type => docker
      port => 12201
  }
}

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"
  }
  mutate {
    add_field => { "read_timestamp" => "%{@timestamp}" }
  }
  date {
    match => [ "[nginx][access][time]", "dd/MMM/YYYY:H:m:s Z" ]
    remove_field => "[nginx][access][time]"
  }
  useragent {
    source => "[nginx][access][agent]"
    target => "[nginx][access][user_agent]"
    remove_field => "[nginx][access][agent]"
  }
  geoip {
    source => "[nginx][access][remote_ip]"
    target => "[nginx][access][geoip]"
  }
}

output {
  elasticsearch {
    hosts => [ 'elasticsearch' ]
    index => "access_log1"
  }
}

参考ページ

補足。なぜ gelf-address: udp://logstash:12201 ではなく gelf-address: udp://localhost:12201 なのか?

ロギング・ドライバに設定するアドレスは Docker コンテナからではなく、Docker ホストから到達可能な URL でなければならないから。

gelf-address needs to use a hostname/IP that is reachable from the host

it doesn’t work because the log driver urls needs to be accessible by the daemon, not by the container.

おわりに

少しずつ進んでいます♪

次は、ログを送る側と、ログを受け取る側を分離して、動かせるようにしたいです。

以上です。

コメントを残す