Dockerコンテナ内Node.jsアプリをChromeDevToolsでリモートデバッグする方法

Dockerコンテナ内Node.jsアプリケーションをデバッグする課題
Dockerコンテナ内で実行されているNode.jsアプリケーションのデバッグは、開発環境でよく直面する課題です。コンテナ化された環境では、従来のローカル開発時のデバッグ手法がそのまま使えないケースが多いため、効率的な開発に支障をきたすことがあります。
具体的な課題として以下のようなものがあります:
- コンテナ内で発生したエラーの詳細な原因追求が難しい
- 変数の中身やコールスタックをリアルタイムで確認できない
console.log
による原始的なデバッグに頼らざるを得ない- ブレークポイントを設置して実行フローを一時停止できない
特に複雑なバックエンド処理やAPI開発では、処理の途中経過を詳細に調査する必要があるケースが多いです。この記事では、ChromeDevToolsを使用してDockerコンテナ内のNode.jsアプリケーションをリモートでデバッグする方法を紹介します。
ChromeDevToolsとNode.jsのリモートデバッグの基本
Node.jsには、ビルトインでリモートデバッグを可能にする機能があります。--inspect
または--inspect-brk
フラグを使うことで、WebSocketプロトコルを通じて外部のデバッガからアプリケーションに接続できるようになります。
主なデバッグフラグ:
--inspect
: デバッグポートを開き、アプリケーションを実行します--inspect-brk
: デバッグポートを開き、最初の行で実行を一時停止します(初回接続時に便利)--inspect=[host:port]
: 特定のホストとポートでデバッグポートを開きます
ChromeDevToolsは、この接続を使用してNode.jsアプリケーションとやり取りします。これにより以下のことが可能になります:
- ブレークポイントの設定と実行の一時停止
- 変数の値をリアルタイムで確認
- コールスタックのトレース
- メモリの使用状況の監視
- コンソールからコマンドの実行
Dockerコンテナ内でNode.jsアプリケーションをデバッグするためには、このデバッグポート(デフォルトは9229)をコンテナの外部に公開する必要があります。
// デバッグ可能なNode.jsアプリケーションの例
const express = require('express');
const app = express();
// ブレークポイントを設定できる場所
app.get('/', (req, res) => {
const message = 'Hello World'; // この変数の値を確認できます
console.log('Request received');
res.send(message);
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
このコードをデバッグするには、node --inspect=0.0.0.0:9229 index.js
のように実行します。0.0.0.0
を指定することで、あらゆるIPアドレスからの接続を許可します。これはDockerコンテナ内で実行する場合に重要な設定です。
Dockerfileとdocker-compose.ymlの設定例
Dockerコンテナ内でNode.jsアプリケーションをデバッグするためには、Dockerfileとdocker-compose.ymlファイルを適切に設定する必要があります。以下に実用的な例を示します。
Dockerfileの例:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# デバッグモードで実行するためのコマンド
# 本番環境では変更することを忘れずに
CMD ["node", "--inspect=0.0.0.0:9229", "index.js"]
# または、起動時に自動的に一時停止する場合
# CMD ["node", "--inspect-brk=0.0.0.0:9229", "index.js"]
重要なポイントは、--inspect=0.0.0.0:9229
フラグを使用していることです。0.0.0.0
は、あらゆるインターフェースからの接続を許可するために必要です。
docker-compose.ymlの例:
version: '3'
services:
app:
build: .
ports:
- "3000:3000" # アプリケーションポート
- "9229:9229" # デバッグポート
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
# 以下はnpmスクリプトでデバッグを開始する場合の例
# command: npm run debug
この設定では、2つの重要なポートマッピングがあります:
3000:3000
- アプリケーションのHTTPポート9229:9229
- Node.jsデバッグポート
package.jsonのスクリプト例:
{
"scripts": {
"start": "node index.js",
"debug": "node --inspect=0.0.0.0:9229 index.js",
"debug-brk": "node --inspect-brk=0.0.0.0:9229 index.js"
}
}
これにより、npm run debug
コマンドでデバッグ可能なモードでアプリケーションを起動できます。または、最初の行で実行を一時停止する場合はnpm run debug-brk
を使用します。
デバッグポートの公開と接続方法
デバッグポートを公開した後、ChromeDevToolsを使ってコンテナ内のNode.jsアプリケーションに接続する方法を説明します。
1. コンテナの起動
まず、設定したDockerコンテナを起動します:
# docker-compose.ymlがある場合
docker-compose up
# または個別のDockerコンテナを起動する場合
docker run -p 3000:3000 -p 9229:9229 your-node-app
コンテナが起動すると、Node.jsアプリケーションがデバッグモードで実行され、以下のようなメッセージが表示されます:
Debugger listening on ws://0.0.0.0:9229/xxxxxxxxxxxx
For help, see: https://nodejs.org/en/docs/inspector
2. Chrome DevToolsでの接続
ChromeブラウザでNode.jsアプリケーションにデバッグ接続する方法はいくつかあります:
方法1: Chrome拡張機能を使用
Node.js V8 Inspector Managerなどの拡張機能を使用すると、デバッグ可能なNode.jsプロセスにワンクリックで接続できます。
方法2: DevTools専用URL
Chromeのアドレスバーに以下のURLを入力:
chrome://inspect
「Discover network targets」をクリックし、「Configure...」ボタンからリモートターゲットを追加します:
localhost:9229
「Done」をクリックして、「Remote Target」セクションに表示されるNode.jsアプリケーションの「inspect」リンクをクリックします。
方法3: コマンドラインから直接開く
# macOSの場合
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check https://localhost:9229/json
3. 接続トラブルシューティング
接続できない場合は、以下を確認してください:
- コンテナが正常に起動しているか
- デバッグポート(9229)が正しくマッピングされているか
- ファイアウォールでポートがブロックされていないか
- Node.jsアプリケーションが
--inspect=0.0.0.0:9229
パラメータで起動されているか
以下のコマンドでポートがリッスンされているか確認できます:
# Dockerコンテナ内のプロセスを確認
docker exec -it <container_name> ps aux | grep node
# ポートが開いているか確認
docker exec -it <container_name> netstat -tulpn | grep 9229
ポートが開いているにもかかわらず接続できない場合は、ネットワーク設定を確認するか、コンテナを再起動してみてください。
ブレークポイントの設定と変数調査のテクニック
ChromeDevToolsに接続できたら、効果的にデバッグを行うための方法を見ていきましょう。
ブレークポイントの設定方法
ソースパネルでコードを特定: ChromeDevToolsの「Sources」タブで、デバッグしたいファイルを選択します。
ブレークポイントを設定: 調査したい行の行番号をクリックしてブレークポイントを設定します。青いマーカーが表示されます。
条件付きブレークポイント: 行番号を右クリックして「Add conditional breakpoint」を選択すると、特定の条件が満たされた場合にのみ実行が停止します。
// 例: userIdが特定の値の場合のみ停止 userId === '12345'
変数とスコープの調査
実行が一時停止したら、以下の方法で変数を調査できます:
Scopesパネル: 現在のスコープで利用可能な変数とその値がすべて表示されます。
Watchパネル: 特定の変数やエクスプレッションの値を継続的に観察できます。「+」ボタンをクリックして監視したい式を追加します。
// 例: 配列の長さを監視 users.length // オブジェクトの特定のプロパティを監視 request.headers.authorization
コンソールでの評価: 一時停止中にコンソールパネルで変数や式を評価できます。
// 例: 現在のスコープにあるusersオブジェクトを調査 > users > users.filter(u => u.isActive)
実行フローの制御
デバッグ中にコードの実行フローを制御するためのボタンがあります:
- Resume (F8): 次のブレークポイントまで実行を再開します
- Step Over (F10): 現在の行を実行し、次の行で停止します(関数呼び出しにはステップインしません)
- Step Into (F11): 関数呼び出しにステップインします
- Step Out (Shift+F11): 現在の関数から抜けます
- Deactivate breakpoints: 一時的にすべてのブレークポイントを無効化します
高度なテクニック
Blackboxing: Node.jsのコアモジュールや依存ライブラリをブラックボックス化して、自分のコードのみにフォーカスします。
設定方法: DevToolsの設定(F1) > Blackboxing > パターンを追加(例:
/node_modules/
)ログポイント: コードを修正せずに「console.log」を挿入したのと同じ効果が得られます。行番号を右クリックして「Add logpoint」を選択します。
// 例: リクエストの内容をログ出力 Request received: {req.url}
非同期コードのデバッグ: 「Async」チェックボックスをオンにすると、Promiseや非同期関数の実行フローを追跡できます。
DOM変更のブレークポイント: フロントエンドのデバッグで特定のDOM要素が変更されたときに一時停止する機能です。
これらのテクニックを駆使することで、複雑なコードの挙動を効率的に調査できます。特にDockerコンテナ内で実行されているコードは直接アクセスしにくいため、リモートデバッグの能力を最大限に活用することが重要です。
実践的なトラブルシューティングと解決例
最後に、Dockerコンテナ内のNode.jsアプリケーションデバッグで遭遇する可能性のある具体的な問題と、その解決方法を紹介します。
ケース1: デバッグポートに接続できない
問題: chrome://inspect
でターゲットが表示されない。
解決策:
コンテナの実行コマンドを確認:
docker ps -a
コンテナ内のNode.jsプロセスを確認:
docker exec -it <container_name> ps aux | grep node
正しいパラメータ(
--inspect=0.0.0.0:9229
)で実行されているか確認します。ポートマッピングを確認:
docker port <container_name>
9229ポートが正しくマッピングされているか確認します。
ネットワーク設定の修正:
# docker-compose.ymlの修正例 services: app: ports: - "127.0.0.1:9229:9229" # 特定のインターフェースにバインド
ケース2: TypeScriptやトランスパイルされたコードのデバッグ
問題: ブレークポイントが機能しない、またはソースマップが正しく読み込まれない。
解決策:
ソースマップを有効にする:
// tsconfig.jsonの設定 { "compilerOptions": { "sourceMap": true, "inlineSources": true } }
Node.jsでソースマップを有効にする:
node --inspect=0.0.0.0:9229 --require source-map-support/register dist/index.js
プロジェクトにソースマップサポートを追加:
npm install --save-dev source-map-support
ケース3: nodemonとデバッグの連携
問題: ホットリロード中にデバッグ接続が切断される。
解決策:
package.jsonのスクリプトを修正:
{ "scripts": { "debug": "nodemon --inspect=0.0.0.0:9229 index.js" } }
nodemonの設定ファイルを作成:
// nodemon.json { "restartable": "rs", "ignore": [".git", "node_modules/**/node_modules"], "verbose": true, "execMap": { "js": "node --inspect=0.0.0.0:9229" }, "events": { "restart": "osascript -e 'display notification \"App restarted due to changes\" with title \"nodemon\"'" }, "watch": ["src/"], "ext": "js,json" }
ケース4: メモリリークの診断
問題: コンテナがメモリを消費し続け、最終的にクラッシュする。
解決策:
Memory Profileを取得:
ChromeDevToolsの「Memory」タブで「Take heap snapshot」を使用。
コードでのヒープダンプの生成:
// index.jsに追加 const heapdump = require('heapdump'); // メモリ使用量が増加したタイミングでダンプを生成 process.on('SIGUSR2', () => { heapdump.writeSnapshot('/app/heapdump-' + Date.now() + '.heapsnapshot'); });
コマンドでヒープダンプを生成:
docker exec -it <container_name> kill -USR2 1
ヒープダンプファイルをローカルにコピー:
docker cp <container_name>:/app/heapdump-xxxx.heapsnapshot ./
ChromeDevToolsの「Memory」タブで「Load」を使って分析。
ケース5: APIリクエストのデバッグ
問題: 特定のAPIエンドポイントで問題が発生し、リクエスト内容の調査が必要。
解決策:
リクエストハンドラーにブレークポイントを設定:
app.post('/api/users', (req, res) => { // ここにブレークポイントを設定 const userData = req.body; // ...処理... });
Network条件付きブレークポイントの活用:
DevToolsの「Sources」タブで、「XHR/fetch breakpoints」にURLパターンを追加します。
リクエストモックツールの活用:
Postmanなどでコンテナに直接リクエストを送信し、デバッグブレークポイントをトリガーします。
これらの実践的なトラブルシューティング例を参考に、Dockerコンテナ内のNode.jsアプリケーションを効率的にデバッグしてください。適切なデバッグ環境を整えることで、開発効率が大幅に向上し、より堅牢なアプリケーションの開発が可能になります。
このトピックはこちらの書籍で勉強するのがおすすめ!
この記事の内容をさらに深く理解したい方におすすめの一冊です。実践的な知識を身につけたい方は、ぜひチェックしてみてください!
おすすめコンテンツ
おすすめDocker2025/5/20Dockerコンテナ内Node.jsアプリのソースマップデバッグが効かない問題の解決法
Dockerコンテナ内でTypeScriptやBabelでトランスパイルされたNode.jsアプリケーションをデバッグする際、ソースマップが正しく機能せず元のコードでデバッグできない問題の具体的な解決...
続きを読む Docker2025/5/20Dockerコンテナ内Node.jsアプリの環境変数トラブル解決法
Dockerコンテナ内でNode.jsアプリケーションを実行すると、環境変数が正しく読み込まれない問題に遭遇することがあります。この記事では、具体的な原因と解決策を実用的なコード例で解説します。
続きを読む Docker2025/5/20Dockerコンテナ内TypeScriptプロジェクトのデバッグ技法
Dockerコンテナ内でTypeScriptプロジェクトを効率的にデバッグする方法を解説します。VSCodeの設定からコンテナ内部のツールを活用したトラブルシューティングまで、具体的なコード例と共に詳...
続きを読む Docker2025/5/20Docker環境でNode.jsのホットリロードが効かない問題の解決法
Docker環境でNode.jsアプリケーションを開発中にホットリロードが効かない問題に悩んでいませんか?この記事では、この特定の問題を解決するための具体的な対処法をシンプルに解説します。
続きを読む JavaScript2025/5/5Node.jsとWebSocketで作る!初心者でも実装できるリアルタイムWebアプリケーション開発チュートリアル
'Webの世界は常に進化しています。かつては「リクエストを送信して応答を待つ」という単方向の通信が一般的でしたが、現代のユーザーはよりダイナミックな体験を求めています。リアルタイムWebアプリケーショ...
続きを読む Node.js2025/5/19Node.jsのStreamで大きなファイルを効率的に処理する方法
メモリ不足エラーに悩まされていませんか?Node.jsのStream APIを使って大きなファイルを少ないメモリで処理する方法を具体的なコード例で解説します。
続きを読む Node.js2025/5/20Node.jsアプリケーションのCORSエラー解決法:5分で実装できる完全ガイド
フロントエンドとバックエンドの連携で頻繁に遭遇するCORSエラーの原因と解決策を具体的なコード例とともに解説します。Node.js環境でのCORSポリシーの正しい設定方法から、開発環境と本番環境での違...
続きを読む Docker2025/5/20Docker環境でNodeモジュールが同期されない問題の解決法
Docker開発環境でのNode.jsプロジェクトでnode_modulesが正しく同期されない問題に悩んでいませんか?このよくある問題の具体的な解決策と実践的なコード例を紹介します。
続きを読む