Docker コンテナ内の Webアプリケーション（Python ＋ Flask） を Window 環境の VSCode からデバッグする

# Docker コンテナ内の Webアプリケーション（Python ＋ Flask） を Window 環境の VSCode からデバッグする

[前回の記事](https://qiita.com/Yu-Chihuahua/items/0be465f08749faf754e7)で、Docker コンテナに Python ＋ Flask ＋ Vue.js ＋ Vuetify の開発環境を構築しました。
今回は、開発をより効率的に進めるため、Docker コンテナ内で起動している Webアプリケーション（Python ＋ Flask）を VSCode からデバッグできるようにしようと思います。

## 今回のゴール
- Docker コンテナ内で起動している Webアプリケーション（Python ＋ Flask）を VSCode からデバッグする

## ディレクトリ構成
今回のディレクトリ構成は下記のようになります。
追加は```/home/appuser/workspace/.vscode/launch.json```ファイルのみですので、他は省略します。
```diff_shell:WSL2 Ubuntu
  /home/appuser

  ├── workspace
  │   ├── docker-compose.yaml
+ │   ├── .vscode
+ │   │   └── launch.json
  │   └── web_app003
  │       ├── Dockerfile
～～～～～～～～～～ 以下省略 ～～～～～～～～～～
```

## 手順
### 資材作成
1. ```docker-compose.yaml```ファイルを修正
    ```docker-compose.yaml```ファイルを下記のように修正します。
    - Flask アプリケーションが自動的に起動しないように```command```を追加
    - デバッグ連携用に5678番ポートを公開
    ```yaml:docker-compose.yaml
    version: '3'
    services:
    
      ##############################################################################
      # Web Application container（Python ＋ Flask ＋ Vue.js ＋ Vuetify）
      ##############################################################################
      web_app003:
        build: "./web_app003/"
        command: "/bin/bash" # Flask アプリケーションが自動的に起動しないようにする設定
        tty: true
        # volumes:
        #   - "./web_app003/opt/web_app/:/opt/web_app/" # ローカル(Ubuntu)のディレクトリと同期する
        ports:
          - "5000:5000" # Flask port
          - "5173:5173" # Vue.js port
          - "5678:5678" # Debug port
        image: "web_app003:develop"
        container_name: "web_app003"
    ```
    <br>

1. ```Dockerfile```ファイルを修正
    ```Dockerfile```ファイルを下記のように修正します。
    - debugpy をインストール対象に追加
    ```shell:Dockerfile
    # Amazon Linux 2023
    FROM public.ecr.aws/amazonlinux/amazonlinux:2023
    
    # ミドルウェアをインストール
    RUN dnf install -y \
        util-linux \
        shadow-utils \
        vim-enhanced-2:9.* \
        sudo-1.9.* \
        python3.11-3.11.* \
        python3.11-pip-22.3.* \
        python3.11-devel-3.11.* \
        nodejs-1:18.*
    
    # Python のライブラリをインストール
    RUN pip3.11 install flask==3.0.*
    RUN pip3.11 install flask_socketio==5.3.*
    RUN pip3.11 install flask-cors==4.0.*
    RUN pip3.11 install flask-wtf==1.2.*
    RUN pip3.11 install debugpy==1.8.*
    
    # ホストOS と同じユーザーを追加する
    # 1000 : host OS $(id -g)
    RUN groupadd -g 1000 appuser
    # 1000 : host OS $(id -u)
    RUN adduser -m appuser -u 1000 -g appuser
    # Add SUDO group.
    RUN groupadd sudo
    # Add SUDO authority.
    RUN usermod -aG sudo appuser
    
    # 資材を配置する
    WORKDIR /opt/web_app/
    RUN mkdir -p /opt/web_app/
    COPY ./opt/web_app/ /opt/web_app/
    COPY ./opt/flask_start.sh /opt/
    
    # オーナーとパーミッションを変更する
    RUN chown appuser:appuser /opt/web_app -R
    RUN chmod 775 /opt/web_app -R
    
    # vite で Vue.js 環境を構築してプロダクションビルドする
    WORKDIR /opt/web_app/frontend/
    RUN npm install
    RUN npm run build
    
    # 起動時のコマンドを設定する
    CMD ["sh","/opt/flask_start.sh"]
    ```
    <br>

1. ```flask_start.sh```ファイルを修正
    ```flask_start.sh```ファイルを下記のように修正します。
    - Flask アプリケーションをデバッグ起動し、デバッグ連携用に5678番ポートを公開する
    ```shell:flask_start.sh
    #!/bin/bash
    
    ################################################################################
    # Flask アプリケーションを起動するシェルスクリプト
    ################################################################################
    
    su -l appuser -c "cd /opt/web_app/src/; python3.11 -m debugpy --listen 0.0.0.0:5678 app_controller.py"
    ```
    <br>

1. ```app_controller.py```ファイルを修正
    ```app_controller.py```ファイルを下記のように修正します。
    - デバッグ起動を確認しやすいように```get_index_html()```関数を追加
    ```python:app_controller.py
    from flask import Flask, render_template
    app = Flask(__name__, static_folder="/opt/web_app/src/templates/static/")
    
    @app.route("/")
    def index():
        """
        初期ページ表示
        """
        index_html = get_index_html()
        return render_template(index_html)
    
    
    def get_index_html():
        file_name = "index"
        file_extension = "html"
        index_html = file_name + "." + file_extension
        return index_html
    
    
    if __name__ == "__main__":
        """
        Flask アプリケーション起動
        """
        app.run(debug=False, host="0.0.0.0", port=5000)
    ```
    <br>

1. VSCode のデバッグ設定```launch.json```ファイルを作成
    VSCode のデバッグ設定```launch.json```ファイルを下記のように作成します。
    - コンテナ内とローカル環境のソースディレクトリをマッピング
    - デバッグ連携用に5678番ポートを公開する
    ```json:launch.json
    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "web_app003 Debugger",
                "type": "debugpy",
                "request": "attach",
                "connect": {
                    "host": "localhost",
                    "port": 5678
                },
                "pathMappings": [
                    {
                        "localRoot": "${workspaceFolder}/web_app003/opt/web_app/src",
                        "remoteRoot": "/opt/web_app/src"
                    }
                ]
            }
        ]
    }
    ```

### VSCode 設定
1. VSCode をインストール
    VSCode を公式サイトからダウンロードしてインストールします。
    公式サイト：https://code.visualstudio.com/download
    <br>

1. 拡張機能 Python Debugger をインストール
    拡張機能 Python Debugger を「拡張機能（Ctrl+Shift+X）」タブから検索してインストールします。
    ![スクリーンショット 2024-10-15 225859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767768/e7dfa072-47d9-8931-93bc-49ad724b6700.png)
    <br>

1. ワークスペースを設定
    ```\\wsl$\Ubuntu-22.04\home\appuser\workspace```を VSCode のワークスペースに追加します。
    ![スクリーンショット 2024-10-16 001512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767768/f7061e29-c506-3898-a0f3-b68a7f70c1d1.png)

### 動作確認
1. Docker Compose でビルド＆起動
    Docker Compose でカスタムイメージをビルドして起動します。
    ```shell:WSL2 Ubuntu
    cd /home/appuser/workspace
    docker-compose build
    docker-compose up -d
    ```
    <br>

1. 起動した Docker コンテナに入る
    ```docker exec```コマンドで、起動した Docker コンテナに入ります。
    ```shell:WSL2 Ubuntu
    docker exec -it web_app003 bash
    ```
    <br>

1. Flask を起動する
    シェルを実行して Flask を起動します。
    ```shell:web_app003
    sh /opt/flask_start.sh
    ```
    <br>

1. VSCode でデバッグ待機
    VSCode の「実行とデバッグ（Ctrl+Shift+D）」タブから、```web_app003 Debugger```を起動します。
    また、```app_controller.py```にブレークポイントを設定します。
    ![スクリーンショット 2024-10-15 232130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767768/294cc1b5-b747-5ec1-771d-2ddbb6352380.png)
    <br>

1. ローカルホストでアクセス
    Windows のブラウザからローカルホストでアクセスします。
    URLは```http://localhost:5000/```です。
    <br>

1. デバッグ操作を確認
    ブレークポイントで処理が止まることを確認します。
    また、ステップオーバー（F10）などの操作ができること、変数の値を参照できることを確認します。
    ![スクリーンショット 2024-10-15 232157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767768/9fa401d6-36f3-23e6-6134-3763c4d11b7c.png)
![スクリーンショット 2024-10-15 232304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767768/27088b2f-0e6e-17a6-250d-2c98d4cba66a.png)

## 最後に
今回は Webアプリケーション（Python ＋ Flask）でデバッグ操作できることを確認しましたが、当然ながら、Webアプリケーションでなくても、同様の手順でデバッグ操作することができます。
開発環境を Docker コンテナで作成する手軽さと、VSCode からデバッグ操作できることの両方のメリットを受けることができますので、開発をより効率的に行うことができそうです。