VS Code の Remote - Containers プラグインを使うと Docker の中で開発ができて最高だよ、という記事を読んで面白そうなので触ってみた。
ちょっとぐぐったら、このプラグインに関する記事がいっぱい出てきた。結構前から人気なのね。知らなかったや。
## Remote - Containers って何なの?
は、だいたいこんな印象。Remote - Containers プラグインが VS Code Server をコンテナの中にインストールして、ローカル側の VS Code がその VS Code Server とコミュニケーションする。
それによって、実際はコンテナの中にある開発環境が、あたかもローカルにあるみたいな気持ちで VS Codeを使うことができる。だから、ローカル側に例えば PHP を入れてなくても、VS Code では PHP のプラグインを動かして、コード補完やデバッグ実行などができる。便利。
- VS Code の UI 拡張はローカル側で、Workspace 拡張はコンテナ側で動くらしい。雰囲気は分かる。
- Docker のポートをローカル側にマッピングしておけば、Webアプリの動作確認なども可能。ですよね。
## Dockerfile or docker-compose.yml ?
最初に触ってみたときは少し戸惑った。
ローカルのソースコードは自動でコンテナの中にマウントされるっぽいのにされないし、ポートは特に devcontainer.json に書かなくてもマッピングされてそうだし、んー?ってなった。
けど、しばらく触ってみて、あぁ、これって Dockerfile を使ってる場合と docker-compose.yml を使ってる場合で設定の方法が違うっぽいな。と気づいた。僕は docker-compose.yml を使ってた。
もうしばらく触ってみて分かったのは、Dockerfile だけではできない部分を devcontainer.json で設定できたり、 Remote - Containers プラグインが自動的にサポートしたりしてるってこと。ポートのマッピングとか、ボリュームのマウントとか、環境変数の指定とか。ほほー。
docker-compose.yml を使う場合は、そういうサポートをほとんど必要としない。元々 Docker Compose にそういう機能がだいたい備わってるから。
じゃ、どっちを使おうかなと考えたんだけど、 docker-compose.yml を使えば Dockerfile でできることはカバーできるだろうから、 Dockerfile よりも docker-compose.yml を使う方向で進めてみることにした。
## やらないこと
- メインで使う言語は、ローカルマシンで環境を整えたいなと思うので、このプラグインでは僕は使わないだろうなと思った。なので Java で使うつもりはない。今回は PHP で試してみてる。
- 実行中のコンテナや k8s のコンテナにアタッチすることもできるみたいだけど、やらない。docker-compose.yml を用意してコンテナをビルドするー。
- 複数プロジェクトで1つのコンテナ設定を共有することもできるみたいだけど、やらない。プロジェクトごとにコンテナ設定を用意する。
- 設定は
.devcontainer/devcontainer.json
か.devcontainer.json
のどちらかが選べるけど、後者は使わない。ディレクトリを用意する。中に色々置きたいから。
さて、進もう。
## Docker Compose を使う場合の情報
を知りたいなという観点で、公式ドキュメントを読んだ。で、満足した。2020-06-07 時点の情報。
こういう観点でメモを残しておこうと思う。ほぼ忘れているであろう来月の自分のため。
- (1) devcontainer.json の仕様 (for docker-compose.yml)
- (2) Dockerfile を使った場合と docker-compose.yml を使った場合の違い
- (3) その他、覚えておきたいことのメモ
## (1) devcontainer.json の仕様 (for docker-compose.yml)
https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference
に仕様が書いてある。docker-compose.yml を使う場合は、以下の部分だけを知ってれば良さそう:
"Docker Compose" の部分
dockerComposeFile
- 文字列または配列。必須。
- devcontainer.json からの相対パスで docker-compose.yml を指定
- 元々存在しているファイルなどを書き換えずに拡張したい場合には、複数ファイルを指定することが可能で、その場合は配列で指定。
- プロジェクトのルートから .env を読み込むっぽい。docker-compose.yml の
env_file
で別のファイルを指定できるっぽい。
感想
- たぶん僕は配列での複数ファイル指定は使わないし、基本的には .devcontainer の下に docker-compose.yml を置くと思うので docker-compose.yml と書くだけになりそう。
- Laravel みたいに .env を使ってる場合は、変な感じにならないといいんだけどな。覚えとこ。
service
- 文字列。必須。
- docker-compose.yml の中のどのサービスに VS Code が接続するかを指定
感想
- この設定自体は問題ないんだけど、ここで指定した以外のサービスは起動するのかな?どうなのかな?と思ったら次に書いてあった。
runServices
- 配列
- docker-compose.yml の中のどのサービスを実行するか
- デフォルトは全てのサービス
感想
- 基本的に docker-compose.yml には起動したいサービスを書くので、この設定は書かないだろう。デフォルトの動きで問題ない。
workspaceFolder
感想
- そだね。マウントしたソースコードのフォルダーを指定すると思う
remoteEnv
感想
- 今の所、必要なさそう。
remoteUser
- 文字列
- リモート側の VS Code を実行するユーザー
- デフォルトはコンテナが使うユーザーと同じ
感想
shutdownAction
none
またはstopCompose
。stopCompose
がデフォルト。- VS Code (Remote) が閉じられたときに、コンテナを停止するかどうか
感想
- VS Code (Remote) を閉じたら docker-compose は停止してほしいので、デフォルトのままでいいな。
General の部分
General の部分にはこれ以外にも指定できる項目があるけど、 Docker Compose 使うならこれくらいで大丈夫だと思う:
name
- 文字列
- 表示名
感想
- 適当で大丈夫。
extensions
感想
- コンテナ側で開いた後にプラグインを右クリックすると devcontainer.json に追加できるので、そこから追加するのが楽
- 例えば PHP だと PHP Extension Pack を追加したりとかそういうの
settings
- VS Code の設定を書いておける
感想
- PHP Extension Pack の設定とかあったら書いておくと便利なのかな
postCreateCommand
- 文字列または配列
- コンテナの作成が終わって起動するときに実行したいコマンドを書いておくことができる
感想
- ソースコードもマウントされた状態で実行されるので
composer install
とか書くと良さそう - 毎回なのかな?1回だけなのかな?と思ってみてみたら1回だけっぽいな。
/root/.vscode-server/data/Machine/.postCreateCommandMarker
というファイルがなければ実行してそのファイルを作成するっぽい。
結局
のところ、書くのはこれくらいだな:
{ "name": "My PHP Application", "dockerComposeFile": "docker-compose.yml", "service": "php-fpm", "workspaceFolder": "/workspace", "extensions": [ "felixfbecker.php-pack" ], "settings": [], "postCreateCommand": "composer install" }
.devcontainer の中身
.devcontainer ディレクトリの中に docker-compose.yml を入れて、その隣にビルドに必要な Dockerfile などを置いておくのが好きだなと思った。こんな感じ:
❯ tree .devcontainer .devcontainer ├── devcontainer.json ├── docker │ ├── app │ │ └── Dockerfile │ └── web │ └── default.conf └── docker-compose.yml
## (2) Dockerfile を使った場合と docker-compose.yml を使った場合の違い
以下の設定は docker-compose.yml を使う場合は devcontainer.json じゃなくて docker-compose.yml の設定で書く
でも、デフォルトの動作が Dockerfile を使う場合と異なり、 docker-compose.yml では明示的に指定しないといけないこともある。
起動コマンド
Dockerfile の場合はコンテナのデフォルトコマンドを上書きして /bin/sh -c "while sleep 1000; do :; done"
にしてしまうらしい。コンテナが終了してしまわないように。
でも docker-compose.yml の場合は自分で command
にこれを指定しないといけない。
# プロセスが終了してコンテナが終了してしまわないように上書きする command: /bin/sh -c "while sleep 1000; do :; done"
ただ、今回僕が使ってみたのは php-fpm のコンテナでコマンドが終了しないので、これはやらなくても良さそう。
ボリュームマウントのタイプ
MacOS の場合は Remote - Containers プラグインはデフォルトでボリュームマウントの consistency に cached を使うらしいんだけど、docker-compose.yml を使う場合は明示的に指定しないといけない(んだと思う):
volumes: - ..:/workspace:cached
cached はホストOS側の変更がコンテナ側に伝わるのに遅延があるけど、パフォーマンスが良くなる。
Use bind mounts | Docker Documentation
コンテナユーザーの UID/GID
僕は Ubuntu を使ってるんだけど Linux の場合はボリュームマウントを使ったときに、コンテナのユーザーの UID/GID でファイルが書き込まれてしまうから例えば root ユーザーを使うと全部 root で書き込まれてしまう。Mac だとホスト側のユーザーになるんだけどね。Windows は知らないけど Mac と同じなんじゃないかなと予想。
なので Linux でボリュームマウントを使うときは UID/GID を指定しておかないといけない。Remote - Containers で Dockerfile を使ってる場合は自動でホスト側の UID/GID を使ってくれるみたい。いいなぁ。 docker-compose.yml の場合はそういう対応はないので、自分で指定する。僕のユーザーは 1000 だからユーザーさえ指定してれば基本的には大丈夫だけど。
## (3) その他、覚えておきたいことのメモ
Git
https://code.visualstudio.com/docs/remote/containers#_sharing-git-credentials-with-your-container
- Git はコンテナの中に入れておくと良さそう。VS Code が変更点とかを表示してくれるから。
- でも push とかの操作はローカル側からやろうかな。SSH キーのことを考えたり、コンテナの中のターミナルを自分に合うようにするの面倒だし。
とはいえ、コンテナの中から Git を使うのに便利なように考えてくれてる。
なので、特に気にせずに Git を VS Code (Remote) の中で利用できそうではある。
Named Volume
https://code.visualstudio.com/docs/remote/containers-advanced#_improving-container-disk-performance
Mac や Windows のボリュームマウントは遅いので、 vendor や node_modules のようにファイルがたくさん置かれるものを bind してしまうと読み込みがすごく遅くなってしまう。
かといってボリュームを使わなかったら毎回クリアされてしまって、毎回 composer install
でライブラリーを引っ張ってくるのは、ない。
ということで、 named local volume を使う。そうすれば bind はされないけどコンテナを再起動しても情報は残る:
version: '3' services: app: build: docker/app working_dir: /workspace volumes: - ..:/workspace:cached - app-vendor:/workspace/vendor (...) volumes: app-vendor:
root 以外でコンテナを実行している場合は postCreateCommand
で初回にオーナーを更新しておく:
"postCreateCommand": "sudo chown user-name-goes-here vendor"
だいたいこれくらい知っておけば良さそうかなぁ。