先日、個人的なPython学習のための環境を作ろうと思った。
自分のマシンの環境を汚したくないし、Dockerで環境を作って、Visual Studio CodeのRemote Developmentでコードを書くことにした。
せっかくPythonの環境を作るのだからパッケージマネージャーのPoetryでライブラリをインストールしてやろうと考えた。
しかし、DockerコンテナにRemote Developmentで接続後にVisual Studio Codeのコンソールでpoetry
を実行するとpoetry: command not found
が表示される。
困った。
結論
先に結論を書いておくとVisual Studio CodeでLinux環境のターミナルを起動した時、デフォルト設定のままではログインシェルを起動しないので
~/.bash_profile
や~/.profile
が読み込まれない。
ログインシェルを起動したいのであれば"terminal.integrated.shellArgs.linux": ["-l"]
をsettings.json
に記述しなければいけない。
2021年6月25日追記
Visual Studio Code 1.57.1 で確認すると"terminal.integrated.shellArgs.linux"
などは動作するが非推奨扱いになっていた。
今後は"terminal.integrated.profiles.linux"
に対してシェルのプロファイル名を記述して詳細な設定を記載していくというスタイルになる様子。
さらに、ターミナルを起動したときに実行するデフォルトのプロファイルは"terminal.integrated.defaultProfile.linux"
で指定する。
settings.json
のサンプル:
...
// デフォルトで`"terminal.integrated.profiles.linux"`の`"bash"`をターミナルで起動させる。
"terminal.integrated.defaultProfile.linux": "bash",
// シェルのプロファイル名に対して`"path"`で実行するシェルのパスを指定し、`"args"`で起動時の引数を指定する。
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash",
"args": [
"-l"
]
},
"zsh": {
"path": "zsh"
},
"fish": {
"path": "fish"
},
"tmux": {
"path": "tmux",
"icon": "terminal-tmux"
},
"pwsh": {
"path": "pwsh",
"icon": "terminal-powershell"
}
},
...
何がやりたかったか
「Docker使うのに何でPoetry使うの?」と言われそうなのでPoetryを使う理由を先に書いておく。
残念ながら私が身を置いている環境ではDockerがまったくと言っていいくらいに使われていない。
もし、業務でアプリケーションを開発する際にPythonを使う機会があってもDockerを使える可能性は低いと考えられる。
この理由に基づいてPythonと一緒にパッケージマネージャーの使い方も学んでやろうと考えて、
PoetryをDockerコンテナの中で使うことにしました。
問題の仮想環境構成ファイル
Remote Development用に作成したファイルは、関連個所を抜粋すると大体以下のような内容だった。
{
"name": "Python 3",
"dockerComposeFile": [
"../docker-compose.yml",
"./devcontainer.extend.yml"
],
"service": "python",
"workspaceFolder": "/workspace",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintPath": "/usr/local/bin/pylint",
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.mypyEnabled": true,
"editor.formatOnSave": true,
"python.linting.lintOnSave": true
},
"extensions": [
"ms-python.python"
],
"shutdownAction": "stopCompose"
}
version: "3"
services:
python:
image: python
container_name: python
build:
context: ./docker/python
dockerfile: Dockerfile
version: "3"
services:
python:
volumes:
- ./:/workspace:cached
FROM python:3.8.1-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apt-utils \
gcc \
build-essential \
curl \
libpq-dev \
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
このような環境でRemote DevelopmentでDocker Compose upしていたが、
Visual Studio Codeのターミナルでpoetry
を実行しようとするとcommand not found
が表示される。
この時のPoetryはバージョン 1.0.5で、公式推奨のインストール方法に従って
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
を実行していた。
get-poetry.py
がPATH
にpoetry
を追加しているのだろうと中身を確認したところ
~/.bash_profile
と~/.profile
でPATH
に~/.poetry/bin
を追加していた。
ターミナルでcat ~/.profile
して中身を確認すると、export PATH="$HOME/.poetry/bin:$PATH"
はちゃんと書き込まれている。
「なんでpoetry
がcommand not found
になるんだ?」と考えながらsource ~/.profile
を実行すると、
それ以降poetry
コマンドは実行できてしまう。
手順に間違いがあるのだろうと考え、比較のために非推奨のpip install --user poetry
でインストールを行うも、
こちらもpoetry
コマンドは正常に実行できてしまう。
ここから「どこかに間違いや勘違いがあるからPATH
が通っていない」と思いながら四苦八苦を開始する。
この時、自分が使い慣れていないDocker周りに勘違いがあるのだろうという思い込みの元、
Dockerfile
にRUN . ~/.profile
を書いてみたりするなど試して間違いを重ねて時間を浪費する。
何が間違っているか分からないまま小一時間が経過し、嫌になってきたので「PATH
通せばいいや」と考え以下の変更を追加。
Dockerコンテナビルドして、poetry
コマンドが実行できることを確認。
FROM python:3.8.1-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apt-utils \
gcc \
build-essential \
curl \
libpq-dev \
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
+ # The path of poetry is added to PATH.
+ ENV PATH="/root/.poetry/bin:${PATH}"
普段からDockerをバリバリ使っているわけでは無いし、時間もあまり使いたくなかった(この時点で一時間使っているけど)。
原因究明は一旦あきらめて、Poetry周りの環境構築はとりあえずOKということにしておいた。
数日後
作業中にふと閃く、「cron
でありがちなログインシェルを経由していないせいで発生する~/.bash_profile
経由しないとコマンドが動作しない現象と同じだ・・・」。
「Visual Studio CodeがRemote Developmentしている時のシェル設定はどこだ」と思ったが、
自分で.devcontainer/devcontainer.json
に"terminal.integrated.shell.linux": "/bin/bash"
を書いていることに気が付く。
しかし、該当設定値はシェルの指定だけのようで/bin/bash
を指定しているが、-l
オプションの指定は別の設定の様だった。
Visual Studio CodeのSettingsを開くと、"terminal.integrated.shellArgs.linux": []
が見つかる。
「デフォルト設定でログインシェル読み込まないのか」と思っていると、
Mac OSは"terminal.integrated.shellArgs.osx": ["-l"]
がデフォルトになっている。
念のためにドキュメントを確認すると__親切に書いてる。
Integrated Terminal in Visual Studio Code
You can pass arguments to the shell when it is launched.
For example, to enable running bash as a login shell (which runs .bash_profile), pass in the -l argument (with double quotes):
// Linux
"terminal.integrated.shellArgs.linux": ["-l"]
.devcontainer/devcontainer.json
に
terminal.integrated.shellArgs.linux": ["-l"]
を追加し、
Dockerfile
に追記したENV PATH="/root/.poetry/bin:${PATH}"
を削除。
DockerコンテナリビルドしてRemote Development起動し、poetry
コマンドにPATHが通っている事を確認。
そして、ここまで事実確認ができたことで、これはLinux OSでVisual Studio Codeのターミナル使ったときに、
いつでも発生する問題なのでは無いかと思い当たり、検索をかけるといくつも事例が出てくる。
- VSCodeのRemote-SSHでリモート先のLinuxのbash_profileを読み込む - Qiita
- vscodeのterminalで.bash_profileが読み込まれない - Qiita
- bash - VSCode Integrated Terminal Doesn't Load .bashrc or .bash_profile - Stack Overflow
完全に自分の見落としだった。