Docker/Apache起動イメージのログ集約を行うのに Fluentd を使ってみます。
Fluentd は Ruby ベースのログ集約ツールです。
http://www.fluentd.org/
ログをすべて JSON として扱い、
プラグイン構造で様々な種類のログを読み込み、
ファイルに書き出したり DB に書き込んだり SaaS(Software as a Service) に forwardしたりできます。
全てのログを Fluentd で方向整理して管理できるので、
docker で複数のコンテナを起動してサービスを行い必要がなくなったらコンテナを終了する、
といった場合に全コンテナ上の Apache のログを一カ所に集めて集中管理するようなことができます。
コンテナを起動すると Apahce が立ち上がる docker イメージ内の Apache ログを
Fluentd で収集し mongodb に保存します。
この想定状況で可能な方法は以下のようなものが考えられます。
1. Fluentd もコンテナ内で動作させ、コンテナ内で Fluentd が読み込んだ Apache ログを
ネットワーク経由で別サーバ上の Fluentd に送信、
受け取った別サーバ上の Fluentd が mongodb に保存する。
2. コンテナ内の Apache のログが書き込まれる PATH をホストOS上にマウントし、
ホストOS上の Fluentd でログファイルを読み込んで mongodb に保存する。
1. の方法では送信側と受信側の二つの Fluentd をそれぞれサーバ上で動作させます。
2. の方法では一つの Fluentd がファイルを読んで nosql に書き込みます。
なお、コンテナ内の Fluentd から送信したログを
コンテナを動かしているホストOS上の Fluentd で受信することはできませんでした。
受信側 Fluentd と送信側 Fluentd は使用 port が一致していないと送受信できませんが、
ホストOS上で Fluentd を起動し通信用 port を使用していると
docker コンテナ起動時に同じ port と通信できるよう forward をしようとしても
$ docker run -d -p 80:80 -p 24224:24224 -p 24224:24224/udp centos:apache+fluentd Error: Cannot start container 2094c72e4485bd9f54e7f3f8de797845d6d8a43db37fd2f4f8231222e4bf377e: port has already been allocated
といったエラーが出てコンテナ自体を起動することができないためです。
今回は docker のコンテナ内もホストOSも CentOS6 を使用しているので、
公式サイトの
rpmパッケージからFluentdをインストールする
に従ってインストールします。
上記ドキュメント内にあるように、Fluentd 開発元の treasure data が提供する安定板 Fluentd は
td-agent という名前でインストールされます。
docker コンテナ内へのインストールは Dockerfile を使わず、
Docker/Apache起動イメージ を detach 状態にしないで起動し bash 上で行っています。
$ sudo docker run -i -p -p 192.168.161:8080:80 centos:apache bash-4.1# curl -L http://toolbelt.treasuredata.com/sh/install-redhat.sh | sh
インストール完了後動作するか確認を行います。
bash-4.1# /etc/init.d/td-agent start Starting td-agent: [ OK ]
設定はまだ行っていませんが正常に起動することを確認できたので停止しておきます。
bash-4.1# /etc/init.d/td-agent stop Stopping td-agent: [ OK ]
この後設定ファイルを編集し bash を抜けてコンテナを終了させてから
docker commit で Fluentd をインストールした状態をイメージにして保存します。
ホストOS上へのインストールは、 docker コンテナ操作の部分を除き上記と全く同じです。
Fluentd の設定ファイルは
/etc/td-agent/td-agent.conf
です。
ログの入力元は Sourceディレクティブ
<source> ..... </source>
ログの出力先は Matchディレクティブ
<match> ... </match>
として記述します。
コンテナ内の送信側 Fluentd の設定は以下のようになります。
<source> type tail path /var/log/httpd/access_log tag apache.access pos_file /var/log/td-agent/httpd-access_log.pos format apache2 </source> <match apache.access> type forward send_timeout 60s recover_wait 30s heartbeat_interval 1s <server> name fluentd-receiver host 192.168.0.204 port 24224 </server> </match>
Apache のアクセスログを読み込んでリモートサーバの Fluentd に送出します。
この設定で
docker run -d -p 80:80 -p 24224:24224 -p 24224:24224/udp centos:apache+fluentd
のように Apache と Fluentd で使用する port を forward してコンテナを起動します。
受信側サーバ(上記例では 192.168.0.204) の Fluentd 設定は以下のようになっています。
<source> type forward port 24224 </source> <match apache.access> type mongo host localhost port 27017 database fluentd collection apache flush_interval 10s </match>
forward されてきたログを mongodb に保存します。
保存されたログを確認すると以下のように Apache のログが JSON 化されて保存されているのがわかります。
$ mongo > show dbs fluentd 0.203125GB local 0.078125GB proj_20140314 0.203125GB > use fluentd switched to db fluentd > show collections apache system.indexes > db.apache.find() { "_id" : ObjectId("53a8e94314cbd22e4e000012"), "host" : "192.168.0.128", "user" : null, "method" : "GET", "path" : "/", "code" : 403, "size" : 5039, "referer" : null, "agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", "time" : ISODate("2014-06-24T02:57:58Z") } { "_id" : ObjectId("53a8e94314cbd22e4e000013"), "host" : "192.168.0.128", "user" : null, "method" : "GET", "path" : "/icons/apache_pb.gif", "code" : 304, "size" : null, "referer" : "http://192.168.0.161", "agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", "time" : ISODate("2014-06-24T02:57:58Z") } { "_id" : ObjectId("53a8e94314cbd22e4e000014"), "host" : "192.168.0.128", "user" : null, "method" : "GET", "path" : "/icons/poweredby.png", "code" : 304, "size" : null, "referer" : "http://192.168.0.161", "agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", "time" : ISODate("2014-06-24T02:57:58Z") } { "_id" : ObjectId("53a8e98514cbd22e4e000015"), "host" : "192.168.0.138", "user" : null, "method" : "GET", "path" : "/", "code" : 403, "size" : 5039, "referer" : null, "agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0", "time" : ISODate("2014-06-24T02:58:28Z") } { "_id" : ObjectId("53a8e98514cbd22e4e000016"), "host" : "192.168.0.138", "user" : null, "method" : "GET", "path" : "/icons/apache_pb.gif", "code" : 200, "size" : 2326, "referer" : "http://192.168.0.161", "agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0", "time" : ISODate("2014-06-24T02:58:28Z") } { "_id" : ObjectId("53a8e98514cbd22e4e000017"), "host" : "192.168.0.138", "user" : null, "method" : "GET", "path" : "/icons/poweredby.png", "code" : 200, "size" : 3956, "referer" : "http://192.168.0.161", "agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0", "time" : ISODate("2014-06-24T02:58:28Z") } { "_id" : ObjectId("53a8e98514cbd22e4e000018"), "host" : "192.168.0.138", "user" : null, "method" : "GET", "path" : "/favicon.ico", "code" : 404, "size" : 290, "referer" : null, "agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0", "time" : ISODate("2014-06-24T02:58:28Z") } >
docker コンテナ内では Fluentd を動作させず、
コンテナを動かしているホストOS上の Fluentd でコンテナ内の Apache のログを読み込むためには
コンテナ内で Apache のログが書かれるディレクトリを以下のようなオプションで
ホストOS上にマウントしてコンテナを起動します。
$ sudo docker run -d -p 80:80 -v /var/log/httpd/:/var/log/td-agent/httpd/
この状態でコンテナを起動しホストOS上の /var/log/td-agent/httpd/access_log へアクセスすれば
コンテナ内の Apache のログを読むことができます。
この Apache ログを読み込んで mongodb へ保存する Fluentd 設定ファイルは以下のようになります。
<source> type tail path /var/log/td-agent/httpd/access_log tag apache.access pos_file /var/log/td-agent/httpd-access_log.pos format apache2 </source> <match apache.access> type mongo host localhost port 27017 database fluentd collection apache flush_interval 10s </match>
match>ディレクティブの設定内容を変更すれば、
ファイルに書き出すこともリモートサーバー上の Fluentd へ送ることも出来ます。