docker nginxイメージのコンテナ内でlogrotateを起動させる

docker nginxイメージのコンテナ内でlogrotateを起動させる

nginxイメージベースのdockerコンテナに対してlogrotateを使用してログのローテーションを行う場合、

  • ログディレクトリをマウントさせ、ホスト側でlogrotateを動かしてローテーションする
  • nginxコンテナ内でlogrotateを動かし、ログのローテーションをコンテナ内で完結させる

のような方法があると思います。

前者の場合は、コンテナ内はnginxに関することだけが動いているのでシンプルになります。
ただ、ログファイルの後始末に関しては常にホスト側で意識する必要があります。

後者の場合は、コンテナ内でnginxとは別にlogrotateも起動させるようなイメージになります。
ログのローテーションまで含めて全部コンテナの中で完結できます。

後者についての設定に関する知見を載せます。

最終的なDockerfileの完成形

FROM nginx:latest

# copy to nginx settings
COPY ./default.conf /etc/nginx/conf.d/
COPY ./nginx.conf /etc/nginx/

RUN apt-get update

##### rsyslog settings #####
RUN apt -y install rsyslog
COPY ./conf/rsyslog/50-default.conf /etc/rsyslog.d/
RUN update-rc.d rsyslog enable

##### logrotate settings #####
RUN apt -y install logrotate
# nginxのlogrotate以外は動かさない
RUN rm /etc/cron.daily/passwd
RUN rm /etc/cron.daily/dpkg
RUN rm /etc/cron.daily/apt-compat
RUN rm /etc/cron.daily/exim4-base
# copy to logrotate settings
COPY ./conf/logrotate/nginx_rotate /etc/logrotate.d/nginx
COPY ./conf/logrotate/daily_crontab /etc/cron.d/
COPY ./conf/logrotate/status /var/lib/logrotate
RUN update-rc.d cron enable

CMD service cron start && touch /etc/crontab /etc/cron.d/* && service rsyslog start && nginx -g 'daemon off;'

logrotateが上手く起動してくれなかった際のトラブルシュートを紹介します。

logrotateが動作しているかを確認する方法

rsyslogで実行結果をログに出力します。

  • rsyslogをインストールする
  • 50-default.conf を用意し、コンテナの中に格納する

50-default.conf


cron.*    /var/log/cron.log

Dockerfile


##### rsyslog settings #####
RUN apt -y install rsyslog
COPY ./conf/rsyslog/50-default.conf /etc/rsyslog.d/
RUN update-rc.d rsyslog enable

rsyslogによって、cronが実行された際にcron.logが生成されます。

出力ログの例

/var/log/cron.log

Aug  1 15:25:00 b3f825fd777a CRON[7148]: (root) CMD (test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) >> /var/log/daily_crontab.txt 2>> /var/log/daily_crontab_error.txt)

logrotateが上手く回転しないトラブルシュート

nginxのlogrotateより前に起動するcronジョブで動作が止まっていた

cron.dailyの中のnginx以外のジョブの定義を削除しました。

Dockerfile


# nginxのlogrotate以外は動かさない
RUN rm /etc/cron.daily/passwd
RUN rm /etc/cron.daily/dpkg
RUN rm /etc/cron.daily/apt-compat
RUN rm /etc/cron.daily/exim4-base

cronの設定が動作しない

cronの設定値を設定したのに動作せず、全て*の毎分設定だと動いたため、以下のようにcronを設定しました。


* *	    * * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) >> /var/log/daily_crontab.txt 2>> /var/log/daily_crontab_error.txt

毎分ジョブが起動するようになっている上で、nginxのlogrotateのローテーション設定の方で日付が変わったらローテーションされるように設定しています。

nginxのlogrotate設定ファイル


/var/log/nginx/*.log {
        daily
        maxsize 1
        missingok
        notifempty
        rotate 180
        dateext
        compress
        delaycompress
        create 0640 www-data adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

コンテナを動かした当日のrotateがされない

cron を起動した直後に作成された status では起動した日で登録されるため、daily で logrotate が設定されている場合翌日から rotate されるようになってしまうことがわかりました。
コンテナが再起動されることも想定すると、起動した日から logrotate を動作させるようにする必要があると思います。
なので、古い日付で作成された status をコンテナの中に格納することで当日もrotateされるようにしました。

statusファイル


logrotate state -- version 2
"/var/log/nginx/error.log" 1999-4-12-3:0:0
"/var/log/dpkg.log" 1999-4-12-3:0:0
"/var/log/apt/term.log" 1999-4-12-3:0:0
"/var/log/apt/history.log" 1999-4-12-3:0:0
"/var/log/alternatives.log" 1999-4-12-3:0:0
"/var/log/wtmp" 1999-4-12-3:0:0
"/var/log/btmp" 1999-4-12-3:0:0
"/var/log/exim4/paniclog" 1999-4-12-3::0
"/var/log/nginx/access.log" 1999-4-12-3:0:0
"/var/log/exim4/rejectlog" 1999-4-12-3::0
"/var/log/exim4/mainlog" 1999-4-12-3::0

Dockerfile


COPY ./conf/logrotate/status /var/lib/logrotate

それでもlogrotateが動作しない

Cron は (少なくとも Debian では) 1 つ以上のハードリンクを持つ crontab を実行しません。
Dockerはオーバーレイを使用しているため、ファイルへのリンクが複数になってしまいます。
そのため、スタートアップスクリプトでタッチして、リンクを切断する必要があります。

よって、DockerfileのCMDパラメータに下のtouchコマンドを追加します。


touch /etc/crontab /etc/cron.d/*

github

全容はこちらに載せています。

https://github.com/itouoti12/logrotate-in-nginx-docker

参考

Cron and Crontab files not executed in Docker

Logrotate – nginx logs not rotating inside docker container

proxyなどでlogrotateやrsyslogがインストールできない場合は以下を参考にしてください。

Debian系パッケージのオフラインインストーラを作る

Nginxカテゴリの最新記事