コンテナ内の Python WebアプリをVSCodeでデバッグする

Docker コンテナで動かしている Python の Webアプリを、Windows の VSCode でデバッグする方法を紹介します。


VSCode でデバッグする際の基本的な解説は[こちら](https://qiita.com/bananuts115/items/3e095be281a8b3074deb)。


## コンテナ内アプリのリモートデバッグ
VSCode で Python をデバッグする場合、一般的に「Python Debugger」拡張機能を使用します。この拡張機能にはリモートコンピュータで動作している Python Webアプリケーションをローカルコンピュータからデバッグする機能が備わっています。コンテナもリモートコンピュータとみなして同様にデバッグすることができます。リモートデバッグを行うにはあらかじめリモート環境にいくつか設定が必要となります。

### リモート環境に必要となる設定
- debugpyパッケージのインストール
  ローカルのVSCodeとリモートコンピュータの間でデバッグを行うときは、このパッケージが両者の橋渡し役となり、デバッグのやりとりを可能にしています。
- debugpyを使用してWebアプリを起動する
  VSCodeからデバッグ接続を行うには、あらかじめWebアプリケーションをdebugpyを使って起動しておく必要があります。  
- デバッグ用ポートを公開する
  VSCodeからリモートのプログラムをデバッグするには、リモート側でデバッグ用のポートを開いておき、VSCodeがそのポートにアクセスできるようにしておきます。



## リモート環境の設定方法
リモート環境の設定を変更したい場合は Dockerfile を書き換えてから、新しくコンテナイメージを作り直すのが一番シンプルな方法です。新しいイメージを作り直すことで、変更が反映された環境を簡単に用意できます。

### Dockerfile の編集
Django フレームワークを使ったWebアプリを例に説明します。
プロジェクトのフォルダ構成は以下とします。


```
PythonProject1\
├ app1\
│  │︙
├ mysite\
│  │︙
├ Dockerfile
├ manage.py
└ requirements.txt
```


Dockerfile にリモートデバッグ用の設定を加えて変更します。


``` diff_Docker:DockerFile
FROM python:3.13-slim

RUN pip install --upgrade pip

RUN mkdir /app
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Django project to the container
COPY ./app1/ ./app1/
COPY ./mysite/ ./mysite/
COPY manage.py .

# Expose the Django port
EXPOSE 8020

# Run Django’s development server
- CMD ["python", "manage.py", "runserver", "0.0.0.0:8020"]
+ CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "manage.py", "runserver", "0.0.0.0:8020"]

+ RUN pip install debugpy
+ EXPOSE 5678
```


- `RUN pip install debugpy`で debugpy パッケージをインストールしています。
- `CMD`の定義を変更して、debugpy を通してDjangoアプリを起動し、外部のエディタからデバッグできるようにしています。
`"python", "-m", "debugpy", "--listen", "0.0.0.0:5678"`の部分で debugpy を起動し、外部からのデバッグ接続を 5678 ポートで待ち受けるようにします。これに続けて`"manage.py", "runserver", "0.0.0.0:8020"`とすることで debugpy から Webサーバーを起動するようにします。
- `EXPOSE 5678`でデバッグ接続に使用する 5678 ポートをコンテナの外部に公開しています。


### イメージビルド・コンテナ作成
Dockerfileを編集したらイメージをビルドしコンテナを作成します。


``` PowerShell:PowerShell
# プロジェクトフォルダへ移動
cd C:\Projects\PythonProject1
# イメージビルド
docker build --pull --rm -f 'Dockerfile' -t 'pythonproject1:latest' '.' 
# コンテナ作成
docker run --rm -d -p 5678:5678/tcp -p 8020:8020/tcp pythonproject1:latest 
```


docker run コマンドの`-p 5678:5678/tcp`でホストの 5678 ポートをコンテナのデバッグ用のポート 5678 にマッピングします。


### Dockerfileを編集しない方法
Dockerで作ったコンテナは、起動するときにコマンドや環境変数などの設定（パラメータ）を追加できます。
そのため、Dockerfile を変更しなくても、デバッグ用の設定や一時的な動作の変更が可能です。


``` PowerShell:PowerShell
docker run --rm -d -p 5678:5678/tcp -p 8020:8020/tcp pythonproject1:latest bash -c 'pip install debugpy && python -m debugpy --listen 0.0.0.0:5678 manage.py runserver 0.0.0.0:8020' 
```


docker run コマンドにパラメータを追加してデバッグ設定を行うことができます。
`-p 5678:5678/tcp`でホストの 5678 ポートをコンテナのデバッグ用のポート 5678 にマッピングします。
`bash -c 'コマンド'`の部分でコンテナ起動時に実行されるコマンドを編集しています。
「debugpy のインストール」と「debugpy から Webサーバー起動」の２つのコマンドを実行するように指定しています。

:::note
Dockerfile の CMD で定義している内容はコンテナ起動時に実行されるコマンドですが、これはデフォルトの内容になっているため、docker run のパラメータでコマンドを指定した場合は上書きされます。
:::


## デバッグ実行
### デバッグ構成の追加
VSCode からコンテナへ接続するためには launch.json にデバッグ接続の構成を追加します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4063083/5626a212-f0a2-46ad-8fe5-28fa129ee337.png" width=100%>

`name`
デバッグ構成の名前。わかりやすい名前にします。
`type`
使用するデバッガーの種類。Pythonをデバッグするので "debugpy" とします。
`request`
実行中のプロセスに接続するため "attach" とします。
`connect`
接続先ホストとポートを指定します。
コンテナ作成時に、ローカルホストの 5678 ポートをコンテナの 5678 ポートへマッピングしてあるのでホスト名は "localhost" ポートは 5678 とします。
`pathMappings`
ローカル環境と接続先環境のアプリケーションフォルダをマッピングします。
${workspaceFolder} は VSCodeで利用できる変数の一つで、ワークスペースのルートディレクトリへのパスを示します。

### デバッグ接続
実行とデバッグのドロップダウンリストにデバッグ構成の名前が表示されるので、デバッグ実行するものを選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4063083/b77cbcce-fa0c-400a-89eb-adbfd6b3da50.png" width=100%>

ドロップダウンリスト左の再生ボタン使用して実行中のコンテナに接続しデバッグを開始します。