CLOVER🍀

That was when it all began.

Docker環境で、コンテナのログをFluentdに出力する(Docker logging driverとして使う)

これは、なにをしたくて書いたもの?

  • Dockerのログ出力先(logging driver)をFluentdにできると聞いて
  • 1度、自分でも試してみようと

参考)

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門

  • 作者:山田 明憲
  • 発売日: 2018/08/25
  • メディア: 単行本(ソフトカバー)

logging driver

Dockerでは、コンテナに出力されたログは「docker logs」コマンドで参照することができます。

View logs for a container or service | Docker Documentation

Configure logging drivers | Docker Documentation

このログの出力先は、logging driverというもので制御されているようです。

logging driverにはいくつか種類があり、デフォルトのlogging driverは「json-file」のようです。これは、ホスト側の
「/var/lib/docker/containers/[コンテナID]/[コンテナID]-json.log」に出力されるものです。

$ docker container run --rm --name httpd httpd:2.4.37

$ docker inspect httpd | grep -i -A 3 Log
        "LogPath": "/var/lib/docker/containers/e01a9083c3a98b48aaeda25292d69ab409b6f5f04e01a9cee31e5549e1a94693/e01a9083c3a98b48aaeda25292d69ab409b6f5f04e01a9cee31e5549e1a94693-json.log",
        "Name": "/httpd",
        "RestartCount": 0,
        "Driver": "overlay2",
--
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },

ちなみに、どんな感じでログが入っているのかというと、

$ sudo cat /var/lib/docker/containers/e01a9083c3a98b48aaeda25292d69ab409b6f5f04e01a9cee31e5549e1a94693/e01a9083c3a98b48aaeda25292d69ab409b6f5f04e01a9cee31e5549e1a94693-json.log
{"log":"AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message\n","stream":"stderr","time":"2019-01-01T15:21:11.353294509Z"}
{"log":"AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message\n","stream":"stderr","time":"2019-01-01T15:21:11.355605364Z"}
{"log":"[Tue Jan 01 15:21:11.357255 2019] [mpm_event:notice] [pid 1:tid 140069608740032] AH00489: Apache/2.4.37 (Unix) configured -- resuming normal operations\n","stream":"stderr","time":"2019-01-01T15:21:11.357434441Z"}
{"log":"[Tue Jan 01 15:21:11.357493 2019] [core:notice] [pid 1:tid 140069608740032] AH00094: Command line: 'httpd -D FOREGROUND'\n","stream":"stderr","time":"2019-01-01T15:21:11.357602487Z"}

「log」という要素に標準出力なりの内容が全部入っているようですね。標準出力か標準エラー出力かは「stream」を
ログの時間については「time」を見れば良さそうです。

Dockerでサポートされているlogging driverは、ここに一覧があります。

Supported logging drivers

なお、「json-fiile」と「journald」以外のlogging driverを選択した場合は、「docker logs」コマンドは使えなくなるようです。

logging driverを含む、コンテナログの設定は、「docker container run」時にコンテナ単位に設定するか、Linuxの場合であれば
「/etc/docker/daemon.json」でDockerデーモン全体の設定として行うこともできるようです。

Configure the default logging driver

Fluentd logging driver

それで、今回はこのlogging driverをFluentdに変更してみます。

Fluentd logging driverについては、Docker、Fluentd両方にドキュメントがあります。

Fluentd logging driver | Docker Documentation

Docker Logging | Fluentd

このあたりを見ながら、設定していってみましょう。

お題と環境

ApacheのDockerイメージに対してFluentd logging driverを設定し、Fluentdにログを送信してみようと思います。

httpd

Fluentd自体もDockerで立ち上げますが、こちらはコンテナ内に自分でインストールしたものを使用することにします。

また、送信されたApacheのログは、Fluentdのログ(stdout)に出力するものとします。

各種バージョン。

$ docker --version
Docker version 18.09.0, build 4d60db4


$ docker container run --rm --name httpd httpd:2.4.37


2019-01-02 03:17:45 +0000 [info]: gem 'fluentd' version '1.2.6'

各コンテナのIPアドレスは、

  • Fluentd … 172.17.0.2
  • Apache … 172.17.0.3

とします。

