dockerでlog-driverにlocalを指定してパフォーマンスを向上


## はじめに

Docker のドキュメントを読んでいると次のような記述をたまたま見つけました。

https://docs.docker.com/config/containers/logging/configure/

> Docker keeps the json-file logging driver (without log-rotation) as a default to remain backward compatibility with older versions of Docker, and for situations where Docker is used as runtime for Kubernetes.
> For other situations, the local logging driver is recommended as it performs log-rotation by default, and uses a more efficient file format.

> Docker は、古いバージョンの Docker との後方互換性を維持するため、そして Docker が Kubernetes のランタイムとして使用される状況のために、json-file ロギングドライバ（ログローテートなし）をデフォルトとして保持しています。その他の状況では、デフォルトでログローテーションを実行し、より効率的なファイルフォーマットを使用する local ロギングドライバを推奨します。

Docker のデフォルトの logging driver は`json-file`ですが、それは後方互換性のためであって、実際は`local`が推奨されるそうです。  
というわけで推奨に従い変更してみます。

## Docker ロギングドライバの変更手順

まず、現在のロギングドライバが json-file であることを確認します。

```bash
$ docker info --format '{{.LoggingDriver}}'
json-file
```

次に、`/etc/docker/daemon.json`ファイルに以下のような内容を追加して、ロギングドライバを local に変更します。

```json
{
  "log-driver": "local"
}
```

これは Linux における手順です。私の環境ではこのファイルは当初存在しなかったため、新規作成しました。  
[ドキュメント](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file)によると windows の場合は`%programdata%\docker\config\daemon.json`らしいですが、確かめられていません。

変更後、Docker サービスを再起動し、ロギングドライバが`local`になっていることを再確認します。

```bash
$ systemctl restart docker
$ docker info --format '{{.LoggingDriver}}'
local
```

## Dockerのログがローテーションされることを確認

`local`に変更すると自動でログローテーションがされるようになるそうです。

```json
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m"
  }
}
```

