はじめに
複数プロジェクトを同時に開発していたりすると依存するライブラリ等がコンフリクトしたり、別の開発者に展開する際に環境構築手順を作らないといけなかったりと地味に時間がかかっています。
またデプロイする際もコンテナで実施することも徐々に増えてきているので、初めからコンテナ上で開発した方がいいよねっていうことでVSCodeの拡張機能「Remote - Containers」を利用したリモート開発環境を構築したので、それについて紹介いたします。
今回実施した内容は以下の通りとなっています。
- 環境構築 (SSH/Docker Context)
- リモート上でのWebアプリ開発・デバッグ
- 設定ではまったこと
- (参考)devcontainerイメージ一覧
- (参考)devcontainer.json設定一覧
構築した環境
構築した環境は以下の通り。WSL2のUbuntu上にDockerをインストールし、そこに接続する形をとっています。
別サーバー上にDockerをインストールしてリモート開発する場合も、ほぼ手順は同じかと思います。
※透過プロキシが入っているのはプロキシ設定を省略するのが目的です。もし必要があれば別記事についても参照ください。
1. 環境構築
標準の手順では、VSCodeのsetting.json
にDockerの接続先を設定していますが、ここでは接続先を切り替えることを考慮してDocker Contextによる接続先の設定、およびDocker拡張機能によるコンテキストの設定方法を説明します。
1.1. SSH認証キーの作成と設定
Docker Contextによる接続では、パスワードによる認証に対応していないため、SSH認証キーを作成しそれぞれ設定します。
ここでは、Windows 10に付属しているOpenSSHを利用します。
OpenSSHをインストールされていない場合は「設定→アプリ→オプション機能→機能の追加」よりOpenSSH サーバー、およびOpenSSH クライアントをインストールしてください。
> ssh-keygen -t ecdsa -f keyfile
作成された公開鍵id_ecdsa.pub
をリモート上に転送し、~/.ssh/authorized_keys
に登録します。
$ cat keyfile.pub >> /home/<user>/.ssh/authorized_keys
$ chmod 600 /home/<user>//.ssh/authorized_keys
もしWSL2を利用されている場合は、dockerと同様に下記の通りSSHのサービスを起動し必要があればWindowsのポートフォワードもしてください。
$ sudo service ssh start
1.2. Docker Contextの作成
作成した認証キーの登録し、Docker Contextの作成を行います。最後のdockerコマンドで作成したContextを指定し、リモート上の実行中のコンテナ一覧が表示されれば正常に作成されています。
> sc config ssh-agent start=auto
> net start ssh-agent
> ssh-add ./keyfile
> docker context create remote1 --docker "host=ssh://<user>@<remote hostname>:<port>"
> docker --context=remote1 ps
※ssh-addでエラーが発生した場合、OpenSSH サーバーがインストールされているか確認してください(参考記事4)。
1.3. VSCode拡張機能のインストール
VSCodeには以下の2つの拡張機能をインストールしてください。
- Docker
- Remote - Containers
Docker拡張機能をインストールすると新たにタブが追加されるので、そのタブを開きCONTEXTS
を開くとDocker Contextの一覧が表示されます。
ここで先ほど作成したContextを利用するように設定(右クリック→USE)します。Context横に接続マークが表示されていれば設定完了です。
2. リモートでのWebアプリ開発・デバッグ
ここではASP.net coreを例に、リモート上でWebアプリの開発、およびデバッグするまでの手順を記載いたします。
リモート上になりますので、ローカルファイルシステムのマウントは出来ず、図に記載した通りリモート上のファイルシステムをマウントするように設定します。
2.1. コンテナ開発設定の初期化
-
Ctrl+Shift+P
を押下しコマンドパレット表示後、Remote-Containers: Add Development Container Configuration Files
を選択します。
-
追加する設定テンプレート一覧が表示されます。ここでは
Show All Definitions...
をクリックし、言語別のテンプレートを表示させます。
-
C# を選択すると、.net coreのバージョンやオプションについて聞かれますが、デフォルトのままでOKボタンを押下します。
2.2. プロジェクトの設定変更
リモート上へのマウント設定の追加
データを保持するために、リモート上にプロジェクト用のフォルダを作成します。
ここでは仮にログインユーザのホームディレクトリにworkspaces
フォルダを作成し、また、その下に項2.1で初期化したフォルダと同名のフォルダを作成します。
これはデフォルトの設定では、コンテナ起動後のVSCode接続時にワークスペースフォルダ中にあるプロジェクトフォルダを開きにいくためです。
$ mkdir -p /home/<user>/workspaces/<Project Folder Name>
devcontainer.json
にworkspaceMount
の項目を追加し、上記のworkspaces
フォルダとのマッピングを追加します。
target=
の設定については、Dockerfileで利用したベースイメージの仕様になります。
{
// --- 略 ----
"workspaceMount": "source=/home/<user>/workspaces,target=/workspaces,type=bind,consistency=cached",
// --- 略 ----
}
ユーザ設定の変更
次にリモート上のユーザと、コンテナ上で実行されるユーザの整合性を取るようにします。
ここの設定を間違えると、読み書きが出来なかったり、リモート上でファイルを開けなかったりするので注意してください。
はじめにリモートホスト上にログインしたユーザのuid
とgid
を確認します。
※下はユーザremote
でログインした場合一例になります。
$ id
uid=1001(remote) gid=1001(remote) groups=1001(remote),999(docker)
確認した上記のuid
とgid
でコンテナ上にユーザを作成します。その他のオプションについてはMSガイドを参照してください。
ここでは試しにdevcon
というユーザ名で作成しています。
ARG USERNAME=devcon
ARG USER_UID=1001
ARG USER_GID=$USER_UID
# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& apt-get update \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
USER $USERNAME
またdevcontainer.json
にユーザ名を設定します。
{
// --- 略 ----
"remoteUser": "devcon"
}
以上で設定の変更は完了です。
後は左下の><
アイコンをクリックして出てきたメニューよりRemote-Containers: Reopen in Container
をクリックすると、Dockerイメージがビルドされコンテナの起動とリモート接続が開始されます。
2.3. コンテナでの開発
ここまでくると通常のローカルでの開発とほぼ同じです。
起動したVSCodeからターミナルを開き、dotnet
コマンドでプロジェクトを初期化し、F5
キーを押下すればデバッグが開始され、ブラウザからの参照やブレークポイントによる変数内容の確認等も可能になってます。
- プロジェクト初期化
$ dotnet new react
上記の通り、VSCodeがデバッグ時にコンテナ上のポートを転送してくれるようになっています。
デバッグを開始した際、左下に「使用可能なポートがX個あります」と表示されていれば転送設定がされており、もしされていない場合はメッセージ部分をクリックすると下記のようなポート転送設定画面が開かれるので、ここに手動で追加してください。
2.4. データのアップロード・ダウンロード
コンテナ上へのデータのアップロード・ダウンロードのVSCodeから行えます。
アップロードする場合は、VSCodeのエクスプローラーにファイルをドラッグ&ドロップするとアップロードでき、ダウンロードする場合は右クリックすると下記の通りダウンロードメニューがあるので、そこから実施できます。
3. 設定ではまったこと
ネットワーク環境が異なる場合の注意点 (主にプロキシ設定)
リモート開発時はローカルとネットワーク環境等が異なると思いますが、標準だとVSCode/gitについて設定が引き継がれるようになっています。
このためローカルでプロキシの設定をしていたりすると、一部プラグインがその設定により正常に動作しなかったりするので、その設定を外す必要があります。
これらの設定を外す場合はdevcontainer.json
を修正し、settings
でVSCodeの設定を、'postStartCommand'でgitの設定を変更するようにします。
devcontainer.json
を修正後は、設定を反映させるためにVSCodeのウィンドウの再読み込みを行ってください。
これまでの設定を実施したdevcontainer.json
は以下の通りとなります。
{
"name": "csharp_container",
"build": {
"dockerfile": "Dockerfile",
"args": {
"VARIANT": "3.1",
"INSTALL_NODE": "true",
"NODE_VERSION": "lts/*",
"INSTALL_AZURE_CLI": "false"
}
},
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"http.proxySupport": "off"
},
"postStartCommand": "git config --global --unset http.proxy && git config --global --unset https.proxy",
"extensions": [
"ms-dotnettools.csharp"
],
"workspaceMount": "source=/home/remote/workspaces,target=/workspaces,type=bind,consistency=cached",
"remoteUser": "devcon"
}
設定失敗時のコンテナイメージのリビルド
Docerfile
やdevcontainer.json
の設定について失敗した場合、メニューのRebuild Container
が正常に動作しないことがあります。
この場合はvsc-<Project Folder Name>
という名称でイメージが作成されているので、それを手動で削除します。
VSCodeのDockerタブのCONTAINERS
より、該当する名称のものを探しRemove...
で削除してください。
複数PCからの接続時の注意点
Remote Containers拡張機能では、コンテナイメージの識別に、プロジェクトフォルダのパスを利用している模様です(※20/11/20時点)。
このため注意点として、複数PC(ユーザ)から同一のリモートホスト(Docker)に接続する場合、プロジェクトのパスを変更しなければならない点が挙げられます。
プロジェクトフォルダのパスが同一だった場合でもVSCodeは立ち上がりますが、同一コンテナ上に接続しに行っているためデバッグ時にポートの競合が起きる等の問題が発生してしまいます。
remoteUser
指定時の挙動について
devcontainer.json
の設定説明を見てみると、uid
, gid
が自動的にマッピングしてくれるとの記載がありますが、そのような挙動は見られませんでした。
利用方法が悪いのかバグなのかは調べきれていませんが、可能な限りDocker上で実行するユーザの設定をしたほうが現時点では無難な感じです。
(参考)devcontainerイメージ一覧
参考までにリモート開発用コンテナ一覧について転記します。
最新のイメージ一覧はこちらから参照してください。
-
mcr.microsoft.com/vscode/devcontainers/base
- alpine, alpine-3.10, alpine-3.11, alpine-3.12
- debian, buster, debian-10, stretch, debian-9
- ubuntu, focal, ubuntu-20.04, bionic, ubuntu-18.04
-
mcr.microsoft.com/vscode/devcontainers/cpp
- buster, debian-10, stretch, debian-9 -
mcr.microsoft.com/vscode/devcontainers/dotnetcore
- 3.1, 2.1 -
mcr.microsoft.com/vscode/devcontainers/go
- 1, 1.15, 1.14 -
mcr.microsoft.com/vscode/devcontainers/java
- 8, 11, 14 -
mcr.microsoft.com/vscode/devcontainers/javascript-node
- 14, 12, 10 -
mcr.microsoft.com/vscode/devcontainers/php
- 7, 7.4, 7.3 -
mcr.microsoft.com/vscode/devcontainers/python
- 3, 3.8, 3.7, 3.6 -
mcr.microsoft.com/vscode/devcontainers/anaconda
- 3 -
mcr.microsoft.com/vscode/devcontainers/miniconda
- 3 -
mcr.microsoft.com/vscode/devcontainers/ruby
- 2, 2.7, 2.6, 2.6 mcr.microsoft.com/vscode/devcontainers/rust
-
mcr.microsoft.com/vscode/devcontainers/typescript-node
- 14, 12, 10 mcr.microsoft.com/vscode/devcontainers/universal
(参考)devcontainer.json設定一覧
参考までにdevcontainer.json
で設定可能な項目の一覧について記載します。
最新の設定はこちらを参照してください。
- 一般設定項目
設定項目 | 型 | 詳細 |
---|---|---|
name | string | リモート接続時の表示名を設定します。 |
extensions | array | コンテナの作成時にコンテナ内にインストールする必要がある拡張機能を指定する拡張機能IDの配列を設定します。 |
settings | object |
settings.json に設定する内容。コンテナ/マシン固有のデフォルト値を追加。 |
forwardPorts | array | コンテナ内からローカルマシンに転送する必要のあるポートの配列を設定します。 |
postCreateCommand | string, array | コンテナ作成後にコンテナ内で実行するコマンド文字列またはコマンド引数のリストを設定します。workspaceFolder がカレントディレクトリとなっており、ソースフォルダがマウントされた後に実行されるため、フォルダ内のシェルスクリプト等を実行することも可能です。。 |
postStartCommand | string, array | コンテナの開始時に実行するコマンド文字列またはコマンド引数のリストを設定します。その他仕様はpostCreateCommand と同様です。。 |
postAttachCommand | string, array | VSCodeが実行中のコンテナにアタッチされた後に実行するコマンド文字列またはコマンド引数のリストを設定します。その他仕様はpostCreateCommand と同様です。 |
initializeCommand | string, array | コンテナイメージ構築前、およびコンテナが作成または開始された際にローカル上で実行するコマンド文字列またはコマンド引数のリスト。コマンドはworkspaceFolder にて実行されます。 |
userEnvProbe | enum | タスクのデバッグや実行の際に利用するユーザ環境変数について取得するための方法を指定します。none (デフォルト), interactiveShell . loginShell . loginInteractiveShell が設定可能で、interactiveShell では/etc/bash.bashrc ,.bashrc に設定された内容が、loginShell では「rc」ファイル、および/etc/profile , .profile に設定された内容が含まれています。デフォルト値の none 以外のモードでは起動が遅くなる可能性があります。 |
devPort | integer | VS CodeServerがコンテナで使用する特ポートを設定します。デフォルトではランダムに設定されます。 |
- 共通項目(Dockerイメージ、Dockerfile、Docker Compose)
設定項目 | 型 | 詳細 |
---|---|---|
remoteEnv | object | VSCode(またはターミナル等のサブプロセス)の環境変数を設定または上書きする名前と値のペアのセット。環境変数と事前定義された変数についても参照可能。[ターミナル]> [統合:環境の継承]が設定でチェックされていることを確認してください。 例: "remoteEnv": { "PATH": "${containerEnv:PATH}:/some/other/path", "MY_VARIABLE": "${localEnv:MY_VARIABLE}" }
|
remoteUser | string | コンテナ内で実行されるVSCodeのユーザを設定します(ターミナル、タスク、デバッグ等のサブプロセス含む)。VSCodeが再起動されたとき(またはウィンドウがリロードされたとき)に更新が適用されます。 [コンテナ] デフォルトは containerUser が設定されます。Linuxでは、指定されたコンテナユーザのUID / GIDは、ローカルユーザのUID / GIDと一致するように更新され、バインドマウントでのアクセス許可の問題を回避します。UID / GIDの更新を適用するには、コンテナを再作成する必要があります。[Compose] デフォルトではDocker Composeファイルで設定された実行ユーザになります。 |
workspaceFolder | string | コンテナに接続時にVSCodeが開くデフォルトのパスを設定します。 [コンテナ] 通常 workspaceMount と組み合わせて使用します。ソースコードのマウントしたパスです。[Compose] コンテナ内でソースコードフォルダをマウントしたパスを設定します。デフォルトは "/" 。 |
shutdownAction | enum | ウィンドウが閉じられた(シャットダウンされた)際にコンテナを停止するかどうか。none , stopContainer (コンテナ時デフォルト), stopCompose (Compose時デフォルト) |
- Dockerイメージ、Dockerfileのみ
設定項目 | 型 | 詳細 |
---|---|---|
image | string | Dockerイメージを利用する場合必須。 VSCodeがコンテナを作成する際のコンテナレジストリ内のイメージの名前を指定します。 |
build.dockerfile | string |
Dockerfile を使用する場合に必須。コンテナの内容を定義する Dockerfile の場所。パスはdevcontainer.json ファイルからの相対パスを記載します。 |
build.context | string |
docker build を実行するdevcontainer.json からの相対パスを設定します。 |
build.args | object |
Dockerfile をビルドするときに渡されるDockerイメージビルド引数を含む名前と値のペアのセット。環境変数と事前定義された変数についても参照可能。例: "build": { "args": { "MYARG": "MYVALUE", "MYARGFROMENVVAR": "${localEnv:VARIABLE_NAME}" } }
|
build.target | string | Dockerfileビルドするときに渡されるターゲット文字列を指定します。 例: "build": { "target": "development" }
|
appPorts | integer, string, array | 通常はforwardPorts プロパティを使用すること推奨。このプロパティでは、コンテナのポートフォワード設定についても実施します。 |
containerEnv | object | コンテナの環境変数を設定または上書きする名前と値のペアのセット。環境変数と事前定義された変数についても参照可能。 例: "containerEnv": { "MY_VARIABLE": "${localEnv:MY_VARIABLE}" }
|
containerUser | string | コンテナで実行される命令について指定したユーザに設定します。デフォルトは、root またはDockerfile のUSER で指定したユーザになります。Linuxでは、指定されたコンテナユーザのUID / GIDは、ローカルユーザのUID / GIDと一致するように更新され、バインドマウントでのアクセス許可の問題を回避します |
updateRemoteUserUID | boolean | Linuxでは、containerUser またはremoteUser が指定されている場合、バインドマウントでのアクセス許可の問題を回避するために、コンテナユーザのUID / GIDがローカルユーザのUID / GIDと一致するように更新されます。デフォルトはtrue 。 |
mounts | array | 作成時にコンテナに追加する追加のマウントポイントの配列。DockerCLIのmount フラグと同じ値をサポートします。環境変数や事前定義された変数についても参照可能です。例: "mounts": ["source=${localWorkspaceFolder}/app-scripts,target=/usr/local/share/app-scripts,type=bind,consistency=cached"]
|
workspaceMount | string | コンテナの作成時に、ワークスペースのデフォルトのローカルマウントポイントを上書きします。DockerCLIのmount フラグと同じ値をサポートします。主に、リモートコンテナの構成やディスクパフォーマンスを向上させる際に変更します。環境変数や事前定義された変数についても参照可能です。 |
runArgs | array | コンテナの実行時に使用するDockerCLI引数の配列。デフォルトは[]。 |
overrideCommand | boolean | コンテナのデフォルトコマンドを上書きするか設定します。 デフォルトでは true に設定されており、/bin/sh -c "while sleep 1000; do :; done" が実行されます。 |
- Docker Composeのみ
設定項目 | 型 | 詳細 |
---|---|---|
dockerComposeFile | string, array | Compose時必須。DockerComposeファイルへのパスまたはパス配列を指定します。パスはdevcontainer.json からの相対パスになります。配列で定義した場合、後で定義された内容で上書きされます。.env ファイルはデフォルトではプロジェクトのルートから取得されますが、DockerComposeファイルにて別のパスの指定も可能です。 |
service | string | Compose時必須。実行後に接続するサービス名。 |
runServices | array | 開始するDocker Compose設定内のサービス名配列。shutdownAction をnone に設定しない限り、VSCode終了時に、これらも停止されます。デフォルトではすべてのサービスが対象です。 |
最後に
Docker関係の知識は多少必要かもしれませんが、思っていた以上に簡単に、また特段の制限なくWebアプリ等の開発環境が構築可能なことに驚きました。
また外注等の開発者の入れ替わりが激しい場合も容易に開発環境を複製することが出来ますので、かなりメリットが大きいと感じています。
今回記載した記事が、何かしら皆さまのお役に立てれば幸いです。
関連記事
参考記事
- VSCodeでリモートホスト上のDocker上で開発する - Qiita
- Visual Studio Code Remote Development
- Developing inside a Container using Visual Studio Code Remote Development
- Can't acess ssh-agent · Issue #1491 · PowerShell/Win32-OpenSSH
- VS Code Remote Development Container Images - Docker Hub
商標
- Microsoft、Windows、Visual Studioは,米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。
- Ubuntuは,Canonical Ltd.の商標または登録商標です。
- DockerおよびDockerのロゴはDocker,Inc.の米国およびその他の国における商標または登録商標です。
- その他記載の会社名、製品名、サービス名等はそれぞれの会社の商標または登録商標です。