目次

コンテナのデバッグ:docker logs、exec、inspect、cp、stats

コンテナはバックグラウンドで実行されるため、エラーが起きても画面には直接表示されません。この節では、よく使うデバッグツールをまとめ、よくあるエラーをいくつか実際に再現します。ここでは nginx コンテナを使います。

docker run -d --name web -p 8080:80 nginx:1.30

ログを確認する:docker logs

コンテナのメインプロセスが標準出力(stdout)と標準エラー(stderr)に出力した内容は、docker logs で確認できます。まず nginx に何度かリクエストを送ります(/page1 から /page3 は存在しません)。その後、ログを確認します。

$ docker logs --tail 3 web
2026/10/12 23:52:59 [error] 28#28: *3 open() "/usr/share/nginx/html/page3" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page3 HTTP/1.1", host: "localhost:8080"
172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET /page3 HTTP/1.1" 404 153 "-" "curl/8.22.0" "-"
172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.22.0" "-"

$ docker logs --tail 2 -t web
2026-10-12T23:52:59.403434333Z 172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET /page3 HTTP/1.1" 404 153 "-" "curl/8.22.0" "-"
2026-10-12T23:52:59.503902089Z 172.18.0.1 - - [12/Oct/2026:23:52:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.22.0" "-"
オプション説明
--tail 3最後の 3 行だけを表示
-t各行の先頭に Docker が記録したタイムスタンプを付ける
-f新しいログを継続して追跡する(tail -f に似ています)。終了するには Ctrl + C を押します
--since 10m直近 10 分のログだけを表示(2026-10-12T23:00:00 のようにも指定できます)

コンテナがすでに停止していてもログを確認できます。「なぜ停止したのか」を調べる最初の手順です。

stdout と stderr

ログをファイルに保存すると、不思議なことに気づきます。

$ docker logs --since 1m web > out.log; wc -l out.log
2026/10/12 23:52:57 [notice] 1#1: using the "epoll" event method
2026/10/12 23:52:57 [notice] 1#1: nginx/1.30.5
2026/10/12 23:52:57 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19)
2026/10/12 23:52:57 [notice] 1#1: OS: Linux 5.4.0-216-generic
2026/10/12 23:52:57 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2026/10/12 23:52:57 [notice] 1#1: start worker processes
2026/10/12 23:52:57 [notice] 1#1: start worker process 28
2026/10/12 23:52:59 [error] 28#28: *1 open() "/usr/share/nginx/html/page1" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page1 HTTP/1.1", host: "localhost:8080"
2026/10/12 23:52:59 [error] 28#28: *2 open() "/usr/share/nginx/html/page2" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page2 HTTP/1.1", host: "localhost:8080"
2026/10/12 23:52:59 [error] 28#28: *3 open() "/usr/share/nginx/html/page3" failed (2: No such file or directory), client: 172.18.0.1, server: localhost, request: "GET /page3 HTTP/1.1", host: "localhost:8080"
13 out.log

$ docker logs --since 1m web > all.log 2>&1; wc -l all.log
23 all.log

> でファイルにリダイレクトしているのに、nginx の起動メッセージとエラーログは画面に表示され、ファイルには 13 行しかありません。これは docker logs が stdout と stderr を別々に保持するためです。nginx のアクセスログは stdout に、エラーと起動メッセージは stderr に書き込まれます。> がリダイレクトするのは stdout だけです。2>&1 を追加すると、両方をファイルに保存できます(23 行)。grep でログを絞り込む場合も同じです:docker logs web 2>&1 | grep error。

プログラムがコンテナ内のファイル(例:/var/log/app.log)にログを書き込む場合、docker logs では確認できません。公式イメージは通常、ログを stdout / stderr に出力します。自分で作成したプログラムも、stdout に直接出力することをおすすめします。

コンテナに入る:docker exec

実行中のコンテナ内でコマンドを実行します。

$ docker exec web cat /etc/nginx/conf.d/default.conf | head -n 12
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

$ docker exec -u nginx web whoami
nginx

$ docker exec -e DEBUG=1 web sh -c "echo DEBUG=\$DEBUG"
DEBUG=1
形式説明
docker exec -it web bash対話型シェルを開く(軽量イメージに bash がない場合は sh を使います)
docker exec web コマンド単一のコマンドを実行し、出力をそのままターミナルに返す
docker exec -u nginx web …指定したユーザーとして実行する
docker exec -e KEY=VALUE web …環境変数を渡す

exec が起動するのは追加のプロセスです。終了(exit)してもコンテナは停止しません。

コンテナが起動直後に終了すると、実行中ではないため exec は使えません。その場合は --entrypoint を使って新しいコンテナを起動し、元のサービスを実行せずに中を確認できます。

$ docker run --rm --entrypoint sh nginx:1.30 -c "ls /docker-entrypoint.d"
10-listen-on-ipv6-by-default.sh
15-local-resolvers.envsh
20-envsubst-on-templates.sh
30-tune-worker-processes.sh

