前回【Day 12】では、コンテナの状態確認(
ps)、安全な停止(stop)、破棄(rm)の基本ライフサイクルを学びました。本日は第13回として、開発やトラブルシューティングの現場で最も頻繁に叩くことになる「コンテナのログ確認とデバッグ(logs, inspect, top)」を徹底解説します!
Windowsイベントビューアーやサーバー上のログファイルを手動で探していたベテランの方ほど、Dockerの標準出力ストリームと診断コマンドの圧倒的な快適さに驚かれるはずです!
① 導入・本日の達成目標
「バックグラウンド(-d)で起動したコンテナが正しく動いているか、どうやって確かめるのか?」
「HTTP 500エラーが発生したとき、C#アプリのエラーログはどこに出力されているのか?」
「コンテナのIPアドレスや割り当てられたポート番号、CPU消費量はどう調べるのか?」
これらはすべて、Dockerが標準で提供する診断コマンド群(logs, inspect, stats, top)によって手元のターミナルから1発で把握できます。
本講義のゴールは以下の3点です。
docker logs -fを使い、コンテナ内部の標準出力を手元のターミナルへリアルタイムストリーミング監視できるようになる。docker inspectを活用し、コンテナのIPアドレス・環境変数・ボリューム設定をピンポイントで調査・抽出できるようになる。docker stats&docker topにより、タスクマネージャー感覚でCPU・メモリ使用率や実プロセスを監視・診断できるようになる。
② VM / Windowsサーバー技術者のためのパラダイムシフト
従来のWindows Serverや物理サーバー環境での障害調査を思い出してみてください。
問題が発生した際、エンジニアは次のような手順を踏んでいました。
- リモートデスクトップ(RDP)で対象サーバーにログインする。
- 「イベントビューアー」を開き、アプリケーションログやシステムログの警告・エラーをスクロールして探す。
- または
C:\inetpub\logs\LogFilesやC:\Logspp.logなどのファイルをテキストエディタで開き、巨大なログの中からタイムスタンプを目視で追う。
複数のサーバーが並ぶクラスタ環境では、この作業をサーバー1台ずつ繰り返す必要があり、多大な時間と精神的負担がかかっていました。
The Twelve-Factor App 原則:ログは「ファイル」ではなく「イベントストリーム」
クラウドネイティブ・コンテナ設計の世界的標準原則である「The Twelve-Factor App(12の設計規範)」では、ログの扱いについて明確な指針が示されています。
「アプリ自体がログファイルのルーティングや保存先を管理してはならない。すべての実行ログは、バッファリングなしで標準出力(stdout)および標準エラー出力(stderr)に書き出されるべきである。」
Dockerはこの原則を全面的に採用しています。コンテナ内で動くアプリケーションが標準出力にテキストを出力すると、Dockerエンジンがそれを自動的に捕捉(キャプチャ)し、JSON形式等のログストレージに蓄積します。
開発者は docker logs コマンドを叩くだけで、手元のPCから即座にログを監視できる のです。
③ docker logs 完全マスター:オプションと実践監視術
基本コマンドは docker logs <コンテナ名またはID> ですが、実務ではオプションの使い分けが極めて重要です。
| オプション | コマンド例 | 現場での活用シーン |
|---|---|---|
| -f, --follow | docker logs -f my-web | リアルタイム監視。Linuxの tail -f と同等。ブラウザでリクエストを送った瞬間にログが流れるため、即座に動作検証できる。終了は Ctrl + C。 |
| --tail <行数> | docker logs --tail 50 my-web | 末尾行の限定取得。長期間動いているコンテナで全ログを出力するとコンソールが数万行で埋まるため、直近50行や100行に絞り込む。 |
| -t, --timestamps | docker logs -t my-web | タイムスタンプ付与。アプリ側が出力に日時を含めていなくても、DockerがUTCタイムスタンプを先頭に付与して表示する。 |
| --since / --until | docker logs --since "10m" my-web | 時間帯フィルタリング。「直近10分間(10m)」や「2026-10-09T09:00:00」以降のログだけを精密に切り出して抽出する。 |
現場で最も使われる黄金の組み合わせ
# 直近100行を表示した上で、リアルタイムストリーミング監視に移行する docker logs --tail 100 -f my-web
このコマンドをターミナルで流しておき、別ウィンドウのブラウザや Postman、curl でAPIを叩くと、C#のリクエスト受付ログやSQLクエリログが手元で鮮やかに流れます。
④ docker inspect:コンテナの「カルテ」を読み解く
「このコンテナに割り当てられた内部IPアドレスは何番か?」
「環境変数(ConnectionStringsやASPNETCORE_ENVIRONMENT)は正しく注入されているか?」
「ホストマシンのどのフォルダがコンテナ内のどこにマウントされているか?」
これらの疑問に一撃で答えてくれるのが docker inspect <コンテナ名> です。
普通に docker inspect my-web を実行すると、数百行に及ぶ巨大なJSONデータが出力されます。
設定のすべて(State, GraphDriver, NetworkSettings, Mounts, Config)が網羅されていますが、必要な情報だけを抽出したい場合は --format(Goテンプレート構文) を使います。
# 1. コンテナの内部IPアドレスのみをピンポイント抽出
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-web
# 出力例: 172.17.0.2
# 2. コンテナの稼働ステータスとPIDを抽出
docker inspect -f '{{.State.Status}} (PID: {{.State.Pid}})' my-web
# 出力例: running (PID: 14205)
# 3. 設定されている環境変数の一覧を抽出
docker inspect -f '{{json .Config.Env}}' my-web
# 4. ポートバインディング(ホストポートとコンテナポートの対応)を確認
docker inspect -f '{{json .NetworkSettings.Ports}}' my-web
⑤ docker stats & docker top:コンテナの健康診断
コンテナが急激に重くなったり、CPUファンが激しく回転し始めたとき、タスクマネージャーを開いても「vmmem(WSL2の全体プロセス)」しか見えず、どのコンテナが犯人なのか分からない ことがあります。
そんなときに活躍するのが docker stats と docker top です。
1. docker stats:リアルタイム負荷モニター
docker stats
実行すると、稼働中の全コンテナのパフォーマンスが1秒おきにリアルタイム更新表示されます。
- CONTAINER ID / NAME: コンテナの識別名
- CPU %: CPU使用率(マルチコア環境では100%超えも表示)
- MEM USAGE / LIMIT: 現在のメモリ使用量 / 割り当て上限(例:
85.4MiB / 7.66GiB) - MEM %: メモリ使用率
- NET I/O: ネットワーク送受信バイト数
- BLOCK I/O: ディスク読み書き量
※ 1回だけの静的スナップショットが欲しい場合は docker stats --no-stream を指定します。CI/CDや自動監視スクリプトに重宝します。
2. docker top:コンテナ内の実プロセス一覧
docker top my-web
コンテナ内部で動いているプロセスツリーをホスト側から確認できます。
ASP.NET Core アプリであれば dotnet MyApi.dll が実行されている様子や、そのプロセスID(PID)、親プロセスID(PPID)が確認できます。
【Day 02】で学んだ「コンテナは独立したVMではなく、ホストOSカーネル上の隔離されたプロセスである」という事実を実感できる瞬間です。
⑥ C# / ASP.NET Core 現場実践:ILogger と標準出力のベストプラクティス
C#エンジニアがコンテナ化を進める際、最もよくぶつかる設計の疑問が「log4net や NLog でログファイルを出力していたのを、コンテナではどう変えればよいのか?」という点です。
コンテナ内にログファイルを保存してはいけない3大理由
- ディスク枯渇の危機: コンテナ内の書き込み可能レイヤーに数ギガのログが溜まると、Dockerの仮想ディスク(vhdx)を圧迫しDocker全体がクラッシュする。
- コンテナ再起動でログが消滅する: コンテナがクラッシュして再起動(または
docker rm)されると、内部ファイルはすべて消え去るため、肝心のクラッシュ原因のログが読めない。 - ログ収集の分断: 複数台にスケールアウトした際、各コンテナにログインしてログファイルを回収するのは不可能。
ASP.NET Core の標準ロガー(Console)をそのまま使う
.NET 6 / 8 の ASP.NET Core では、標準で Console ロガープロバイダーが組み込まれています。
Program.cs や DI(依存性の注入)で ILogger<T> を使って出力されたログは、自動的にコンテナの標準出力(stdout)へ送られます。
// ASP.NET Core Minimal API でのロギング例
app.MapGet("/api/order/{id}", (int id, ILogger logger) =>
{
logger.LogInformation("注文ID {OrderId} の処理を開始しました", id);
try
{
// 業務ロジック...
return Results.Ok(new { Status = "Success", OrderId = id });
}
catch (Exception ex)
{
logger.LogError(ex, "注文ID {OrderId} の処理中に予期せぬエラーが発生しました", id);
return Results.Problem("処理エラーが発生しました");
}
});
このようにC#コード側は「単に ILogger を呼ぶだけ」で完結します。
出力されたログは Docker 経由で docker logs -f で追跡でき、本番環境(AWS ECS / Azure Container Apps / Kubernetes)ではログ収集エージェントが標準出力を集約して CloudWatch や Azure Monitor、Datadog へ自動転送してくれます。
⑦ ハンズオン実習:Nginx & .NET アプリでの実践デバッグ手順
それでは、実際にターミナル(PowerShell または WSL2 Ubuntu)を開いて、本日の診断コマンドを一通り実践してみましょう!
# 1. テスト用Webコンテナをバックグラウンド(-d)で起動
docker run -d -p 8080:80 --name debug-nginx nginx:alpine
# 2. 直近の起動ログを確認
docker logs debug-nginx
# 3. リアルタイムストリーミング監視を開始(別ターミナルまたはバックグラウンド)
docker logs -f debug-nginx
# 4. (別のターミナルから)リクエストを送り、ログがリアルタイムに流れるのを目撃!
curl http://localhost:8080/
# 5. コンテナの詳細カルテ(IPアドレス等)を inspect で確認
docker inspect debug-nginx
docker inspect -f '{range .NetworkSettings.Networks}{.IPAddress}{end}' debug-nginx
# 6. コンテナのリソース使用率(CPU・メモリ)を stats で確認(確認したら Ctrl+C)
docker stats debug-nginx
# 7. コンテナ内の実行プロセス一覧を top で確認
docker top debug-nginx
# 8. 実習完了!コンテナを停止して綺麗にお掃除
docker stop debug-nginx
docker rm debug-nginx
⑧ ベテランが陥りやすい落とし穴・現場の知恵袋
⚠️ ログ&デバッグの3大現場トラブルと回避策
罠① docker logs が肥大化してホストPCのCドライブを食い尽くす
Dockerのデフォルト設定(json-file)では、コンテナを破棄しない限りログファイルが無制限にディスクに蓄積されます。
対策として、コンテナ起動時に --log-opt max-size=10m --log-opt max-file=3 を付与するか、Dockerデーモンの設定(daemon.json)でデフォルトのログローテーションを設定しましょう。
罠② 停止(Exited)したコンテナのログが見られないと思い込む
「コンテナが異常終了して停止してしまった!原因のログが見られないのでは?」
安心してください。docker rm で削除されない限り、停止したコンテナに対しても docker logs は完全に動作します。クラッシュ原因(例外スタックトレース)は停止後に落ち着いて docker logs <コンテナ名> で確認しましょう。
罠③ inspect で調べたコンテナのIPアドレスに依存した設計をしてしまう
docker inspect で表示される内部IP(例: 172.17.0.2)は、コンテナを再起動したり再作成するたびにコロコロ変わります。
コンテナ間通信でIPアドレスを固定指定するのは厳禁です。Dockerネットワークのサービス名(DNS)による名前解決や、ホストへのポートマッピングを利用しましょう(第4部で詳解します)。
- コンテナのログはファイルではなく「標準出力(stdout/stderr)」に流すのが現代の絶対基準。
docker logs -f(または--tail 100 -f)で、リアルタイムのログストリームを手元で快適に監視できる。docker inspectにより、IPアドレスや環境変数などの内部カルテを--formatでピンポイント抽出できる。docker statsでCPU・メモリのリアルタイム負荷測定、docker topで実行プロセスを確認できる。
『稼働中コンテナへの潜入操作(docker exec -it)』〜Bash/shシェルで内部デバッグ〜
コメント
コメントを投稿