2022/07/31: 内容を充実させて書き直したものを投稿しました。そちらをご参照ください。
DevContainer の作成
まずはコマンドパレットで > Remote-Containers: Add Development Container Configuration Files...
を実行し、DevContainer の設定ファイルを作成します。
この時、テンプレートを選べるので Docker from Docker
(DevContainer を docker-compose で動かす場合は Docker from Docker Compose
) を選択します。
これでもう > Remote-Containers: Reopen in Container
を実行すればコンテナ内で Docker を使うことができます。
追加で何か言語などをインストールしたい場合は .devcontainer/Dockerfile
を編集してベースイメージを変えてしまうのが簡単です。Debian または Ubuntu ベースのイメージであれば何でも使うことができます。
以下は Go 言語の公式 DevContainer イメージをベースにする例です。
# Note: You can use any Debian/Ubuntu based image you want.
FROM mcr.microsoft.com/vscode/devcontainers/go:1.15
# 以下略
2021/10/15 追記:
新機能の Dev container features (preview) を利用することでもセットアップ可能です。
こちらは特に作成済みの DevContainer で Docker CLI を使いたい場合に便利です。
紹介記事を書いたのでこちらも参照してみてください。
DevContainer 内で Docker の bind mount を使う
DevContainer 内で bind mount を使うときは注意が必要です。
以下のように何も考えずにマウントすると、コンテナ内にマウントしたはずのファイルが見つかりません。
$ docker run --rm -it -v $(pwd):/app golang:1.15 /bin/bash
これは DevContainer 内の Docker はホストで動作している Docker を共有していることに起因します。
そのため、bind mount を行う際は DevContainer 内のパスではなくホストのパスを指定してあげる必要があります。
この問題を解決するために、.devcontainer/devcontainer.json
にはデフォルトで以下のような環境変数が定義されています。
{
// ...
// Use this environment variable if you need to bind mount your local source code into a new container.
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
// ...
}
${localWorkspaceFolder}
は devcontainer.json
で使用できる変数で、開いているフォルダのホスト側のパスを意味します。
この設定により、DevContainer 内では環境変数 LOCAL_WORKSPACE_FOLDER
からホストのパスを参照することができます。
つまり、先ほどの例を正しく動作させるためには以下のようにします。
$ docker run --rm -it -v $LOCAL_WORKSPACE_FOLDER:/app golang:1.15 /bin/bash
DevContainer 内で docker-compose の bind mount を使う
docker-compose の場合も同様に bind mount を使う場合はホスト側のパスを指定してあげる必要があります。
以下の設定は DevContainer 内では動作しません。
version: "3"
services:
app:
image: ruby:2.7
volumes:
- .:/app
working_dir: /app
command: bundle exec rackup
以下のように書くことで動作します。
version: "3"
services:
app:
image: ruby:2.7
volumes:
- ${LOCAL_WORKSPACE_FOLDER}:/app
working_dir: /app
command: bundle exec rackup
ただ、上記のような書き方をしてしまうと DevContainer の外では動かすことができません。
それでは不便なので DevContainer 用の設定は以下のように docker-compose.override.yml
1 等に書いてあげると良さそうです。
services:
app:
volumes:
- ${LOCAL_WORKSPACE_FOLDER}:/app
ホスト OS が Windows の場合
ホスト OS が Windows の場合、上記のように ${LOCAL_WORKSPACE_FOLDER}
を使用した設定でもエラーが出てしまいます。
$ docker-compose up
ERROR: Named volume "c:\Users\frozenbonito\dev\docker-from-docker:/app" is used in service "app" but no declaration was found in the volumes section.
これはホスト OS が Windows の場合、${localWorkspaceFolder}
の値が Windows 形式のパスになり、docker-compose がそれを誤って Volume 名と認識してしまうためです。
解決方法は2つあります。
volumes の long syntax を使う
以下のように volumes 設定の long syntax を使ってあげることで、docker-compose に Windows のパスを正しく解釈させることができます。
services:
app:
volumes:
- type: bind
source: ${LOCAL_WORKSPACE_FOLDER}
target: /app
環境変数 COMPOSE_FORCE_WINDOWS_HOST
を設定する
環境変数 COMPOSE_FORCE_WINDOWS_HOST
に true
または 1
が設定されていると、docker-compose が DevContainer のような Linux 環境で動作していたとしても short syntax 中の HOST パスを Windows のパスとして解釈するようになります。
以下のように devcontainer.json
で設定してあげると良いでしょう。
{
// ...
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}",
"COMPOSE_FORCE_WINDOWS_HOST": "true"
},
// ...
}