😎

WSL2でdevcontainerで気が付いたこと

に公開

はじめに

devcontainerのやり方のネタは、
https://www.youtube.com/watch?v=EWvQEGWgO2s&list=PLL8RZJqj2LQcwlF83dVnrg9edepcOZPZ6
この再生リストの動画のうち、
1本目、2本目までの動画の知識でやってみた。
3本目の動画は特殊なすごいやり方のようだが、それは実践してない。
1本目、2本目までの動画は、ハンズオンで、そのとおりになるのを体験した。
3本目の動画は、個人的に環境の準備がなく、動画の視聴にとどめた。

1本目、2本目までの動画で身に着けたことに基づき、

今回、実践したのは、
元々、直Dockerでdocker-compose.ymlにて
docker composeで環境作ってたものを
devcontainerの環境にしてみて、同じようにアプリが動作するところまでを実践してみた
一応、同じようにアプリが動作するところまで、確認できた。
のを実践した。

環境は、
Windows 11 proのWSL2環境。( Windows側とipアドレスを共有する「ミラーモード」にしてます )
Racher DesktopでのDocker環境
この環境で、
docker-compose.ymlを準備し、
ターミナルで直接、「docker compose なにがし」のコマンドで作ってる環境
★ devcontainer環境との対比で、以後、「 直のDocker環境 」と、当記事内で称することとする ★
その「 直のDocker環境 」で、
動作させていたLaravelのwebアプリが既にあった。

そのLaravelのwebアプリを、
今回は、devcontainerの環境で動作させる状態にしていった。

まず、はじめに、
Laravelのwebアプリに対して、VSコードを開くフォルダの
直下に、.devcontainer/devcontainer.json
を作って置いた。
前述の動画を参考に、VSコードの機能で自動生成したものより、
手編集を加えたもの

必要に応じて、
そのファイルを別名に適当にリネーム後に、再度、VSコードの操作より
自動生成させたdevcontainer.jsonを作っては、
先ほど、リネームした分との、いいところどりで、マージしたもので、動かす。

問題があり、設定を変更したい事があるたびに、
そのような事を繰り返していった。

ベースが出来上がってきたら、もう自動生成はせず、手編集後に、
再度、リビルドのみを繰り返すようになっていった。

VSコードでのdevcontainerでの
コンテナ内での環境で、
Laravelのcomposer installや、php artisan系のコマンドでの環境構築など
をやってる際中に、異変に気が付いたら、また、
devcontainer.jsonをブラッシュアップしていくようなやり方。

何度も、失敗しながら、最終形の満足いく形となり、
元の直Docker環境と、devcontainer環境で同等に動作し、開発作業が行える状況までこぎつけた。

上記の一連の
環境構築の作業中に、苦戦したこと。
それを解決していく中で、気が付いたことを、当記事に書いて記録に残すことにした。

一番、最初に苦戦したのは、VSコードのdevcontainerで作られたコンテナやイメージが行方不明になったこと。

直Dockerの環境では、
docker compose stop で、一括でコンテナを停止
docker compose down で、一括でイメージまでの削除
までやるのが、簡単にできる

今作業中のコンテナや、イメージが要らなくなったときに、
dockerのvolumeや、networkなど、その他もろもろ、一式について
きれいに、お掃除して、
後始末をきっちり、やっておかないと

同一、PC内の他のものを動作させようとしたときに、干渉して
エラーで、コンテナを作れないとか、起動しない
などが、Dockerを使ってるときによくあることだと思います

しかし、だからと言って、Docker環境内のものをがっつり全部削除みたいなことは
したくないですよね。

今、作業に必要なもの以外も全部消えたら、別のものは、
はじめから時間かけて、ダウロード、ビルドのやりなおしになるじゃないですか

だからといって、dockerコマンドを使って、正味、該当する分をきれいにお掃除していく
作業が、煩雑極まりないため、

docker compose stop で、一括でコンテナを停止
docker compose down で、一括でイメージまでの削除
までを、簡単に、正味、該当分だけ、お掃除できるのが

直Dockerで、docker composeでやってるときには、ありがたかったわけですよ

これがあるから、安心して、気軽に何個も環境を並列して作れるわけですよ。
( もちろん、コンテナ名や、ホスト側のポートは、重複しないようにの変更調整は要りますけど )

しかし、VSコードでdevcontainer環境で、作ると・・・
docker-compose.ymlを読み込ませての一括作成や、起動をしたのにも関わらず、

