コンテナ化された Python 開発 – パート 3

これは、コンテナ化されたPython開発環境をセットアップして最適化する方法を示す 一連のブログ投稿 の最後の部分です。 最初の部分では、Python サービスをコンテナー化する方法と、その開発のベスト プラクティスについて説明しました。第 2 部では、Python アプリケーションに必要なさまざまなコンポーネントを簡単に設定する方法と、Docker Compose を使用してプロジェクト全体のライフサイクルを簡単に管理する方法を示しました。

この最後のパートでは、プロジェクトの開発サイクルを確認し、コードの更新を適用し、コンテナー化された Python サービスのエラーをデバッグする方法について詳しく説明します。 目標は、開発プロセスのこれらの繰り返しフェーズをスピードアップする方法を分析して、ローカル開発と同様のエクスペリエンスを得ることです。

コード更新の適用

一般に、コンテナ化された開発サイクルは、コードの記述/更新、ビルド、実行、デバッグで構成されます。

Python 開発パート 3

ビルドと実行のフェーズでは、ほとんどの場合実際に待たなければならないため、これらのフェーズを非常に迅速に実行して、コーディングとデバッグに集中する必要があります。

次に、開発中にビルドフェーズを最適化する方法を分析します。 ビルドフェーズは、Python ソースコードを変更するときのイメージビルド時間に対応します。 コンテナーを起動する前に、コンテナーで Python コードの更新を取得するには、イメージを再構築する必要があります。

ただし、イメージをビルドしなくてもコードの変更を適用できます。 これは、ローカルソースディレクトリをコンテナ内のパスにバインドマウントするだけで実行できます。 このために、作成ファイルを次のように更新します。

docker-compose.yaml

...
  app:
    build: app
    restart: always
    volumes:
      - ./app/src:/code
...

これにより、更新されたコードに直接アクセスできるため、イメージのビルドをスキップし、コンテナーを再起動してPythonプロセスをリロードできます。

さらに、ファイルの変更を監視し、変更が検出されるとPythonプロセスの再起動をトリガーするリローダープロセスをコンテナ内で実行すると、コンテナの再起動を回避できます。 前述のように、Composeファイルにソースコードがバインドマウントされていることを確認する必要があります。

この例では、デバッグモードでリローダーと呼ばれる非常に便利なモジュールを実行するFlaskフレームワークを使用します。 リローダーはすべてのソース コード ファイルを監視し、ファイルが変更されたことを検出したときにサーバーを自動的に再起動します。 デバッグモードを有効にするには、デバッグパラメータを以下のように設定するだけです。

server.py

server.run(debug=True, host='0.0.0.0', port=5000)

アプリコンテナのログを確認すると、フラスコサーバーがデバッグモードで実行されていることがわかります。

$ docker-compose logs app
Attaching to project_app_1
app_1 | * Serving Flask app "server" (lazy loading)
app_1 | * Environment: production
app_1 | WARNING: This is a development server. Do not use it in a production deployment.
app_1 | Use a production WSGI server instead.
app_1 | * Debug mode: on
app_1 | * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
app_1 | * Restarting with stat
app_1 | * Debugger is active!
app_1 | * Debugger PIN: 315-974-099

ソースコードを更新して保存すると、ログに通知が表示され、リロードされます。

$ docker-compose logs app
Attaching to project_app_1
app_1 | * Serving Flask app "server" (lazy loading)
...
app_1 | * Debugger PIN: 315-974-099
app_1 | * Detected change in '/code/server.py', reloading
app_1 | * Restarting with stat
app_1 | * Debugger is active!
app_1 | * Debugger PIN: 315-974-099

コードのデバッグ

主に2つの方法でコードをデバッグできます。 

1つ目は、オブジェクト/変数の実行時値をチェックするために、コード全体にprintステートメントを配置する昔ながらの方法です。 これをコンテナ化されたプロセスに適用するのは非常に簡単で、 docker-compose logs コマンドを使用して出力を簡単に確認できます。

第 2 に、より深刻なアプローチは、デバッガを使用することです。 コンテナー化されたプロセスがある場合は、コンテナー内でデバッガーを実行し、そのリモート デバッガーに接続して、インスタンス データを検査できるようにする必要があります。

例として、Flaskアプリケーションを再び取り上げます。 デバッグモードで実行する場合、リローダーモジュールとは別に、インタラクティブなデバッガーも含まれています。 例外を発生させるようにコードを更新すると仮定すると、Flask サービスは例外を含む詳細な応答を返します。

Python 開発パート 3 1

もう 1 つの興味深いケースは、コードにブレークポイントを配置してライブ検査を行う対話型デバッグです。 このためには、PythonとリモートデバッグをサポートするIDEが必要です。 コンテナーで実行されている Python コードをデバッグする方法を示すために Visual Studio Code に依存することを選択した場合は、VSCode から直接リモート デバッガーに接続するために、次の手順を実行する必要があります。 

まず、デバッガーへの接続に使用するポートをローカルにマップする必要があります。 これは、ポートマッピングをComposeファイルに追加することで簡単に実行できます。

docker-compose.yaml

...
  app:
    build: app
    restart: always
    volumes:
      - ./app/src:/code
    ports:
      - 5678:5678

...

次に、デバッガーモジュールをソースコードにインポートし、Composeファイルで定義したポートでリッスンさせる必要があります。 依存関係ファイルにも追加し、アプリ サービスのイメージを再構築してデバッガー パッケージをインストールすることを忘れないでください。 この演習では、VS Code でサポートされている ptvsd デバッガー パッケージを使用することを選択します。

server.py

...
import ptvsd
ptvsd.enable_attach(address=('0.0.0.0', 5678))
...

requirements.txt

Flask==1.1.1
mysql-connector==2.2.9


ptvsd==4.3.2

作成ファイルに加えた変更については、作成コマンドを実行して現在のコンテナー設定を削除してから、docker-compose upを実行して、作成ファイル内の新しい構成で再デプロイする必要があることを覚えておく必要があります。

最後に、デバッグ モードを起動するために、VS Code で "リモート アタッチ" 構成を作成する必要があります。

プロジェクトの launch.json は次のようになります。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Remote Attach",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}/app/src",
                    "remoteRoot": "/code"
                }
            ]
        }
    ]
}

パスマップをローカルとコンテナ内で更新する必要があります。 

これを行うと、IDEにブレークポイントを簡単に配置し、作成した構成に基づいてデバッグモードを開始し、最後にコードをトリガーしてブレークポイントに到達できます。

結論

この 一連のブログ投稿 では、コンテナー化された Python 開発環境をすばやくセットアップし、プロジェクトのライフサイクルを管理し、コードの更新を適用し、コンテナー化された Python サービスをデバッグする方法について説明しました。私たちが議論したすべてを実践することで、コンテナ化された開発エクスペリエンスをローカルの開発エクスペリエンスと同じにする必要があります。 

リソース

フィードバック

「コンテナ化されたPython開発–パート0」に関する3つの考え