のように log-opts にローテーションの調整をすることも可能です。（参照：[Options](https://docs.docker.com/config/containers/logging/local/#options)）

| オプション | 説明                                                                                                                                         |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| max-size   | ログがロールされる前の最大サイズ。単位を表す修飾子（k、m、g）を伴う正の整数。デフォルトは 20m。                                              |
| max-file   | 存在できるログファイルの最大数。ログのロールにより余分なファイルが作成された場合、最も古いファイルが削除されます。正の整数。デフォルトは 5。 |
| compress   | ローテートされたログファイルの圧縮を切り替えます。デフォルトで有効。                                                                         |

### 実際に確認

まずロギングドライバを`json-file`のままで大量にログを出力してみます。

```bash
$ docker run -d --rm --name test-log-generator log-generator
# docker inspect でログファイルの出力場所を確認
$ docker inspect ce385c1bbb9c | grep Log
        "LogPath": "/var/lib/docker/containers/ce385c1bbb9c096049c6af6ff322e4a01d42d62d766ef98a92b58955efa566bc/ce385c1bbb9c096049c6af6ff322e4a01d42d62d766ef98a92b58955efa566bc-json.log",
            "LogConfig": {
$ ls -lh /var/lib/docker/containers/ce385c1bbb9c096049c6af6ff322e4a01d42d62d766ef98a92b58955efa566bc
合計 52M
-rw-r----- 1 root root  52M 11月 30 01:35 ce385c1bbb9c096049c6af6ff322e4a01d42d62d766ef98a92b58955efa566bc-json.log
drwx------ 2 root root 4.0K 11月 30 01:32 checkpoints
-rw------- 1 root root 2.6K 11月 30 01:32 config.v2.json
-rw------- 1 root root 1.4K 11月 30 01:32 hostconfig.json
-rw-r--r-- 1 root root   13 11月 30 01:32 hostname
-rw-r--r-- 1 root root  174 11月 30 01:32 hosts
drwx--x--- 2 root root 4.0K 11月 30 01:32 mounts
-rw-r--r-- 1 root root  603 11月 30 01:32 resolv.conf
-rw-r--r-- 1 root root   71 11月 30 01:32 resolv.conf.hash
```

`/var/lib/docker/containers`に大きなログファイルが出力されていることがわかります。  
次にロギングドライバを`local`にして実験してみます。

```bash
$ docker inspect fff836f6c524 |grep Log
        "LogPath": "",
            "LogConfig": {
$ ls /var/lib/docker/containers/fff836f6c524f9079995437cbc8f1ae8a557c6cdf3d209772ca80370cf9a296b
checkpoints  config.v2.json  hostconfig.json  hostname	hosts  local-logs  mounts  resolv.conf	resolv.conf.hash
$ ls -lh /var/lib/docker/containers/fff836f6c524f9079995437cbc8f1ae8a557c6cdf3d209772ca80370cf9a296b/local-logs/
合計 27M
-rw-r----- 1 root root  18M 11月 30 12:45 container.log
-rw-r----- 1 root root 2.3M 11月 30 12:44 container.log.1.gz
-rw-r----- 1 root root 2.3M 11月 30 12:42 container.log.2.gz
-rw-r----- 1 root root 2.3M 11月 30 12:41 container.log.3.gz
-rw-r----- 1 root root 2.3M 11月 30 12:39 container.log.4.gz
```

`docker inspect`でログファイルの場所が表示されなくなっていましたが、`/var/lib/docker/containers`下にログらしいファイルがありました。また、それらのファイルがログローテーションされていることも確認できます。

なお、ログファイルを直接読もうとすると、

```bash
$ tail /var/lib/docker/containers/fff836f6c524f9079995437cbc8f1ae8a557c6cdf3d209772ca80370cf9a296b/local-logs/container.log
stdout�ׯ�����8Thu Nov 30 03:45:21 UTC 2023 - Random log message: 26138LK
stdout��诒����7Thu Nov 30 03:45:21 UTC 2023 - Random log message: 8075KK
stdout���������7Thu Nov 30 03:45:21 UTC 2023 - Random log message: 5253KK
stdout�ҋ������7Thu Nov 30 03:45:21 UTC 2023 - Random log message: 5133KL
stdout襝������8Thu Nov 30 03:45:21 UTC 2023 - Random log message: 13395LK
stdout���������7Thu Nov 30 03:45:21 UTC 2023 - Random log message: 5485KK
stdoutɰ�����7Thu Nov 30 03:45:21 UTC 2023 - Random log message: 1341KL
stdout��߰�����8Thu Nov 30 03:45:21 UTC 2023 - Random log message: 23393LL
stdout��򰒺���8Thu Nov 30 03:45:21 UTC 2023 - Random log message: 10785LL
stdout���������8Thu Nov 30 03:45:21 UTC 2023 - Random log message: 30872L
```

のように表示が崩れてしまいました。`local`ロギングドライバは

> uses a more efficient file format

とのことなので、単純なテキストファイルでない形式でファイルを保存するようです。  
また、

https://docs.docker.com/config/containers/logging/local/

によると、

> The local logging driver uses file-based storage. These files are designed to be exclusively accessed by the Docker daemon. Interacting with these files with external tools may interfere with Docker's logging system and result in unexpected behavior, and should be avoided.

とのことなので、このファイルは Docker で内部的に利用され、直接読むものではないでしょう。  
実際`local`ロギングドライバでも

```bash
$ docker logs fff836f6c524 --tail 10
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 29472
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 30256
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 14975
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 32123
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 22574
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 6237
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 21984
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 1140
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 32059
Thu Nov 30 03:47:17 UTC 2023 - Random log message: 5599
```

のように`docker logs`コマンドでログを確認できます。通常はこれで困ることはないはずです。

`json-file`のままでもログローテーションさせることは可能ですが、現在は`local`に設定するのが王道と思われます。