devcontainerのremoteEnvでプロジェクト内の.devcontainer/binにPATHを通す

  • Dev Containers
  • VS Code
  • Setup

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

やりたかったこと

プロジェクト専用のちょっとしたスクリプトを .devcontainer/bin にまとめて置いておき、コンテナ内のターミナルからフルパスなしで叩けるようにしたかった。 Dockerfile で /usr/local/bin にコピーする手もあるけど、スクリプトを書き換えるたびにリビルドするのは面倒。ワークスペースをそのまま PATH に入れてしまえば、編集が即反映される。

結論

devcontainer.json の remoteEnv にこう書くだけで動いた。

{
"remoteEnv": {
"PATH": "${containerWorkspaceFolder}/.devcontainer/bin:${containerEnv:PATH}"
}
}
  • ${containerWorkspaceFolder} はコンテナ内でのワークスペースのパスに展開される
  • ${containerEnv:PATH} はコンテナにもともと設定されている PATH に展開される

既存の PATH を後ろに残しつつ、.devcontainer/bin を先頭に足す形になる。先頭に置いているので、同名コマンドがあればこっちが優先される。

containerEnv ではなく remoteEnv を使う理由

devcontainer.json には環境変数の置き場が containerEnv と remoteEnv の2つある。

  • containerEnv:コンテナ作成時に設定される。コンテナ全体に効くが、この時点ではまだコンテナがないので ${containerEnv:...} で既存の値を参照できない
  • remoteEnv:ツール(VS Code など)がコンテナに接続してからプロセスを起動するときに設定される。コンテナ側の既存の環境変数を ${containerEnv:...} で参照できる

既存の PATH に追記したいなら、参照ができる remoteEnv 一択になる。

remoteEnv が効く範囲

remoteEnv はツール経由で起動されたプロセスにだけ適用される。

flowchart LR
  subgraph applied["remoteEnv が効く"]
    T[VS Code ターミナル]
    E[拡張機能]
    L[postCreateCommand などのライフサイクルコマンド]
  end
  subgraph notApplied["remoteEnv が効かない"]
    D[docker exec で直接入ったシェル]
    C[ENTRYPOINT / CMD のプロセス]
  end

普段の作業は VS Code のターミナルなので困らなかった。ただ、ホスト側から docker exec で入ったときに「コマンドが見つからない」となるのはこれが原因なので、そこは割り切る。

ハマりそうなところ

実行権限

.devcontainer/bin 配下のスクリプトには実行権限が必要。ローカルで chmod +x しただけだと、ほかの人の環境や Windows ホスト経由で権限が落ちることがあるので、Git に権限ごと記録しておくと安心。

ターミナル
git update-index --chmod=+x .devcontainer/bin/example-script

ログインシェルでの PATH 上書き

ターミナルをログインシェル(bash -l など)で起動する設定にしていると、ベースイメージによっては /etc/profile が PATH を組み立て直して、追加した分が消えることがあるらしい。自分の環境では起きなかったので実機未確認。PATH が効いていないときは、まずシェルの起動方法を疑うといい。