はじめに
dockerを運用していると、docker logコマンドでトラブルシューティングをする機会が多いと思います。開発環境や、少人数の環境ではdocker logコマンドで十分ですが、
- 複数のコンテナで構成されたアプリケーション全体の流れを追いたい
- 複数のホストでコンテナを利用している
- 法令、コンプライアンスでログの保存期間が決まっている場合
などのケースでは、課題が残ります。
dockerのログはlog driverを変更することで出力先を指定できます。 想像しやすい例だとsyslog driver
でしょうか。
公式ドキュメントには、サポートされているlog driverの一覧があります。
今回は公式サポートの ドライバーすべてを試して 設定方法、使用感をお伝えしたいと思います。
ドライバ | 説明 |
---|---|
none |
コンテナに対するログを記録せず、 docker logs は利用できなくなる |
local | 独自のファイル方式で保存され、ドライバの中で一番オーバーヘッドが少ない |
json-file | JSON 形式で保存され、デフォルトのドライバー |
syslog | Syslogサーバへ転送する |
journald | ホストマシンのjournaldに保存する |
gelf | Graylog、 Logstach などのような Graylog Extended Log Format (GELF) エンドポイントに記録 |
fluentd | ログメッセージを fluentd に記録(forward input)する |
awslogs | ログメッセージを Amazon CloudWatch Logs に記録する |
splunk | HTTP Event Collector を使い、 splunk にログメッセージを記録する |
etwlogs | Event Tracing for Windows (ETW) events としてログメッセージを記録する(Windows) |
gcplogs | Google Cloud Platform (GCP) ロギングにログメッセージを記録する |
ドライバーの制限
これから紹介するdriverですが、一部を除き変更するとdocker logs
コマンドでのログが確認できなくなります。Docker Enterprise のユーザは "dual logging" を利用できるため、docker logs
コマンドでの確認と、ドライバーへの送信両方使えるドライバーが多いです。
表. ドライバ変更とdocker logs
が両立できるドライバー
Docker Community Engine(無料) | Docker Enterprise(有償) | |
---|---|---|
local | 〇 | 〇 |
json-file | 〇 | 〇 |
journald | 〇 | 〇 |
syslog | ×→〇 ※2023/10/27検証 | 〇 |
gelf | ×→〇 ※2023/10/27検証 | 〇 |
fluentd | ×→〇 ※2023/10/27検証 | 〇 |
awslogs | ×→〇 ※2023/10/27検証 | 〇 |
splunk | ×→〇 ※2023/10/27検証 | 〇 |
etwlogs | × ※2023/10/27未検証 | 〇 |
gcplogs | ×→〇 ※2023/10/27検証 | 〇 |
ドライバーの設定方法
log driverは以下の通り、個別に設定する方法と、システム全体で指定する方法があります。
- docker composeファイルに記述(個別)
- docker runコマンドで起動時に指定(個別)
- docker daemon.json設定ファイルに記述(システム全体)
以下に指定方法をそれぞれ示します。それぞれ単語の省略、単数複数など若干変換が必要ですが、基本的にはすべて同じように指定ができます。
指定方法(compose)
version: "3"
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- 0.0.0.0:30080:80
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
# - ./conf.d:/etc/nginx/conf.d
logging:
driver: json-file
options:
max-file: '1'
max-size: 3m
指定方法(docker run)
$ docker run --rm \
-p 0.0.0.0:30080:80 \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx
指定方法(システム全体)
ファイルを編集 sudo vi /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
記事の以降ではcomposeのlogging
セクションのみ記載します。
ドライバーの優先順位
それぞれの設定が優先順位は以下の通りです。
- runやcomposeの個別の指定
- docker daemon.jsonによる全体の指定
- デフォルト値 (現在は: json-file)
daemon.jsonで指定したシステム全体の設定をrunやcomposeの個別指定は上書きできます。
同じドライバーを指定することもできるので、何も設定しない場合、全体設定でrsyslogのOOファシリティ、個別に設定してrsyslogのXXファシリティを指定するなどもできます。
検証環境
検証環境は、docker composeを用いて構築したNginx Webサーバです。そのNginxコンテナのログを様々な方法で取得し検証していきます。
dockerのインストールは公式ドキュメントに従いました。本記事では、Ubuntu22.04を用いており、Dockerのバージョンは以下の通りです。
$ docker -v
Docker version 24.0.7, build afdd53b
$ docker compose version
Docker Compose version v2.21.0
作業用フォルダに移動します。
$ mkdir nginx-log
$ cd nginx-log
compose.yaml
を作成します。docker-compose.yamlから徐々に移行中です
version: "3"
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- 0.0.0.0:30080:80
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
# - ./conf.d:/etc/nginx/conf.d
公式ドキュメントに従い、最新のNginxコンテナから初期状態の設定ファイルを取得します。
docker runコマンドで一時的にコンテナを起動し、その中からnginx.confを取得します。
$ docker run --name tmp-nginx-container -d nginx
$ docker cp tmp-nginx-container:/etc/nginx/nginx.conf ./nginx.conf
$ docker rm -f tmp-nginx-container
nginx.conf
を修正します。初期設定ではファイルにログを出力しているので標準出力、標準エラーに変更します。これによりdocker経由でログを取得することができます。
アクセスログを標準出力に流すことについては賛否があります。ファイルとして保存し、従来の方法で収集する方が好まれる印象がありますが、今回の検証では標準出力に流します。
user nginx;
worker_processes auto;
#標準エラーに出力
error_log /dev/stderr warn;
#error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#標準出力に出力
access_log /dev/stdout main;
#access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
コンテナを起動します。
$ docker compose up -d
コンテナの起動を確認します。
$ docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx nginx:latest "/docker-entrypoint.sh nginx -g 'daemon off;'" nginx 58 seconds ago Up 57 seconds 0.0.0.0:30080->80/tcp
ブラウザでコンテナにアクセスします。
ログを確認してみます。
$ docker compose logs
nginx | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:02 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 2023/10/27 22:47:02 [error] 29#29: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.144.32, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.144.34:30080", referrer: "http://192.168.144.34:30080/"
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:02 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://192.168.144.34:30080/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [27/Oct/2023:22:47:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [27/Oct/2023:22:49:26 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 2023/10/27 22:49:26 [error] 31#31: *3 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.144.32, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.144.34:30080", referrer: "http://192.168.144.34:30080/"
nginx | 192.168.144.32 - - [27/Oct/2023:22:49:26 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://192.168.144.34:30080/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
現在利用されているlog driverを確認します。json-fileが用いられているようです。
$ docker info --format '{{.LoggingDriver}}'
json-file
none
コンテナに対するログを記録せず、 docker logs
は何も出力しないそうです。使う機会があるかは不明ですが。試してみます。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: none
logsコマンドで確認すると、想定通り、ログが確認できません。
$ docker compose logs nginx
WARN[0000] Can't retrieve logs for "nginx": Error response from daemon: configured logging driver does not support reading
一方でdocker runの場合、起動したターミナルでログが確認できます。これはログではなく、docker runコマンドの標準出力のため、想定通りの動作となります。
$ docker run --rm \
-p 0.0.0.0:30080:80 \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf \
--log-driver none \
nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
192.168.144.32 - - [28/Oct/2023:00:17:08 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
192.168.144.32 - - [28/Oct/2023:00:17:08 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
192.168.144.32 - - [28/Oct/2023:00:17:09 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
別のターミナルから起動中のnginxコンテナを見てみると想定通り、ログが確認できません。
$ docker logs eager_burnell
Error response from daemon: configured logging driver does not support reading
Local file logging driver
ロギングドライバーlocal
は、コンテナーの stdout/stderr を保存します。デフォルトでは、local
ドライバーはコンテナーごとに 最大100MB のログ メッセージを保存し、自動圧縮を使用してディスク上のサイズを削減します。
dockerが管理するローカルディスクに独自形式で保存するためパフォーマンスが最も良いです。しかし、ほかのアプリケーションからファイル経由でのアクセスは避けるよう記載があります。
例では、最大サイズを10MBに、ローテーションを3に指定します。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: local
options:
max-size: 10m
max-file: 3
動作確認をします。logs
コマンドでログが取得できています。
ubuntu@test-nginx:~/nginx-log$ docker compose logs nginx
nginx | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx | /docker-entrypoint.sh: Configuration complete; ready for start up
利用可能なオプションは以下の通りです。
オプション | 説明 | 値の例 |
---|---|---|
max-size |
ログの最大サイズ。正の整数に、測定単位を表す修飾子 ( k 、m 、またはg ) を加えたもの。デフォルトは 20m です。 |
--log-opt max-size=10m |
max-file |
ログのローテーション数で、超えると最も古いファイルから削除されます。正の整数。デフォルトは 5 です。 | --log-opt max-file=3 |
compress |
ローテーションされたログ ファイルの圧縮を切り替えます。デフォルトで有効になっています。 | --log-opt compress=false |
JSON File logging driver
デフォルトの設定で、コンテナーの stdout/stderr をJSON形式のファイルに保存します。JSON形式は各行にその出所(stdoutまたはstderr)とタイムスタンプを注釈します。各ログファイルは1つのコンテナに関する情報のみを含みます。
例では、最大サイズを10MBに、ローテーションを3に指定します。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: json-file
options:
max-size: 10m
max-file: 3
動作確認をします。logs
コマンドでログが取得できています。
$ docker compose logs
nginx | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx | /docker-entrypoint.sh: Configuration complete; ready for start up
ログの出力先を確認します。
$ docker inspect nginx |grep LogPath
"LogPath": "/var/lib/docker/containers/264dd92738c22bc708d87cb19c2f859972af90ee4e1ae1ab6e60370d0e7f0720/264dd92738c22bc708d87cb19c2f859972af90ee4e1ae1ab6e60370d0e7f0720-json.log",
ログファイルを覗いてみます。確かに1行1行Jsonファイルとして保存されています。
$ sudo cat /var/lib/docker/containers/264dd92738c22bc708d87cb19c2f859972af90ee4e1ae1ab6e60370d0e7f0720/264dd92738c22bc708d87cb19c2f859972af90ee4e1ae1ab6e60370d0e7f0720-json.log
#省略
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n","stream":"stdout","time":"2023-10-28T01:07:45.45693319Z"}
{"log":"/docker-entrypoint.sh: Configuration complete; ready for start up\n","stream":"stdout","time":"2023-10-28T01:07:45.46027774Z"}
Jsonファイルは{}のルート要素を1つのファイル1つとしているためこのファイルは正確にはJsonファイルとは言えません。ほかのアプリケーションでパースする際は注意してください。1行1行をJsonとして読み込みましょう。
1行のログは以下のようになっています。ログのほかにも、標準出力/エラー、時刻が記録されています。
{
"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n",
"stream":"stdout",
"time":"2023-10-28T01:07:45.45693319Z"
}
利用可能なオプションは以下の通りです。
オプション | 説明 | 値の例 |
---|---|---|
max-size |
ログの最大サイズ。正の整数に、修飾子 ( k 、m 、またはg ) を加えたもの。デフォルトは -1 (無制限) です。 |
--log-opt max-size=10m |
max-file |
ログのローテーション数で、超えると最も古いファイルから削除されます。デフォルトは 5 です。 | --log-opt max-file=3 |
compress |
ローテーションされたログ ファイルの圧縮を切り替えます。デフォルトで有効になっています。 | --log-opt compress=false |
labels |
ログメッセージをタグで分類する際に使用します。詳細はドキュメントを参照してください。 | --log-opt labels=production_status,geo |
labels-regex |
” | --log-opt labels-regex=^(production_statusgeo) |
env |
" | --log-opt env=os,customer |
env-regex |
" | --log-opt env-regex=^(oscustomer) |
Syslog logging driver
syslog
ドライバーはログをサーバーに転送します。オプションパラメータで、サーバアドレス、ファシリティを指定します。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: syslog
options:
syslog-address: udp://172.17.0.1:514
syslog-facility: daemon
tag: "{{.ID}}_{{.Name}}"
syslog-format: rfc5424
サーバ側はrsyslogを用います。/etc/rsyslog.conf
# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")
$AllowedSender TCP, 127.0.0.1, 172.17.0.1/16
syslogを確認します。f60d2def811e_nginx
はコンテナのIDと名前になっています。
$ sudo tail -f /var/log/syslog
Oct 28 01:48:33 test-nginx f60d2def811e_nginx[9334] 192.168.144.32 - - [28/Oct/2023:01:48:33 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
Oct 28 01:48:35 test-nginx f60d2def811e_nginx[9334] 192.168.144.32 - - [28/Oct/2023:01:48:35 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
コマンドでも確認してみます。以下の通り取得できています。
$ docker compose logs -f
nginx | 192.168.144.32 - - [28/Oct/2023:01:48:33 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [28/Oct/2023:01:48:35 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
利用可能なオプションは以下の通りです。
オプション | 説明 | 値の例 |
---|---|---|
syslog-address |
syslogサーバを指定、TCP/UDP/UNIX、TLS有無 |
--log-opt syslog-address=udp://192.168.1.3:514 --log-opt syslog-address=tcp+tls://192.168.1.3:514 --log-opt syslog-address=unix:///tmp/syslog.sock
|
syslog-facility |
syslogのファシリティを名称、または番号で指定 | --log-opt syslog-facility=daemon |
tag |
デフォルトはコンテナ IDの先頭12文字 使える特殊表現 |
--log-opt tag=test-app --log-opt tag={{.Name}}
|
syslog-format |
指定しない場合は、ローカルの Unix syslog 形式が使用されます。rfc3164 RFC-3164 互換形式rfc5424 RFC-5424 互換形式rfc5424micro 形式 |
--log-opt syslog-format=rfc5424 |
syslog-tls-ca-cert |
CA によって署名された信頼証明書への絶対パス | --log-opt syslog-tls-ca-cert=/ca.pem |
syslog-tls-cert |
TLS 証明書ファイルへの絶対パス。 | --log-opt syslog-tls-cert=/cert.pem |
syslog-tls-key |
TLS キー ファイルへの絶対パス。 | --log-opt syslog-tls-key=/key.pem |
syslog-tls-skip-verify |
TLS 検証がスキップされます。 | --log-opt syslog-tls-skip-verify=true |
Journald logging driver
journaldに転送するdriverです。journaldは、Systemdシステム管理デーモンの一部として提供されるログ管理ツールです。システムとサービスのログ情報を効率的に収集、管理、クエリするために設計されています。
伝統的なテキストベースのログファイル(例:/var/log/syslog)とは異なり、バイナリフォーマットでログを保持し、メタデータを活用して高速に検索やフィルタリングが可能です。journaldはログのローテーションや保持期間の設定、自動圧縮もサポートしており、システムのログ管理を中心的に担当します。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: journald
options:
tag: "dev"
本ドライバーは以下のメタデータをログ本文と合わせてジャーナルに送信します。
フィールド | 説明 |
---|---|
CONTAINER_ID |
先頭12文字のコンテナID |
CONTAINER_ID_FULL |
完全な64 文字のコンテナ ID |
CONTAINER_NAME |
起動時のコンテナ名 |
CONTAINER_TAG 、SYSLOG_IDENTIFIER
|
コンテナタグ ( ログタグオプションのドキュメント) ドライバーのオプションで指定したものが送信される |
CONTAINER_PARTIAL_MESSAGE |
ログの整合性を示すフィールド。長いログ行のロギングを改善します。 |
ジャーナルから確認してみます。コンテナ名でも、オプションで指定したタグdev
でも検索ができます。
$ sudo journalctl CONTAINER_NAME=nginx
Oct 28 02:02:53 test-nginx dev[9334]: 192.168.144.32 - - [28/Oct/2023:02:02:53 +0000] "GET / HTTP/>
Oct 28 02:02:53 test-nginx dev[9334]: 192.168.144.32 - - [28/Oct/2023:02:02:53 +0000] "GET / HTTP/>
Oct 28 02:02:53 test-nginx dev[9334]: 192.168.144.32 - - [28/Oct/2023:02:02:53 +0000] "GET / HTTP/>
Oct 28 02:02:54 test-nginx dev[9334]: 192.168.144.32 - - [28/Oct/2023:02:02:54 +0000] "GET / HTTP/>
Oct 28 02:02:54 test-nginx dev[9334]: 192.168.144.32 - - [28/Oct/2023:02:02:54 +0000] "GET / HTTP/>
$ sudo journalctl CONTAINER_TAG=dev
# 同様
journalctlはless互換のため、検索や移動が容易です。dockerからもログは確認できます。
$ docker compose logs
nginx | 192.168.144.32 - - [28/Oct/2023:02:02:54 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
nginx | 192.168.144.32 - - [28/Oct/2023:02:02:54 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "-"
Graylog Extended Format logging driver
本ドライバーはGELF形式での転送を行います。GEFLはGraylogやFluentdが有名です。
GELFのログメッセージはすべて次のフィールドを持つ辞書です。
- バージョン
- ホスト (最初にメッセージを送信した人)
- タイムスタンプ
- メッセージの短いバージョンと長いバージョン
- 自分で設定したカスタムフィールド
ドライバーの指定方法
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: gelf
options:
gelf-address: "udp://172.17.0.1:12201"
Graylog構築
version: '3'
services:
mongo:
image: mongo:5
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
environment:
- http.host=0.0.0.0
- transport.host=localhost
- network.host=0.0.0.0
- "ES_JAVA_OPTS=-Dlog4j2.formatMsgNoLookups=true -Xms512m -Xmx512m"
graylog:
image: graylog/graylog:5.1
environment:
- GRAYLOG_PASSWORD_SECRET=somepasswordpepper
# Password: admin
- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9000/
entrypoint: /usr/bin/tini -- wait-for-it elasticsearch:9200 -- /docker-entrypoint.sh
restart: always
depends_on:
- mongo
- elasticsearch
ports:
- 9000:9000 # Graylog web interface and REST API
- 1514:1514 # Syslog TCP
- 1514:1514/udp # Syslog UDP
- 12201:12201 # GELF TCP
- 12201:12201/udp # GELF UDP
古いCPUではMongoDB 5.0系が動かないので注意です。
$ docker compose logs mongo -f
graylog-mongo-1 |
graylog-mongo-1 | WARNING: MongoDB 5.0+ requires a CPU with AVX support, and your current system does not appear to have that!
graylog-mongo-1 | see https://jira.mongodb.org/browse/SERVER-54407
graylog-mongo-1 | see also https://www.mongodb.com/community/forums/t/mongodb-5-0-cpu-intel-g4650-compatibility/116610/2
graylog-mongo-1 | see also https://github.com/docker-library/mongo/issues/485#issuecomment-891991814
graylog-mongo-1 |
起動後、Graylogダッシュボードにログインし、GELF inputを作成します。
Nginxのアクセスログを確認します。
コンテナのログとしては検索などが可能ですが、messageフィールドをNginxフォーマットで分析するにはGraylogでの追加設定が必要です。本記事では詳細は扱いません。
Fluentd logging driver
Fluentdへログを転送するドライバーです。Fluentdはオープンソースのデータ収集ソフトウェアで、複数のデータソースからのログやイベントデータを効率的に収集、変換、送信することを目的としています。クラウド環境や大規模なシステムでのログ集約や分析のための中心的なツールとして広く利用されています。
- 多数のプラグインが利用可能で、データの収集、変換、出力先をカスタマイズ
- データの一時的な保存や再送をサポートし、データの紛失リスクを低減
- リソースの消費が少なく、大量のデータも効率的に処理
- Input Plugins(Source)
- ログの入力を定義します
-
tail
: コマンドのtail -fと同様にファイルを監視し追記分を入力とします -
forward
: fluentd形式の入力を受け付けますDockerドライバは本形式で出力する -
http
: jsonのPOSTを受け付ける -
syslog
: syslogサーバとして機能する
- Filter Plugins(filter)
- 通過するログをフィルタリングします
-
grep
: 正規表現などを用いてログをフィルタリングします -
geoip
: IPアドレスから地域を判別できます
- Output Plugins(match)
- フィルタリングやパースを行ったログを出力する
-
stdout
: デバッグなどに用い、標準出力を利用します -
forward
: Fluentd形式で次のFluentd転送する -
mongo
: mongoDBに保存する - 他にも
s3
,elasticsearch
などがあります
- その他
- その他にもログ転送前に様々な処理を行うPluginが存在します。
- Parser Plugins
- Formatter Plugins
- Buffer Plugins
- Metrics Plugins
ドライバーの指定方法
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: fluentd
options:
fluentd-address: "172.17.0.1:24224"
tag: "docker_{{.Name}}"
Fluent構築
本記事ではinput
にドライバーの主力形式であるforward
、処理は行わずoutput
に標準出力を用います。
fluent.conf
を作成します。
<source>
@type forward
</source>
<match docker_**>
@type stdout
</match>
上記設定ファイルを組み込んだDockerイメージを作成するためのDockerfile
FROM fluent/fluentd:v1.16-1
COPY fluent.conf /fluentd/etc
compose.yaml
を作成します。
version: '3'
services:
fluentd:
build: ./
ports:
- 24224:24224
- 24224:24224/udp
Fluentdを起動します。起動後、NginxにアクセスするとFluentdを起動したターミナルの標準出力でログが確認できます。
$ docker compose up
[+] Running 2/2
✔ Network fluentd_default Created 0.1s
✔ Container fluentd-fluentd-1 Created 0.0s
Attaching to fluentd-fluentd-1
~~ 省略 ~~
fluentd-fluentd-1 | 2023-10-28 03:43:30.000000000 +0000 docker_nginx: {"source":"stdout","log":"192.168.144.32 - - [28/Oct/2023:03:43:30 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\" \"-\"","container_id":"3a8a296963b63a9b0f1d51dd3141749d0812662ace6188f027b9d708c0508c95","container_name":"/nginx"}
fluentd-fluentd-1 | 2023-10-28 03:43:30.000000000 +0000 docker_nginx: {"container_id":"3a8a296963b63a9b0f1d51dd3141749d0812662ace6188f027b9d708c0508c95","container_name":"/nginx","source":"stdout","log":"192.168.144.32 - - [28/Oct/2023:03:43:30 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\" \"-\""}
fluentd-fluentd-1 | 2023-10-28 03:43:30.000000000 +0000 docker_nginx: {"container_id":"3a8a296963b63a9b0f1d51dd3141749d0812662ace6188f027b9d708c0508c95","container_name":"/nginx","source":"stdout","log":"192.168.144.32 - - [28/Oct/2023:03:43:30 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\" \"-\""}
注意点としては、コンテナ起動時にFluentdが起動している必要があります。Fluentd側に問題があるとコンテナは起動できません。
$ docker compose up -d
[+] Running 2/2
✔ Network nginx-log_default Created 0.1s
✔ Container nginx Created 0.2s
Error response from daemon: failed to create task for container: failed to initialize logging driver: dial tcp 192.168.0.5:24224: connect: connection refused
Amazon CloudWatch Logs logging driver
CloudWatchへ転送するdriverです。本章では親和性を考慮してEC2サーバ上のコンテナからの転送を想定します。Amazon CloudWatchは、AWSリソースおよびアプリケーションをモニタリングするサービスです。
- リアルタイムモニタリング: AWSリソースのメトリクスをリアルタイムで収集し、表示
- アラーム: 予め設定したしきい値を超えると、通知や自動アクションをトリガーするアラーム
- ダッシュボード: 複数のメトリクスを一つのビューで見るためのカスタマイズ可能なダッシュボード
- ログファイルの統合: CloudWatch Logsを使用して、アプリケーションのログファイルをモニタリングし、保存、分析
- カスタムメトリクス: 独自のメトリクスをCloudWatchに送信し、モニタリング
- イベント管理: CloudWatch Eventsを使用して、AWSリソースの変更や状態遷移を検出し、応答
- トレース: CloudWatch ServiceLensとX-Rayの統合を通じて、アプリケーションのパフォーマンスボトルネックや問題点を追跡・分析する
ドライバーの指定方法
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: awslogs
options:
awslogs-region: ap-northeast-1
awslogs-group: my-log-group
awslogs-create-group: "true"
AWS CloudWatchでの設定
IAMからポリシーを作成し、本ポリシーをロール経由でEC2にアタッチします。
CloudWatchへのログ送信のみを許可した最低限のポリシーです。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup"],
"Effect": "Allow",
"Resource": "*"
}
]
}
EC2にログインし、Nginxを起動します。セキュリティグループには30080
を適切に追加します。
[ec2-user@ip-XX nginx-log]$ sudo docker-compose up -d
[+] Running 1/1
⠿ Container nginx Started
起動前には、ドライバーがロググループを作成し、認証情報の確認などを行っています。
CloudWatchを確認すると、指定した名称でロググループが作成されています。
ライブテールからログを確認します。
Splunk logging driver
本ドライバーは SplunkへHTTP イベント コレクターとして送信します。Splunk Enterprise と Splunk Cloud に利用可能です。Splunk Cloudはあらゆるニーズに対応する柔軟なデータプラットフォームサービスです。※2
- 機械学習とAI
- 対応だけでなく予測と防止を視野に入れ、マシンレベルのインテリジェンスをデータに統合して、セキュリティとビジネス成果を向上
- データストリーミング
- リアルタイムのストリーム処理によってデータをミリ秒単位で収集、処理し、Splunkやその他の送信先に配信
- 拡張可能なインデックス
- SaaSをはじめとする数千に及ぶデータソースからテラバイト規模のデータを収集、取り込み
- コラボレーションツール
- モバイル、TV、AR (拡張現実)機能によって、場所に縛られないコミュニケーションとコラボレーションを実現
- 統合サーチ
- オンプレミスやサードパーティのデータストアを含む多様なデータエコシステムを横断的にサーチしてデータを相関付け、組織レベルで分析
- 強力なダッシュボード
- 直感的なダッシュボード画面で、複雑なデータストーリーでも簡単に状況を把握
ドライバーの指定方法
https://prd-p-XXXXXXX.splunkcloud.com:8080
はインスタンス払い出し時に届くメールアドレスに記載があります。そこにポート番号を付け加えます。今回は検証のため、Splunk Cloudサーバの証明書確認を無効としています。
version: "3"
services:
nginx:
image: nginx:latest
# 省略
logging:
driver: splunk
options:
splunk-token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
splunk-url: https://prd-p-XXXXXXX.splunkcloud.com:8088
splunk-insecureskipverify: "true"
tag: "{{.Name}}/{{.FullID}}"
labels: location
Splunk Cloudでの設定
Splunk Cloudは15日の無料トライアルが可能です。制限はありますが、メールアドレスのみで作成可能です。
データの追加を行うため、HTTP イベント コレクターを作成します。作成後、テキストトークンが表示されるので保存します。ログ送信時に必要になります。
設定値が正しい場合、Nginxコンテナが起動できます。Nginxにアクセス後、Splunk Cloudから検索をかけます。ドライバーがログを送信する場合、オリジナルのNginxのログはline
に表示されるため上手くパースできていませんが、本章では以上となります。
ETW logging driver
Event Tracing for Windows (ETW) ログ ドライバーは、コンテナー ログを ETW イベントとして転送します。ETW は Windows の Event Tracing の略で、Windows でアプリケーションをトレースするための共通のフレームワークです。各 ETW イベントには、ログとそのコンテキスト情報の両方を含むメッセージが含まれています。その後、クライアントはこれらのイベントをリッスンするための ETW リスナーを作成できます。
ETWはWindows PowerShellのlogmanコマンドを使用して設定を行います。以下のコマンドでイベントのリスナーを起動します。
logman start -ets DockerContainerLogs -p {a3693192-9ed6-46d2-a981-f8226c8363bd} 0 0 -o trace
公式ドキュメントよりETWとして転送されたログのサンプルを示します。イメージ名からも分かる通りWinsowsコンテナのため本記事での紹介は以上とさせていただきます。
container_name: backstabbing_spence,
image_name: windowsservercore,
container_id: f14bb55aa862d7596b03a33251c1be7dbbec8056bbdead1da8ec5ecebbe29731,
image_id: sha256:2f9e19bd998d3565b4f345ac9aaf6e3fc555406239a4fb1b1ba879673713824b,
source: stdout,
log: Hello world!
gcplogs
Google Cloud Logging
へログを転送します。クラウドベンダーが提供するログ基盤系のドライバーです。
まず、ログ転送用のサービスアカウントを作成します。Cloud Loggingサービスエージェントのロールを付与してください。プロジェクト単位より詳細にアクセス権限をコントロールしたい場合は新たなロールを作成してください。
作成したサービスアカウントのキーを生成してJSON形式でダウンロードします。
ダウンロードしたキーをログを転送する環境に設置します。
vim /etc/docker/gcp_credentials.json
Dockerログドライバーにcredentialの場所を渡します。
sudo vi /lib/systemd/system/docker.service
~~~ 省略 ~~~
[Service]
Environment=GOOGLE_APPLICATION_CREDENTIALS=/etc/docker/gcp_credentials.json
~~~ 省略 ~~~
確認用にNginxを起動します。
docker run \
-p 0.0.0.0:8080:80 \
--log-driver=gcplogs \
--log-opt gcp-project=プロジェクトID \
--log-opt gcp-meta-zone=west1 \
--log-opt gcp-meta-name=`hostname` \
nginx:latest
GCPログエクスプローラーで以下のクエリを実行します。
logName="projects/プロジェクトID/logs/gcplogs-docker-driver"
Nginxのログが確認できます。
おわりに
検証したすべてのドライバーをログの保存先で分類し、使用感をまとめました。
ドライバ | 分類 | |
---|---|---|
none |
ローカル系 | コンテナに対するログを記録しない。ログをボリュームに書き出し、fluentbitで転送する場合などに有効 |
local | ローカル系 | 独自のファイル方式で保存され、ドライバの中で一番オーバーヘッドが少ない※コンテナ再作成で消える |
json-file | ローカル系 | JSON 形式で保存され、デフォルトのドライバー※コンテナ再作成で消える |
journald | ローカル系 | 検索しやすく、単一ホストでの運用では有力※デフォルトの設定ではホスト再起動で消える |
etwlogs | ローカル系 | Windowsサーバなどを運用している場合は有力だが、Windowsコンテナを利用する機会が少なく、判断が難しい |
syslog | ログ基盤系 | 既存のログ基盤と相性が良く、ファイルに保存する場合は一番制御しやすいと感じた |
gelf | ログ基盤系 | Graylogを採用している場合は最有力 |
fluentd | ログ基盤系 | 複数のログ基盤があり、基本はsyslog、アクセスログなどはsplunkに投げる、等使い分けるときは一元管理できる |
splunk | ログ基盤系 クラウド系 |
Splunkを採用しているプロジェクトでは一択 |
awslogs | クラウド系 | AWSを主に採用している場合は有力 |
gcplogs | クラウド系 | GCPを主に採用している場合は有力、Log explorerが使いやすい |
上記から、ドライバーの選定には以下のケース別に判断すると良いと考えました。
- 単一ホストの場合
- journaldに格納し、永続化の設定を行う
- 複数ホストの場合
- syslogドライバーを使用し、ファイルに保存を行う
- 法令、コンプライアンスでログの保存期間が決まっている場合でも対応が可能
- クラウド基盤を利用している場合
- 使用しているクラウドに対応するドライバーを使用する