言語を切り替える
テーマを切り替える

Docker コンテナデバッグガイド:exec で内部に入って問題を特定する正しい方法

テスト環境の API が突然 502 を返しました。docker ps を実行すると、コンテナのステータスは「Up 2 hours」と表示され、正常に動いているように見えます。ログを見ても、「Connection refused」という冷たい一行だけ。

こういうとき、一番イライラします——コンテナは動いているのに、中で何が起きているのか分からない。設定ファイルは合っているか? プロセスは本当に起動しているか? ポートはリッスンしているか? これらを確認するには、コンテナ内部に「入る」必要があります。まるでブラックボックスの中身を覗くようなものです。

正直、Docker を始めたばかりの頃は、コンテナへの入り方も分かりませんでした。ネットで調べると docker exec を勧める記事もあれば docker attach を勧める記事もあり、再起動を勧める記事までありました。いくつもつまずいてから、コンテナデバッグには正しい手順があると理解しました。

この記事では、docker exec でコンテナに正しく入り、問題を切り分ける方法を解説します。exec と attach の本質的な違い、コンテナ内でツールが不足しているときの対処法、実践的なデバッグテクニックまでカバーします。これらを押さえれば、コンテナのトラブル時に「とりあえず再起動」以外の手が使えるようになります。

docker exec 基礎 — コンテナに入る正しい方法

最もシンプルな入り方

稼働中のコンテナに入るとき、最もよく使うコマンドはこれです:

docker exec -it my-nginx bash

