ローカルを汚さずに Web開発するための Devcontainer テンプレート
devcontainerテンプレート
devcontainerを使って開発したいなと思っていたが、 devcotnainer環境を作りたいモチベーションがいくつか出てきたので早速立ち上げてみた。
目的
以下の4つが主なモチベーションになる。
- ホスト環境を汚したくない
- macOSとWindowsの両方で開発するので、環境を一致させたい(WindowsでDBを立てて、macOSでも同じものを構築し直すのは面倒)
- 昨今話題のnpm周りのサプライチェーン攻撃を踏まえて、悪意あるパッケージを入れてしまった場合のリスクを少しでも抑えたい
- CLI型のAIエージェントが暴れ回っても、ホスト環境への被害を最小限に抑えられるようにしたい
ホスト環境を汚したくない
これは個人の好みだがホストにDBを構築したりNodeのインストールの数が増えたりするのがあまり好みじゃないという理由
MacとWindowsの両方で開発するので、環境を一致させたい(WindowsでDBを立てて、macOSでも同じものを構築し直すのは面倒)
これが大きいかもしれない。気分でWindowsとMacで開発するPCを変えるので、そのたびに環境構築するのは面倒という理由。
あとは単純に開発環境(OS)が完全に一致する点でも、おま環がなくなるのでストレスはなくなりそう。
昨今話題のnpm周りのサプライチェーン攻撃を踏まえて、悪意あるパッケージを入れてしまった場合のリスクを少しでも抑えたい
昨今話題ではあるが、npmのパッケージに悪意のあるスクリプトが含まれていたとき、ホストにある重要な情報などが盗まれることなどもありえるだろうが、ホストと隔離されていることもありある程度防げるかと思う。
ただ、devcontainerだからといって完全に安全になるわけではないが、1Passwordでの秘密情報管理と組み合わせつつ被害の範囲を限りなく抑えるような取り組みはしていきたい。
CLI型のAIエージェントが暴れ回っても、ホスト環境への被害を最小限に抑えられるようにしたい
CLI型のエージェントが意図しないファイルの削除などを行うのを自分は体験してはないがそういった話はよく聞くので、devcontainerであれば完全に削除されても復元可能な点で安心できる部分はある。
devcontainerの前準備
構成の話の前に軽く構築手順をメモ。
- Docker DesktopをインストールしたらWSL2を疎通させる。
Docker Docs - Turn on Docker Desktop WSL 2
- VSCodeでDevcontainerの拡張機能を入れる。
Visual Studio - Dev Containers
全体構成
現状は以下の構成としている。
- モノレポ前提
- パッケージマネージャはpnpm
- ランタイムはbun
- mise
- DBはPostgreSQL
Dockerfileの構成
ベースイメージ
UbuntuとDebianで迷ったが、 Ubuntu はいろいろ入っていて安心感がある。 Debianは余計なものが少なそうで、コンテナを圧迫したくないという理由で選んだ。
正直、ディストロの差異を感じるほど使い込んだこともないのでひとまずDebian系としている。
{ "name": "devcontainer-monorepo-template", "dockerComposeFile": "docker-compose.yml", "service": "app", "workspaceFolder": "/workspace", "remoteUser": "root", "forwardPorts": [5432], "postCreateCommand": "mise install", "customizations": { "vscode": { "settings": { "terminal.integrated.defaultProfile.linux": "bash" }, "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] } }}devcontainerが作成された直後に実行される、postCreateCommandでmise installを実行して以下をインストールしている。
[tools]node = "24"bun = "1.1.26"pnpm = "9.12.2"
[tasks.dev]run = "pnpm dev"
[tasks.build]run = "pnpm build"あとはdockeignoreで不要なファイルをDockerのビルドコンテキストに含めないというのを以下の記事を見て行った。
「そのDockerfile、卒業しよう」実務で通用するベストプラクティス
Dockerfile の最適化で見落とされやすいのが、ビルドコンテキストに含まれる不要ファイルです。 Dockerはdocker buildの際に現在のディレクトリ(コンテキスト)を丸ごと送信するため、余計なファイルが多いほどビルドが遅くなり、イメージにも不要物が含まれやすくなります。
【npm】11月21日以降にnpm installした人へ - Shai-Hulud感染チェック & 多層防御ガイド
蒸気を参考に、pnpm-workspace.yamlに以下を記述している
minimumReleaseAge: 2880公開から間もないパッケージ乗っ取り -> 悪意ある新バージョン公開のような公開直後に踏む事故を避けるために、公開されてから2880分(2日)経っていない新しいバージョンは 更新・インストール対象にしないという設定。
あくまで保険的な役割だが、npmのサプライチェーン攻撃が流行してしまっている以上やれることはやっておきたく、全てのプロジェクトで共通の設定になるようにテンプレートに組み込んでおく。
devcontainer CLI
上記はVSCode拡張機能でdevcontainerを利用することを想定していたが、最近VSCodeからWezterm + neovimに開発環境を移行したこともあり、devcontainer CLIを導入した。
以下はmiseで導入した例
"npm:@devcontainers/cli" = "latest"mise insallまたは
mise use -g devcontainer-cli@latestdevcontainer CLI + neovim前提なら、SSH agent sockは転送する必要なくなった(git操作はhomeのzshで行えばいいので)。というより、VSCodeでもそういうことは出来たけどVSCodeとターミナル両方開かなきゃいけないとこに不便さは感じていたのだが、そのあたりはターミナル完結できる上に不必要にSSH agent sockをdevcontainerに転送する必要なくなったのも大きい。
結論、正直使わないかもしれない
ここまでやっておいてだが、 正直個人でdevcontainer使うのは安全性と引き換えに開発効率が落ちるのでやりたくない。
dotfilesを見てもらえるとわかる通り、開発効率を上げるためのzshプラグインやneovim、weztermの設定など色々入れているがもちろんこれはdevcontainer内では使用できない。
dotfilesをdevcontainer起動時にクローンして展開できることも知っているが、 にしてもプロジェクトごとにそれを展開するとなるとコスパの悪さが目立って、それならホストでいいじゃんって思ってしまう。
それに加え、基本すべてのプロジェクトの.envの環境変数などは1Passwordに保管し、1Password CLIで参照してくる運用なのだが、devcontainerに1Password CLIを入れる(そしてビルドする度)と必ず最初にアカウント接続の作業をしなければならなく、かなり面倒に感じるという側面もある。
ので、正直このテンプレはめったなことがない限りはおそらく使用しない。