はじめに
先日参加したハッカソンでDockerで環境構築してチームメンバーと開発をしたが、メンバーの1人がVSCodeの設定によるエラーで苦戦していた。そこで今回は、VSCode devcontainerとDockerを使って、Dockerのコンテナ内でVSCodeを起動して開発する方法についてまとめる。
前提知識:Docker / Docker-composeの概念をある程度理解している。
実行環境:Windows10, DockerHub, VSCode
到達レベル:面倒な環境構築をVScodeのエディタごとチームメンバーと共有できる
VSCode devcontainerとは?
VSCode の拡張機能パックである Dev Container(旧 Remote-Containers)を使用して構築する開発環境のことを指す。
引用元:Dev Container 公式ドキュメント
ローカルのワークスペースからファイルシステムをマウントするかコンテナにコピーまたは複製することでコンテナ上で作業することができる。また、どうやらVSCodeの拡張機能もコンテナにインストールして利用するみたい。つまり、コンテナごとでエディタを含めた開発環境全体をシームレスに切り替えることができる。
これでチームメンバー間でのエディタの設定等によるエラーを防ぐことができる。
ただし、エディタはVSCodeに限られてしまうが......
利用手順
Docker のインストール
詳細についてはここでは割愛します。
Docker Desktop のインストールはここから
Dev Container のインストール
VSCodeを起動して拡張機能検索からDev Container
を見つける。
発見したらInstall
ボタンをクリック!
ちなみに、
Dev Container
の下にRemote Development
という似たような拡張機能があるが、これはVSCode Remote Developmentといい、Remote - WSLと、Remote - Containers、Remote - SSHをひとまとまりでインストールできる拡張機能パッケージのようなものらしい。
devcontainerコンテナのビルド
Dev Container
をインストールすると、左端に新しいステータスバー項目が表示される。
ステータスバーをクリックすると、以下のようにコンテナのメニュバーが表示される。
既に.devcontainer
ディレクトリが存在するリポジトリがあれば、Open Folder in Container...
を選択してコンテナを展開すればOK。
ここでは、Try a Dev Container Sample...
でサンプルの Node.js コンテナを展開する。
選択後は、コンテナがビルドされるのでしばらく待機...
ビルドが完了すると、左端のステータスバーにコンテナ名が表示される。
これでVSCodeとビルドしたコンテナとの接続は完了。
コンテナのビルド後は、以下のようなディレクトリ構造になる(Node.jsの場合)
.
├── CODE_OF_CONDUCT.md
├── .devcontainer
├── .eslintrc.json
├── .git
├── .gitattributes
├── .gitignore
├── LICENSE
├── node_modules
├── package.json
├── README.md
├── SECURITY.md
├── server.js
├── .vscode
└── yarn.lock
devcontainer.json
devcontainer.json
は、開発コンテナの構築方法と起動方法を決定する構成ファイル。
.devcontainer
ディレクトリ直下にある。
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye",
"customizations": {
"vscode": {
"settings": {},
"extensions": [
"streetsidesoftware.code-spell-checker"
]
}
},
"portsAttributes": {
"9000": {
"label": "Hello Remote World",
"onAutoForward": "notify"
}
},
"postCreateCommand": "yarn install"
}
主なオプション | 内容 |
---|---|
dockerfile |
Dockerイメージとして使用したいファイルへの相対パス |
customizations |
VSCodeなどのツール固有のプロパティを設定 |
settings |
コンテナ/マシン固有の設定ファイルの追加 |
extensions |
コンテナ作成時にインストールする拡張機能を指定 |
forwardPorts |
コンテナ内のポートをローカルで利用できるようにする |
postCreateCommand |
コンテナ作成後に実行されるコマンド |
remoteUser |
コンテナ内でVSCodeを実行するユーザーを上書き |
※ remoteUser
のデフォルトはcontainerUser
全てのオプション集はこちら
Dockerfile と docker-compose.ymlの作成
特にDockerコンテナをカスタマイズしない人は作成する必要はないが、大抵は開発していく中で色々といじりたくなってくる。そこで.devcontainer ディレクトリ下に Dockerfileとdocker-compose.ymlを作成してコンテナを好きなようにカスタマイズする。
Dev Container
のような Docker コンテナ内で Docker を使用する方法には、docker-from-docker という方式と docker-in-docker という方式の 2 つがあるらしい。
今回は、Docker コンテナにホストの Docker ソケットをバインドマウントすることにより、コンテナ内からホストの Docker を使用するため、前者のdocker-from-docker
の方式を採用する。
詳細は以下を参照。
Dockerfile
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye
# 以下略
docker-compose.yml
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ${LOCAL_WORKSPACE_FOLDER}:/app
working_dir: /app
command: sh -c "yarn install"
${localWorkspaceFolder}
はdevcontainer.json
で使用できる変数で、ホスト側のフォルダのパスを指す。
詳細は以下を参照。
追記[2022/12/31]:
docker-compose の ver.3.2以降はvolumesはlong syntax
で記述すると、良いそう。
version: "3.9"
# 略
volumes:
- type: bind
source: ${LOCAL_WORKSPACE_FOLDER}
target: /app
# 略
short syntax
の場合、
- 意図せずroot権限でホストにディレクトが自動生成される。
- ファイルをマウントしようとしたが、ディレクトリがマウントされる。
-
docker-compose up
でエラーを吐く場合が度々ある。
などのデメリットがあるみたい。
詳細は以下を参照。
devcontainer.json
{
"name": "Node.js",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
"extensions": [
"streetsidesoftware.code-spell-checker"
]
}
ローカルサーバの起動
ひと通り環境が整ったのでサーバを立ち上げてみる。
$ node server.js
上記のコマンドでローカルサーバを起動。
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const express = require('express');
// Constants
const PORT = 3000;
const HOST = '0.0.0.0';
// App
const app = express();
app.get('/', (req, res) => {
res.send('Hello remote world!\n');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
ルートディレクトリ直下にserver.js
があるので、「Hello remote world!」と返されれば成功。
コンテナのリモート接続を閉じる
File
->Close Remote Connection
でローカルのVSCodeに戻すことができる。
参考文献
まとめ
今回は、VSCode devcontainer
を使って、Dockerコンテナ上でシームレスな開発環境を構築してみた。ファイルシステムだけでなく、開発環境全体を揃えられることで、チーム開発で不必要なエラーで悩まされることは無くなりそう。ただ、メンバー全員がVSCode縛りになってしまうのが少し痛い......