ElasticBeanstalkのSingle Container DockerでNode.jsのアプリを動かしています。
ある日アプリが動かなくなっていて、その原因を調べたところ、
/var/lib/docker/containers/<Container ID>/<Container ID>-json.log
というファイルが肥大化して、EC2の容量がいっぱいになっていることがわかりました。
この記事ではそのファイルが無限大に大きくならないようにするために試したことを紹介しようと思います。
現在唯一の解決策
問題ファイルの肥大化を防止し、かつ、デメリットが少ないものは今現在以下の1つの方法しかわかっていません。
もしより良い方法をご存知の方がいらっしゃったら、教えてください・・!
解決策: Docker Daemonの設定ファイルを使用する
方法
- 以下のファイルを.ebextensionsに配置する
files:
"/etc/docker/daemon.json":
content: |
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
}
}
services:
sysvinit:
docker:
enabled: "true"
ensureRunning: "true"
files:
- "/etc/docker/daemon.json"
以上の設定をするとログファイル容量が20MBに達したらログローテート&ログファイルは最新から3つだけ(xxx.log, xxx.log.1, xxx.log.2)を維持します
設定できる値の詳細は公式ドキュメントを参照してください
デメリット
- ログローテート後からなのか最初からなのか、
/var/log/docker-events.log
へのログ出力がおかしくなる(以下しか出力されなくなる)
unexpected EOF
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
過去に試した回避策
上の解決策に至る前に、色んな方法を試しました。
どれもデメリットが発生したり、問題の根本的解決にはなっていないので回避策としました。
回避策1: 定期的にアプリのデプロイを行う
-
<Container ID>-json.log
が大きくなりすぎる前に、(過去のバージョンでも新しいバージョンでも)アプリをデプロイする- デプロイをするとコンテナが切り替わるので、
/var/lib/docker/containers/<Container ID>
以下がごっそり消える
- デプロイをするとコンテナが切り替わるので、
デメリット
- デプロイの自動実行などを設定していない限り、手間になってしまう
- デプロイ手段によってはアプリが止まる時間が発生する
こんな場合にオススメ
- ログ出力量が予測可能かつ定期的にデプロイすることが負担にならない(または既にそのような運用になっている)
- 他の回避策にあるような設定ファイルを書きたくない
回避策2: <Container ID>-json.log
をログローテートする
- .ebextensionsを使って設定ファイルを配置して
<Container ID>-json.log
をログローテートする
デメリット
- ログローテート直後から
/var/log/eb-docker/containers/eb-current-app/<Container ID>-stdouterr.log
に新しいログが追記されなくなる- AWSサポートに聞いてみたところ、
<Container ID>-stdouterr.log
が<Container ID>-json.log
に依存していることがわかった。-
<Container ID>-json.log
= Docker コンテナが出力する標準のログファイル -
<Container ID>-stdouterr.log
= Beanstalk 環境内で実行されているdocker logs
コマンドが出力しているログファイル -
docker logs
コマンドはコンテナのログ出力(=<Container ID>-json.log
)にアクセス
-
- AWSサポートに聞いてみたところ、
こんな場合にオススメ
-
<Container ID>-stdouterr.log
を使わない (そんな人はそもそもアプリログをどこにも出力させないかも・・?) - アプリが止まるのだけは避けたい
- ログ出力量が予測不能or大量で頻繁に対策が必要
方法
- 以下のファイルを.ebextensionsに配置する
files:
"/etc/logrotate.elasticbeanstalk.hourly/logrotate.elasticbeanstalk.containers.conf":
mode: "00644"
owner: "root"
group: "root"
content: |
/var/lib/docker/containers/*/*.log {
size 1k
rotate 5
missingok
compress
notifempty
copytruncate
dateext
dateformat %s
olddir /var/lib/docker/containers/rotated
}
"/etc/cron.hourly/cron.logrotate.elasticbeanstalk.containers.conf":
mode: "000755"
owner: "root"
group: "root"
content: |
#!/bin/sh
test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.elasticbeanstalk.hourly/logrotate.elasticbeanstalk.containers.conf
回避策3: <Container ID>-json.log
と<Container ID>-stdouterr.log
をログローテート & docker restart
する
- .ebextensionsを使って設定ファイルを配置して
<Container ID>-json.log
をログローテートする - ログローテート後の操作として、
docker restart
を埋め込む
デメリット
-
docker restart
が走っている間、アプリが止まってしまう- 私の環境では10秒前後止まってしいます。
- ログローテート後、
/var/log/docker-events.log
へのログ出力がおかしくなる(以下しか出力されなくなる)
unexpected EOF
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
こんな場合にオススメ
-
<Container ID>-stdouterr.log
は使いたいが、docker-events.log
は不要 - アプリが多少止まっても構わない(クライアント側に策があるor使用のない時間帯がある)
方法
- 以下のファイルを.ebextensionsに配置する(ログローテートの頻度をhoulyからdailyに変更しているので少し複雑です)
files:
"/tmp/custom-logrotate.conf":
mode: "00644"
owner: "root"
group: "root"
content: |
/var/log/eb-docker/containers/eb-current-app/* /var/lib/docker/containers/*/*.log {
size 1k
rotate 5
missingok
compress
notifempty
copytruncate
dateext
dateformat %s
olddir /var/log/eb-docker/containers/eb-current-app/rotated
sharedscripts
postrotate
/sbin/service docker restart > /dev/null 2>&1 || true
endscript
}
"/etc/cron.d/cron-my-custom":
mode: "000644"
owner: root
group: root
content: |
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
05 04 * * * root run-parts /etc/cron.my.custom/
container_commands:
00-create-rotate-daily-dir:
command: mkdir -p /etc/logrotate.elasticbeanstalk.daily
01-copy-rotate-conf:
command: cp -f /tmp/custom-logrotate.conf /etc/logrotate.elasticbeanstalk.daily/logrotate.elasticbeanstalk.applogs.conf
02-remove-existing-applogs-rotate-conf:
command: rm -f /etc/logrotate.elasticbeanstalk.hourly/logrotate.elasticbeanstalk.applogs.conf
03-create-custom-cron-dir:
command: mkdir -p /etc/cron.my.custom
04-move-applogs-cron-conf:
command: mv /etc/cron.hourly/*applogs.conf /etc/cron.my.custom/
ignoreErrors: true
05-modify-applogs-cron-conf:
command: sed -i s/hourly/daily/g /etc/cron.my.custom/*applogs.conf