Docker Desktop では、コンテナを選択した後に Exec タブを開いてシェルを起動することもできます。

Docker Desktop の Exec タブ
Docker Desktop のコンテナ詳細ページにある Exec タブ。docker exec -it と同じです。画像出典:Docker 公式ドキュメント(Apache-2.0)

設定と状態を確認する:docker inspect

docker inspect はコンテナの設定と状態を完全な JSON 形式で出力します。--format と組み合わせると、必要なフィールドを取り出せます。

$ docker inspect --format '{{.State.Status}} {{.State.ExitCode}}' web
running 0

$ docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
172.18.0.2

$ docker inspect --format '{{json .HostConfig.PortBindings}}' web
{"80/tcp":[{"HostIp":"","HostPort":"8080"}]}

$ docker inspect --format '{{.Path}} {{.Args}}' web
/docker-entrypoint.sh [nginx -g daemon off;]
確認したいことフィールド
停止した理由.State.ExitCode、.State.Error、.State.OOMKilled
マウントされているフォルダー.Mounts
環境変数.Config.Env
実際に実行されたコマンド.Path、.Args
IP アドレス.NetworkSettings.Networks
ポートの割り当て.HostConfig.PortBindings
再起動回数.RestartCount

ファイルをコピーする:docker cp

ホストとコンテナの間でファイルをコピーできます。コンテナが停止していても使えます。

$ docker cp web:/etc/nginx/nginx.conf ./nginx.conf

$ head -n 5 nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;

$ echo "<h1>copied in</h1>" > index.html

$ docker cp ./index.html web:/usr/share/nginx/html/

$ curl -s http://localhost:8080
<h1>copied in</h1>

設定ファイルを取り出して参考にしたり、一時的にファイルを入れてテストしたりするのに便利です。本番環境では Dockerfile に記述するか、Volume をマウントしてください。

リソースとプロセス:docker stats、top、diff

$ docker stats --no-stream
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O          BLOCK I/O       PIDS
4a43d09d0bcb   web       0.00%     7.59MiB / 1.919GiB   0.39%     2.79kB / 2.5kB   15MB / 8.19kB   2

$ docker top web
PID                 USER                TIME                COMMAND
1180                root                0:00                nginx: master process nginx -g daemon off;
1238                101                 0:00                nginx: worker process
  • docker stats:CPU、メモリ、ネットワーク、ディスク I/O を表示します。--no-stream を付けないと継続的に更新されます(Ctrl + C で終了)。メモリ上限を設定していない場合、LIMIT はホスト(または Docker Desktop 仮想マシン)の総メモリです。
  • docker top:コンテナ内のプロセスを表示します。nginx イメージには ps コマンドがありません(最初のコンテナを参照)。docker top なら外部から確認できます。
$ docker diff web
C /run
A /run/nginx.pid
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp

docker diff は、コンテナの書き込み可能レイヤーで元のイメージから追加(A)、変更(C)、削除(D)されたファイルを一覧表示します。先ほど docker cp でコピーした index.html が変更として表示されます。default.conf は nginx の起動スクリプトが自動で変更したものです(IPv6 を有効化)。これらの変更はコンテナを削除すると失われます。

よくある問題の例

コンテナが起動直後に終了する

$ docker run -d --name broken postgres:18
Unable to find image 'postgres:18' locally
18: Pulling from library/postgres
ecc510c1e359: Already exists
4a3cafbebf6d: Pull complete
28ced28a309b: Pull complete
ab69e2551985: Pull complete
1f04dfa92b9f: Pull complete
5a487c9461a5: Pull complete
e0d4a6e58470: Pull complete
496ce2ef5b2f: Pull complete
c8145e79cc2b: Pull complete
d23c975c4693: Pull complete
06ea90d3bcc9: Pull complete
dc25540d793f: Pull complete
7967f593457f: Pull complete
Digest: sha256:74935e72241653ca55e0414067e6d8763aceb8a810eb51b452253ec3dcfc4336
Status: Downloaded newer image for postgres:18
05a9084084fc2b744e4414e95323159bbc7455a1872784176f7333d31e875bda

$ docker ps -a --filter name=broken
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS                     PORTS     NAMES
05a9084084fc   postgres:18   "docker-entrypoint.s…"   4 seconds ago   Exited (1) 4 seconds ago             broken

$ docker logs broken
Error: Database is uninitialized and superuser password is not specified.
       You must specify POSTGRES_PASSWORD to a non-empty value for the
       superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".

       You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
       connections without a password. This is *not* recommended.

       See PostgreSQL documentation about "trust":
       https://www.postgresql.org/docs/current/auth-trust.html

docker run -d がコンテナ ID を出力したので成功したと思っても、docker ps -a を見ると数秒後に Exited (1) になっています。docker logs が原因を直接示しています。POSTGRES_PASSWORD が設定されていません。調査は必ず、docker ps -a で状態を確認し、docker logs で原因を見る順に行います。