ホスト側のその、docker-compose.ymlの配下で、
docker compose psで、それらが表示させようとしても
表示されない状況になっていた。
つまり、ホスト側からのdocker composeからの制御から外れてしまってる
( VSコードのdevcontainer経由は、該当のdocker-compose.ymlを利用してやってるにもかかわらず )

devcontainer経由だと、docker-compose.ymlを利用しても
元の環境ではなく、/tmpなどに一時的なファイルを作って、それらの
よくわからないデータを通じて、イメージや、コンテナを作って起動するような
動きになり。
元のホスト側のターミナルでのdocker-compose.ymlの配下の場所で
docker compose psで、それらが表示されない状況になっていた。

これは、もしかすると、Mac環境ではそんなことはないのかもしれません。( そこはわかりません )
WSL2特有の事象かもしれません。
( ここは、Macユーザにどうでしたかと、状況を聞いてみたいところ・・ )

一括で簡単にお掃除する術がなく、普通のdockerコマンドとgrepコマンドを組み合わせて
該当しそうなものを探しては、停止したり、削除したりして
お掃除をしていた。
お掃除しないと、devcontainer.jsonなどを変更し、リビルドしようとしたときに
中途半端に残ってるものと、干渉して、途中でエラーにしまうことが頻発した。
しかも、お掃除ちゃんとやったと思ったら、
まだ、残ってるものがあったらしく、
それが、あるときは、volumeだったり、また、別の、あるときは、別のものだったり
法則性も見いだせず、毎回、お掃除が不十分のため、リビルドしては失敗して
あれ、あれ?って、毎度、試行錯誤で悩まなければならなくなった。

これは、メンドクサイ!! なんとかならんかなー。
って思ってました。

まず、これをどう解決するか、devcontainerの環境の中身をどう設定するかの
問題以前に、ここをなんとかしなければ、作業効率悪すぎで
前進しにくい状況でした。

また、あらかじめ、ホスト側で、
docker compose build --no-cache
docker compose up -d
のコマンドを打ち込んで、ホスト側で制御できる状況にしたものに
対して、VSコードからアタッチするようなやり方をとった場合は、
devcontainer.jsonの設定値が有効にならず、
devcontainerでやってる意味がそもそもないです。

ですから、
VSコードのdevcontainerのやり方経由で、docker-compose.ymlを通じて
起動したものたちについて、

ホスト側で、なんとか、それを認識して
docker compose stop で、一括でコンテナを停止
docker compose down で、一括でイメージまでの削除
に相当する、簡単、お掃除ができるやり方を

なんとかして、見つけなければならないという状況に直面しました

解決策見つけた!! しかし、まずは、docker composeで作られた「プロジェクト名」を取得する必要あり、そこを順を追って説明する

詳しいことは知らんけど
dockerでは、作られたコンテナやイメージにプロジェクト名なるものが
付与されたりするらしい。

そして、docker composeで起動されたものに関しては
それ、直Dockerでのターミナルからの起動であろうが、
VSコードのdevcontainer経由であろうが、

必ず、com.docker.compose.projectの文字列をlabel情報として保持しているとのこと。

だから、
docker ps --filter "label=com.docker.compose.project" --format "{{.Label "com.docker.compose.project"}}" | sort | uniq
で、docker composeで作られているもののプロジェクト名の一覧を得ることができる
それは、コンテナが起動してなくて、イメージだけ残ってるものも対象として
リストを得ることができる
たいてい、プロジェクト名は、ホスト側で
docker-compose.ymlを置いてるフォルダ名がそのまま、プロジェクト名になってるようだ。
そういう仕様なのか知らないが、経験則でそうなってるように見えた。

実際の例として、

$ docker ps --filter "label=com.docker.compose.project" --format "{{.Label \"com.docker.compose.project\"}}" | sort | uniq
chousa_kankyo_joint_develop_docker
dev-container_joint_develop_docker
laravel_next_docker
$
となった。これ実際に実行して表示された例です。

実際問題、
/myDocker/chousa_kankyo_joint_develop_docker
直下に、docker-compose.yml
があり、直Docker ( devcontainerでない )
環境を作っている
これは、コンテナは起動してないが、作られたイメージなどが
環境に残っていた
その、chousa_kankyo_joint_develop_docker
の、フォルダ名がプロジェクト名として表示されている

