VS CodeのRemote DevelopmentでFlaskアプリをデバッグしてみた

こんにちは。プロダクトグループの坂井です。

ローカル開発環境で実装する際は、IDEやエディタでコードを追加・修正し実行・デバッグしながら進めていくかと思います。ローカルPCにすべて開発環境を構築していれば、特に困らないのですが、Dockerや仮想環境(Vagrantなど)で環境を作成した際は、どのようにデバッグしようか悩んでしまうことはないでしょうか? 今回は解決案の1つとして、Dockerで作成したFlask環境にリモート開発環境を構築し、デバッグしてみようと思います。

Flask環境をDockerにて構築する方法については、こちらにて執筆させていただいておりますので、参考にしていただければと思います。

また、VS CodeのRemote Developmentについては、弊社ブログに利用例がありますので、参考にしていただければと思います。

VS Code Remote Development

VS Code Remote Developmentについて詳しくは以下のサイトを確認してみてください。 リモート接続の拡張機能の種類としてはSSH、Containers、WSL(Windows Subsystem for Linux)があり、今回はContainersを利用します。

VS Code Remote Development

環境

  • macOS Mojave 10.14.6
  • Visual Studio Code 1.37.0
    • Remote-Containers 0.67.3
  • Docker 19.03.1
  • Docker Compose 1.24.1

拡張機能は、以下のRemote - Containersをインストールしておきます。

Visual Studio Code Remote - Containers

Dockerコンテナの準備

Python + Flaskが動くようにコンテナを準備します。Docker Composeで起動したいので、以下の通り設定しました。

FROM python:3.7.4

ARG project_directory
WORKDIR $project_directory

RUN pip install flask
version: "3.7"
services:
  web_flask:
    build:
      context: .
      args:
        project_directory: "/projects/"
    ports:
      - "5000:5000"
    volumes:
      - ".:/projects"
    environment:
      TZ: "Asia/Tokyo"
      FLASK_ENV: "development"
    command: "sleep infinity"

デバッグ対象のソースは以下となります。 Flask Tutorial in Visual Studio Code を参考にさせていただきました。

from flask import Flask, request
from datetime import datetime
import re

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

@app.route("/hello/<name>")
def hello_there(name):
    now = datetime.now()
    formatted_now = now.strftime("%A, %d %B, %Y at %X")

    # Filter the name argument to letters only using regular expressions. URL arguments
    # can contain arbitrary text, so we restrict to safe characters only.
    match_object = re.match("[a-zA-Z]+", name)

    if match_object:
        clean_name = match_object.group(0)
    else:
        clean_name = "Friend"

    content = "Hello there, " + clean_name + "! It's " + formatted_now
    return content

これでコンテナの準備は完了です。

リモート接続設定

リモート接続設定するためのファイル.devcontainer.jsonを作成します。VS Codeでいずれかのフォルダを開いている状態じゃないと、該当のメニューが表示されない可能性があります。(各ファイルを開いている状態では表示されませんでした)もし表示されないようでしたら、フォルダを開いている状態かをご確認ください。

今回はDocker Composeで起動するので、From docker-compose.ymlを選択して、ファイルの雛形を生成しました。 生成したファイルをもとに必要に応じて追記・修正していきます。下記のリファレンスにも記載されていますが、Dockerfileまたはimageを使う場合と、Docker Composeを使う場合で設定するべき項目が異なるので注意してください。

devcontainer.json reference

{
	"name": "Flask Remote Sample",
	"dockerComposeFile": "docker-compose.yml",
	"service": "web_flask",
	"workspaceFolder": "/projects",
	"extensions": [
		"ms-python.python"
	]
}

extensionsは、コンテナ作成時にインストールする拡張機能を指定することができます。 拡張機能のIDを配列で指定します。今回はPythonの拡張機能を指定しました。

起動してみる

これまで作成した各ファイルは、以下の通り配置しています。

[実行ディレクトリ]
├── .devcontainer.json
├── Dockerfile
├── app.py
└── docker-compose.yml

実行ディレクトリを開いている状態の場合はRemote-Containers: Reopen Folder in Container、実行ディレクトリを指定して起動する場合はRemote-Containers: Open Folder in Containerを選択し起動します。

起動したら以下のような表示となります。

.devcontainer.jsonで指定した拡張機能がリモート側にインストールされていますね。

デバッグしてみる

続いてリモート開発環境を起動し接続した状態で、デバッグ設定を行います。 デバッグ設定ファイルの生成で、Flaskを選択し、launch.jsonを生成します。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Flask",
            "type": "python",
            "request": "launch",
            "module": "flask",
            "env": {
                "FLASK_APP": "app.py",
                "FLASK_ENV": "development",
                "FLASK_DEBUG": "0"
            },
            "args": [
                "run",
                "--no-debugger",
                "--no-reload",
                "--host=0.0.0.0"
            ],
            "jinja": true
        }
    ]
}

ほとんどデフォルトのままで良いかと思いますが、今回はホスト側からアクセスしたかったので、argsに--host=0.0.0.0を追加しました。他の項目や設定について詳しくはこちらをご確認ください。

これで準備が整ったので、ブレークポイントを設定し、デバッグを起動してみます。

curlコマンドかブラウザでhttp://localhost:5000/hello/hogehogeにアクセスしてみます。

curl http://localhost:5000/hello/hogehoge
Hello there, hogehoge! It's Thursday, 15 August, 2019 at 15:01:44

デバッグできていますね!

さいごに

こんな機能がリリースされたんだぁとなんとなくRemote Development機能の存在については知っていました。 正直、試すにも時間がかかりそう、構築するのが大変そうという印象を持っていました。

ですが、今回実際にやってみると、そんな印象が払拭されました。 すぐに構築することができ、コンテナ内に開発環境を構築するのでクライアントの環境を考慮する必要が少なくなりそうです。

VS CodeとDockerさえあればなんでもできそう!と思えるほど便利な機能でしたので、ぜひお試しください。

参考