Fluentdによる柔軟なPHPのアプリケーションログ管理をDockerでシミュレートしたい(1)

超今更感が有りますが、fluentdを使ってログを柔軟に扱えるシステムを組んでみようかなあって思ってしまいました。
せっかくだから、dockerを使って、ローカルでAWSチックな分散システムにでもしてみようかなと思います。

# ロードマップ

というほどだいそれたものではないですが、こんなことやりたいよっていうのを示します。

1. PHPログを同じサーバ上のFluentdに流す
2. Fluentdから別の集約用のFluentdにログを流す
3. 集約用のFluentdからMongoDBにログを流す

これらの機能をdockerのコンテナ上で実現しようと考えました。

で、題名から見ても分かる通り、妙に分量が多くなってしまったので、今回はロードマップの１番までの内容を報告しようと思います。

# 結果

経緯とかは後で書きますが、まずはどうなったかの結果だけ書きますと、
https://github.com/niisan-tokyo/log_experioment/tree/singleContainer
で、一応実現できました。

こいつをローカルに落として、

```
$ vagrant up
$ vagrant ssh
$ sudo su
# docker build -t niisan-tokyo/php56 niisan-tokyo/
# docker run -d -p 8080:8080 niisan-tokyo/php56
```

ここまでやったら
http://192.168.33.40:8080/
にアクセスすると、

<img width="233" alt="スクリーンショット 2015-12-16 19.48.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/102182/ec43d116-1f0e-0f5f-3c15-1c29d8d80f2e.png">

こんな画面が出ます
かくスコアに数値を入れてやり、送信ボタンを押すと、裏でログに吐き出されます
ログの確認はこんなふうにすればよいです

```
# docker exec -it <コンテナID or コンテナ名> /bin/bash
# cd /var/log/td-agent
# ls
# tail -f app.<ハッシュ文字列>
```

コンテナ名やコンテナIDは```docker ps ```コマンドを打てばわかります
ハッシュ文字は```ls```で出てきたappで始まるログを確認すればよいです
ログはこんな感じです

```
2015-12-16T09:18:02+00:00	app.scores	{"score1":33,"score2":23,"score3":232}
2015-12-16T09:19:18+00:00	app.scores	{"score1":41,"score2":56,"score3":84}
```

とりあえず今回の目的は果たせました
ここから先は、ここに至るまでの過程をダラダラと書いています。

# 詳細経緯

## 環境の構築

### CentOS環境を別途用意する

dockerのコンテナ上での開発はかなり面倒というか、ちょっとわかりにくかったので、一旦別のCentOS環境を用意しました。
環境にはPHP5.6とComposerを突っ込んでありました。

### BEAR.Sundayを導入する

Phalconはエクステンション入れないといけないし、Laravelの今のバージョンよくわからんし、CakePHPでもDBなしの場合どうなるかわからんかったので、わかりやすいBEAR.Sundayを導入することにしました。
BEAR.Sundayの導入は、公式サイトにあるので、それに従って作ります。

```
$ composer create-project bear/skeleton niisan-tokyo/Logexp
```

これでプロジェクトのスケルトンを構築できます。途中にベンダー名とプロジェクト名を聞いてくるので、それぞれ入力します。（例：`NiisanTokyo` / `Logexp`）

### 必要なパッケージを突っ込む

チュートリアルの方法以外でのHTMLの表示方法がわからなかったので、とりあえず、テンプレート用のパッケージを入れます。

```
composer require madapaja/twig-module ~1.0
```

これでHTML出力できるようになりました。
あとは、fluentdにログを投げるためのパッケージも入れちゃいましょう

```
composer require fluent/logger v1.0.0
```

本当はこいつをPSR4のLoggerInterfaceに合うようにラッピングしておくべきなんでしょうが、面倒なのでやってません。。。

### フォームを作る

簡単なスコアを入力するだけのフォームを作成します。
コードの内容は先のURLにあるリポジトリに全部あげているので、詳細には書きません。
ただ、チュートリアルに従うと少々動作しない部分があるので、その点だけ書きます

* ```var/www/index.php```の```$context```に```prod-html-app```と入れると、必ず```apc_fetch```関数の呼び出しが発生し落ちるので、```html-app```と書くと良いです。
* FluentLoggerはPSR4のLoggerInterfaceの実装になっていないため、チュートリアルのmonologと同じようにAppModuleに設定すると、コンパチエラーが発生します。

フォームができて、POSTでデータを送信できるようになれば、一旦PHPの作業は終わりです

### Fluentd入れる

フォームができてもFluentdがないとログを処理できないので、導入します。
Fluentdはコマンド一発で入れられるので、「現在作業している環境」上では簡単です。

```
curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh
```

これでFluentdのインストールが終わるので、設定ファイル```/etc/td-agent/td-agent.conf```に書き込んでやりましょう