また、
/myDocker/dev-container_joint_develop_docker
直下に、docker-compose.yml
がある。
今回、このdocker-compose.yml配下の領域の
/myDocker/dev-container_joint_develop_docker/src/laravelapp
をVSコードで開いて、
/myDocker/dev-container_joint_develop_docker/src/laravelapp/.devcontainer/devcontainer.json
で、
"dockerComposeFile": "../../../docker-compose.yml",
の記述をした状況で、
/myDocker/dev-container_joint_develop_docker
直下の、docker-compose.yml
を参照しながら、
devcontainer経由で、コンテナを起動していた。
そのdevcontainer経由で起動したものが、
/myDocker/dev-container_joint_develop_docker
配下で、docker compose psしたら、表示できない。
つまり、行方不明で、ホスト側から制御できない。
「docker compose なにがし」での、簡単、お掃除ができない
問題点がありました。
その dev-container_joint_develop_docker
のフォルダ名がそのまま、プロジェクト名として表示されている

また、
/jit_myDocker/laravel_next_docker
直下に、docker-compose.yml
があり、直Docker ( devcontainerでない )
環境を作っている

環境内でdocker composeで作られたプロジェクト名のリストが取得できて、なにが嬉しいのか

直下に、docker-compose.ymlを置くフォルダ名を
PC内で重複がないように、さえ、気を付けていれば

docker ps --filter "label=com.docker.compose.project" --format "{{.Label "com.docker.compose.project"}}" | sort | uniq

を打ち込めば、行方不明になっていた
devcontainer経由で、作成されたものの、プロジェクト名を一意に特定できることを意味している

【 これが、肝なんです 】、ここがミソなんです!!

では、解決策の結論を言います。

ようやく、そのときが、来た!!

解決策は、「 docker compose -p 「プロジェクト名」 「なにがし」 」は、「docker compose 「なにがし」」ができることは、全て、できる事を利用すること!!

だから、今回の環境での例で示すと

docker compose -p dev-container_joint_develop_docker stop
で、一括でコンテナを停止
docker compose -p dev-container_joint_develop_docker down
で、一括でイメージまでの削除

での、簡単、お掃除ができてしまうということなんです!!

実際やった状況は、以下のとおり
ホスト側のWSL2のターミナル上で、
devcontainer経由で起動して行方不明になってたものを「-p プロジェクト名」によって
ちゃんと認識してとらえて、お掃除できてます。

$ docker ps --filter "label=com.docker.compose.project" --format "{{.Label \"com.docker.compose.project\"}}" | sort | uniq
chousa_kankyo_joint_develop_docker
dev-container_joint_develop_docker
laravel_next_docker

上記で、環境内のdocker composeで作られているプロジェクト名の一覧を取得する

$ docker compose -p dev-container_joint_develop_docker stop
[+] Stopping 3/3
 ✔ Container jo_adminer      Stopped                                                                               0.7s
 ✔ Container jo_laravel_app  Stopped                                                                               0.0s
 ✔ Container jo_laravel_db   Stopped                                                                               0.0s
$ docker compose -p dev-container_joint_develop_docker down
[+] Running 4/4
 ✔ Container jo_adminer                                Removed                                                     0.0s
 ✔ Container jo_laravel_app                            Removed                                                     0.1s
 ✔ Container jo_laravel_db                             Removed                                                     0.0s
 ✔ Network dev-container_joint_develop_docker_default  Removed                                                     1.1s
$

再度、プロジェクト名の一覧を取得すると、
$ docker ps --filter "label=com.docker.compose.project" --format "{{.Label \"com.docker.compose.project\"}}" | sort | uniq
chousa_kankyo_joint_develop_docker
laravel_next_docker

今度は、dev-container_joint_develop_dockerは、表示されません。
イメージまで、ちゃんと消えて、
正味「dev-container_joint_develop_docker」の分だけ、お掃除が完了したからです。

これで、VSコードのdevcontainerで「rebuild」や、「rebuild without cache」
が、安心して、できます。

ちゃんと、お掃除してからの実行となるため、
残ってる何かがある事が、原因でのエラーに悩まされなくなります

docker compose -p dev-container_joint_develop_docker down
のときに、

 ✔ Network dev-container_joint_develop_docker_default  Removed                                                     1.1s

のようなものが削除されましたよね。
普通のdockerコマンドや、grepを駆使して、探して、お掃除してたときに、
この手の何かが、残ってて、その法則性が見いだせず
毎回、なんでや、なんでや、とエラーと格闘してたのが、つらかったわけです

それが、
「 docker compose -p 「プロジェクト名」 「なにがし」 」
のやり方で
devcontainer経由で作成の、いったん、行方不明になるものが
簡単に、きれいにお掃除できる状況となり、

ようやく、devcontainerの中身の環境をどうするかに集中できる状況となったのです。