また、Apacheのイメージはindex.htmlしか入っていないので、ApacheのドキュメントをDocumentRootに設置し、
ドキュメントに対するアクセスログを見ていくことにします。

こんな感じで。

$ wget https://www-eu.apache.org/dist//httpd/docs/httpd-docs-2.4.33.en.zip
$ unzip httpd-docs-2.4.33.en.zip
$ docker container run --rm --name httpd -v `pwd`/httpd-docs-2.4.33.en:/usr/local/apache2/htdocs httpd:2.4.37

この時点では、まだFluentd logging driverは設定していません。

Fluentdの設定

Fluentd側は、ドキュメント側に習ってデフォルトの設定ファイルを編集してこのように設定。

Docker Logging | Fluentd

/etc/td-agent/td-agent.conf

<source>
  @type forward
  @id input_forward
</source>

<match *.**>
  @type stdout
  @id output_stdout
</match>

「@id」は付けておきました。

ドキュメントだとportおよびbindも指定していますが、デフォルト値そのものみたいなので、まあいいかなと。

forward - Fluentd

Apache

ドキュメントルートにApacheのドキュメントを置きつつ、構築したFluentdに対してlogging driverを設定します。

$ docker container run --rm \
  --name httpd \
  -v `pwd`/httpd-docs-2.4.33.en:/usr/local/apache2/htdocs \
  --log-driver=fluentd \
  --log-opt fluentd-address=tcp://172.17.0.2:24224 \
  --log-opt tag=docker.{{.ImageName}}.{{.Name}}.{{.ID}} \
  httpd:2.4.37

「--log-driver」に「fluentd」を指定し、「--log-opt」でオプションの設定を行います。このあたりの情報は、こちらに
記載があります。

Fluentd logging driver / Options

「fluentd-address」では送信先のFluentdを指定し(デフォルトは「localhost:24224」)、「tag」ではFluentdで使うタグを
指定します(デフォルトでは12文字のコンテナID)。

今回は、タグとして「docker.[イメージ名].[コンテナ名].[コンテナID(12文字)]」を指定しています。指定している
テンプレートの意味は、こちらを参照してください。

Customize log driver output | Docker Documentation

このタグは、Fluentdのタグとして使われます。

確認

では、ファイルを参照して確認してみましょう。

ここは、一気にwgetでミラーしてみます。

$ wget -m -p -r -nH -np 172.17.0.3

Fluentd側には、こんな感じでログ出力されます。

2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET / HTTP/1.1\" 200 7004","container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stdout"}
2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"container_name":"/httpd","source":"stdout","log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET /robots.txt HTTP/1.1\" 404 208","container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34"}
2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stdout","log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET /style/css/manual-zip.css HTTP/1.1\" 200 874"}
2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stdout","log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET /style/css/manual-zip-100pc.css HTTP/1.1\" 200 885"}
2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET /style/css/manual-print.css HTTP/1.1\" 200 13200","container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stdout"}
2019-01-02 03:55:42.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stdout","log":"172.17.0.1 - - [02/Jan/2019:03:55:42 +0000] \"GET /style/css/prettify.css HTTP/1.1\" 200 3616"}

含まれる要素は、「log」、「container_name」、「container_name」、「source」のようです。

「source」は、標準出力か標準エラー出力かを表すようですね。

例えば、Apache起動時のログは標準エラー出力に出るようなので、こんな感じになります。

2019-01-02 03:44:54.000000000 +0000 docker.httpd:2.4.37.httpd.76d3304af17a: {"container_id":"76d3304af17a71ce363407f855d544bccab2c0e39142c4be1dc2ba4385304c34","container_name":"/httpd","source":"stderr","log":"[Wed Jan 02 03:44:54.260937 2019] [core:notice] [pid 1:tid 140541962106048] AH00094: Command line: 'httpd -D FOREGROUND'"}

この時、Apache側のコンテナに対して「docker container logs」を実行すると、エラーになります。

$ docker container logs httpd
Error response from daemon: configured logging driver does not support reading

こんな感じで動作確認できました。

また、ログメッセージのJSONをパースするサンプルや、ログメッセージが複数行になっている場合に結合する
サンプルも、こちらのドキュメントに記載があります。

Docker Logging | Fluentd

こんなところで。