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がインストールできない場合は以下を参考にしてください。