サーバー

Ubuntuでログローテートするためにfluentdを導入する

Ubuntuでログローテートするためにfluentdを導入

こんにちは、日本は今年暖冬なおかげか昼間は暖かいですね。
朝夜はそこそこ寒いですが、まだ余裕でサンダルで過ごせています。

今日は案件の兼ね合いで久しぶりにfluentdに触ったのでその記録をしていきます。
「とりあえず突っ込んでおけば幸せになるもの」という認識の人もいるかもしれませんが、fluentdはOSSのログ集約ソフトウェアとしては一強なほど優秀なツールです。

少し古めですが、Ubuntu 16.04 LTS Xenialへインストールから設定したので、ハンズオン形式で紹介していきます。

インストール前の下準備

「そもそもこのサーバに入っているUbuntuのバージョンってなんだったっけ」というところからなので、本当に最初の段階から書いていきます。

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

冒頭で述べた通りUbuntu 16.04 LTS Xenialですね。
少し前はサーバで使うスタンダードなOSでしたが、ここ最近はDockerのおかげで多様化したりしているので他のOSをご利用であれば多少食い違いはあるかもしれません。

NTP(Network Time Protocol)をインストール

NTPとは、通信機器において世界基準に対して時間を正確なものへ同期するための通信プロトコルを指します。
私のところにはデフォルトで入っていたので特にインストールしませんでした。
もし入っていなくてUbuntuであれば、下記のようにインストールできます。

$ sudo apt-get -y install ntp

ログにとって、正しいタイムスタンプ(時刻表示)は非常に大切です。
日本であれば世界標準時より9時間プラスしなくてはいけないので、時刻同期を設定されていないサーバであれば、9時間の誤差が生まれてしまうことになります。

$ sudo ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*metadata.google 71.79.79.71      2 u  613 1024  377    0.605    0.015   0.043

上記のように現在の同期状況を調べることができます。

ulimitでファイルディスクリプタを確認

ファイルディスクリプタとは、ファイルへのアクセスにおいて制限を加えるための設定です。
以下のコマンドで現在の設定を調べることができます。

$ ulimit -n
1024

これはだいたいデフォルトで1024に設定されていますが、fluentdの利用には適さない数値です。
なので、以下の設定ファイルを変更して増量します。

$ sudo emacs /etc/security/limits.conf

追加内容は以下です。

*    soft nofile 65536
*    hard nofile 65536
root soft nofile 65536
root hard nofile 65536

65536は2の16乗でキリがいい数字というだけです。

これで一回ログアウトしてSSHログインし直すと変わっています。

$ ulimit -n
65536

fluentdインストール

今回はUbuntu Xenialなので以下のコマンドでapt repositoryからインストールします。

$ curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-xenial-td-agent3.sh | sh

同時に td-agent がインストールされているはずなので以下コマンドで確認。

