What is it, naokirin?

Dockerコンテナのlogging-driverを変えずにKibanaにDockerのログを表示する

Dockerコンテナからログファイル出力がアプリケーション的に難しい、けれどエンジニア以外でもログを見たいという話が出たので調査してみました。

方針としては、以下を目指しています。

  • docker-compose でできる
  • ログファイル出力がなくてもできる
  • docker logs でログを見ることができる
  • 社内のみの利用を想定してセキュリティはあまり考慮しないが、そのぶん保守コストは抑えたい

上記を解決するために Logspout, Logstash, Elasticsearch, Kibana を選択してみることにしました。

Logspout を導入する

Logspout の導入は比較的簡単でした。

version: '2'

services:

  logspout:
    image: gliderlabs/logspout:v3.2.4
    command: <コマンドは後述>
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock

dokcer-compose.yml

Logspoutはdocker.sockをマウントする必要がある代わりに、コンテナとして起動するだけでホスト上にあるDockerコンテナすべてのログを、既存のコンテナを変更することなく集約することができます。 本番運用する際には、以下の点があり、気をつける必要があります。

  • Logspout自体が停止した場合やルーティング先が停止した場合にログが欠損する
  • docker.sockをマウントするため、セキュリティ面の懸念がある
  • Dockerに流れるログのみしか扱えない

とはいえ、特に開発用の環境などの手軽に集約できることが重視されるような状況だと便利だと思います。

Logstash を建てて、Logspoutからルーティング設定する

次に Logstash を建てて、Logspout からログ情報を受け取るようにします。

version: '2'

services:

  logspout:
    image: gliderlabs/logspout:v3.2.4
    command: syslog://logstash:5000
    environment:
      - RETRY_COUNT=100
    links:
      - logstash
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock

  logstash:
    image: docker.elastic.co/logstash/logstash:5.6.0
    environment:
      - LOGSPOUT=ignore
      - XPACK_MONITORING_ENABLED=false
    volumes:
      - ./config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf

dokcer-compose.yml

Logstash に関しては設定が必要になるため、logstash.conf をマウントするようにしています。また今回は、X-Packの機能を使う予定は無いため、X-Pack Moniteringを無効化しています。

LOGSPOUT=ignore は logspout にログ収集してほしくないコンテナに設定しておくとそのコンテナのログは収集されなくなります。

Logspout には、Logstash へのルーティング設定とLogstashが起動する前にLogspoutが起動してしまった場合に備えて、 ルーティング先への接続のリトライ数を設定する RETRY_COUNT を増やしています。

logstash.conf を設定する

今回はとりあえず Logspout 経由で取得されたログを見やすい形にすることだけを目的にしています。 詳細は省きますが、syslogによる余計なデータを省略し、コンテナのメッセージのみに削って流れるようにしています。

Logstash では色々とログのメッセージをパイプライン処理できるため、今回やっていること以上に複雑なことにも対応できます。

input {
  syslog {
    port => 5000
    type => "docker"
  }
}

filter {
  grok {
    match => { "message" => "%{SYSLOG5424PRI}%{NONNEGINT:ver} +(?:%{TIMESTAMP_ISO8601:ts}|-) +(?:%{HOSTNAME:service}|-) +(?:%{NOTSPACE:containerName}|-) +(?:%{NOTSPACE:proc}|-) +(?:%{WORD:msgid}|-) +(?:%{SYSLOG5424SD:sd}|-|) +%{GREEDYDATA:msg}" }
  }
  syslog_pri { }
  date {
    match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
  }
  mutate {
    remove_field => [ "message", "priority", "ts", "severity", "facility", "facility_label", "severity_label", "syslog5424_pri", "proc", "syslog_severity_code", "syslog_facility_code", "syslog_facility", "syslog_severity", "syslog_hostname", "syslog_message", "syslog_timestamp", "ver" ]
  }
  mutate {
    rename => { "msg" => "message" }
  }
}

output {
  elasticsearch { hosts => "elasticsearch:9200" }
  stdout { codec => rubydebug }
}

config/logstash.conf

Elasticsearch + Kibana でログを表示する

Elasticsearch と Kibana を起動する

version: '2'

services:

  kibana:
    image: docker.elastic.co/kibana/kibana:5.6.0
    environment:
      - LOGSPOUT=ignore
      - ELASTICSEARCH_URL=http://elasticsearch:9200
      - XPACK_MONITORING_ENABLED=false
      - XPACK_SECURITY_ENABLED=false
    links:
      - elasticsearch
    ports:
      - 5601:5601

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:5.6.0
    environment:
      - LOGSPOUT=ignore
      - node.name=dev-log-kibana
      - bootstrap.memory_lock=true
      - xpack.security.enabled=false
      - xpack.monitoring.enabled=false
      - xpack.watcher.enabled=false
      - xpack.graph.enabled=false
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    mem_limit: 2g
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536

わかりやすい部分の細かい説明は省きます。

Elasticsearch の環境変数では、スワップの無効化、X-Pack の無効化、Javaのヒープサイズの設定を行っています。
メモリはJavaヒープサイズの2倍、ulimit でカーネルの設定を行います。このあたりの設定を行っていないと起動時にメモリ不足等で起動しなかったりします。

Kibana でログを確認する

Kibana は起動時に最適化処理が走るため、少々時間がかかります。 なので、 数分待ってから localhost:5601 にアクセスしてみます。

f:id:naokirin:20180218022648p:plain

最初にデフォルトのインデックスパターンを設定します。 上記の画面で Create を押せばOKです。

そのあと Discover を表示するとログを見ることができます。

まとめ

Logstash や Elasticsearch の設定周りはやや難しいですが、一度動かせるようになれば既存のコンテナにはほぼ手を加えずにログを集約、可視化できます。

今回は使用したい状況に対して、ちょっとメモリ使用量が多くなりすぎてしまったので本来想定していた用途としては厳しいかもというところですが、実際コレだけで動くのはかなり使いやすいと思います。おそらくElasticsearch, Kibana を使わずに、 Logstash の File output plugin を利用してみるか、Elasticsearch + Kibana だけを別に建ててみることになりそうです。

今回書いたもののサンプルをGitHubに公開したので興味ある方はそちらを参考にしてみてください。

github.com