これが、最初の大きな、前進でした!!

ただし、時々、リビルド時にエラーにはなります。
これは、既知で、たいてい、それは、再試行したらなおります。
問題ないです。
お掃除が不十分なのが原因のときは、やりなおしても、無理です。
だから、ハマってたのです。

でも、お掃除が不十分の理由でのエラーがなくなったため
やりなせば、いけるということが、わかりきった状況になったので、大きな前進です。

また、他の環境を作ったときに、干渉しないように、今作業中の環境について
VSコードを閉じたうえで、お掃除をしておきたい
となったら、簡単ですね。

結局、docker composeを利用してる状況で、
コンテナ名と、ホスト側のポート番号が、PC内で重複しないように配慮しなければ
ならないのであるが、それは、お掃除が完了しているものについては、
気にしなくてもよいということです。
つまり、お掃除が完了しているものと、「コンテナ名と、ホスト側のポート番号」が
重複した設定で、別の環境を作って起動することはできるわけです。

ですから、長期間、もう使わないな
と思う環境は、きれいにお掃除しておきたいわけです。

元々、直Dockerで、docker composeでしてたときは、
既に、ノウハウがあったわけですが、

今回、devcontainer経由で、一旦、行方不明になるものも含めて
簡単に、きれいに、お掃除できる方法が見つかった。
というわけなんです。

これを見つけたときは、本当に、ガッツポーズがでました。
それぐらい、切望してたノウハウだったわけです。

本当に、説明するのが、メンドイ話でした

どのような問題があったのかの経緯から説明しないと、
なんのために、こんなことしてんの? ってなるし、理解してもらえない

文章だけで、これを説明するとなると、このような長文にならざるを得ない。

ここからは、別の話題になります。

devcontainerでのXdebugがyesだとXdebug使わない人に影響がある

まず、前提の話からすると、
docker-compose.ymlにて、appのコンテナについてはDockerfileで作る構成にしていて
Dockerfile内でXdebugをインストールしてる
ホスト側でXdebugの設定が含まれたphp.iniを準備しておき、
Dockerfile内に記載したコマンドで、それをコンテナの中の所定の位置にコピーしている

php.ini内で、
xdebug.start_with_request=yes
にしていた。
これは常に、Xdebugが有効になってるモードである。

Xdebugが有効の時、
VSコード内の「PHP Debug」のプラグインがインストールされている状況で、
下記の「.vscode/launch.json」を準備しておく必要がある。
下記の9011は、php.iniの「 xdebug.client_port=9011 」の設定値と同期をとる必要がある。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",

            // ミラーモードでないWSL2は必要だが
            // ミラーモードのWSL2なら不要。
            // 他、WSL2以外も不要。
            // "hostname": "0.0.0.0",

            "port": 9011,
            "pathMappings": {
                "/var/www/html/laravelapp": "${workspaceFolder}"
            }
        }
    ]
}

この状況で、デバッガーを起動しておけば、
コンテナ内部のphpのランタイムが動作時に、Xdebugが動作して
上記の9011での接続をコンテナから、ホストの「PHP Debug」のプラグインへの
接続の通信を確立させての、リモートデバッグを機能できる。

上記の環境ができてなくても、
直Dockerの環境では、特に弊害がなかった。
厳密には、弊害はあるが、
単に、その通信が、ごく短時間でタイムアウトし、警告がでるだけなのである。

しかし、devcontainerの環境では、
Xdebugが
xdebug.start_with_request=yes
で常に有効な状況で、上記の
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
これらをうち、1つでも、やってない状況で
php artisan なにがし
を打ち込むと、固まってプロンプトが返ってこない現象が発生した。

launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
をやれば、
php artisan なにがし
が固まることがない

これは、Xdebugを利用しない人には、影響がある。
別に、Xdebug要らない、使わないって人がチーム内にいたとき
チーム内で環境統一を図る目的で、devcontainerを導入時に、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
を、Xdebugが要らないという人にも、強制することになってしまう。

そこで、
Xdebugを使わない人は、面倒な設定しなくても、無影響
Xdebugを使いたい人は、設定して、そして、使いたいときに使える
これをdevcontainer環境で実現するやり方が必要になった。

devcontainerでのXdebugはtriggerにしとくべき

devcontainerでのXdebugの環境を構築時は、
php.ini内では、
xdebug.start_with_request=trigger

にしておくべき
triggerは、ある「きっかけ」があるときだけ、
Xdebugが有効になる。

