ディスク圧迫事故を二度と起こさないlogrotateコマンド

公開:2021/02/14
更新:2021/02/14
9 min読了の目安(約8500字TECH技術記事

はじめに

ディスク圧迫事故、怖いですね。
ある日突然エラーが大量発生してログが増大し限界を超えてシステムダウンなんて発生した日には目も当てられない(実話です)

そんなこともう二度と起こさせない。

しかし、どうすれば、、、

これから教えるコマンドは
logrotateというログファイルを圧縮、削除、メール送信出来る非常に便利なコマンドです。
これさえあればもうディスク容量圧迫してシステムが死ぬということはありません(注:設定によります)

環境構築

Amazon Linux2のEC2立ててSSHで接続した後そこにlogディレクトリ作成しておいてください。
(そこで作業します)

$ pwd
/home/ec2-user/log

logrotateとは

configの情報をもとにログをrotate、圧縮、削除等を行います。

$ logrotate <config_file>

今回は以下のような形で実行予定です。

# 注) test_rotateはこちらで作成しました
$ logrotate /etc/logrotate.d/test_rotate

細かい説明をここでするよりかは、実際にみていただいた方が早いかと思われます。
(configは/etc/logrotate.confというものがあるのですが後述します)

rotateするとは

2MBのtest.logを作成します(無限while loopのechoで5秒ほど)

$ while [ 1 ]; do echo "test" >> test.log; done

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:47 test.log

logrotateを実行します(config設定済み前提)

$ logrotate /etc/logrotate.d/test_rotate

もう一度ログを確認してみます。

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:47 test.1.log
-rw-r--r-- 1 ec2-user ec2-user    0  2月 14 14:48 test.log

test.logのバイト数が0になり、test.1.log(2.0M)が作成されました。
もう一度test.logの中身を適当に増やしてやります。

$ while [ 1 ]; do echo "test" >> test.log; done

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:53 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 4.6M  2月 14 14:57 test.log

4.6MBになってのでもう一度logrotate実行してログを確認します。

$ logrotate /etc/logrotate.conf

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 4.6M  2月 14 14:57 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:53 test.2.log
-rw-r--r-- 1 ec2-user ec2-user    0  2月 14 14:58 test.log

ログがずれましたね。これがrotateです。

configについて

configの中身を見てみる

configファイルはこんな感じに設定していました。
基本これをテンプレートとしてコピーしたら楽かと思います(または/etc/logrotate.dディレクトリ配下に他のconfigが設定されているのでそちらを参考にしても良いと思います)

$ cat /etc/logrotate.d/test_rotate

/home/ec2-user/log/test.log {
  missingok
  create 644 ec2-user ec2-user
  rotate 10
  maxsize 1M
  su ec2-user ec2-user
  extension .log
}

それぞれのディレクティブの説明

読むのが面倒であれば「設定してみよう」まで飛んでください。

missingok

If the log file is missing, go on to the next one without issuing an error message. See also nomissingok.

rotateすべきログファイルなかったとしてもエラーにしない。

create

create <mode> <user> <group>

rotate完了時に空のtest.logファイルを作成するか否か。
ファイルの権限もここで指定できる(丁度chmodchownで指定するように)

指定する

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 4.6M  2月 14 14:57 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:53 test.2.log
-rw-r--r-- 1 ec2-user ec2-user    0  2月 14 14:58 test.log

指定しない

$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 4.6M  2月 14 14:57 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 2.0M  2月 14 14:53 test.2.log

rotate

rotate <count>

個人的に一番大事なディレクティブ。
<count>5と設定すると以下のようになります。
test.5.log以降は削除されていきます。

# 10回logrotate実行
$ ls -lh
-rw-r--r-- 1 ec2-user ec2-user 1.6M  2月 14 15:49 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 1.4M  2月 14 15:48 test.2.log
-rw-r--r-- 1 ec2-user ec2-user 1.9M  2月 14 15:48 test.3.log
-rw-r--r-- 1 ec2-user ec2-user 3.8M  2月 14 15:48 test.4.log
-rw-r--r-- 1 ec2-user ec2-user 3.9M  2月 14 15:48 test.5.log
-rw-r--r-- 1 ec2-user ec2-user 1.2M  2月 14 15:49 test.log

maxsize

1Mと設定した場合はrotate処理対象は1M超えたログファイルになります。それを超えてないログファイルはrotateされません。こいつがディスク圧迫する時に大いに役立ってくれます。

maxsize <size>  # e.g 100 | 100k | 100M | 100G

su

su <user> <group>

rotateを実行するユーザー/グループ
これを正しく設定していないとPermissionに引っかかり実行出来ないため気を付けてください。

extension

extention .log

こうしておかないとrotateする時に.logが末尾に付かないのでキモくなります。

指定前

$ ls -lh

-rw-rw-r-- 1 ec2-user ec2-user 970K  2月 14 15:38 test.log
-rw-rw-r-- 1 ec2-user ec2-user 4.0M  2月 14 15:38 test.log.1
-rw-rw-r-- 1 ec2-user ec2-user 1.2M  2月 14 15:38 test.log.2

指定後

$ ls -lh

-rw-rw-r-- 1 ec2-user ec2-user 970K  2月 14 15:38 test.log
-rw-rw-r-- 1 ec2-user ec2-user 2.3M  2月 14 15:28 test.1.log
-rw-rw-r-- 1 ec2-user ec2-user 3.2M  2月 14 15:28 test.2.log

設定してみよう

そちらの手元の環境にはtest_rotateファイルなんてものはないので
そのまま上の設定をtest_rotateファイルをrootユーザーで作成して貼り付けてください。

$ vim /etc/logrotate.d/test_rotate

/home/ec2-user/log/test.log {
  missingok
  create 644 ec2-user ec2-user
  rotate 10
  maxsize 1M
  su ec2-user ec2-user
  extension .log
}

完了です。

logrotate実行する前に

今実行してもrotateするべきファイルが何もないので別画面で以下を実行したままにしてください。
(注:以下のコマンド実行すると大体秒間0.5MBずつ増えていきます)

$ pwd
/home/ec2-user/log

$ while [ 1 ]; do echo "test" >> test.log; done

「あ、ディスク容量やばいかも」となったら止めていただいて構いません。
その場合は大きくなり過ぎたログを削除してコマンドを実行し直してください。

そしてもう一つ画面を開き(なんどもSSHログインするの面倒でしょうけれど)
以下のコマンドを実行してファイルのrotate状況をリアルタイムで監視できるようにしてください。
watchコマンドは[Ctrl+C]でやめられます)

