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 exec と docker attach の両方に触れますが、本質的な違いを説明しているものは少ないです。私も attach を誤って使い、コンテナが謎の停止を起こしたことがあります。
シンプルに言うと:
- docker exec:コンテナ内で新しいプロセスを起動する。新しいウィンドウを開くイメージ
- docker attach:コンテナの**メインプロセス(PID 1)**に接続する。既存の画面に投影するイメージ
抽象的に感じますか? 具体例を見てみましょう。
docker attach my-nginx で Nginx コンテナに接続し、Ctrl+C や exit で退出すると、コンテナのメインプロセス(Nginx)に終了シグナルが送られ、コンテナ全体が停止します。本番環境でこれをやると大事故です。
一方、docker exec -it my-nginx bash なら独立した bash プロセスを起動するだけです。この bash を終了しても Nginx のメインプロセスには影響せず、コンテナは正常に稼働し続けます。
exec と attach、いつ使い分ける?
私のおすすめはシンプルです:99% のケースでは exec で十分。
attach が役立つのは、メインプロセスと直接対話する必要があるときだけです。例えば:
- コンテナ内で対話型プログラム(Python REPL など)が動いている
- メインプロセスのリアルタイム出力を見たい
- 複数端末で同じ内容を「同期表示」したい(画面共有のような用途)
ただ、こうしたシーンは稀です。大抵はファイル確認、設定変更、コマンド実行が目的で、exec の方が安全で便利です。
比較表で覚える
| 特性 | docker exec | docker 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 つ:
- セキュリティ:一時インストールしたパッケージに脆弱性がある可能性
- 再現性:コンテナ再起動でツールが消え、次回また入れ直しが必要
長期的な対策: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 は不要です。cat や less はほぼ全コンテナに入っています:
# ファイル全体を表示
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 が必要になることが多いです:
- システム設定の変更:
/etc/配下の各種設定ファイル - パッケージのインストール:apt-get、yum などは root が必要
- システムログの閲覧:
/var/log/配下の多くは一般ユーザーでは読めない - ファイル権限の調整:chmod、chown などの操作
- ネットワーク問題のデバッグ: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: コンテナに入る: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: ツール不足と権限問題の解決
ツールのインストール方法:
• 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: 体系的デバッグチェックフロー
デバッグチェックリスト(順番に実行):
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:メインプロセスの stdin/stdout に接続する。終了するとコンテナが停止する
そのため exec はデバッグに適し、安全にコンテナ内部を調査できる。attach は主にリアルタイムログ出力の確認向け
コンテナ内に 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 でコンテナに入った後、コンテナを止めずに退出するには?
• exit を入力、または Ctrl+D:正常退出。コンテナに影響なし
• Ctrl+P の後 Ctrl+Q:デタッチモードで退出。コンテナは稼働を続ける
• ターミナルを直接閉じる:-it 使用時はウィンドウを閉じるだけで OK
注意:docker attach で入った後に Ctrl+C を押すと、メインプロセスが停止する。exec で入ったコンテナは、退出してもメインプロセスの稼働に影響しない
5分で読めます · 公開日: 2025年12月18日 · 更新日: 2026年6月8日
Docker 実践ガイド
検索からこのページに来た場合は、前後の記事もあわせて読むと同じテーマの理解がかなり早く深まります。
前の記事
Dockerログ削除の完全ガイド:json.log でディスクがあふれない 5 つの方法
Docker のログが増え続けてディスクが満杯に?json.log の安全な削除、ログローテーションの設定、ログドライバーの選び方まで、Docker ログでディスクが破綻する問題を根本から解決する方法を解説します。
第 34 / 37 記事
次の記事
Docker コンテナが起動直後に終了する?完全トラブルシュート(Exit Code 137/1 対応)
Docker コンテナが起動直後に Exited になるときの体系的な調査法。Exit Code 137/1 の意味、4 ステップ調査、5 つの典型失敗パターンと対処を解説し、起動問題を素早く特定・修復できます。
第 36 / 37 記事
関連記事
Dockerfile入門:ゼロから最初の Docker イメージを作る(実例付き)
Dockerfile入門:ゼロから最初の Docker イメージを作る(実例付き)
Docker vs 仮想マシン:5分で理解する性能差とシーン別選び方ガイド
Docker vs 仮想マシン:5分で理解する性能差とシーン別選び方ガイド
Docker インストールの落とし穴ガイド 2025:permission denied から正常起動までの完全解決策
コメント
GitHubアカウントでログインしてコメントできます