そのきっかけは、
CLI環境で、php artisan系のコマンドなどでは、
(php artisan系のコマンドを自作して、そのコードをXdebugでデバッグ実行したい時もあるでしょう)
VSコード内のターミナルで
export XDEBUG_SESSION=1
をしておくこと。
これをしていない場合は、
Xdebugが有効でないから、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
をしなくても、
php artisan なにがし
が固まることがない
Xdebugを使わない人には、無影響である。

一方、
Xdebugを使いたい人は、
export XDEBUG_SESSION=1
をしたうえで、
php artisan なにがし
をすればよい
ただし、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
してなかったら、
php artisan なにがし
が固まるよ。
でも、問題ない。だって、Xdebugを使いたい人が
意図して、
export XDEBUG_SESSION=1
するのだから
その人は、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
すればよいのである。

また、

ホスト側でchromeブラウザで、http://localhost:8080などでアクセスして
アプリを動作させる際には、

Chromeのブラウザに、
Xdebug Helper by JetBrains 1.0.3
のプラグインをインストールして、


図のとおり、Debugのボタンを押して、これが緑色になっていたら
Xdebugが有効である。

Xdebug Helper by JetBrains 1.0.3
で、Debugが緑のとき

図のように、
Cookieに、XDEBUG_SESSIONが登録されている

この状況であればXdebug有効なのである

これも、Xdebugを使わない人は、別にこんなことしないだろうし、
その場合は、Xdebugは有効ではないため
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
してなくても、
アプリが固まることがないため
Xdebugを使わない人には、無影響である

一方、
Xdebugを使う人は、
Xdebug Helper by JetBrains 1.0.3
で、Debugを押して緑にすればよい
そしたら、
Xdebugは有効になるので、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
してなかったら、アプリの動作は固まってしまう
でも、問題ないです
Xdebugを使いたい人が、意図して
Xdebug Helper by JetBrains 1.0.3
で、Debugを押して緑にするのだからです。
その状況で、
launch.jsonの準備や、
「PHP Debug」のプラグインのインストール
デバッガーの起動
して、アプリのデバッグ実行(ステップ実行)すればよいのです。

直Dockerでは、Xdebugが有効なのに、準備が整ってない場合は、
ごく短時間でタイムアウトし、警告がでるだけで、ほぼ影響なしだが
devcontainerでは、固まってしまう、
そのため、yesだと、Xdebug使わない人に影響があり、
Xdebug使わない人にまで、準備作業を強要してしまうので、それはよくない
だから、Xdebugをtriggerにして、
Xdebug使わない人には、無影響な状況として
Xdebug使いたい人が、所定の準備をして、使える状況

として、devcontainer上でXdebugの環境を作っておくのが、よろしいでしょう。

<追記>
★★★★★★★★★★★★★★★★★★★★★★★★★★★★
APIを開発時にpostmanでの動作確認を行ってる際に、
Xdebugがtriggerのものを発火させる方法としては、

Headersタブで、
Key: XDEBUG_TRIGGER
Value: yes などの任意の文字列
を指定しておくとのこと。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★

devcontainerでは、VSコードでコンテナ内にログインしターミナル操作をするユーザはUID=1000、GID=1000のユーザとしておくのがお作法。

表題のお作法は、何か?
マイクロソフトが、
devcontainerでは、UID=1000、GID=1000のユーザで、コンテナにログインし、
VSコードのターミナルでは、UID=1000、GID=1000のユーザで作業することを推奨している。

仮に、Dockerfileそのままでは、UID=1000、GID=1000のユーザは作られず、
デフォルトでは、rootユーザでログインするようになってたとしても、

devcontainer.jsonにて、
ghcr.io/devcontainers/features/common-utils
のfeatureを下記のようにすれば、
ユーザ名:vscode で、
UID=1000、GID=1000のユーザをコンテナに作ってくれる。
元のDockerfileでの構築が完了後に、追加で、そのユーザ作成をしてくれる。

	"features": {
		"ghcr.io/devcontainers/features/common-utils:2": {
			"installZsh": true,
			"installOhMyZsh": true,
			"installOhMyZshConfig": true,
			"upgradePackages": true,

			// 2025/03/23
			// "automatic"だと、UID=1000のユーザがない場合は、
			// rootでのログインになってしまう。
			// FROM php:7.4-apache がベースには、
			// UID=1000のユーザがなく
			// Dockerfileにも、UID=1000のユーザを追加する記述もない
			// "username": "automatic",
			// "userUid": "automatic",
			// "userGid": "automatic"

			// 下記の記述をしておけば、
			// vscodeでUID=1000, GID=1000のユーザをコンテナに作ってくれる
			"username": "vscode",
			"userUid": 1000,
			"userGid": 1000
		}
	},

