Dockerfileの記述が終わったら、これを基にイメージを作成する。これにはターミナルから「docker build ……」コマンドを実行してもよいが、Docker拡張機能をインストールしていれば、Dockerfileを開いたエディタ内でどこかを右クリックして、コンテキストメニューから[Build Image]を選択するのが簡単だ(コマンドパレットには[Docker: Build Image]コマンドもある)。すると、Dockerイメージのイメージ名とタグ名を指定するダイアログが表示されるので、適当なものを入力して(ここではデフォルトの「todoapi:latest」のままとした)[Enter]キーを押せば、イメージが作成される。
これにより、ターミナルが新規に開かれ、そこで「docker build」コマンドが実行される。作成したイメージは、アクティビティーバーの[Docker]アイコンをクリックして、[Docker Explorer]ビューを表示すると、その[Images]の下に一覧される。
ベースイメージの「python:3.6.5-alpine」と「todoapi:latest」の2つが[Images]の下にあることが分かる。
コンテナの起動には、「todoapi:latest」を右クリックして、コンテキストメニューから[Run]または[Run Interactive]を選択する。ここでは[Run Interactive]を選択してみた。
これにより、ターミナルが新規に開き、「docker run」コマンドが実行される。
この画像を見ると分かるが、[Docker Explorer]ビューの[Containers]の下には、「todoapi:latest」イメージから作成したコンテナが表示されている。また、ウィンドウ右下にはターミナルが開かれ、そこで「docker run」コマンドが実行されている。実際にDockerコンテナでコードが実行されているかを調べるために、ブラウザで「localhost:5000」にアクセスした結果を以下に示す。
Dockerfileでは環境変数TODOAPI_ENVの値を「docker」に指定していた。これにより、config.pyファイルで定義したDockerConfigクラスを利用して、__init__.pyファイルの「app.config.from_object」メソッドが実行されたことで、ブラウザには「configured by DockerConfig in config.py」というメッセージが表示されている。前回に見た、from_objectメソッドと環境変数を組み合わせ、さらにインスタンスフォルダを使用することで、アプリを実行する環境に合わせた構成を行う一例として見てほしい。
また、[Docker Explorer]ビューでは、今見たようなイメージからコンテナを起動したり、イメージを削除したり、あるいはコンテナを再起動したり停止したり、削除したり、起動中のコンテナのシェルにアタッチしたりといった操作が可能なので、便利に使ってみてほしい。特にコンテナを多数作った後で削除するのが面倒という場合は、[Docker Explorer]ビューの右上にある[System Prune]ボタンでまとめて削除できるので、覚えておこう。
最後に、VS Codeからコンテナ内で実行されているPythonコードをリモートデバッグする方法についても簡単に見ておこう。
これには、ptvsdパッケージが必要になる。また、以下ではデバッグ構成を行うのに、[Python Experimental]を利用する。利用したptvsdのバージョンは4.1.1だ。
まずは「pip install ptvsd」を実行して、開発環境にptvsdパッケージを追加しておく。Dockerfileでpipコマンドを実行している行でも同様な変更を行っておく。また、リモートデバッグで使用するポートもリッスンするようにしておこう。
# ……省略……
RUN pip install --user flask flask-sqlalchemy flask-restless flask-cors waitress ptvsd
# ……省略……
EXPOSE 5000 3000
# ……省略……
main.pyファイルには次の行を追加した(強調書体の部分)。
from todoapi import app
from waitress import serve
import os
import ptvsd
if os.getenv("TODOAPI_REMOTE_DEBUG") == "on":
ptvsd.enable_attach(address=("0.0.0.0", 3000))
ptvsd.wait_for_attach()
ptvsd.break_into_debugger()
if __name__ == "__main__":
serve(app, host="0.0.0.0", port=5000)
ここでは環境変数TODOAPI_REMOTE_DEBUGが「on」の場合に(そのようにDockerfileでは指定していた)、ptvsdパッケージが提供するenable_attach関数でリモートデバッグを有効にし、wait_for_attach関数でプロセスにアタッチされるのを待機して、最後にアタッチされたらbreak_into_debugger関数で実行を中断している。開発環境では環境変数TODOAPI_REMOTE_DEBUGを定義しない、またはon以外に設定しておけば、上記のコードは実行されない。
[デバッグ]ビューの歯車アイコンをクリックして、[環境の選択]ダイアログが表示されたら、[Python Experimental]を選択し、launch.jsonファイルを作成する。その後、「Python Experimental: Attach」という名前の設定項目を探して、以下のように修正をしておこう。
{
"version": "0.2.0",
"configurations": [
// …… 省略 ……
{
"name": "Python Experimental: Attach",
"type": "pythonExperimental",
"request": "attach",
"port": 3000,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/home/todoapi"
}
]
},
// …… 省略 ……
]
}
ポートは先ほど述べたように3000を指定する。pathMappings項目は、ローカルの開発環境とリモートの実行環境のディレクトリ構造が一致するように指定する。ここではlocalRoot項目には「${workspaceFolder}」つまりVS Codeで開いているフォルダを、remoteRoot項目にはDockerfileのWORKDIR命令で指定したディレクトリである「/home/todoapi」を指定している。
変更後のDockerfileからイメージを再作成して(これにより、上記のptvsdパッケージのインストールや、main.pyファイルの変更が反映されたイメージが作成される)、コンテナを起動すると、コンテナはアタッチされるのを待機する。そこで、VS Codeの[デバッグ]ビューでデバッグ構成に[Python Experimental: Attach]を選択して、デバッグを開始する。アタッチが完了すると、次のようにif節の最後のbreak_into_debugger関数が終了した状態で実行が中断する。
本稿ではデバッグしたくなるほどのコードを書いていないので役には立たないが、このようにすることでDockerコンテナ内のコードのリモートデバッグも可能だ。ただし、ブレークポイントがうまく機能していないといった報告もWeb上では見かけたので、注意はしよう(ptvsdを活用したい方は、GitHubにあるptvsdリポジトリのIssuesなどを定期的に訪れるとよいだろう)。
今回は、これまでの総まとめという感じで、Web APIをコンテナ化してみた。まだ他にも話題はあるが、VS Code+Flaskという組み合わせはここでいったんお終いとして、しばらくしたらまた別のネタでVS Code+Pythonの連載を続ける予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.