目的
コンテナ上で動いているアプリが出力するログのローテーションを logrotate で実施する。
構成
※ アプリの実行バイナリは /app、出力されるログは /log/app.log とする
ディレクトリ構造
.
├── Dockerfile
├── app
├── entrypoint.sh
└── logrotate.conf
各ファイル内容
/log/app.log # ログローテーション対象のファイル
{
compress
copytruncate
daily
dateext
dateyesterday
ifempty
missingok
noolddir
dateformat .%Y%m%d
rotate 90
}
ローテーションの設定なので内容は任意。
各設定値の意味は こちらのページ が man を日本語訳してくれています。
#!/bin/sh
crond && /app
FROM alpine:latest
COPY ./logrotate.conf /etc
COPY ./entrypoint.sh /
# tzdata は日本時間にするためなので任意
RUN apk --update-cache --no-cache add tzdata logrotate \
&& cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& apk del tzdata \
&& chmod 644 /etc/logrotate.conf \
&& chmod +x /entrypoint.sh /app
ENTRYPOINT ["/entrypoint.sh"]
備考
- Docker コンテナの apline では cron は初期状態では動いていないので明示的に起動する必要がある。
- Dockerfile の RUN はイメージ作成時に実行されるので RUN crond としても立ち上げたコンテナ上では cron は動いておらず、ENTRYPONIT (または CMD) で起動する必要がある。
- アプリと cron 両方を実行するため、entrypoint.sh を作成してその中で立ち上げを行っている。
アプリを実行するコンテナとログローテーションを行うコンテナに分けるべきか?
1 コンテナ 1 プロセスと考えるとアプリを実行するコンテナと logrotate を実行するコンテナは分けたほうが良いのかも知れない。
ログをためておく用の volume を 1 つ定義し、各アプリが吐くログを全てその volume に集約して、その volume に対して logrotate を実行するコンテナを別途立てておくと良いかもしれない。
- 別のアプリ実行コンテナ起動時はログ用 volume にログを吐くようにマウントする
- ログを確認するときはログ用 volume を見ればよい
- ログローテーションは logrotate 実行用コンテナに任せる
= アプリ内でログローテーションの設定を考える必要が無くなる
logrotate 実行用コンテナの例
FROM alpine:latest
COPY ./logrotate.conf /etc
RUN apk --update-cache --no-cache add tzdata logrotate && \
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
apk del tzdata && \
chmod 644 /etc/logrotate.conf
ENTRYPOINT ["crond", "-f"]
logrotate.conf を Dockerfile で COPY しているのでローテーションの設定を変更したいときはイメージの作り直しから必要(もしくはコンテナ内に直接入って修正する)。
docker-compose.yaml でバインドマウントすればコンテナを作り直すだけで済むかもしれないが、logrotate.conf のファイル権限周りが面倒なので素直に docker compose down && docker compose up --build
した方が楽かも。