また、
ghcr.io/devcontainers/features/common-utils
は、sudoコマンドが使えるように初期設定してくれる

UID=1000、GID=1000のユーザがvscodeのケースで、

$ sudo cat /etc/sudoers.d/vscode
vscode ALL=(root) NOPASSWD:ALL

上記のように、vscodeがパスワードなしでsudoコマンドが使えるように
/etc/sudoers.d/vscode を初期設定してくれる

devcontainer.jsonにて、下記のように書くことで
VSコードがターミナルをコンテナで起動する際に、そのログインユーザがvscodeになる。

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
	// 2025/03/23 追記。
	// コンテナログイン時のユーザを"vscode"にする。
	"remoteUser": "vscode"
}

devcontainerを使わず、
直Docker環境で、コンテナにrootでログインする設定になっていて、
そのままrootにログインして、コンテナ側で作業したとする。
その際、実行ユーザがrootで、ホスト側のフォルダをマウントした領域で
コンテナ側から、ファイルや、フォルダを作成したとする。
コンテナ側で、それらのファイルや、フォルダは所有者がrootになる。

この場合、それらのファイルがホスト側で見たときにどうなっているかの話だが、

Linuxや、WSL2の環境の場合、ホスト側でも、それらのファイルや、フォルダは
root所有になっている。よって、ホスト側で操作している一般ユーザで
それらのファイルや、フォルダに対しての操作は権限エラーになってしまう
それを回避するため、

https://zenn.dev/tazzae999jp/articles/07bed12c3ae6c0#posix-acl
にて、POSIX ACLで、
ホスト側の一般ユーザに対して、「ls -l」でのパーミッションがどうあれ、
gitのローカルリポジトリのルートより、末端を対象として、
問答無用でフル権限を与えておけば、root所有のファイルや、フォルダに対しても
追加、変更、削除が行えるので( POSIX ACLの設定が優先され、勝ちます )
この問題を回避できる。
一度、設定しとけば、その後、配下に、ファイルや、フォルダが作成されても
自動的にそれらも対象になる。
特に、この権限問題は、gitでのプルや、ブランチの切り替えや、マージなど実ファイルや、
フォルダに対する、追加、変更、削除を行う操作のときに、
権限エラーになってしまう問題として、表面化していた。
それを、POSIX ACLで解決していたのであるが、
それは、あくまで、直Dockerの話で、devcontainer環境でのお作法としては
マイクロソフトが、Linuxや、WSL2のユーザに配慮し、
UID=1000、GID=1000でコンテナにログインして、作業するように推奨している
というのは、
Linuxや、WSL2で初期の一般ユーザを作成時
(PCの所有者自身が通常使う初期の一般ユーザで一番最初に作る一般ユーザの話です )
ほぼ、UID=1000、GID=1000で作られる
そして、多くの場合、このUID=1000、GID=1000でホスト側のターミナルで
開発作業を行うのであるから
devcontainer環境にて、コンテナ側で、UID=1000、GID=1000のユーザでログインしてれば、
コンテナ側でファイルや、フォルダを作成する作業をしても、
ホスト側で、見た時も、所有者がUID=1000、GID=1000として
一致した状況となり、所有者が異なることによる権限問題のトラブルにならないのである。
これが、マイクロソフトがdevcontainer環境で、UID=1000、GID=1000方式とする
ことを推奨している理由である。
なお、UID=1000、GID=1000のユーザについて、ホストとコンテナで、ユーザ名が違うのは
問題ない。Unixや、Linux系でネットワーク越しでのユーザが一致してるかどうかを判断に
使われるのは、UIDや、GIDであって、ユーザ名は、その判断としては意識されないからだ。

Macユーザの場合は、一番最初の初期ユーザはUID=500だったりするとのこと ( 知らんけど )
でも、★ Mac環境は、後述する理由で、権限エラーはおきない ★
そうであれば、コンテナ側のログインユーザは、Macユーザにとっては、
何でもいいわけですから
それなら、マイクロソフトが推奨しているお作法通りに、
devcontainer環境は、UID=1000、GID=1000方式でやっとけよって、ことです。
(そうじゃなかったら、そうしろや、タコ!! って、突っ込まなければならい。この記事読め!!って)
(そうなってない環境が連携されたら、WSL2のユーザはローカルだけで変更調整したり、)
(この話をして、なおしてくれ、と相談したりしなければならなくなる。)

