LoginSignup
18
16

More than 1 year has passed since last update.

VSCode DevContainer の中で Docker を使う方法

Last updated at Posted at 2020-10-03

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 イメージをベースにする例です。

.devcontainer/Dockerfile
# 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 にはデフォルトで以下のような環境変数が定義されています。

.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 内では動作しません。

docker-compose.yml
version: "3"

services:
  app:
    image: ruby:2.7
    volumes:
      - .:/app
    working_dir: /app
    command: bundle exec rackup

以下のように書くことで動作します。

docker-compose.yml
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 等に書いてあげると良さそうです。

docker-compose.override.yml
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 のパスを正しく解釈させることができます。

docker-compose.override.yml
services:
  app:
    volumes:
      - type: bind
        source: ${LOCAL_WORKSPACE_FOLDER}
        target: /app

環境変数 COMPOSE_FORCE_WINDOWS_HOST を設定する

環境変数 COMPOSE_FORCE_WINDOWS_HOSTtrue または 1 が設定されていると、docker-compose が DevContainer のような Linux 環境で動作していたとしても short syntax 中の HOST パスを Windows のパスとして解釈するようになります。

以下のように devcontainer.json で設定してあげると良いでしょう。

.devcontainer/devcontainer.json
{
	// ...

	"remoteEnv": {
		"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}",
		"COMPOSE_FORCE_WINDOWS_HOST": "true"
	},

	// ...
}
  1. docker-compose がデフォルトで読みこむオプショナルな設定ファイルです。docker-compose.yml
    の設定を上書きします。詳しくはこちらを参照してください。

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16