これは何?
前記事では,AIエージェントを企業で導入するにあたって,コンテナを使ってAIエージェントを隔離することでセキュリティを担保庵を検討した。
今回の記事では,実際にDev Containersを使って開発環境をコンテナ化するにあたってのベストプラクティスをまとめた。
Dev Containersとは
Dev Containersを使うと,Docker Container内でVS Codeを開くことができ,コンテナ内のソースコードを直接編集できる
- Dev Containers起動時に設定ファイルに記載のあるVS CodeのExtensions等も一括でインストールできる --> チームで開発環境を統一しやすい
- Dockerfileやcompose.yamlを汚さずにツールのインストールや設定変更ができる
- GitHub Codespacesを使用する際にDev Containeersを選択することで,環境構築を自動化できる。
Dev Containersをとりあえず試したい方
サンプルリポジトリを更新したのでこちらを参照されたし。
AIエージェントをDev Containers内で使用するメリット
前記事を見てもらったほうが良さそうだが,一旦箇条書きしておく。
- コンテナ外のリソースを意図せずに破壊される心配がない
- コンテナのほうがクラウドやVDIと違い,ローカルで実行できるのでネットワーク遅延の影響を受けにくい
- Dev Containersは開発環境をコンテナ化する上である程度枯れている。
AIエージェントが使用しやすいDev Containersの設定とは?
AIエージェント≒人間がストレスを感じにくいということを意識して,開発環境をコンテナ化したい。
基本的には今まで言われていたことと変わらない気はするが以下の3つの観点で本記事は記載する。
Dev Containersを使う前に
Multi Stage build使ってDev Containers用の環境を作る
基本的にデプロイされるコンテナに不必要なものは含めたくないので,Multi Stage buildを使ってDev Containers用の環境を作ることが推奨される。
Dockerfileでtargetを指定
-
compose.yamlを使わず,Dockerfile使う場合にはdevcontainer.jsonでtargetの指定ができる。
FROM mcr.microsoft.com/devcontainers/ typescript-node:22-bookworm AS devcontainer # target名を指定する
-
.devcontainer/devcontainer.jsonでtargetを指定する
A string that specifies a Docker image build target that should be passed when building a Dockerfile. Defaults to not set. For example: "build": { "target": "development" } 1
{ "name": "dev-container-test", "build": { "dockerfile": "Dockerfile", "target": "devcontainer" }, }
compose.yamlを使ってtargetを指定
compose.yamlを使う場合にはtarget
をcompose.yaml側で指定するためにDev Containers用に.devcontainer/compose.yaml
を作成する必要がある。2,3
# compose.yaml
services:
react-app:
build:
target: devcontainer // targetを指定
context: ./
dockerfile: Dockerfile
image: react-img-devcontainer:latest
container_name: react-container-devcontainer
FROM mcr.microsoft.com/devcontainers/typescript-node:22-bookworm AS devcontainer # target名を指定する
compose.yamlのservices
名をdevcontainer.jsonのservice
に指定する。
{
"name": "dev-container-test", // 任意の名前
"dockerComposeFile": [
"../compose.yaml",
"compose.yaml"
],
"service": "react-app", // compose.yamlのサービス名
}
コンテナとローカルの差異を減らす
Dev Containers公式イメージを使う
公式イメージを使うことで,通常のコンテナをベースにするよりもある程度開発で使用されるツールがインストールされている。
Dev Containers公式イメージがいくつかの言語ではサポートされている。
例えば,base-debianはbuilderpack-depsをベースにして作成されている。
builderpack-depsとは,ビルド時に必要なパッケージをまとめたイメージ。
A collection of common build dependencies used for installing various modules, e.g., gems.4
dotfilesを使い,設定ファイルをローカルと共通化する
dotfilesは設定ファイルやスクリプト等をまとめたリポジトリのこと。
e.g. .bashrc, .gitconfig, .vimrc, etc.
VSCodeの個人用のsettings.jsonに以下を参考に記載することでdotfilesをDev Containersに持ち込むことができる。5
.gitconfigは何もしなくてもDev ContainersのHOMEディレクトリにコピーされる。
// Dev Containersでdotfilesを使う。
"dotfiles.repository": "https://github.com/RyosukeDTomita/dotfiles.git", // fixme
"dotfiles.targetPath": "~/dotfiles", // fixme
"dotfiles.installCommand": "install.sh", // fixme ~/dotfilesのrepository topからみたスクリプトのパスを指定する。
dotfiles.installCommand
には~/dotfilesのrepository topから見たスクリプトのパスを指定する。
そのため,dotfilesのGitHub Repositoryにinstall.shは配置が必要。自分のdotfilesのinstall.sh
dotfiles TIPS
Dev Containerの環境では,REMOTE_CONTAINERS=true
が環境変数に定義されており,これを使ってDev Containerかどうかを判別できるためローカル用とDev Containers用で処理を分けることができる。dotfilesのinstall scriptでREMOTE_CONTAINERS=trueで分岐する例
VS Code ExtensionsをDev Containersに持ち込む
devcontainer.jsonに記載することで,コンテナビルド時に自動でVS CodeのExtensionsをインストールでき,コンテナビルド時に毎回Extensionsを手動でインストールしなくて良くなる。
Extensionsを追加する方法
Extension IDを.devcontainer/devcontainer.jsonに記載する。
"extensions": [
"formulahendry.auto-rename-tag",
],
DevContainerに自分だけが使用するExtensionsを持ち込む
- 個人用のsettings.jsonに記載することで,リポジトリの設定を変更せずにExtensionsを追加できる。
// Dev containersに個人的に使うExtensionsを入れる。
"dev.containers.defaultExtensions": [
"vscodevim.vim"
],
Extensionsの設定をどこに記載するか
- devcontainer.jsonと.vscode/settings.json両方に記載ができる。
- 基本はリポジトリ配下の.vscode/settings.json配下に設定を記載するで良いと思っている。
Dockerfileを汚さずにDev Containersにツールをインストールする
features一覧から使用可能なツールを探すことができる。
devcontainer.jsonにfeaturesを記載することで,ツールをインストールすることができる。
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/guiyomh/features/vim:0": {},
"ghcr.io/dhoeric/features/hadolint:1": {}
},
features一覧に記載がないツールに関しては
postCreateCommand
にinstallコマンドを記載する。
おまけ: コンテナのportを開放する設定について
devcontainer.jsonでportを開放する方法は3つある。
-
addPort
は非推奨。forwardPorts
を使う方が良い。In most cases, we recommend using the new forwardPorts property. 6
-
forwardPorts
を使うことで,コンテナのポートをローカルにフォワードすることができる。 -
portAttributes
を使うことで,portに関連する追加属性を設定することができる。
2025年3月に動作検証したところ,ローカルのVS CodeではportAttributeのみでportフォワーディングが可能だった。
しかし,GitHub Codespacesを使う場合にはportAttributes
のみではportフォワーディングがされなかった。
forwardPorts
も追加すると自動的にportフォワーディングされる
実際に公式ドキュメントにはforwardPorts
のみしか記載がなく7,forwardPorts
とportAttributes
を併用することが推奨される。
{
"name": "dev-container-test", // 任意の値
"dockerComposeFile": [
"../compose.yaml",
"compose.yaml"
],
"service": "react-app", // compose.yamlのサービス名
"workspaceFolder": "/app",
"forwardPorts" : [5173, 5173],
"portsAttributes": {
"5173:5173": {
"label": "Vite application",
"protocol": "http",
"onAutoForward": "notify"
}
},
"postStartCommand": "cd react-app/ && yarn dev --host 0.0.0.0",
}
サービスをコンテナビルドなしで再起動可能にする
Dev Containersを起動しつづけるために永続コマンドが必要であるが,このサービスの再起動が必要になった場合には,コンテナの再ビルドが必要である。
CMD ["nginx", "-g", "daemon off;"]
しかし,これは非効率的なので,Dev Containersにはコンテナのイベントをトリガーしてコマンドを実行する機能8を使い,サービスの再起動を可能にすることができる。
-
OverrideCommand
をtrue
に設定することで,コンテナを永続化することができる1。 -
postStartCommand
でサービスを起動することで,コンテナの永続化にサービスが使われなくなり,再起動が可能になる。
{
"name": "dev-container-test",
"dockerComposeFile": [
"../compose.yaml",
"compose.yaml"
],
"service": "react-app",
"workspaceFolder": "/app",
"overrideCommand": true,
"forwardPorts" : [80, 80],
"postStartCommand": "nginx"
}
ビルド時間を短くするには
以下の2軸でビルド時間を短くできる。
- imageサイズの縮小
- キャッシュの有効活用
References
-
https://containers.dev/implementors/json_reference/#general-properties ↩ ↩2
-
https://github.com/microsoft/vscode-remote-release/issues/7810 ↩
-
https://stackoverflow.com/questions/78421879/devcontainer-docker-compose-best-practice ↩
-
https://code.visualstudio.com/docs/devcontainers/containers#_personalizing-with-dotfile-repositories ↩
-
https://containers.dev/implementors/json_reference/#image-specific ↩
-
https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace#automatically-forwarding-a-port ↩
-
https://containers.dev/implementors/json_reference/#lifecycle-scripts ↩