カテゴリー: BackEnd

Docker上のLaravelのログをFluentdに出力する

はじめに

こんにちは。前回に続いてログの扱いをあれこれ調べてました。今回はログ集約をやってみたくてFluentdについてです。Docker上に構築したLaravelだとどうやるのかを調べています。

環境

  • PHP 7.3.6
  • Laravel 5.8.29

Fluentdについて

冒頭にもあるように、ログ集約のためのミドルウェアで、Ruby製OSSです。サーバ上ではnginx,Apache,MySQL,Redis,postfixなど様々なミドルウェアと、その上に構築・実装したアプリケーションが都度ログを吐き出しています。通常はあちこちに散ってるログを一括して受けつけ、任意の形式・場所にまとめて出力してくれるのがFluentdです。
もう少し短く言うと「ログの入出力を一本化するミドルウェア」になるでしょうか。

今まで関わったプロジェクトのサーバで「なんかログ集めるやつが動いてる」という雑な認識しかしておらず、自分で構築やチューニングした経験はありませんでした。

目的

  • DockerでFluentdを動作させたい
  • Laravelのアプリから吐き出したログをFluentdで受け付けたい

nginxのログをFluentdに出力する記事はすぐ見つかったんですが、Laravelのログはどうすれば?というのが見当たらなかったので、入門がてら調べてみたのが今回の記事になります。

Fluentd本体はdocker-composeで導入

公式がイメージを用意してくれていますので、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

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で出力を制御しています。
各オプションについてはまだ理解しきれていませんが、こちらを参考にさせてもらい、作成しました。


  @type  forward
  @id    input1
  @label @mainstream
  port  24224


  @type stdout

db

データベースのコンテナです。今回はDBログには触れてないのと、docker-compose.ymlに書いてある以上のことはしていないため、割愛します。

app

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

web

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からログをFluentdに出力する

パッケージ導入

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.

PHPコード例

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を選べたり、夢が広がります。引き続き学習して使いこなせるようになりたいです。

おすすめ書籍

nomura

シェア
執筆者:
nomura

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前