ところで、上述の、★ Mac環境は、後述する理由で、権限エラーはおきない ★
について、詳しく説明すると、
そもそも、DockerはLinuxのカーネルでしか動作しない。
WSL2環境では、WSL2の共通のLinuxカーネルで、
Dockerや、Ubuntuなどのディストリビューションが動作している
DockerはLinuxのネームスペースの仕組みで、隔離、分離しているだけのもので、
コンテナがホストのある領域をマウントするといっても、
同じカーネル上で動作してる別のプロセスがただ、参照してるだけ
ファイルシステムも、ともにext4だから、余計な仲介処理や変換処理が一切なく
直接的なため非常に高速である。こういう背景で、コンテナとホストで
ファイルや、フォルダの所有者のUID、GIDが常に一致するのであろう
一方、
MacはLinuxではない、Darwinと称されるBSD系のUnixの一種である
そもそも、DockerはLinuxのカーネルでしか動作しないため、
直接、Dockerを動作させることができない。
そのため、Limaとか、hyperkitと称されるようなVM ( 詳細は知らんけど )
で、Linuxカーネルを動作させて、そこでDockerを動かしている
Docker for Macは、本体のMacとは、
共有ファイルの仕組みをつかって、くっつけて、マウントを実現している。
それゆえ、マウントが、Linuxや、WSL2環境でのDockerを使うときとの比較で
低速である。
最近、virtioFSという高速なファイル共有がでてきて、かなり、マシになったとのことだが
それ以前の、osxFSや、Fuseなどと称される仕組みでのファイル共有の時代は
Mac環境でDockerは、ぜんぜん、使い物にならなく、涙ぐましい努力をされていたとのこと
( 意図的に、マウントするファイルや、フォルダのサイズを減らすとか、開発してるタスクに応じて、
要る分だけ、マウント対象にするなどの、めんどいことをやって凌ぐなど )

そして、このvirtioFSが、意図して、そうしてるのか、
たまたま、バグってそうなってるのか、知らんけど。
コンテナ側でroot所有や、他のユーザの所有となるようなファイルや、フォルダを作っても、
ホスト側では、そのとき、作業してる一般ユーザ(おそらく、Dockerを起動したユーザではないか )
の所有であるかのように見せるような動きになってる

Macユーザは、どうせ、ホストの一般ユーザがUID=500などだったとして、
devcontainer環境で、UID=1000、GID=1000で作業してても、
上記のvirtioFSが、ホスト側で見たときに、UID=500の所有者であるかのうように
見せてる環境で、所有者違いの権限問題がおきないのだから、
devcontainer環境で、UID=1000、GID=1000でやっとけよ!!
って、ことです。

virtioFSが、「ホスト側で見たときに、UID=500の所有者であるかのうように見せてる」
ような動きについて、
意図して、そうしてるなら、かしこいと思うんですが、
不具合のような状態でそうなってるのではないか。( その可能性もある )

実際、virtioFSは、RedHatが開発した仕組みとのことで、
( Dockerとか関係なく、) virtioFS単体で見たときに、
aplfsとext4との間のファイル共有で、権限などをうまく同期がとれないようなバグの報告が
あるとのこと。
virtioFSは、こういったところを緩くやって、厳密にはしないことで、
高速化を図ってるような代物らしいです
そして、そのvirtioFSを、Docker for Macが採用したが、ゆえに
コンテナ側でのログインユーザがrootになってしまうような環境であろうが
Macでは、権限問題おきないとのこと。( 意図してなのか、不具合のようなもので結果としてかは不明 )

そして、ここまで、いろいろ、記載した諸事情を知ってから知らずか
わからんけど、Macの環境では問題なかった環境を、「 問題がない環境 」と称して、
チーム内にLinuxや、WSL2のユーザがいても、おかまいなしにその環境で連携するなどすれば
WSL2のユーザは、gitでブランチ切り替えとかしたときに、root所有のファイルが
動かせずに、突然、gitのコマンドがエラーになる。なんでや!!
ってなってしまうんだよ!!
それを、WSL2ユーザとしては、仕方がないから、
POSIX ACLで解決してあげてるわけで!!

そんなん、おかしいやろ!!
( 環境差異があるなら、本来、本番環境に近いLinux側にあわすべきだろ。そういう意味でおかしい )
ということで、
devcontainer環境については、UID=1000、GID=1000でのコンテナログインの方式で
やっとけよ!!
というのを、マイクロソフトが推奨しているんだと思います!!

