
以前、ある開発者のマシンでしか発生しないバグを追いかけるのに、スプリント全体を費やしたことがあります。原因は、些細なNode.jsのバージョン不一致でした。私たちは3日間、会議、コードレビュー、そしてイライラするデバッグセッションに時間を費やしました。解決策が見つかってしまえば、修正は5分で終わりました。
その経験が、私の開発環境に対する考え方を変えました。
「私のマシンでは動く」という問題は、何十年もの間、私たちの業界を悩ませてきました。私たちはあらゆることを試しました。凝ったセットアップスクリプト、詳細なREADMEファイル、数週間で腐ってしまうWikiページ。何も定着しませんでした。Dev Containersに出会うまでは。
Dev Containerは、Dockerベースの開発環境で、一度設定すればチームの全員が全く同じものを使えるようになります。コードは、必要な依存関係、ツール、設定がすべてプリインストールされたコンテナ内で実行されます。
仮想マシンと考えるとわかりやすいですが、より軽量で使い捨て可能です。単一の設定ファイルで、破壊したり、再作成したり、共有したりできます。
設定はプロジェクトのルートにある.devcontainerフォルダに置かれます。その中に、ベースイメージ、チームが必要とする拡張機能、および作成後のスクリプトを定義します。誰かがVS Codeでプロジェクトを開くと、コンテナ内で再度開くように促されます。ワンクリックで準備完了です。
複雑に聞こえますか?私も最初はそう思いました。
Dev Containersを使う前、私はNode.jsプロジェクトで働いていました。チームの半分はmacOSを使い、半分はLinuxを使っていました。問題ないように聞こえますよね?しかし、私たちのネイティブモジュール依存関係は、プラットフォームごとに異なる方法でコンパイルされていました。数週間ごとに、誰かのローカル環境がずれていきました。
新しい開発者が、私たちのフロントエンドをビルドするだけで2日間も苦労していたのを覚えています。オンボーディングドキュメントは8ページもありました。何ヶ月も必要なかった手順が記載されていました。何かが変更されるたびに、誰もが更新を忘れていました。
これは珍しい話ではありません。開発者が環境との戦いに費やす時間は、機能開発に費やされない時間です。
その美しさはシンプルさにあります。この構造から始めましょう。
your-project/
├── .devcontainer/
│ ├── devcontainer.json
│ └── Dockerfile
devcontainer.jsonファイルは、すべてがまとまる場所です。私が最初に使った基本的な設定は次のとおりです。
プロジェクトのルートに.devcontainer/devcontainer.jsonを追加します。このファイルは、開発コンテナをビルドして接続する方法をエディタに指示します。
スタックに合ったDockerイメージを選択します。Node.jsプロジェクトの場合、私は通常mcr.microsoft.com/devcontainers/javascript-nodeから始めます。Microsoftのリポジトリには、ほとんどすべての人気のあるスタックのイメージがあります。
featuresプロパティを使用して、カスタムのDockerfileコマンドを記述することなく、一般的なツールを追加します。Git、Docker CLI、またはデータベースツールが必要ですか?それぞれ1行で済みます。
チームが必要とするVS Code拡張機能をリストアップします。これらはコンテナが起動すると自動的にインストールされます。私のJavaScriptプロジェクトには、常にESLint、Prettier、およびDocker拡張機能がインストールされます。
私の実際の構成の1つは次のようになります。
{
"name": "My Project Development",
"image": "mcr.microsoft.com/devcontainers/javascript-node",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
これだけです。14行で、私のチーム全体が同じ環境で作業できます。
この方法で設定されたプロジェクトを初めて開くと、エディタ(VS CodeまたはCursor)が設定を検出します。Dockerイメージをビルドし、コンテナを作成し、それに接続します。あなたはホストマシンではなく、コンテナ内で作業しています。
ターミナルは、そのコンテナ内のbashセッションになります。拡張機能もそこで実行されます。ファイルシステムはホストからマウントされているため、通常通り編集できますが、実行はコンテナ内で行われます。
最初のビルドには数分かかります。その後は、コンテナの起動は数秒で済みます。
Dev Containersはオーバーヘッドを追加するだろうと予想していました。動作が遅くなったり、複雑になったりするだろうと思っていました。しかし、私が発見したのはその逆でした。
私のチームは、その後の数ヶ月で3人の新しい開発者をオンボーディングしました。彼らは皆、リポジトリをクローンしてから20分以内にコードを書き始めていました。「Xのインストールを手伝ってくれませんか」とか、「Yのバージョンは何ですか」といった質問もなく、謎もありませんでした。
また、環境関連のバグも完全に発生しなくなりました。全員が同じOS、同じツール、同じバージョンで実行していれば、その種の種類の問題は単純に消滅します。
生産性の向上は、目に見える形で劇的ではありませんでした。スプリントレポートに載るようなものではありません。しかし、私はより小さなこと、例えばセットアップの問題に関するSlackメッセージの減少、フロー状態での時間の増加、コードレビューの迅速化といった点でそれに気づきました。
私は経験を通じて、Dev Containersが最も輝く場所を学びました。
チームプロジェクトが最も恩恵を受けます。複数の開発者が同じコードベースに触れる場合、環境の一貫性は複合的な利益をもたらします。
オンボーディングの状況は明らかな勝利です。私がこれまで見てきた新しい採用者は皆、従来のセットアップドキュメントに従うよりも早く生産的になっています。
複雑な依存関係が管理しやすくなります。データベース、キャッシュ、または特殊なツールを必要とするプロジェクトは、最適な候補です。
CI/CDのパリティは隠れた利点です。本番ビルドがコンテナで実行される場合、開発コンテナを使用すると、開発者は同じ問題をローカルで捕捉できます。
しかし、常に解決策となるわけではありません。簡単な個人的なスクリプト、単一ファイルの実験、使い捨ての探索には、この儀式は必要ありません。
ベースイメージをあまりカスタムにしすぎないでください。私は一度その間違いを犯し、依存関係が変更されるたびに再ビルドに20分かかるイメージを構築しました。確立されたベースイメージに固執し、その上にカスタマイズを追加してください。
シンプルに始めましょう。私の最初のdevcontainer.jsonは過度に複雑でした。使わない機能やスクリプトがたくさんありました。必要なときにだけ追加してください。
ホストファイルシステムはマウントされますが、大きなnode_modulesフォルダではパフォーマンスが低下する可能性があります。これに遭遇した場合は、Microsoftのドキュメントでキャッシュ戦略を調べてください。
私たちは、環境の不整合を共同ソフトウェア開発の避けられないコストとして許容してきました。Dev Containersは、私にとってその前提を変えました。
毎日使い始めて3年になりますが、昔の方法に戻ることは想像できません。数ヶ月に一度、不要だと反論する新しい開発者が現れます。彼らは皆、最初の1週間で考えを変えました。
「私のマシンでは動く」という言い訳?それは私たちのチームの語彙から消えました。もう凝ったオンボーディングドキュメントは必要ありません。「昨日までは動いていた」というデバッグセッションも必要ありません。
標準のDockerコンテナはアプリケーションのランタイム(Nodeサーバーなど)を実行します。Dev Containerは、コンテナを完全な開発環境に変え、IDE拡張機能、開発者CLIツール、デバッガー、言語サーバーをコンテナ内に直接インストールします。
.devcontainer/devcontainer.jsonファイルは、VS Code Dev Containers拡張機能に、Dockerイメージのビルド方法、ホストポートのマッピング、プロジェクトボリュームのマウント、ワークスペース設定と拡張機能の自動構成方法を指示します。
macOS/Windowsでのバインドマウントのパフォーマンスオーバーヘッドを解消するには、VS CodeのDev Containers: Clone Repository in Named Container Volumeコマンドを使用して、リポジトリを名前付きDockerボリュームに直接クローンします。
ある開発チームは、環境設定のための詳細なREADMEを使用しているにもかかわらず、異なる開発者のマシン間でビルドの失敗や依存関係の競合が頻繁に発生しています。彼らはDev Containersの導入を検討しています。このシナリオにおいて、Dev Containersが直接解決する最も重要な現実世界の問題は次のうちどれですか?
AI CLIログの整形、Cron式の作成、JWTの解析、chmod権限の計算をオフラインで実行。

Turborepoリモートキャッシュを大規模運用するための包括的なガイド:Pruned Dockerビルド、GCSキャッシュ、CIパイプライン高速化を本番環境レベルのアーキテクチャとコード例で解説します。
続きを読む
Astral uv、マルチステージターゲット、BuildKit永続キャッシュマウント、軽量runtimeイメージを活用して、Python Dockerビルドを数分から数秒に高速化します。
続きを読む
マルチコンテナアーキテクチャ、マルチステージDockerfile、healthcheckによる起動順序制御、環境シークレット管理、BuildKitキャッシュマウント、本番環境を模倣したネットワークなど、ローカル開発向けDockerComposeの包括的な設定ガイドです。
続きを読む