$ sudo service td-agent status
● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
   Loaded: loaded (/lib/systemd/system/td-agent.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: https://docs.treasuredata.com/articles/td-agent

ちゃんと入っていますね。
td-agentfluentdのdaemonだと思ってもらえればOKです。
fluentdはRubyのgemとして扱われるもので、 td-agent にはfluentdと安定版のプラグインが含まれています

これだけではfluentdは動かないので、以下のコマンドで起動します。

$ sudo service td-agent start
$ sudo service td-agent status
● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
   Loaded: loaded (/lib/systemd/system/td-agent.service; disabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-11-15 16:13:18 JST; 1s ago
     Docs: https://docs.treasuredata.com/articles/td-agent
  Process: 12755 ExecStart=/opt/td-agent/embedded/bin/fluentd --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td-agen
 Main PID: 12774 (fluentd)
    Tasks: 11
   Memory: 45.7M
      CPU: 1.309s
   CGroup: /system.slice/td-agent.service
           ├─12774 /opt/td-agent/embedded/bin/ruby /opt/td-agent/embedded/bin/fluentd --log /var/log/td-agent/td-agent.log --daemon /
           └─12782 /opt/td-agent/embedded/bin/ruby -Eascii-8bit:ascii-8bit /opt/td-agent/embedded/bin/fluentd --log /var/log/td-agent

Nov 15 16:13:18 stg-user systemd: Starting td-agent: Fluentd based data collector for Treasure Data...

さらにちゃんと動いているか確認しましょう。

$ curl -X POST -d 'json={"message":"test"}' http://localhost:8888/test

などと打ったあとにログを確認します。

$ cat /var/log/td-agent/td-agent.log
2018-11-15 16:15:42.808842850 +0900 test: {"message":"test"}

正しくデータが挿入されていることが確認できました。
以後、fluentdでうまくいかない場合やエラーが出た場合は td-agent.log を参照します。

fluentdの設定

設定ファイルはデフォルトで /etc/td-agent/td-agent.conf にあります。
パッと見た感じはXMLファイルのようですが、ここに各種ログローテートの設定を区切りつつ書いていけます。

基本的にプラグインは in_xxxxxout_xxxxx のような名前の形で入っているのようになります。
たとえばWebサーバ前面から流入は in_forward 、ログのファイルへの出力は out_file は以下となります。

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

<match test.log>
@type file
@id output_file
path /var/log/test.log
</match>

source ディレクティブはソースとなるデータのエンドポイントを示すもので、 @type の中に利用するプラグインを指定できます。
要は「そのデータはどこから来るん?」ってことです。

match ディレクティブの中にはアウトプット先を定義できます。
つまり「fluentdに何をさせたいんよ?」ってことです。
引数としてフィルターを利用できます。
match ブロックのフィルターの書き方の例として、 *(アスタリスク) の使い方が挙げられます。

上記の test.log の部分を、

<match test.*>

とすると、 test.log でも test.txt でもOKになります。
これを **(アスタリスク x 2) とすると、 test.debug.logtest.debug.1.log のように . でつないでいくことができます。

fluentdの中のformatパラメータでを正規表現を使用することができますが、チェックしたい場合は以下のサービスで確認できます。

fluentular

その他のディレクティブ

filter ディレクティブはinputとoutputのパイプライン、つまり橋渡し役として効果を発揮します。

たとえばmatchで定義した出力先に対して、出力するメッセージを加工したりフィルタリングしたい、というときに便利です。
そのままmatchに実装するのは変な感じになってしまいます。

system ディレクティブはfluentdのオプションで指定できるものと同じ設定を設定ファイルの中に盛り込むためのブロックです。

  • workers – workerの数を示す。
  • root_dir – rootディレクトリを設定できる。
  • log_level – ログ出力レベル。trace, debug, info, warn, error, fatalから選べる。
  • suppress_repeated_stacktrace – 繰り返されるエラーメッセージの抑制。
  • emit_error_log_interval – エラーログ出力の間隔。
  • suppress_config_dump – config出力の抑制。
  • log_event_verbose – ログイベントの冗長化。
  • without_source – input系プラグインなしで起動。
  • rpc_endpoint – RPCのエンドポイント指定。
  • enable_get_dump – dump放出の許可。
  • process_name – workerやsupervisorのprocess名の指定。
  • file_permission – ファイル権限。644や755など8進数表記。
  • dir_permission – ディレクトリ権限。644や755など8進数表記。
  • <log> section – ログのフォーマット。textかjsonか選べる。
  • time_format – 日時フォーマット。

label ディレクティブはfilterやoutputに対する内部ルーティングをグルーピングできます。
fluentdはtagと呼ばれる識別子を設定につけることができますが、得てして複雑化しやすいので、内部ルーティングのtagはlabelとしてひとまとめにできるようになりました。

プラグインインストール

td-agentを入れていれば、おそらく td-agent-gem コマンドを使えると思います。
これはtd-agentのプラグインを管理するためのコマンドですが、単純にgemのパッケージとして配布されいてるものであれば、 gem install でもインストール可能です。

配布されているプラグイン一覧は公式プラグインページから参照できます。

例として、実際にプラグインをインストールしてみます。
ここではログの貯蔵先としてStackdriver loggingを利用することを想定して、Google公式のRuby Gemである fluent-plugin-google-cloud をインストールします。

$ sudo td-agent-gem install fluent-plugin-google-cloud

※sudoでないとFilePermissionErrorが出ます。

また、今回はGCE(Google Compute Engine)のインスタンスへエージェントをインストールします。

$ curl -sSO https://dl.google.com/cloudagents/install-logging-agent.sh
$ sudo bash install-logging-agent.sh
$ dpkg -l google-fluentd
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                        Version            Architecture       Description
+++-===========================-==================-==================-============================================================
ii  google-fluentd              1.6.0-1            amd64              Google Fluentd: A data collector for Google Cloud Logging

それでは追加したプラグインを使ってStackdriver loggingへログを集めてみます。
以下はデフォルトでstdoutされるログをStackdriver loggingへ送る設定です。

ちなみに google-fluentd をインストールした場合は /etc/google-fluentd/google-fluentd.conf にあらかじめ以下設定が存在します。

<match **>
  @type	google-cloud
</match>

ここまでやると、ブラウザでStackdriverを見てfluentdのログを確認できるはずです。

Nginxのアクセスログを収集

まず下準備でtd-agentユーザーがnginxのログを触れるように権限を変更します。

$ sudo chown /var/log/nginx/access.log
$ sudo chown /var/log/nginx/error.log

また、別でtd-agentユーザーではなくrootユーザーでtd-agentを走らせるという方法もあるようです。

$ sudo emacs /etc/init.d/td-agent

td-agentの実行ユーザーがtd-agentになっているので、rootに変更。

- TD_AGENT_USER=td-agent
+ TD_AGENT_USER=root

私の意見としてはinit.dをいじるよりもそのときの設定に必要な権限なりを追加するほうが良いと思っています。
アップデートしたときに消失する可能性がありますし、あとで見返すときにinit.dをわざわざ見に行くことはなかなかないからです。

さて、実際の設定は以下を参考にしてください。

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

<source>
  @type tail
  path /var/log/nginx/access.log
  pos_file /var/log/td-agent/nginx.access.log.pos
  tag nginx.access
  time_format %d/%b/%Y:%H:%M:%S %z
  format ltsv
</source>

<match nginx.access>
  @type file
  format out_file
  append true
  path /var/log/td-agent/nginx/log
  time_slice_format %Y-%m-%d
  time_slice_wait 10m
  compress gzip
  buffer_type memory
  flush_interval 1m
</match>

発信側の @type に書いてあるtailはLinuxコマンドのtailのようにファイル展開するプラグインで、受信側のfileのほうはファイル出力を示します。
あまりfluentdでファイル出力したままにしておくこともありませんが、このあとAWS S3やGCP Google Cloud Storageへアップロードする機構をつくる予定の場合は上記で一時的に保存するとよいです。

path は言葉通り、それぞれソースとなるログファイルと吐き出し先のログファイルのパスを示しています。
pos_file は参照元ログファイルのpositionを示しており、要は「どこまで入力元として拾ったか」を表している数値が入っています。

受信側の append true は出力されるログファイルを分割せずに一つのファイルへ追加していく設定となります。
これによって無駄にファイル数が増えなくて済みます。

吐き出されるファイルは time_slice_format で設定したフォーマットを利用して /var/log/td-agent/nginx/log.2018-11-21.log.gz のように保存されます。

buffer_type memory はバッファをメモリ上に乗せる設定なので、fluentdを停止したら解放されます。
永続化したい場合は buffer_type file を選び、 buffer_path を設定してあげると良いでしょう。

td-agentをリロって設定を反映してみてください。

$ sudo service td-agent reload

活用の仕方は無限大なスマートログローテート

他にもたくさんの活用方法がありますので、おいおいさまざまなパターンのfluentdの事例を紹介していこうと思います。
nginxのログをあえて別口で取ることによる恩恵を受け取ったり、可視化を行うことで視認性をよくしたりすることなどもできます。

何か障害が起きたときに慌てないように、そもそも障害が起きる前に気づくように適切なログ確認を目指してぜひ導入を考えてみてください。

ABOUT ME
UOT合同会社 / SOT Co.,Ltd 合同開発部
UOT合同会社 / SOT Co.,Ltd 合同開発部
UOT合同会社 / SOT Co.,Ltd開発部の合同公式ブログ。 代表がITエンジニア出身のデジタルノマド→日本とベトナム・ホーチミンでIT企業設立。 海外デジタルノマドやエンジニアのリモートワーク、プログラミング、オフショア開発やミニラボ情報などをまとめていきます。