こんにちは。前回に続いてログの扱いをあれこれ調べてました。今回はログ集約をやってみたくてFluentdについてです。Docker上に構築したLaravelだとどうやるのかを調べています。
冒頭にもあるように、ログ集約のためのミドルウェアで、Ruby製OSSです。サーバ上ではnginx,Apache,MySQL,Redis,postfixなど様々なミドルウェアと、その上に構築・実装したアプリケーションが都度ログを吐き出しています。通常はあちこちに散ってるログを一括して受けつけ、任意の形式・場所にまとめて出力してくれるのがFluentdです。
もう少し短く言うと「ログの入出力を一本化するミドルウェア」になるでしょうか。
今まで関わったプロジェクトのサーバで「なんかログ集めるやつが動いてる」という雑な認識しかしておらず、自分で構築やチューニングした経験はありませんでした。
nginxのログをFluentdに出力する記事はすぐ見つかったんですが、Laravelのログはどうすれば?というのが見当たらなかったので、入門がてら調べてみたのが今回の記事になります。
公式がイメージを用意してくれていますので、docker-compose.ymlに記述すれば使えるようになります。
以下、nginx+PHP-FPM+MariaDB+Fluentd全ての設定を記述したファイルです。それぞれ説明を後述します(全項目はさすがに説明しきれませんが…)。
version: "3" services: fluentd: build: ./fluentd command: > /usr/bin/fluentd -c /fluentd/etc/fluent.conf -v ports: - "127.0.0.1:24224:24224" - "127.0.0.1:24224:24224/udp" volumes: - ./fluentd/logs:/fluentd/log - ./fluentd/my_fluentd.conf:/fluentd/etc/my_fluentd.conf environment: FLUENTD_CONF: my_fluentd.conf TZ: Asia/Tokyo db: image: mariadb:latest ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: root MYSQL_USER: test MYSQL_PASSWORD: test MYSQL_DATABASE: testdb volumes: - ./db-data:/var/lib/mysql app: build: ./php volumes: - .:/var/www/html depends_on: - db web: image: nginx:mainline-alpine ports: - 80:80 volumes: - ./web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html depends_on: - app links: - app logging: driver: fluentd options: fluentd-address: "localhost:24224" tag: "docker.{{.Name}}"
Fluentdの最新は1.6系ですが、stableとlatestは1.3系です。基本はAlpine Linuxで、別途debian版もあります。
以下、fluentdビルド用のDockerfileです。イメージからコンテナを作るだけでなく、コンテナ内であれこれしたい場合はbuild
で指定したパスにDockerfileを置きます。apk add --update
でパッケージ全体を更新した後で、apk add --update --no-cache
でパッケージを個別にインストールしています。bashはコンテナ内でCUIを操作しないのであれば不要です。
tzdataはApline LinuxのデフォルトがUTC+0
なので、日本のタイムゾーンに合わせるためです。
FROM fluent/fluentd:latest RUN apk add --update && \ apk add --update --no-cache build-base curl curl-dev git zip unzip vim bash tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ echo "Asia/Tokyo" > /etc/timezone
以下、FLUENTD_CONF
で指定して差し替えているFluentdの設定ファイルです。source
でFluentdへの入力、match
で出力を制御しています。
各オプションについてはまだ理解しきれていませんが、こちらを参考にさせてもらい、作成しました。
データベースのコンテナです。今回はDBログには触れてないのと、docker-compose.ymlに書いてある以上のことはしていないため、割愛します。
PHP-FPMが稼働するコンテナです。Fluentd導入に際して特別なことはしていませんが、ビルド用のDockerfileは以下のとおりです。docker-compose up -d
の後、コンテナの中でcomposer create-project --prefer-dist laravel/laravel testapp
を実行してLaravelをインストールしています。
FROM php:7.3-fpm-alpine RUN apk add --update && \ apk add --update --no-cache build-base curl curl-dev git zip unzip vim bash tzdata RUN cd /usr/bin && curl -sS https://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer && \ apk add libxml2-dev $PHPIZE_DEPS && \ pecl install xdebug && \ docker-php-ext-install pdo_mysql mbstring xml curl session tokenizer json && \ docker-php-ext-enable pdo_mysql mbstring xml curl session tokenizer json xdebug && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ echo "Asia/Tokyo" > /etc/timezone && \ apk del tzdata # CMD crond -l 1 -b WORKDIR /var/www/html
nginxコンテナです。logging
セクション以下でログドライバとしてfluentdを指定し、ログの出力先とタグを指定しています。
タグはFluentdの基本機能で、受け付けたログの出し分けに使います。本筋から外れるのと、私がまだきちんと理解しきれていないので、参考ページの紹介に留めます…
今回の主旨はLaravelのログ出力ですが、nginxのログも以下のように出力しています(見やすく整形)。
{ "container_name":"/20190725_web_1", "source":"stdout", "log":"192.168.144.1 - - [24/Jul/2019:10:19:58 +0000] \"GET /register HTTP/1.1\" 200 4905 \"http://localhost/login\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36\"", "container_id":"f10447b18f1b515bac3a2afc29fe17f4c1a552b737514e7ff598cd5c95f322cd" }
Laravelデフォルトではstorage/logs
以下にログファイルがデイリーで生成されていきます。
また、LaravelはロガーとしてMonologを使用しており、Monolog用のログハンドラがパッケージとして公開されていますので、有り難く使わせていただきます。
bash-4.4# composer require dakatsuka/monolog-fluent-handler Do not run Composer as root/super user! See https://getcomposer.org/root for details Using version ^1.2 for dakatsuka/monolog-fluent-handler ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Nothing to install or update Generating optimized autoload files > Illuminate\Foundation\ComposerScripts::postAutoloadDump > @php artisan package:discover --ansi Discovered Package: beyondcode/laravel-dump-server Discovered Package: fideloper/proxy Discovered Package: laravel/tinker Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully.
Laravelからは以下のように出力します。5.6以降はconfig/logging.php
に記述することでもっとスマートに書けるかなと思うのですが、一応動くコードです。
use Dakatsuka\MonologFluentHandler\FluentHandler; use Monolog\Logger; trait RegistersUsers { public function showRegistrationForm() { $logger = new Logger('example'); $logger->pushHandler(new FluentHandler()); $logger->debug('laravel', ['message' => 'from testapp to docker-fluent']); return view('auth.register'); }
これでFluent側のログには以下のように出力されます。
見やすいように改行を入れてますが、実際は1行です。
なお出力先は前述したFluentdの設定ファイル(my_fluentd.conf)のmatch docker.**
内で指定したパスになります。
2019-07-24T20:17:56+09:00 docker.20190725_web_1 { "source":"stderr", "log":"2019/07/24 11:17:56 [error] 7#7: *4 FastCGI sent in stderr: \"PHP message: Fluent\\Logger\\FluentLogger example.laravel: {\"message\":\"from testapp to docker-fluent\",\"level\":\"DEBUG\"}\" while reading response header from upstream, client: 192.168.144.1, server: , request: \"GET /register HTTP/1.1\", upstream: \"fastcgi://192.168.144.4:9000\", host: \"localhost\", referrer: \"http://localhost/login\"", "container_id":"f10447b18f1b515bac3a2afc29fe17f4c1a552b737514e7ff598cd5c95f322cd", "container_name":"/20190725_web_1" }
昔から知ってはいたFluentdですが、いざ触ってみると自由度が高く、出力先としてS3やBigQueryを選べたり、夢が広がります。引き続き学習して使いこなせるようになりたいです。