VSCode Dev ContainersでPython環境を構築する際のベストプラクティス
はじめに
VSCodeのDev Containers機能を用いて、Pythonプロジェクトの開発環境を構築しました。
そこで得られた知見を共有します。
実現する構成
- Python
- Poetry
- セッションストア(Redis)
- データベース(Microsoft SQL Server)
完成形
devcontainer.json
{
"name": "devcontainer-python",
"dockerComposeFile": ["docker-compose.yml"],
"service": "server",
"runServices": ["db", "server"],
"mounts": [
{
"type": "volume",
"source": "poetry-cache",
"target": "/home/vscode/.cache/pypoetry"
},
{
"type": "volume",
"source": "venv-cache",
"target": "${containerWorkspaceFolder}/.venv"
}
],
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/jlaundry/devcontainer-features/mssql-odbc-driver": {
"version": 18
},
"ghcr.io/itsmechlark/features/redis-server": {
"version": "latest"
},
"ghcr.io/devcontainers-contrib/features/poetry": {
"version": "latest"
}
},
"postAttachCommand": "sudo chown -R vscode /home/vscode/.cache/pypoetry ${containerWorkspaceFolder}/.venv && poetry config virtualenvs.in-project true && poetry install",
"remoteUser": "vscode",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/workspace/.venv/bin/python"
},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"streetsidesoftware.code-spell-checker",
"charliermarsh.ruff",
"tamasfe.even-better-toml",
"ms-azuretools.vscode-docker"
]
}
}
}
docker-compose.yml
version: "3"
services:
server:
hostname: server
image: "mcr.microsoft.com/devcontainers/python:3.11-bullseye"
command: /bin/sh -c "while sleep 1000; do :; done"
user: vscode
ports:
- "8000:8000"
volumes:
- ..:/workspace:cached
db:
hostname: db
image: "mcr.microsoft.com/mssql/server:2022-latest"
env_file:
- ../.env
expose:
- "1433"
ports:
- "1433:1433"
Dev Containersのfeaturesを極力使う
Dockerfileをこねこねせずとも、以下のことはDev ContainersのFeaturesを使えばできてしまいます。
- データベースドライバ(SQLServerならODBC)のインストール
- Redisサーバーの用意
- Poetryのインストール
利用可能なfeaturesは以下のリポジトリから探すとよいです。
.venv
にいれる
ライブラリはリポジトリ直下の「プロジェクトに参加する開発者全員の開発環境を一定に揃える」ために Devcontainer でさらにバージョン固定を行うことは明らかな過剰剛性であり,センスがありません.当たり前ですが,コンテナは多くのリソースを使用します.特にこの過剰剛性によってイメージサイズが大きくなることは避けることができません(中略)
さらに,概してライブラリというのは変更や追加されることなど開発用のツールほど少なくはありません.ライブラリの変更が行われるたびにコンテナのビルドが行われては開発どころではないでしょう.
この記事に則り、Dev Containerにアタッチ後、poetryが.venv
にライブラリをインストールするよう設定しました。
.venv
はDockerボリュームに退避する
ホストとコンテナで.venv
を共有すると、PythonのIntelliSenseが非常に遅くなります。
これは.venv
をDockerボリュームに切り出すことで対策できます。
また、docker-compose.yml
を使わずとも、devcontainer.json
に以下のような設定を加えるだけで実現できます。
ただし、マウントされたボリュームのオーナーはroot
になるので、sudo chown -R vscode .venv
でvscode
ユーザーに変更する必要があります。
"mounts": [
{
"type": "volume",
"target": "${containerWorkspaceFolder}/.venv"
}
],
"postAttachCommand": "sudo chown -R vscode ${containerWorkspaceFolder}/.venv && poetry config virtualenvs.in-project true && poetry install",
Poetryのキャッシュもボリュームに退避する(オプション)
コンテナをリビルドするとPoetryがキャッシュしていたPythonライブラリのキャッシュも消えてしまいます。
Dev Containerの設定を作成する際は頻繁にコンテナのリビルドを行うと思いますが、その度にライブラリのダウンロードが発生するため、検証のサイクルが遅くなります。
これを回避するには、poetryのキャッシュディレクトリもボリュームに切り出します。
"mounts": [
{
"type": "volume",
"source": "poetry-cache",
"target": "/home/vscode/.cache/pypoetry"
},
{
"type": "volume",
"source": "venv-cache",
"target": "${containerWorkspaceFolder}/.venv"
}
],
"postAttachCommand": "sudo chown -R vscode /home/vscode/.cache/pypoetry ${containerWorkspaceFolder}/.venv && poetry config virtualenvs.in-project true && poetry install",
rootユーザーは使わない
保存を行ったコンテナにおいて, VSCode がコンテナの root ユーザーでファイルの保存を行った場合, root として保存され,上書きされたファイルのアクセス権限はホストマシンにも適用されます.
また、ユーザー名はvscode
とすることをおすすめします。
VSCode公式のコンテナイメージを使う
公式が提供するコンテナイメージを使えば、vscode
ユーザーの作成などでDockerfileをこねこねする必要はありません。
利用可能なコンテナイメージは以下のリポジトリから探すとよいです。
デフォルトで入ってほしい拡張機能をdevcontainer.jsonにいれる
デフォルトで以下の拡張機能を入れることをおすすめします
- ms-python.python: 言わずもがなVSCode公式のPythonサポート
- ms-python.vscode-pylance: MS渾身のPython型チェッカー
- streetsidesoftware.code-spell-checker: スペルチェックでタイポを防ぐ
- charliermarsh.ruff: Rustで書かれたちょっぱやのPythonフォーマッター・リンター
- tamasfe.even-better-toml: pyproject.tomlのシンタックスハイライト
また、devcontainer.json
の"customizations"."extensions"
に記述した拡張はコンテナビルド時に自動で入ります。
一方.vscode/extensions.json
に記述した拡張は自動では入りませんが、
"extensions.ignoreRecommendations": false
でインストール催促のポップアップを出すことはできます。
.env
に集約する
環境変数はリポジトリ直下の環境変数に限らず設定の類はいつも気づけばカオスになります。
The Twelve-Factor Appというアプリケーション開発の11原則にある通り、設定はすべて環境変数で渡せるようにしておくのがよいです。
また.env
は.gitignore
した上で、example.env
に雛形を用意しておくとよいです。(シークレットは書かないこと!)
M1対応のためにDockerfileにplatformを指定する必要はない
platformにx86やarmを指定することでプルするコンテナイメージのアーキテクチャを指定できますが、デフォルトでApple Silicon Macならarmが指定されるので、わざわざ書く必要はありません。
.vscode
配下に記述する
Dev Containers固有の設定以外はDev Containersを使わない場合にも対応できるよう、Dev Container固有の設定以外は.vscode/settings.json
に記述しましょう。
以下のように、フォーマッターの設定などは.vscode/
配下に記述し、逆にPythonのパスなどはdevcontainer.json
に記述しましょう。
{
"cSpell.words": [ // スペルチェッカーの追加辞書
"devcontainer"
],
"files.exclude": {
// 余計なファイルを表示しないようにする
"**/__pycache__": true,
"**/.mypy_cache": true,
"**/.pytest_cache": true
},
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true
},
"editor.defaultFormatter": "charliermarsh.ruff"
},
"extensions.ignoreRecommendations": false // 推奨のエクステンションを必ず表示する
}
結局は公式ドキュメントが一番頼りになる
公式は正義
参考
以下の記事はとても参考になりました!ありがとうございます!
Discussion