$ pwd
/home/ec2-user/log

$ watch ls -lh

準備は整いました。

logrotate実行

くらえ

# 以下のように指定すると5秒毎にlogrotate実行してくれます(面倒な時に便利です)
$ watch -n 5 logrotate /etc/logrotate.d/test_rotate

watch ls -lhを実行した画面を見てみてください。

Every 2.0s: ls -lh

合計 39M
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 6.2M  2月 14 16:04 test.10.log
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.2.log
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.3.log
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.4.log
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.5.log
-rw-r--r-- 1 ec2-user ec2-user 1.7M  2月 14 16:13 test.6.log
-rw-r--r-- 1 ec2-user ec2-user 5.9M  2月 14 16:13 test.7.log
-rw-r--r-- 1 ec2-user ec2-user 6.2M  2月 14 16:12 test.8.log
-rw-r--r-- 1 ec2-user ec2-user 2.4M  2月 14 16:12 test.9.log
-rw-r--r-- 1 ec2-user ec2-user 733K  2月 14 16:13 test.log

このようにリアルタイムにrotateしている状況が見えているかと思います。

いいですねぇ。
しかし、これではまだ手動でlogrotate実行しているだけなので、どこかに設定しなければなりません。

一度全ての画面で動作しているコマンドを止めて次に進みます。