そして、世の中には、Dockerfileがそもそも、その多くが、上述のMacユーザが作ったからなのか
一般ユーザ作らず、rootで、直で、ログインする設定になってるDockerfileが
たくさん、あるため、それらをコピペ元にして、量産されたDockerfileも
おそらく、そうなってたりする。

だから、devcontainer環境は、そんなDockerfileで構築された
コンテナであっても後から、追加的に、UID=1000、GID=1000のユーザを
作って、それでログインするような仕掛けや、
root以外でログインしても困らないように、
sudoが使えるようにしたり、UID=1000、GID=1000をパスワードなしでのsudoersに
登録したりの仕掛けなどが、devcontainer.jsonで、簡単に、できるようになっている

補足:
composer install とか、
php artisan なにがし とか、
npm install とか、
設定系でも、アプリの設定系は、UID=1000、GID=1000のユーザにて行い

sudo apt update
sudo apt install なにがし
のようなシステム系の設定は、sudoで(実行ユーザがrootにて)行う

ということ。

そういうの利用して、

devcontainer環境については、UID=1000、GID=1000でのコンテナログインの方式で
やっとけよ!!
というのを、マイクロソフトが推奨しているんだと思います!!

本当に、説明するのが、メンドイ話でした。

devcontainerはどうやら、開発環境のみで、そのままを本番環境にしないようである。

あくまで、devcontainerは開発環境の利便
開発環境をあわせる。
複数の開発環境をPCに作っても、干渉しあわないように分離する

そういう目的らしい

ですから、devcontainerは、開発環境での諸事情だけ考えればよい

だから、↓↓↓↓↓ の話題に続くのであるが。

devcontainerでLaravelの環境構築時、「storage」、「bootstrap/cache」は、apache実行ユーザの所有に変えず、UID=1000、GID=1000の「chmod 777」でよいのが現実解。

https://zenn.dev/tazzae999jp/articles/0934afe501db0c#storageディレクトリの所有者をapache実行ユーザにするのはlaravelの開発環境構築のお作法

にて、「storage」、「bootstrap/cache」フォルダは、
所有者をapacheの実行ユーザ(www-dataだったりする。)すべきだと書いた

apacheの実行ユーザで、Laravelのアプリが動作するため
「storage」、「bootstrap/cache」のフォルダに書き込み権限がないと、
実行時にエラーになる

本番環境意識したら、「storage」、「bootstrap/cache」フォルダは、
所有者をapacheの実行ユーザにしとくべきで、

開発環境もそうしたほうがよいという意味で↑↑の記事で書いたが、

それは、直Dockerでコンテナにrootでログインしている場合の開発環境なら
なら、それでよいと思うです

「storage」や、「bootstrap/cache」の
所有者が「apacheの実行ユーザ」で、775や、755だったとき、

普通のユーザで、php artisan なにがし
を実行した結果、
「storage」にログ出力や、「bootstrap/cache」に何かが
出力されるような時、書き込みできません。

ということになってしまいますが、

rootは、そもそも、スーパーユーザで、そんな場合でも書き込みできないの権限エラーにならないため

直Dockerでコンテナにrootでログインしている場合の開発環境なら

「storage」や、「bootstrap/cache」の
所有者が「apacheの実行ユーザ」で、775や、755でよい

という意味です。

ただ、
devcontainerでUID=1000、GID=1000でコンテナにログインすると、

「storage」、「bootstrap/cache」フォルダの所有者が、www-dataだと不都合がある。
それは、
php artisan なにがし
を、UID=1000、GID=1000のユーザで実行するからです。

php artisan なにがし
は、「storage」、「bootstrap/cache」フォルダの中への書き込みを伴うことが多い
多くの場合は、ログであるが、cacheの場合もある
その際、「storage」、「bootstrap/cache」の所有者がwww-dataで
php artisan なにがし
の実行ユーザが、UID=1000、GID=1000だと書き込みができなくなる。
結果として、
php artisan なにがし
自体がエラーになってしまい、やりたいことができなくなる。

「UID=1000、GID=1000」のユーザか、www-dataのいずれかが、他方のグループにも
所属させるようにすれば解決できるかもしれないし
POSIX ACLを駆使して調整すれば、解決できるかもしれないが、

そこまで、しなくても、
「storage」、「bootstrap/cache」に対して
sudo chmod -R 777 をしておいて、
所有者は、UID=1000、GID=1000 にしておけば、十分だろう

devcontainer環境は、開発環境専門のものであるから、その割り切りで構わないだろう。

Discussion