Pythonでお仕事する前提で、現在のところで自分が最適と考えるチーム開発のための環境整備についてまとめてみました。今までももろもろ散発的に記事に書いたりしていたのですが、Poetryで環境を作ってみたのと、過去のもろもろの情報がまとまったものが個人的にも欲しかったのでまとめました。前提としては次の通りです。
- パッケージ管理や開発環境整備でPoetryを使う
- 今時はコードフォーマッター、静的チェックは当たり前ですよね?
- コマンドでテスト実行、コードチェックとか実行とかができる(CI/CD等を考えて)
- VSCodeでもコマンドで実行しているのと同じコードチェックが可能(ここコンフリクトすると困る)
- デプロイはDockerイメージ
- コンテナのデプロイ環境でコンテナに割り当てられたCPU能力を比較的引き出せて、スケールさせたら線形にパフォーマンスアップできるようなasyncioを前提とした環境構築
Pythonのasyncio周りで@aodagと@moriyoshitにアドバイスをいただきました。
Poetryのインストール(1回で良い)
https://python-poetry.org/docs/
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - |
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python - |
ホームの.poetry/bin以下にコマンドが作成される。ここにパスを通すか、どうせpoetryコマンドだけなのでこれのシンボリックリンクをパスの通っているところに作る。
プロジェクト作成
プロジェクトフォルダはコマンドで一緒に作られるので、フォルダをおきたい親フォルダでコマンドを実行
poetry new sample-server |
これでsample-serverフォルダが作られて、その中に設定ファイル一式がつくられる。
ここで必要なライブラリのインストールとかしてもいいがその前にやっておくと良いことがある。venv環境をプロジェクトの中に作ると、VSCodeとかで仮想環境を上手く扱ってくれるのでこの設定をやっておくと良い。プロジェクトファイル内にpoetry.tomlというファイルが作られる。これをコミットしておけば、プロジェクト全員が同じフォルダ構成になるため、プロジェクトの平準化がしやすい。
cd sample-server |
ここで仮想環境を有効にして、必要なライブラリをインストール。
poetry install |
デフォルトでpytestが入っており、これでテストができる。
poetry run pytest |
ツールのインストール
Poetryの標準テンプレートでpytest入りますが、linter (flake8, mypy)とフォーマッター (black)を入れていきます。
これからぼちぼち設定をいじったりもするので、最初にVSCodeの設定をします。poetry installで作られた.venv環境を参照するようにします。
{ |
これでエディタを開いて、Pythonバージョンに(‘.venv’ :venv)とかかれていれば成功です。
フォーマッターはblack、linterはflake8とmypyを入れます。またVSCodeのターミナルを起動すると自動で.venv環境に入ってくれるようになります。
poetry add --dev mypy black flake8 |
ツールの実行はまとめて行いたい、みたいなことがありますが、poetryにはツールランチャーの機能はないので、taskipyを入れます。
poetry add taskipy |
https://tech.515hikaru.net/post/2020-02-25-poetry-scripts/
次のように定義することで、コマンド名とかを覚えなくても良いようにします。
[tool.taskipy.tasks] |
次の名前で開発タスクが行えるようになります。
poetry run task test
: テストの実行(lintも行う)poetry run task fmt
: スタイルの修正poetry run task lint
: lintの実行(flake8, mypy, blackの差分チェック)poetry run task --list
: タスク一覧表示
VSCodeの方も、これらの設定に合わせます。
linterはコード入力の中でリアルタイムで適用してチェックされるようになるし、保存時にblackでフォーマットされるようになります。テストはテスト関数の関数定義の行の前に出てくるRun Testボタンでもできますし、コマンドパレットでRun All Testでも実行できるようになります。
{ |
無視するファイルも登録しておきます。
__pycache__ |
これで一通り設定完了です。.vscode/settings.jsonを含めて各種ファイルを全部リポジトリに入れておけば、チェックアウトしたユーザーはpoetry install
を実行すれば環境が整います。
サーバーの開発
必要なライブラリをインストールします。今回はasyncio対応ということでFastAPIを選びました。Starletteでもいいと思います。
poetry add fastapi uvicorn gunicorn |
Poetryが作ったコード用のフォルダの中にmain.pyファイルを作り、FastAPIのサンプルコードを貼り付けます。
from typing import Optional |
テストサーバー起動をpoetryコマンドから行えるように、タスク定義を追加しておきます。
[tool.taskipy.tasks] |
これで次のコマンドで8000ポートで開発サーバーが起動するようになります。ファイルを変更すると自動リロードします。
$ poetry run task start |
これでどんどんコードを書いてブラウザで動かして・・・というのはできるのですが、デバッグもしたいですよね? VSCodeの設定ファイルを作っておいておきます。
{ |
これを作っておくと、Run and DebugアイコンをクリックしたときにRUNのところに表示されますので、▷ボタンを押すとデバッガーでアプリが起動します。あとはブレークポイントを置いたりステップ実行したり、変数をみたり、自由自在です。
サーバーのDocker化
Dockerのイメージにするところまで作っておきましょう。まずはビルド時に不要なファイルを設定する.dockerignoreファイルを作ります。
__pycache__ |
次にDockerfileです。ウェブサーバーはデータベースのライブラリが必要になったりすることを考えてDebianベースで作っています。Distrolessだとバイナリパッケージ追加がちょっと厳しいかもというのと、Pythonバージョンが3.7とちょっと古いので・・・バイナリパッケージの問題や型チェックで新しい書き方を使わなくても構わない場合はDistrolessが良いと思います。
Gunicornの起動ではアクセスログをコンソールに流すようにしています。ログドライバーが取得して収集しやすくなるので、ローカルファイルに置くのではなくて、出力するのがコンテナ時代やり方ですね。
# ここはビルド用のコンテナ |
各DB接続ライブラリのasyncioサポートと必要なパッケージの組み合わせは次の通りです。
- SQLAlchemy
- PostgreSQL: asyncpg
- databases
- PostgreSQL: asyncpg
- MySQL: aiomysql
- SQLite: https://pypi.org/project/aiosqlite/
上記のライブラリ群を使う限り、ビルドイメージはslimで大丈夫ですし、追加のパッケージインストールも不要です。asyncpgはCythonで作られていますが、manylinux1なバイナリが提供されているのでDebian系のイメージを使う限りはCコンパイラは不要(slimなイメージのままで大丈夫)です。また、同期接続なPyMySQLもpure Pythonなのでそのままで大丈夫です。型チェックの書き方さえPython3.7でよければDistroless化も簡単です。
PostgreSQLで、同期接続のpsycopg2を使う場合にlibpq5(とlibxml2)が必要となりますし、Cコンパイラも必要になるので、ビルドイメージをslimじゃないものにして、次のコードを実行イメージのFROMのところに入れておきます。ビルドイメージのslimじゃないbusterイメージには最初からlibpq5-devとかも入っているので追加インストールは実行イメージ側だけで大丈夫です。
# ここはビルド用のコンテナ |
実行はいつもの通りです。
docker build -t sample-server . |