Dockerコンテナで発生したログを確認するのにdocker logsが使われる。しかし、従来のログのようにSyslogやfluentdで管理したい時が有る。これを実現するにはDocker1.6から追加されているLogging Driverを使えばいい。Driverにはいくつか種類があるが、Syslog Driverを利用すればDockerホストのSyslogにコンテナのログを出力することが出来るし、fluentd Driverを使えばfluentdでログを集約できる。

この記事では、Logging Driverでログを管理することを目的として、最近Logging Driverの1つとして追加されたfluentdを利用したコンテナ内のログ管理をしてみる。

検証環境

➤  system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: OS X 10.10.5 (14F1021)
      Kernel Version: Darwin 14.5.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal

➤  vagrant -v
Vagrant 1.7.4

➤  docker-machine -v
docker-machine version 0.5.4, build 6643d0e

検証構成

20151224_logging_architecture

準備

Docker Machine + Vagrantで任意のLinuxディストリビューションでDockerホストを構築するを参考にしてDockerホストを用意する。

fluentd Logging Driverを使う

ここからfluentd Logging Driverを使ったログの集約を行う。docker composeを使って構成で示した環境を構築するものとする。

Log collectorの設定ファイル準備

fluentdの公式イメージを利用する。fluentdのオリジナルDockerfileではDockerfileをビルドするときにflunet.confがあればそれをコンテナ内にコピーするようになっているので予め用意する。

➤ mkdir fluentd
➤ mkdir -p fluentd/plugins
➤ touch fluentd/fluent.conf
➤ touch fluentd/Dockerfile

また、fluent.confはLogging Driverのドキュメントを参考に作成する。

➤  cat fluent.conf
<source>
  type forward
  port 24224
  bind 0.0.0.0
</source>
<match docker.**>
  type stdout
</match>

最後にDockerfileを以下の内容で編集する。

FROM fluent/fluentd

Web1,2の設定ファイルの準備

Nginxコンテナを2つ立てて、アクセスログをfluentd回収したいので、Log collectorの設定ファイルと同様にこちらも設定ファイルを作る。

➤ mkdir web1
➤ touch web/index.html
➤ touch web/server.conf
➤ touch web/Dockerfile

また、index.htmlserver.conDockerfileをそれぞれ以下の内容を編集する。

➤  cat index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>nginx</title>
    <link rel="stylesheet" href="">
</head>
<body>
  This is Web1 !!
</body>
</html>

➤  cat server.conf
server {
    listen 80 default;
    server_name _;
    root /var/www/html;
    index index.html;
    charset utf-8;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
}

➤  cat Dockerfile
FROM nginx
ADD server.conf /etc/nginx/conf.d/server.conf

RUN mkdir -p /var/www/html
ADD index.html  /var/www/html/index.html

web2もweb1と同様に設定ファイルを作成する。内容は同じなので割愛する。

composeでコンテナを起動する

Composeでコンテナを管理するため以下の内容のdocker-compose.ymlを作る。

➤  cat docker-compose.yml
log_collector:
  build: fluentd/
  container_name: log_collector
  volumes:
    - /var/lib/docker/containers:/var/lib/docker/containers
  ports:
    - '24224:24224'
web1:
  build: web1/
  container_name: web1
  links:
    - log_collector
  ports:
    - '80:80'
  log_driver: 'fluentd'
  log_opt:
    fluentd-address: localhost:24224
    fluentd-tag: docker.{{.FullID}}
web2:
  build: web2/
  container_name: web2
  links:
    - log_collector
  ports:
    - '8080:80'
  log_driver: 'fluentd'
  log_opt:
    fluentd-address: localhost:24224
    fluentd-tag: docker.{{.FullID}}

全てのファイルが準備出来るとこのようなファイル構成になっているはず。

➤  tree .
.
├── Vagrantfile
├── docker-compose.yml
├── fluentd
│   ├── Dockerfile
│   ├── fluent.conf
│   └── plugins
├── web1
│   ├── Dockerfile
│   ├── index.html
│   └── server.conf
└── web2
    ├── Dockerfile
    ├── index.html
    └── server.conf

composeを使ってコンテナを起動する。

➤  eval "$(docker-machine env log-test-vm)"
➤  docker-compose up -d
Creating log_collector
Creating web2
Creating web1

動作確認

ログがfluent Logging Driverで集められていることを確認する。今回、ログ情報は全てLog Collectorコンテナに集約しているので、dockerコマンドを使いWeb1、Web2にアクセスした時に発生するログを確認する。  

➤  docker logs -f log_collector

tail -fのように-fオプションをつけるとストリームモードでログを確認できる。この状態でMacからcurlでWeb1、Web2にアクセスする。

➤  curl 192.168.33.17:80
➤  curl 192.168.33.17:8080 

すると、Log Collectorコンテナのログに以下が出力された。

2015-12-24 08:01:18 +0000 docker.39259aed960d070bb72cd6f56f6ae4333d3681317e0db56ef21dcbabd109461e: {"container_name":"/web1","source":"stdout","log":"192.168.33.1 - - [24/Dec/2015:08:01:18 +0000] \"GET / HTTP/1.1\" 200 222 \"-\" \"curl/7.43.0\"","container_id":"39259aed960d070bb72cd6f56f6ae4333d3681317e0db56ef21dcbabd109461e"}
2015-12-24 08:01:19 +0000 docker.39259aed960d070bb72cd6f56f6ae4333d3681317e0db56ef21dcbabd109461e: {"source":"stdout","log":"192.168.33.1 - - [24/Dec/2015:08:01:19 +0000] \"GET / HTTP/1.1\" 200 222 \"-\" \"curl/7.43.0\"","container_id":"39259aed960d070bb72cd6f56f6ae4333d3681317e0db56ef21dcbabd109461e","container_name":"/web1"}
2015-12-24 08:01:56 +0000 docker.757355aae2715e7b2ca01c9fd452d3657392a1eea6b6ac55802195a00836c61e: {"container_name":"/web2","source":"stdout","log":"192.168.33.1 - - [24/Dec/2015:08:01:56 +0000] \"GET / HTTP/1.1\" 200 227 \"-\" \"curl/7.43.0\"","container_id":"757355aae2715e7b2ca01c9fd452d3657392a1eea6b6ac55802195a00836c61e"}

良い感じで使えるようだ。

参考

公式

先人の知恵