🫡

Dockerコンテナ内のFastAPIのコードをVS Codeでデバッグする

2023/10/01に公開

はじめに

Dockerコンテナで動作するFastAPIのコードを以下のようにVSCodeでデバッグ(変数の状態を確認したり、ステップ実行したり)するための方法を記載します。
DjangoやFlaskでも同様の方法でデバッグの設定を行うことができると思います。

コンテナ側の設定

requirementsファイルにdebugpyを追加

debugpy

dockerfile内でdebugpyで起動するように設定

CMD ["python3", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "uvicorn", "app.main:app", "--reload", "--host", "0.0.0.0"]

例えば以下のようなステージにしておくと簡単に切り替えやすい
※ 検証用に色々余計なパッケージを入れているので、適宜読み替えてください

##################################################
# build image
##################################################
FROM python:3.11-slim-bookworm  as builder
RUN apt-get update && \
  apt-get install -y libmariadb-dev gcc default-mysql-client build-essential vim gettext

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /src

##################################################
# local image
##################################################
FROM builder as local

COPY ./src/requirements /src/requirements
RUN pip install --upgrade pip && \
  pip install --no-cache-dir --upgrade -r requirements/base.txt

COPY ./src /src

CMD [ "uvicorn", "app.main:app", "--host", "0.0.0.0", "--reload" ]

##################################################
# debug image
##################################################
FROM local as debug

CMD ["python3", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "uvicorn", "app.main:app", "--reload", "--host", "0.0.0.0"]

デバッグ用のdocker-composeファイルを作成
例えば以下のようなサービスを持つ、docker-compose.debug.yamlを作成する

version: "3.8"
services:
  api:
    build:
      context: .
      dockerfile: ./containers/api/Dockerfile
      target: debug
    depends_on:
      - mysql
    volumes:
      - ./src:/src
    env_file:
      - ./.env
    ports:
      - "8006:8000"
      - "5678:5678"
    tty: true

ターゲットはdebug用ステージを指定する

target: debug

debugpyで待ち受けているポートをマッピングさせる

ports:
- "8006:8000"
- "5678:5678"

VSCode側の設定

プロジェクトルート配下にある.vscodeの中にlaunch.jsonを作成する

{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python: FastAPI Container Debug",
      "type": "python",
      "request": "attach",
    "connect": {
        "host": "localhost",
        "port": 5678
      },
      "pathMappings": [
        {
          "localRoot": "${workspaceFolder}/src/app",
          "remoteRoot": "app"
        }
      ],
      "justMyCode": true
    }
  ]
}

未作成の場合、launch.jsonを作成します。という部分から雛形を作ることができる

pathMappingはプロジェクトのディレクトリ構成に合わせる
私の環境では以下のディレクトリ構成になっているため、プロジェクト側は${workspaceFolder}/src/app

├── docker-compose.debug.yaml
├── docker-compose.yaml
├── src
│   ├── app

コンテナ側のWORKDIRはsrc/ なので、appをマッピングしている。

debugを起動

コンテナをデバッグモードで起動する

docker-compose -f docker-compose.debug.yaml up -d --build

launch.jsonを読み取ってデバッグの起動ができるようになっているはずなので、起動する

起動すると、以下のような画面になる

ソースコードにブレイクポイントを設定し、APIを叩いてみると、処理が一時停止し、デバッグのプレビューが確認できる

devcontainersを使用したい場合

docker-compose.debug.yamlで.vscodeフォルダ以下をワークディレクトリ配下にマウントする

version: "3.8"
services:
  api:
    build:
      context: .
      dockerfile: ./containers/api/Dockerfile
      target: debug
    depends_on:
      - mysql
    volumes:
      - ./src:/src
      - ./.vscode:/src/.vscode

devcontainer.jsonを作成する
debug用と分けたい場合は下記のようなフォルダ構成にすると良さそう

├── .devcontainer
│   ├── debug
│   │   └── devcontainer.json
│   └── local
│       └── devcontainer.json
├── docker-compose.debug.yaml
├── docker-compose.yaml

devcontaier.jsonの例

{  
  "name": "fastapi-sample",
  "dockerComposeFile": ["../../docker-compose.debug.yaml"],
  "service": "api",
  "workspaceFolder": "/src",
  "settings":{
		// mypy
		"python.linting.pylintArgs": [
			"--disable", "E1101,E0213,R0201",
			"--extension-pkg-whitelist", "pydantic"
		],
		"python.pythonPath": "/usr/local/bin/python",
		// format settings
		"[python]": {
      "editor.formatOnSave": true
		},
		// lint,mypy settings
    "python.linting.mypyEnabled": true,
    "python.linting.enabled": true,
    "python.linting.mypyPath": "/usr/local/bin/mypy",
    "python.linting.mypyArgs": ["--config=${containerWorkspaceFolder}/mypy.ini"],

		"python.analysis.typeCheckingMode": "strict",
		"python.analysis.diagnosticSeverityOverrides": {
      "reportUnusedImport": "none",
			"reportMissingTypeStubs": "none",
			"reportUnknownParameterType": "none",
  		"reportUnknownMemberType": "none",
  		"reportUnknownArgumentType":  "none",
			"reportUnknownVariableType": "none",
			"reportUntypedBaseClass" : "none"
		}
  },
	"extensions": [
		"ms-python.python",
    "njpwerner.autodocstring",
    "mosapride.zenkaku",
    "ms-python.vscode-pylance",
		"ms-python.black-formatter"
  ]
}

devcontainerで開く

ビルドが必要な場合は
remote-containers.rebuildAndReopenInContainer

devcontainer.jsonファイルを選択できるので、debug用を選択する

ブレイクポイントを設定し、APIを叩くと、devcontainer内でもデバッグできることが確認できる

VSCodeでデバッグするデメリット

ソースコードを編集したときの開発サーバのreloadやアプリケーションの実行が重くなる気がします。そのため、デバッグの必要がない場合は、デバッグを含まない構成で起動した方が良いと思いました。

Discussion