CRONにlogrotate設定

logrotateは毎日CRON実行されるように設定されています。
(以下を読む必要は別にない)

$ cat /etc/cron.daily/logrotate 

#!/bin/sh

### ↓これです
/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

しかし、毎日ではなく毎分実行するようにしたいので、以下のようにCRONをrootユーザーで設定してください(本来であればlogrotate.confを指定してそれ経由でtest_rotateファイルを読み込ませる形が望ましいがわかりやすさベースで以下のようにします)

$ crontab -e

# 毎分logrotateコマンド実行
* * * * * /sbin/logrotate /etc/logrotate.d/test_rotate

これで自動実行されるようになりました。
あとは先ほどの手順でそれぞれの画面で以下を実行して様子をみてください。

# 画面A
$ while [ 1 ]; do echo "test" >> test.log; done

# 画面B
$ watch ls -lh
Every 2.0s: ls -lh

-rw-r--r-- 1 ec2-user ec2-user  21M  2月 14 16:28 test.1.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:16 test.10.log
-rw-r--r-- 1 ec2-user ec2-user  28M  2月 14 16:27 test.2.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.3.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.4.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.5.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.6.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.7.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.8.log
-rw-r--r-- 1 ec2-user ec2-user 1.8M  2月 14 16:17 test.9.log
-rw-r--r-- 1 ec2-user ec2-user 7.3M  2月 14 16:28 test.log

素晴らしいですね。これで完了です。
これでディスク圧迫に悩まされることはありません。あとは放置です。
watchコマンドは状況確認用なので終わったら止めてください)

補足

ファイルを日付にして毎日rotateさせたい

/home/ec2-user/log/test.log {
  missingok
  create 644 ec2-user ec2-user
  rotate 10
  maxsize 1M
  su ec2-user ec2-user
  extension .log
  dateext    <--- これ
  dateformat %Y-%m-%d  <--- フォーマット変更したい場合はこれ(dateext指定必須)
  daily  <--- これ
}

複数ファイル指定したい

# ↓ここ
/home/ec2-user/log/*.txt
/home/ec2-user/log/test2.log
/home/ec2-user/log/test.log {
  missingok
  create 644 ec2-user ec2-user
  rotate 10
  maxsize 1M
  su ec2-user ec2-user
  extension .log
  dateext
  dateformat %Y-%m-%d
}

ログを圧縮させたい

/home/ec2-user/log/test.log {
  missingok
  create 644 ec2-user ec2-user
  rotate 10
  maxsize 1M
  su ec2-user ec2-user
  extension .log
  dateext
  dateformat %Y-%m-%d
  compress   <---- これを指定すると`gzip`により`.gz`になります
}

注意事項

$ logrotate /etc/logrotate.conf

このように指定しても中で/etc/logrotate.d/ディレクトリ配下のconfigが全てincludeされているので/etc/logrotate.d/test_rotateは問題なく読み込まれますが、/etc/logrotate.confにもdataext等のディレクティブは設定されているため、もしも/etc/logrotate.confには指定されていて/etc/logrotate.d/test_rotateには指定されていないディレクティブがある場合、/etc/logrotate.conf側の設定が代わりに使われますので注意が必要です(今回であれば、dateextlogrotate.confに設定されているので、logrotate /etc/logrotate.confとした場合はdateextの指定されていないtest_rotateにもその影響を受けます。つまり、test_rotateファイルにdateext設定していないにも関わらずログファイル名に日付が入ります)

最後に

logrotate、便利ですね。
エンジニアならばぜひ覚えておきたいコマンドです。
これさえあれば急激に増加するログにも対応し、ディスク容量枯渇によりシステムが落ちる恐怖に苛まれなくなります。

では、もう深夜になってしまったので自分はベッドにダイブします。
事実確認しながらは流石に疲れました...