ポートがすでに使用されている

$ docker run -d -p 8080:80 nginx:1.30
c7b7a64eab9314885fb41d5ac82352c519240a17ea2e2e53098a0536a3264e6c
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint youthful_aryabhata (aff407d4a63df5baee04263bfdc54732e45cb69016b909a8e809c9010d81e926): Bind for 0.0.0.0:8080 failed: port is already allocated

Run 'docker run --help' for more information

ホストの 8080 ポートはすでに web コンテナが使用しています。最初の行にコンテナ ID が出力されている点に注意してください。コンテナはすでに作成されていて、起動に失敗しただけです。docker ps -a に Created 状態で残るので、忘れずに削除してください。解決するには、別のホストポート(-p 8081:80)を使うか、使用中のプロセスを特定します(docker ps。Docker 以外のプログラムなら sudo lsof -i :8080)。

exec format error

$ docker run --rm --platform linux/arm64 alpine:3.23 uname -m
Unable to find image 'alpine:3.23' locally
3.23: Pulling from library/alpine
ace1621be7ff: Pull complete
Digest: sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0
Status: Image is up to date for alpine:3.23
exec /bin/uname: exec format error

このホストは amd64(x86_64)ですが、arm64 版のイメージを強制的に実行しようとしています。この CPU ではプログラムを実行できません。実際によくあるのは、Apple Silicon Mac でビルドしたイメージを、一般的な x86 クラウドホストで実行するケースです。解決方法はマルチプラットフォームイメージを参照してください。

メモリ不足(OOM)

コンテナが --memory で設定した上限を超えると、Linux カーネルがプロセスを強制終了します。

  • docker ps -a に Exited (137) と表示される
  • docker inspect --format '{{.State.OOMKilled}}' コンテナ名 に true と表示される

終了コード 137 でも OOMKilled が false の場合は、通常 docker kill または docker stop のタイムアウトによって強制終了されています。--memory の値を増やすか、プログラムでメモリリークが発生していないか確認してください。

ディスクの空き容量がありません

Docker がディスク容量を使いすぎています。まず docker system df で確認します。

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          6         2         1.026GB   757.3MB (73%)
Containers      3         2         122.9kB   4.096kB (3%)
Local Volumes   1         0         0B        0B
Build Cache     0         0         0B        0B

RECLAIMABLE は削除できる容量です。削除方法はディスク容量のクリーンアップを参照してください。

トラブルシューティングの流れ

  1. docker ps -a:コンテナは実行中ですか?終了コードはいくつですか?
  2. docker logs コンテナ(必要に応じて 2>&1 | grep を追加):プログラムは何を出力していますか?
  3. 終了コードを確認します。1 はログを確認、127 はコマンドが見つからない、137 は強制終了または OOM、139 はプログラムのクラッシュ(segfault)です。
  4. docker inspect:環境変数、マウント、ポート、実行コマンドが想定どおりか確認します。
  5. docker run -it --rm --entrypoint sh イメージ:中に入って手動で実行し、不足しているものを確認します。

まとめ

  • まず docker ps -a で状態と終了コードを確認し、次に docker logs を確認します。
  • docker exec で実行中のコンテナに入り、docker cp でファイルを取り出します。
  • docker inspect -f で設定と状態を調べ、docker stats でリソース使用量を確認します。
  • コンテナが起動直後に終了する場合は、--entrypoint sh で新しいコンテナを起動して手動で調査します。

練習問題

練習 1:docker run --name broken alpine:3.23 ls /not-exist を実行し、この章の方法で失敗の原因と終了コードを調べてください。

解答
docker ps -a --filter name=broken
docker logs broken
docker inspect -f "{{.State.ExitCode}}" broken

ログには ls: /not-exist: No such file or directory と表示され、終了コードは 1 です。

練習 2:docker run -d --name w nginx:1.30-alpine を起動し、コンテナ内にファイルを作成します。コンテナとイメージを比較して、変更されたファイルを一覧表示するには、どのコマンドを使いますか?

解答

docker diff w です。A は追加、C は変更、D は削除を表します。仕組みについては内部の仕組みを参照してください。

よくある質問

コンテナが起動直後に終了し、exec で入れない場合はどうすればよいですか?

まず docker logs コンテナ を確認します。次に docker run --rm -it --entrypoint sh イメージ で新しいコンテナを起動し、元のコマンドを手動で実行してエラーを確認します。

docker logs の量が多すぎて確認できません。

--tail 50 で最後の 50 行だけを表示するか、--since 10m で直近 10 分のログだけを表示し、2>&1 | grep キーワード と組み合わせます。全オプションは [docker logs](/ja/docker/docker-logs/) を参照してください。

エラーメッセージの意味はどこで調べられますか?

[よくあるエラーメッセージ一覧](/ja/docker/errors/) を参照してください。25 種類のエラーについて、実際の出力と解決方法をまとめています。

更新日 2026年10月14日