3 つのポイントがあります:

  • -it:2 つのオプションの短縮形。-i は標準入力を開いたまま維持、-t は端末を割り当てます。コンテナと「対話」できる状態になります
  • my-nginx:コンテナ名。コンテナ ID でも OK(例:docker exec -it abc123def456 bash
  • bash:コンテナ内で実行するコマンド。ここでは bash シェルを起動

このコマンドを実行すると、プロンプトが root@abc123def456:/# のように変わり、コンテナ内部に入れたことが分かります。あとは通常の Linux サーバーと同じようにコマンドを実行できます。

bash がない場合は?

次のようなエラーが出ることがあります:

$ docker exec -it my-alpine bash
OCI runtime exec failed: exec failed: container_linux.go:380:
starting container process caused: exec: "bash": executable file not found

慌てなくて大丈夫です。Alpine Linux のような超軽量イメージでは、デフォルトで sh だけで bash が入っていないことが多いです。コマンドを変えれば OK:

docker exec -it my-alpine sh

経験上、まず bash を試して、ダメなら sh。これで 90% は解決します。

コンテナ ID を使うと柔軟

コンテナ名を調べるのが面倒なときは、ID の先頭数文字だけで入れます:

# コンテナ ID を確認
$ docker ps
CONTAINER ID   IMAGE    COMMAND                  CREATED
abc123def456   nginx    "/docker-entrypoint.…"   2 hours ago

# ID プレフィックスで入る(3〜4 文字で十分)
$ docker exec -it abc1 bash

Docker は ID プレフィックスを自動マッチします。重複しなければ問題ありません。コンテナが多い環境では特に便利です。

コンテナから退出する正しい方法

作業が終わったら、exit を入力するか Ctrl+D を押します:

root@abc123def456:/# exit
exit
$

重要なのは、exec で入ったコンテナは、退出しても停止しないことです。次のセクションで、その理由を説明します。

exec vs attach — もう間違えない

本質的な違い

多くのチュートリアルが docker execdocker attach の両方に触れますが、本質的な違いを説明しているものは少ないです。私も attach を誤って使い、コンテナが謎の停止を起こしたことがあります。

シンプルに言うと:

  • docker exec:コンテナ内で新しいプロセスを起動する。新しいウィンドウを開くイメージ
  • docker attach:コンテナの**メインプロセス(PID 1)**に接続する。既存の画面に投影するイメージ

抽象的に感じますか? 具体例を見てみましょう。

docker attach my-nginx で Nginx コンテナに接続し、Ctrl+Cexit で退出すると、コンテナのメインプロセス(Nginx)に終了シグナルが送られ、コンテナ全体が停止します。本番環境でこれをやると大事故です。

一方、docker exec -it my-nginx bash なら独立した bash プロセスを起動するだけです。この bash を終了しても Nginx のメインプロセスには影響せず、コンテナは正常に稼働し続けます。

exec と attach、いつ使い分ける?

私のおすすめはシンプルです:99% のケースでは exec で十分

attach が役立つのは、メインプロセスと直接対話する必要があるときだけです。例えば:

  • コンテナ内で対話型プログラム(Python REPL など)が動いている
  • メインプロセスのリアルタイム出力を見たい
  • 複数端末で同じ内容を「同期表示」したい(画面共有のような用途)

ただ、こうしたシーンは稀です。大抵はファイル確認、設定変更、コマンド実行が目的で、exec の方が安全で便利です。

比較表で覚える

特性docker execdocker attach
新プロセス起動✓ はい✗ いいえ
exit 後にコンテナ停止✗ いいえ✓ はい(危険!)
任意コマンド実行✓ はい✗ いいえ
複数端末が独立✓ はい✗ いいえ(同一 tty を共有)
デバッグ推奨度⭐⭐⭐⭐⭐

ここまで読めば、なぜ exec を強調しているか分かるはずです。attach はコンテナ出力の確認向けに設計されており、日常のデバッグ用途ではありません。

コンテナ内でツールが不足している場合の対処

なぜコンテナにはコマンドがほとんどないのか

ようやくコンテナに入れた。vim で設定ファイルを編集しようとすると:

root@abc123:/# vim /etc/nginx/nginx.conf
bash: vim: command not found

curl で API をテストしようとしても:

root@abc123:/# curl localhost:8080
bash: curl: command not found

ping すらありません。初めて遭遇したときは、当惑しました——これではデバッグできないのでは?

これは Docker イメージの設計思想です:必要最小限だけ入れ、それ以外は入れない。フル Ubuntu イメージは数百 MB ですが、Alpine は 5 MB 程度。vim、curl、ping といった「当たり前に入っているはず」のツールを削ることで、ここまで小さくなっています。

一時的にツールをインストールする

必要なツールをその場で入れる方法です。ディストリビューションに応じてパッケージマネージャーが異なります。

Debian/Ubuntu 系(apt/apt-get):

# パッケージリストを更新
apt-get update

# 常用ツールをインストール
apt-get install -y vim curl wget net-tools

# ネットワーク診断ツールが必要な場合
apt-get install -y iputils-ping dnsutils

CentOS/RedHat 系(yum):

yum install -y vim curl wget

Alpine 系(apk):

apk update
apk add vim curl bash

コンテナの OS を調べる方法

OS が分からないときは、次の 2 つが簡単です:

# 方法1:ディストリビューション情報を確認
cat /etc/os-release

# 方法2:パッケージマネージャーの有無を確認
which apt-get   # あれば Debian/Ubuntu
which yum      # あれば CentOS/RedHat
which apk      # あれば Alpine

私はまず apt-get update を試し、エラーが出たら別の方法に切り替えます。コンテナが壊れることはありません。

これは安全か?

一時インストールには注意点があります。

開発環境:自由に入れて問題ありません。テスト用コンテナは再起動でリセットされ、インストールしたものも消えます。

本番環境:緊急の切り分け時だけ使いましょう。問題解決後は、必要なツールを Dockerfile に書いてイメージを再ビルドしてください。

理由は 2 つ:

  1. セキュリティ:一時インストールしたパッケージに脆弱性がある可能性
  2. 再現性:コンテナ再起動でツールが消え、次回また入れ直しが必要

長期的な対策:Dockerfile で事前インストール

よく使うデバッグツールがあるなら、ビルド時に入れておくのがベストです:

FROM nginx:latest

# 常用デバッグツールをインストール
RUN apt-get update && apt-get install -y \
    vim \
    curl \
    wget \
    net-tools \
    iputils-ping \
 && rm -rf /var/lib/apt/lists/*  # キャッシュ削除でイメージサイズを削減

# その他の設定...

最後の rm -rf /var/lib/apt/lists/* は良い習慣です。イメージをかなり小さくできます。

実用的な小技

設定ファイルの内容を確認するだけなら、vim は不要です。catless はほぼ全コンテナに入っています:

# ファイル全体を表示
cat /etc/nginx/nginx.conf

# ページ送り表示(長いファイル向け)
less /etc/nginx/nginx.conf  # q で終了

# 先頭数行だけ表示
head -n 20 /etc/nginx/nginx.conf

編集が必要で vim がない場合、sed で直接置換できます。直感的ではありませんが、緊急時には有効です:

# listen 80 を listen 8080 に変更
sed -i 's/listen 80/listen 8080/g' /etc/nginx/nginx.conf

特定ユーザーとしてコンテナに入る

なぜユーザーを指定する必要があるのか

コンテナに入ったあと、こういう状況に遭遇することがあります:

root@abc123:/app# cat /var/log/app.log
cat: /var/log/app.log: Permission denied

ファイル権限を変更しようとしても:

root@abc123:/app# chmod 644 config.yaml
chmod: changing permissions of 'config.yaml': Operation not permitted

プロンプトは root なのに権限がない? これはコンテナが非 root ユーザーで実行されているためです(本番環境では推奨される設定)。exec のデフォルトユーザーはコンテナの実行ユーザー設定を引き継ぎます。

root として入る

この場合、root として明示的に入る必要があります:

docker exec -it --user root my-app bash

短縮形:

docker exec -it -u root my-app bash

これで本当の root 権限が得られ、任意のファイルの閲覧・設定変更が可能になります。

特定 UID として入る

特定のユーザー ID で入る必要がある場合もあります。例えばアプリユーザーが UID 1000 のとき:

# UID 1000 として入る
docker exec -it --user 1000 my-app bash

# ユーザー名指定(コンテナ内にユーザーが存在する場合)
docker exec -it --user appuser my-app bash

# ユーザーとグループを指定(形式:ユーザー:グループ)
docker exec -it --user 1000:1000 my-app bash

権限問題のデバッグに特に有用です。アプリが特定ディレクトリに書き込めない疑いがあるなら、アプリユーザーとして入って試します:

# アプリユーザーとして入る
docker exec -it --user appuser my-app bash

# データディレクトリにファイルを作成できるか試す
appuser@abc123:/app$ touch /data/test.txt
touch: cannot touch '/data/test.txt': Permission denied

# 原因特定——権限問題が確認できた

root 権限が必要なシーン

経験上、次のケースでは root が必要になることが多いです:

  1. システム設定の変更/etc/ 配下の各種設定ファイル
  2. パッケージのインストール:apt-get、yum などは root が必要
  3. システムログの閲覧/var/log/ 配下の多くは一般ユーザーでは読めない
  4. ファイル権限の調整:chmod、chown などの操作
  5. ネットワーク問題のデバッグ:tcpdump、netstat などは root が必要なことが多い

ただし、root は必要なときだけ。特に本番環境では、root で変更した内容は必ず記録し、セキュリティリスクを残さないようにしてください。

セキュリティ上の注意

root でコンテナに入れるとはいえ、以下に注意:

テスト環境:自由に使って問題ありません。コンテナ再起動でリセットされます。

本番環境

  • 中身を確認する → OK
  • 設定を一時変更して救急 → ギリ OK。ただし変更内容を必ず記録
  • コンテナ内でコードをコンパイルしたりソフトをインストール → NG。こうした変更は Dockerfile に書くべき

なぜか? コンテナは「不変インフラストラクチャ」という思想で設計されています。稼働中のコンテナで変更した内容は、再起動ですべて消えます。本当の変更は Dockerfile に反映し、再現可能にする必要があります。

さらに、コンテナ内の root とホストの root が、設定によっては同一 UID 0 を共有する場合があります。名前空間で隔離されていても、設定ミスがあるとコンテナ内 root がホストに影響を与える可能性があります。本番環境で非 root ユーザー実行が推奨される理由の一つです。

実践テクニックとよくあるシーン

対話型シェルに入らず単一コマンドを実行

コンテナ内に留まる必要がなく、結果だけ確認したいときは -it を付けません:

# ディレクトリ内容を確認
docker exec my-nginx ls -la /etc/nginx/

# 設定ファイルを表示
docker exec my-nginx cat /etc/nginx/nginx.conf

# プロセスを確認
docker exec my-nginx ps aux

# ポートリッスン状況を確認
docker exec my-nginx netstat -tlnp

# ネットワーク疎通をテスト
docker exec my-nginx curl -I localhost:80

スクリプトやクイックチェックに最適です。アプリの正常応答確認によく使います:

# ヘルスチェックスクリプト
if docker exec my-app curl -f http://localhost:8080/health; then
  echo "App is healthy"
else
  echo "App is down!"
fi

コンテナデバッグの標準フロー

コンテナ問題に遭遇したら、だいたいこの順序で切り分けます:

1. まずコンテナ状態を確認

docker ps -a  # コンテナが稼働中か確認

2. ログで手がかりを探す

docker logs my-app --tail 100  # 直近 100 行
docker logs my-app -f          # リアルタイム追跡(tail -f 相当)

3. コンテナ内でプロセスを確認

docker exec my-app ps aux

起動すべきプロセスが動いているか確認。Nginx コンテナなら nginx master と worker プロセスが見えるはずです。

4. ポートリッスンを確認

docker exec my-app netstat -tlnp
# netstat がない場合
docker exec my-app ss -tlnp

アプリがリッスンしているポートが正しいか確認します。

5. サービスの可用性をテスト

# コンテナ内部からテスト
docker exec my-app curl localhost:8080

# curl がない場合、telnet でポート疎通を確認
docker exec my-app telnet localhost 8080

6. 設定ファイルを確認

docker exec my-app cat /etc/nginx/nginx.conf
docker exec my-app cat /app/config.yaml

設定が期待どおりか確認します。

7. ディスク容量を確認

docker exec my-app df -h

コンテナ内のディスクが満杯で、ファイル書き込みに失敗しているケースもあります。

便利なデバッグコマンドの組み合わせ

環境変数を確認:

docker exec my-app env | grep DATABASE

DB 接続設定が正しいか確認できます。

特定ファイルを検索:

docker exec my-app find /app -name "*.log"

ファイル権限を確認:

docker exec my-app ls -la /app/

権限問題の切り分けに有用です。

コンテナリソースをリアルタイム監視:

docker stats my-app

exec は不要で、ホスト上で直接実行。CPU、メモリ、ネットワーク、I/O の使用状況をリアルタイムで確認できます。

複数コンテナの一括操作

複数コンテナをチェックする場合、シェルスクリプトと組み合わせます:

# 稼働中の全コンテナのメモリ使用を確認
for container in $(docker ps -q); do
  echo "Container: $container"
  docker exec $container free -h
  echo "---"
done

ネットワーク問題のデバッグ

コンテナ間の疎通確認:

# コンテナ A からコンテナ B へ ping
docker exec containerA ping containerB

# 外部ネットワークへのアクセスをテスト
docker exec my-app ping -c 3 google.com

# DNS 解決を確認
docker exec my-app nslookup google.com

コンテナ IP を確認:

docker inspect my-app | grep IPAddress
# またはコンテナ内で確認
docker exec my-app ip addr show

コンテナが再起動を繰り返す場合

起動直後に終了して、exec する間もないことがあります。この場合:

方法1:起動コマンドを上書き

# 元の CMD を実行せず、シェルで待機させる
docker run -it --name debug-app my-app-image sh

コンテナはシェルで停止し、元の起動スクリプトは実行されません。問題調査の時間が確保できます。

方法2:停止したコンテナを確認

# 停止したコンテナを起動
docker start my-app

# すぐにログを確認
docker logs my-app

# まだ終了していなければ、急いで exec
docker exec -it my-app bash

このセクションのテクニックは、実戦で少しずつ蓄積したものです。Docker コンテナのデバッグは最初は戸惑いますが、これらのコマンドに慣れれば、切り分けはかなり速くなります。

まとめ

長くなりましたが、Docker コンテナデバッグの核心は次のとおりです:

docker exec でコンテナに入るのが最も安全な方法です。退出してもコンテナは停止しません。覚えておく万能コマンド:docker exec -it コンテナ名 bash。bash がなければ sh を試してください。

exec と attach を混同しない。attach はメインプロセスに接続するため、exit でコンテナが停止します。自分が何をしているか明確でない限り、exec を使いましょう。

ツール不足は慌てない。一時的にインストールすれば OK(apt-get/yum/apk)。ただし救急用であり、長期的には Dockerfile に書くべきです。

root 権限が必要なら --user root を追加。本番環境では慎重に使い、変更内容を記録して、できるだけ早くイメージに反映しましょう。

デバッグには順序がある:まずログ、次にプロセス、設定を確認、最後にネットワーク。この順序で 90% 以上の問題を解決できます。

次にコンテナで問題が起きたら、いきなり再起動しないでください。中を覗けば、設定ミス、権限問題、ポート競合といった単純な原因が多いです。exec を使いこなせば、コンテナデバッグはそれほど難しくありません。

最後に、問題発生時のチェックリストです:

コンテナデバッグチェックリスト:

  • コンテナは稼働中か?(docker ps)
  • ログにエラーはあるか?(docker logs)
  • プロセスは起動しているか?(docker exec ps aux)
  • ポートリッスンは正常か?(docker exec netstat -tlnp)
  • 設定ファイルは正しいか?(docker exec cat config)
  • ディスク容量は十分か?(docker exec df -h)
  • ネットワークは通るか?(docker exec curl/ping)

これらを順に確認すれば、だいたい問題の所在が特定できます。

Docker コンテナデバッグ完全フロー

exec コマンドでコンテナに入り問題を切り分ける完全手順。コマンド解説、ツールインストール、権限管理、体系的デバッグ方法を含む

⏱️ 目安時間: 30 分

  1. 1

    ステップ1: コンテナに入る:exec と attach の違いを理解する

    exec vs attach の本質的な違い:exec は新プロセスを作成してコンテナに入る(推奨・メインプロセスに影響なし)、attach はメインプロセスの stdin/stdout に接続する(非推奨・終了でコンテナ停止)。

    基本コマンド:
    • docker exec -it container-name /bin/bash(bash に入る)
    • docker exec -it container-name sh(sh に入る・Alpine でよく使う)
    • docker exec container-name command(対話なしで単一コマンド実行)

    パラメータ説明:
    • -i:STDIN を開いたまま維持(対話型)
    • -t:疑似端末を割り当て(整形された出力)
    • 両方を組み合わせると効果的

    適用シーン:exec はデバッグ、ツールインストール、設定変更に適し、attach はリアルタイムログ出力の確認向け
  2. 2

    ステップ2: ツール不足と権限問題の解決

    ツールのインストール方法:
    • Debian/Ubuntu:apt-get update && apt-get install -y tool-name
    • Alpine:apk add --no-cache tool-name
    • CentOS/RHEL:yum install -y tool-name

    読み取り専用ファイルシステムの場合、先に以下を実行:
    docker exec -u root container-name sh -c 'mount -o remount,rw /'

    ユーザー権限の指定:
    • -u root で root 権限取得:docker exec -u root container-name
    • --user uid:gid で特定ユーザーを指定
    • 現在のユーザー確認:whoami
    • ファイル権限確認:ls -la
    • 権限変更:chmod 755 file、chown user:group file

    注意:本番環境では root 権限を慎重に使い、変更内容を記録して Dockerfile に反映。コンテナ再起動で変更は失われる
  3. 3

    ステップ3: 体系的デバッグチェックフロー

    デバッグチェックリスト(順番に実行):
    1) ログ確認:docker logs container-name、またはコンテナ内で /var/log を確認
    2) プロセス状態:ps aux | grep process-name で重要プロセスの稼働を確認
    3) ポートリッスン:netstat -tuln | grep port、または ss -tuln
    4) 設定ファイル:cat /path/to/config で設定の正しさを確認
    5) ディスク容量:df -h で十分な空きがあるか確認
    6) ネットワーク疎通:curl http://localhost:port、ping hostname

    デバッグフロー:
    まずログでエラーを特定 → プロセスでサービス稼働を確認 → 設定で設定ミスを除外 → 最後にネットワークで疎通を確認

    この順序で切り分ければ、90% 以上のコンテナ問題を体系的に解決できる

FAQ

なぜ attach ではなく exec を使うべきなのか?
exec と attach の核心はプロセスの扱い方の違い:

• exec:新プロセスを作成してコンテナに入る。メインプロセスに影響せず、終了してもコンテナは稼働を続ける
• attach:メインプロセスの stdin/stdout に接続する。終了するとコンテナが停止する

そのため exec はデバッグに適し、安全にコンテナ内部を調査できる。attach は主にリアルタイムログ出力の確認向け
コンテナ内に bash や sh がない場合は?
bash や sh がない場合、以下を試してください:

• 別のシェルを使う:docker exec -it container-name /bin/ash(Alpine でよく使う)
• コマンドを直接実行:docker exec container-name command(対話型シェル不要)
• 利用可能なシェルを確認:docker exec container-name ls /bin/
• busybox を使う:一部の最小イメージでは docker exec -it container-name busybox sh を試す

対話型デバッグが必要なら、Dockerfile で bash や sh を事前にインストールすることを推奨
読み取り専用ファイルシステムのコンテナでツールをインストールするには?
読み取り専用ファイルシステムのコンテナは、先に書き込み可能に再マウントする必要がある:

1. ルートを書き込み可能に再マウント:
docker exec -u root container-name sh -c 'mount -o remount,rw /'

2. 通常どおりツールをインストール:
docker exec -u root container-name apt-get update
docker exec -u root container-name apt-get install -y tool-name

注意:コンテナ再起動で変更は失われる。ツールのインストール手順を Dockerfile に追加するか、マルチステージビルドで常用ツールを事前インストールすることを推奨
コンテナ内から外部ネットワークにアクセスできない場合は?
コンテナネットワーク問題の切り分け手順:

1. ネットワークモードを確認:
docker inspect container-name | grep NetworkMode

2. DNS 解決をテスト:
docker exec container-name nslookup google.com

3. ネットワーク疎通をテスト:
docker exec container-name ping -c 3 8.8.8.8

4. ファイアウォールルールを確認:
docker exec container-name iptables -L

5. カスタムネットワーク使用時は設定を確認:
docker network inspect network-name

よくある原因:DNS 設定ミス、ファイアウォール制限、ネットワークモードの設定問題
exec でコンテナに入った後、コンテナを止めずに退出するには?
exec でコンテナに入った後、安全に退出する方法:

• exit を入力、または Ctrl+D:正常退出。コンテナに影響なし
• Ctrl+P の後 Ctrl+Q:デタッチモードで退出。コンテナは稼働を続ける
• ターミナルを直接閉じる:-it 使用時はウィンドウを閉じるだけで OK

注意:docker attach で入った後に Ctrl+C を押すと、メインプロセスが停止する。exec で入ったコンテナは、退出してもメインプロセスの稼働に影響しない

5分で読めます · 公開日: 2025年12月18日 · 更新日: 2026年6月8日

関連記事

コメント

GitHubアカウントでログインしてコメントできます