```
<source>
  type forward
</source>

<match app.**>
  type file
  path /var/log/td-agent/app
</match>
```

とりあえずこの項目があれば大丈夫だと思います。
詳細は上に上げたリポジトリの niisan-tokyo/etc/td-agent.conf を見てください

あとは``` sudo service td-agent start```してあげれば、fluentdによるログ収集が始まります。

## Dockerに移す

と、ローカルのcentos環境でゴリゴリやるのは慣れているのでいいのですが、問題はこれらをDockerコンテナ上で実現するということです。

### 手順

作業は以下の様な手順で行われました

1. dockerのホストマシンを用意する
2. コンテナのイメージを作る
3. 起動する

実際には2->3の手順を何度も繰り返すはめになりました

### ホストマシンの容易

ホストマシンはdockerに特化したディストリビューションである、[Atomic Host](http://www.projectatomic.io)を使用しました
Vagrantのイメージもあるので、これを利用すると楽ちんです
https://atlas.hashicorp.com/centos/boxes/atomic-host

### コンテナのイメージを作る

#### Dockerfileを作る

とても変な場所にDockerfileおいてありますが(niisan-tokyo/Dockerfile)、これには理由があって(言い訳)、コンテナイメージの中にソースコードを入れてしまい、一種のimmutableなアプリケーションサーバを作ろうと考えたためです。
で、Dockerfileがホストにあるファイルやディレクトリをイメージに送るためには、自分と同じ階層か低い階層にターゲットがなければならないという制約があるのです。

```
ADD ../../niisan-tokyo/Logexp
```

とか書いたら、エラーが出ました。
というわけで、あの位置にDockerfileをおいています。
https://github.com/niisan-tokyo/log_experioment/blob/singleContainer/niisan-tokyo/Dockerfile

#### PHPの導入

これはremiリポジトリを普通に導入しています。

```
#install remi
RUN yum -y install epel-release
RUN yum -y install wget
RUN wget -P /etc/yum.repos.d http://rpms.famillecollet.com/enterprise/remi.repo

#install php
RUN yum -y --enablerepo=remi,remi-php56 install php php-common

#install composer
RUN curl -sS https://getcomposer.org/installer | php; mv composer.phar /usr/local/bin/composer
```

あとで使うのでcomposerもこの時点で導入しています。

#### Fluentdの導入

なぜかDockerfile上でFluentdを導入しようとすると、先に行った、ワンライナーでの導入ができません(```sudo```がないとか言われる)
なので、[件のコマンド](https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh)をバラしてDockerfileに入れています。

```
#install fluentd
ADD etc/td.repo /etc/yum.repos.d/td.repo
RUN rpm --import https://packages.treasuredata.com/GPG-KEY-td-agent; yum check-update; yes|yum install -y td-agent
RUN service td-agent start; chkconfig td-agent on
ADD etc/td-agent.conf /etc/td-agent/td-agent.conf
```

td-agent.confは設定ファイルで、現在はログをファイルに出力するように設定してあります
次回ではここを集約用のfluentdに投げるように修正します

#### アプリケーションのデプロイ

Logexpディレクトリ配下のファイルを全て/var/www 配下にコピーし、しかるのちにcomposerを使って、パッケージを入れます

```
#build application
WORKDIR /var/www
ADD Logexp ./
RUN composer install --no-dev

EXPOSE 8080
```

#### アプリケーションの起動コマンドを設置

Dockerは1コンテナ1アプリが原則らしいので、複数アプリケーションの起動はちょい面倒くさいです。
やり方としては、起動スクリプトをファイルに吐き出して、イメージ上に設置し、コンテナ起動時にこの起動スクリプトを作動させればよいです。

# まとめ

ということで、とりあえずPHPのログをFluentdに突っ込んで内容を確認できるところまでやりました。
次は集約用のFluentd用のコンテナを用意して、さらにデータ格納用のMongoDBコンテナを用意し、ログを流すところまで作りたいです。

少々ダラダラ書きすぎましたが、今回はこの辺で失礼します。

[Fluentdによる柔軟なPHPのアプリケーションログ管理をDockerでシミュレートしたい(2)](http://qiita.com/niisan-tokyo/items/1cc4e66730c44dfb2801#_reference-cfd155b3d70fa90624c7)

# 追記

koriymさんより指摘いただきましたので、BEAR.Sundayの導入部分が修正されました
```composer create-project bear/skeleton MyVendor.Weekday```入力後、対話型でベンダー名とプロジェクト名を聞いてくるので、そこで入力した内容が名前空間に反映されるようで、実際に検証した結果、そのとおりになりました。
-n対話スキップオプションをつけると、名前空間がMyVendor\MyProjectになるとのことです。
私の場合はエンター連打でもしたのかもしれません。。。