ロギングドライバー

Dockerの標準出力はロギングドライバーの設定によって出力先が変わる。

ロギングドライバーの設定はdocker-compose.ymlloggingで指定する。

version: "3.9"

services:
  linux:
    image: ...
    logging:
      driver: ドライバー名

loggingを指定していない場合、デフォルトではjson-fileになっている。

JSON File logging driver | Docker Docs

json-fileドライバーの場合、コンテナの標準出力は/var/lib/docker/containers/コンテナID/コンテナID-json.logに出力される。

コンテナIDはdocker psコマンドで確認できる。

$ docker ps
CONTAINER ID   IMAGE                                                      COMMAND       CREATED         STATUS         PORTS     NAMES
4485fc9e22f1   public.ecr.aws/amazonlinux/amazonlinux:2023.2.20231018.2   "/bin/bash"   4 minutes ago   Up 4 minutes             docker-test-linux-1

上記の場合は/var/lib/docker/containers/以下のa7a6696a3640から始まるフォルダを探せばよい。

$ ls /var/lib/docker/containers/4485fc9e22f1028654e02f6485048efc88b1c01b35993c7c60887bdeb26cd4bf/4485fc9e22f1028654e02f6485048efc88b1c01b35993c7c60887bdeb26cd4bf-json.log
{"log":"Hello, world!\n","stream":"stdout","time":"2021-11-03T01:59:02.000000000Z"}

journaldドライバー

journaldドライバーを使うとコンテナの標準出力をjournaldに出力できる。

Journald logging driver | Docker Docs

version: "3.9"

services:
  linux:
    image: public.ecr.aws/amazonlinux/amazonlinux:2023.2.20231018.2
    logging:
      driver: journald

シェルスクリプトでDockerログ(コンテナの標準出力)に出力する

まずコンテナ内で実行するシェルスクリプトの標準出力をDockerログ(コンテナの標準出力)に出力する。
シェルスクリプトでDockerログ(コンテナの標準出力)に出力するには/proc/1/fd/1に出力すればよい。

#!/bin/sh

echo "Hello, world" > /proc/1/fd/1

/proc/1/fd/1はコンテナの標準出力のファイルディスクリプタ。

ホストOS側のjournalctl -fで出力を表示すれば確認できる。

$ journalctl -f
Nov 03 03:59:23 ip-10-0-13-80.ap-northeast-1.compute.internal 1f2417b25f21[27000]: Hello, world

標準エラーに出力したい場合は/proc/1/fd/2に出力すればよい。

#!/bin/sh

echo "Hello, world" > /proc/1/fd/2

標準エラーの場合もDockerログに出力されるので、journaldロギングドライバーを指定していればjournalctlで確認できる。

コンテナIDを指定してjournalctlで出力を確認する

journaldへのログにコンテナ名をつける

docker-compose.ymlに以下の設定を加えるとjournaldへ出力されるログにコンテナ名をつけられる。

  • container_nameでコンテナ名をつける
  • logging.options以下にtag="{{.Name}}を追加する

例えば以下のような設定となる。

version: "3.9"

services:
  linux:
    image: public.ecr.aws/amazonlinux/amazonlinux:2023.2.20231018.2
    container_name: test-container
    logging:
      driver: journald
      options:
        tag: "{{.Name}}"

動作確認としてコンテナ内で以下を実行する。

$ echo "Hello, world" >> /proc/1/fd/1

ホストOS側でjournalctl -fを実行すると以下のように出力される。

$ journalctl -f
Nov 03 04:09:13 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: Hello, world

test-containerというコンテナ名が表示されている。

journalctlでコンテナ名で絞り込む

コンテナ名で絞り込むにはjournalctlの引数にCONTAINER_NAME=コンテナ名を追加して実行する。 例えば以下のようになる。

$ journalctl -f CONTAINER_NAME=test-container
Nov 03 04:09:13 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: Hello, world

シェルスクリプトでDockerログに出力する

/proc/1/fd/1、/proc/1/fd/2 に出力する

コンテナ内で実行するシェルスクリプトの標準出力をDockerログ(コンテナの標準出力)に出力するには/proc/1/fd/1に出力すればよい。

#!/bin/sh

echo "Hello, world" > /proc/1/fd/1
echo "Hello, world" > /proc/1/fd/2

/proc/1/fd/1はコンテナの標準出力のファイルディスクリプタ。
/proc/1/fd/2はコンテナの標準エラー出力のファイルディスクリプタ。

コンテナ内で上記スクリプトを実行する。

$ sh ./test.sh

ホストOS側のjournalctlで出力を確認する。

$ journalctl -f
Nov 03 04:32:50 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: Hello, world
Nov 03 04:32:50 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: Hello, world

標準出力、標準エラー出力の両方が出力されている。

exec コマンドで一括でDockerログ(コンテナの標準出力)に出力する

execコマンドを使うとコンテナ内で実行したコマンドの標準出力をDockerログ(コンテナの標準出力)に出力できる。
シェルスクリプトの先頭で実行しておくと以降のコマンドの出力先を個別に指定する必要がなくなる。
そのためスクリプトを簡潔にできる。

例えば以下のようなシェルスクリプトを実行する。

#!/bin/sh

exec 1>> /proc/1/fd/1 2>> /proc/1/fd/2

echo "Hello, world"
ls aaa # 存在しないパスでエラーを発生させる

コンテナ内で上記スクリプトを実行する。

$ sh ./test.sh

ホストOS側のjournalctlで出力を確認する。

$ journalctl -f CONTAINER_NAME=test-container
Nov 03 04:35:19 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: Hello, world
Nov 03 04:35:19 ip-10-0-13-80.ap-northeast-1.compute.internal test-container[27000]: ls: cannot access 'aaa': No such file or directory

標準出力、標準エラー出力の両方が出力されている。