概要
DockerとPipenvでPythonの実行環境を管理して、それをVSCodeのRemote Developmentで切り替える仕組みについて紹介します。Facebookがこの機能のためにMicrosoftと提携したというニュースが最近あるくらい今アツい機能です。これを導入することで得られる恩恵としては、
- Docker: Pipenvでは管理できない依存ライブラリ(LAPACKなど)や環境変数の設定なども管理可能
- Pipenv: 開発にのみ必要なpackage(autopep8など)を実行環境と分離して管理でき、かつ、pipよりも依存管理が容易
- VSCode: 上記2つで構築したdocker container上でシームレスに開発可能で、各種extensionが強力
などがあるので、これらを組み合わせて開発環境を構築するメリットは大きいと思います。イメージとしては以下のような形で構成します。
また、VSCodeでPythonの開発をする上でオススメの拡張機能や設定も紹介しています!
Version情報
- VSCode: 1.40.1
- Docker: 18.09.7
- docker-compose: 1.24.1
下準備
- VSCodeのinstall: Downloadページからサクッと
- Dockerのinstall: Community版をinstallしてnon-rootで動かす設定も
公式以外で詳しい説明はいろんな記事があると思うので、上記で不十分な方は各々調べてください。
環境構築のステップ
- Dockerfileを作成
- Pipfileを作成
- docker-compose.yml に実行環境用のbuild方法を記載
- Remote Developmentの拡張機能をinstall
- docker-compose.extend.yml にRemote Development特有の設定を記載
- .devcontainer.jsonに必要な設定を記述
- VSCodeでコマンド打ってbuild!!
1~3はプロダクトをDockerやPipenvを利用して運用している方は既に作ってあると思いますので、4まで読み飛ばしてください。ちょっと道のりは長いですが、快適環境を目指して頑張りましょう!
やり方解説
以下の構造で設定ファイルを記述していきます。それぞれのファイルの役割と作り方を順に解説していきます。{repo-name}はレポジトリ名、{tool-name}は開発ツールのroot directoryと読み替えてください。
{repo-name}
├── .devcontainer
│ ├── devcontainer.json
│ └── docker-compose.extend.yml
├── Dockerfile
├── Pipfile
├── docker-compose.yml
└── {tool-name}
Dockerfileの作成
恥ずかしながらそこまでDockerに詳しいわけではないので、ツッコミどころは多々あると思いますが、例えば以下のような形で環境を作ります。
# Python 3.8ならslim-busterがオススメらしい
# 参照: https://pythonspeed.com/articles/base-image-python-docker-images/
FROM python:3.8-slim-buster
# 環境変数とかを設定
ENV HOME /root
ENV TZ Asia/Tokyo
WORKDIR $HOME
# Pythonで利用するライブラリをいろいろinstall
# software-properties-commonとwgetは後段のclang 8のinstallに必要
RUN set -ex \
&& apt-get update \
&& apt-get install -y g++ git openssh-client wget libblas-dev liblapack-dev gnupg software-properties-common make
# clang 8のinstall
# numbaがllvmliteに依存しているので、clang 8系をまとめてinstall
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \
&& add-apt-repository "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-8 main" \
&& apt-get update \
&& apt-get -y install clang-8 lldb-8 lld-8 gfortran
# llvm-configへのpathを登録
ENV LLVM_CONFIG=/usr/lib/llvm-8/bin/llvm-config
# host key情報をknown_hostsに記載
# 参照: https://gist.github.com/gregdeane/56a7499fddac7251f01dcc9bb64e8486
RUN mkdir -p -m 0600 ~/.ssh \
&& ssh-keyscan github.com >> ~/.ssh/known_hosts
# Pipenv のinstall
RUN pip3 --no-cache-dir install pipenv
# 開発したいレポジトリ名でディレクトリを作っておく.
RUN mkdir {repo-name}
今回はGitHub上のprivate repositoryを開発することを前提としているので、Dockerfile内ではrepositoryのcloneや依存のinstallまでは行いません。docker-compose側で--ssh defaultのサポートがまだ行われていないので、別の方法でinstallします。もし、public repositoryで開発する場合は、Dockerfileでgit clone
やpipenv install --dev
も行ったほうが良いと思います。
Pipfileの作成
実行環境に必要なライブラリを追加しつつ、開発環境で必要なツール群は[dev-packages]
以下に記載しましょう。例えば、
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
Cython = "*"
joblib = "*"
numpy = "*"
scipy = "*"
scikit-learn = "*"
lightgbm = "*"
[dev-packages]
nose = "*"
coverage ="*"
flake8 = "*"
isort = "*"
Sphinx = "*"
sphinx-autodoc-typehints = "*"
autopep8 = "*"
setuptools = "*"
mypy = "*"
[requires]
python_version = "3.8"
こんな感じです。まずは実際に上記のDockerfileを元に docker run
をしてみて、このPipfileが正しく動作するかを確認してみましょう。
Remote Developmentの導入
Remote DevelopmentのTurorialを元にinstallします。これは以下のVSCodeのGUIから簡単にinstallすることができます。
簡単ですね。
docker-compose.yml に動作環境用のbuild方法を記載
上述のDockerfileをbuildするdocker-compose.yml
を作成します。build-arg
を指定する必要があるようなDockerfileの場合はここで設定してください。最もシンプルな例だと、
version: "3.7"
services:
dev:
build:
context: .
dockerfile: Dockerfile
のような形かと。
docker-compose.extend.yml にRemote Development特有の設定を記載
ここからが本番ですね。Remote Developmentをするのに必要な設定のみで構成されたdocker-compose.extend.yml
を作成します。次のセクションで作成する.devcontainer.json
で2つのyamlファイルを渡すことでそれぞれの設定が順番に適用された設定でbuildが行われます。例えば、
version: "3.7"
services:
dev:
volumes:
- ~/.ssh/id_rsa:/root/.ssh/id_rsa:ro
command: sleep infinity
のように作ります。
volumes
の項目ではlocalの公開鍵をRemote Developmentで利用するDocker imageにmountしています。なので、自身のlocal machineの公開鍵をGitHubに登録しておく必要があります。詳しいやり方はこちらを参照してください。繰り返しになりますが、public repositoryで開発する場合は認証がいらないので不要な項目です。
また、command
は今回必須です。これがないと、Remote Developmentはbuildだけして死んでしまうので…
.devcontainer.jsonに必要な設定を記述
ここまでくればもう一息です。上で作成したDockerfileのbuild方法などを指定するファイルです。以下に例と、それぞれのパラメータがもつ役割をコメントで記載していきます。
{
# Workspaceの名前になる.
"name": "{repo-name} DevEnv",
# 設定ファイルのありかを指定する場合に使うルートディレクトリ.
"context": ".",
# docker-compose upで利用されるymlへのpathのリスト.順番厳守.
"dockerComposeFile": [
"../docker-compose.yml",
"docker-compose.extend.yml"
],
# 開発環境用のbuild設定が記載されたdocker-compse.yml上のservice名.
"service": "dev",
"shutdownAction": "stopCompose",
# VSCodeのProjectになるroot directory.
"workspaceFolder": "/root/{repo-name}",
# Dockerのbuildが完了した際に実行するコマンド.ここでrepositoryのcloneとinstallを行う.
"postCreateCommand": "git clone -b {branch name} {GitHub url} . && pipenv install --dev",
# Remote Developmentで立ち上げた新たなVSCodeに適用する設定.
"settings": {
"autoDocstring.docstringFormat": "sphinx",
"autoDocstring.guessTypes": false,
"editor.formatOnSave": true,
"editor.suggestSelection": "first",
"git.autofetch": true,
"git.confirmSync": false,
"kite.showWelcomeNotificationOnStartup": false,
"python.formatting.autopep8Args": [
"--max-line-length=200"
],
"python.linting.pylintEnabled": false,
"python.linting.flake8Args": [
"--max-line-length=200"
],
"python.linting.flake8Enabled": true,
"python.linting.mypyEnabled": true,
"python.jediEnabled": false,
"terminal.integrated.inheritEnv": false,
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue"
},
# Remote環境で採用したい拡張機能のIDを登録しておくと、環境構築時に自動でinstallしてくれる.
"extensions": [
"ms-python.python",
"njpwerner.autodocstring",
"ms-azuretools.vscode-docker",
"visualstudioexptteam.vscodeintellicode"
]
}
Extensionについて補足すると、
njpwerner.autodocstring
Pythonで関数やクラスのdocstringを自動生成してくれるツール.Sphinxでドキュメントのhtmlを自動で生成したいので、"autoDocstring.docstringFormat": "sphinx"
でdocstringのstyleも設定しています。
visualstudioexptteam.vscodeintellicode
Python向けに補完などを非常に強力にやってくれる超便利ツール."python.jediEnabled": false
が必須の設定になります。
python.linting
Python3系でType Hintingを記載しないのは罪だと思っているので、"python.linting.mypyEnabled": true
は必須で、あとは今時のモニタでmax-line-lengthがデフォルトなのは読みづらくて仕方がないので、autopep8
とflake8
のそれぞれで"--max-line-length=200"
を指定しています。VSCodeのPythonのデフォルトのlinterはpylintなのですが、ぼくが使った時にimport周りでやたらハマった経験があったので、flake8を使っています。
という感じです。
VSCodeでコマンド打ってbuild!!
(Ubuntuの場合)VSCode上でCtrl + Shift + pでcommand windowを開いて以下のように Open Folder in Container...
を叩いて、
localのDockerfileがあるディレクトリを指定すれば、自動でbuildが始まってDocker Container上に構築された環境上で動くVSCodeが新たに立ち上がります。初回時はdockerのbuildやpipenv installに時間がかかるので辛抱強く待ちましょう。
最後にPythonのInterpreterがpipenvの環境を認識しないことがありますが、command windowからreload window
を実行すれば直ります。
これで開発環境は完成です!お疲れ様でした!!