虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

コンテナ開発に必須! VSCode拡張機能 Remote - Containers

20211203212928

こんにちは、虎の穴ラボのはっとりです。

虎の穴ラボ Advent Calendar 2021 - Qiita 7日目の記事です。

6日目は大場さんによるSwagger + API Gateway + lambda でAPI定義を流用したAPIサーバー構築でした。

8日目はおっくんによるDeno を AWS Lambda 関数 で動かす ~ GitHub Actions で マイグレーションまで自動化 ~です。

今回はDocker Composeで開発している際に便利な、VSCodeの拡張機能Visual Studio Code Remote - Containersを紹介します。

今回試したバージョンは以下になります。

  • macOS Big Sur(11.6)
  • VSCode 1.62.3
    • Remote - Containers v0.205.2
  • Docker 20.10.10
  • Docker Compose 2.1.1

目次

コンテナ開発でVSCodeを使う場合のツラミ

Docker,Docker Composeは環境を作る・壊すが容易なので大変便利です。
開発するプロダクトによって言語やライブラリのバージョンに差異があっても「Dockerfile」や「docker-compose.yml」に書いてあればコマンド一発ですぐに用意できます。

しかし、VSCodeで開発する際に便利なコード補完、静的解析等の拡張機能を使えるようにするには
結局、ホストマシン側に各種言語やライブラリを別途インストールする必要があります。

この拡張機能に出会う前はRubocopやESLint等をホストマシンに入れて開発していましたが、
ホストマシンとコンテナでバージョンを合わせるのがとても面倒でした。

今回紹介する拡張機能「Visual Studio Code Remote - Containers」(以下 Remote Containers)を使うとホストマシン側には言語やライブラリをインストールしなくても各VSCode拡張機能がコンテナ内の言語やライブラリを使ってくれます。

Remote Containersのセットアップ

※VSCode, Docker, Docker Composeのインストールについては省略します。

VSCode横にある拡張タブから「Remote Containers」と入力してください。
Microsoftの「Remote - Containers」が出てくるので「install」を押します。
インストールが終わるとVSCodeのウィンドウ左下に画像のような緑色の領域が出来ています。

f:id:toranoana-lab:20211203204558p:plain

これで準備完了です。

既存のプロジェクトに入れて使う

Remote Containersはイチから「Dockerfile」を用意してくれる機能もありますが、 今回紹介するのは既存の「Dockerfile」,「docker-compose.yml」を使う方法です。

例としてDenoのプロジェクトに入れていきます。
※もちろんDeno以外にも使えます。自分の実績としてはNode.js,Ruby,Goで使えました。

使用するソースコードは以下のとおりです。

f:id:toranoana-lab:20211203205132p:plain

ソース全体を取得する場合はこちらから
https://github.com/toranoana/remote-container-deno-sample

基本の使い方

  1. 左下の緑色の領域をクリックします。
  2. 上にパレットが出てくるので「Reopen in Container」を選択します。
  3. Docker Composeを使用するので「From 'docker-compose.yml'」を選択します。 4.「docker-compose.yml」に記載したserviceがある場合、その一覧が出てきてどれを使うか選択肢が出てきます。VSCodeで開きたいソースが含まれたservice名を選択します。(今回の例だと「app」です)
  4. しばらくするとコンテナが起動してVSCode上でコンテナ内のソースコードを開くことが出来ます。

f:id:toranoana-lab:20211203205147g:plain

ためしにソースコードを開いてみるとエラーが出ています。
※DenoはTop-Level Awaitが使えるはずですが、VSCode標準のTypeScriptによるコード解析をされてしまっているようです。

f:id:toranoana-lab:20211203205222p:plain

予めDenoの拡張機能をインストールしていたのですが動いていないようです。

拡張機能のタブを開いてみましょう。

f:id:toranoana-lab:20211203205349p:plain

Denoのプラグインに警告マークが出ています。

一部の拡張機能は改めてコンテナ内にインストールする必要があります。
「Install in Dev Container: 〜」を押してインストールします。

インストールしたらパレットを開き、「Deno: initialize Workspace Configuration」を選択してDeno拡張の設定をします。

f:id:toranoana-lab:20211203205407g:plain

改めて先程のソースを開いてみるとawaitのエラーが消え、更にDeno Lintの警告も出ているのでDeno拡張機能が動いていることが確認できます。
※import の部分の赤いエラーはモジュールをキャッシュすると消えます。

f:id:toranoana-lab:20211203205521p:plain

これで基本の使い方はできるようになりました。

左下の緑色の領域をクリックし「Reopen Folder Locally」を押すとRemote Containerが終了し、ホストマシン側に戻ります。
このとき、Dockerコンテナも停止されます。

f:id:toranoana-lab:20211203205534g:plain

Remote Container動作をカスタマイズする

Remote Containerのカスタマイズについても説明します。

先程までの操作で「.devcontainer」というディレクトリが出来ています。
中には「devcontainer.json」「docker-compose.yml」の2ファイルがあります。

Remote Containerの設定は「.devcontainer/devcontainer.json」で行います。

自動的に作成された設定は以下の通りになります。(一部のコメント部分は除去しています。)

// .devcontainer/devcontainer.json
{
  "name": "Existing Docker Compose (Extend)",
  "dockerComposeFile": [
    "../docker-compose.yml",
    "docker-compose.yml"
  ],
  "service": "app",
  "workspaceFolder": "/workspace",
  "settings": {},
  "extensions": []
  // "forwardPorts": [],
  // "runServices": [],
  // "shutdownAction": "none",
  // "postCreateCommand": "apt-get update && apt-get install -y curl",
  // "remoteUser": "vscode"
}

各設定

各設定について説明します。

1. name

Remote Container起動時にVSCode上と左下の名前に使用されます。

{
  "name": "Denoアプリケーション",

  // ...
}

f:id:toranoana-lab:20211203205605p:plain f:id:toranoana-lab:20211203205614p:plain

2. dockerComposeFile

コンテナ起動時に使用する「docker-compose.yml」を指定します。
配列により、複数の設定ファイル指定可能で設定内容はマージされます。
重複部分は後勝ちで上書きされます。
パスについては「.devcontainer」ディレクトリからの相対パスになります。

{
  // ...

  // Update the 'dockerComposeFile' list if you have more compose files or use different names.
  // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
  "dockerComposeFile": [
    "../docker-compose.yml",
    "docker-compose.yml"
  ],

  // ...
}

これはdocker-composeコマンドを直接利用する際の、
-fオプションで設定ファイルを複数指定する場合と同等の挙動をしてくれます。

% docker-compose -f docker-compose.yml -f .devcontainer/docker-compose.yml build
% docker-compose -f docker-compose.yml -f .devcontainer/docker-compose.yml up -d

自動的に作成された「.devcontainer/docker-compose.yml」の内容を見てみると下記のようになっています。(コメント部分は除去しています)

# .devcontainer/docker-compose.yml
version: '3.8'
services:
  app:
    volumes:
      - .:/workspace:cached
    command: /bin/sh -c "while sleep 1000; do :; done"

予め用意してあった「docker-compose.yml」ではRemote Containerで動かすには不十分だった場合に「.devcontainer/docker-compose.yml」で設定を追加・上書きすることが可能です。

今回用意した「docker-compose.yml」ではすでにvolumeマウントしているため「.devcontainer/docker-compose.yml」からは削除して問題ありません。
また、commandにはdocker-compose up -dしたときに起動しっぱなしになるコマンドを指定します。
こちらに関しても「docker-compose.yml」の方ではtail -f /dev/nullのようにコマンドを指定しているので「.devcontainer/docker-compose.yml」には不要になります。

結果的に「docker-compose.yml」だけで問題なさそうなので
今回のケースでは「.devcontainer/docker-compose.yml」は削除出来ます。

  "dockerComposeFile": [
    "../docker-compose.yml",
-    "docker-compose.yml"
  ],

3. service

VSCodeで開きたいソースが含まれたservice名を指定しています。
設定の自動生成時に指定したserviceが設定されているはずです。

{
  // ...

  // The 'service' property is the name of the service for the container that VS Code should
  // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
  "service": "app",

  // ...
}

4. workspaceFolder

VSCodeで開きたいソースが含まれたディレクトリを指定しています。
自動生成だと「.devcontainer/docker-compose.yml」で指定された/workspaceディレクトリになっています。

{
  // ...

  // The optional 'workspaceFolder' property is the path VS Code should open by default when
  // connected. This is typically a file mount in .devcontainer/docker-compose.yml
  "workspaceFolder": "/workspace",

  // ...
}

今回の例では「docker-compose.yml」の方で指定しているディレクトリを使うようにします。

-  "workspaceFolder": "/workspace",
+  "workspaceFolder": "/usr/src/app",

5. settings

Remote Container使用時のVSCodeの設定をここに書くことが出来ます。

{
  // ...

  // Set *default* container specific settings.json values on container create.
  "settings": {},

  // ...
}

VSCodeのsettings.jsonと同じ様に設定できます。

- "settings": {},
+  "settings": {
+    "deno.enable": true,
+    "deno.lint": true
+  },

6. extensions

Remote Container内で利用する拡張機能を指定できます。
Remote Containerを起動した際に一部の拡張機能は改めてインストールする必要がありました。
Remote Container内でインストールした拡張機能はコンテナを再作成すると消えてしまいます。
こちらの設定に入れておけば再作成時に自動的に拡張機能をインストールしてくれます。

{
  // ...

  // Add the IDs of extensions you want installed when the container is created.
  "extensions": []

  // ...
}

値は拡張機能のIDで指定します。
拡張機能のIDはどこから取るのかというと拡張機能のタブを開いた後、
歯車アイコンを押したときに出てくる「Copy Extension ID」で取得できます

f:id:toranoana-lab:20211203205701p:plain

ホストマシン側にインストールしていない拡張機能でも指定できます。

- "extensions": []
+  "extensions": [
+    "denoland.vscode-deno",
+    "editorconfig.editorconfig",
+    "streetsidesoftware.code-spell-checker"
+  ],

7. forwardPorts

ポートフォワーディングの設定ができます。「docker-compose.yml」での指定とは別に追加で指定できます。

{
  // ...

  // Use 'forwardPorts' to make a list of ports inside the container available locally.
  // "forwardPorts": [],

  // ...
}

書式は"(ポート番号):(ポート番号)"の様に文字列で指定するか単に数字で指定します。

-  // "forwardPorts": [],
+  "forwardPorts": [
+    "8000:8001",
+    8002
+  ],

この設定とは別にRemote Containerにはコンテナ内のポートを利用するプロセスを検知して自動的にポートフォワードする機能があります。

8. runServices

Remote Container起動時に起動するサービスを明示的に指定します。
指定がない場合は全サービスが起動されます。(docker-compose upと同じ挙動)

{
  // ...

  // Uncomment the next line if you want start specific services in your Docker Compose config.
  // "runServices": [],

  // ...
}

下記の様にappのみ指定すると他のサービスは起動されません。
ただし、serviceで指定したサービスだけは必ず起動します。

-  // "runServices": [],
+  "runServices": ["app"],

9. shutdownAction

デフォルトではRemote Containerを終了時にコンテナも終了しますが、
"shutdownAction": "none"を指定するとRemote Containerを終了してもコンテナは起動したままになります。

{
  // ...

  // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
  // "shutdownAction": "none",

  // ...
}

10. postCreateCommand

コンテナ作成時に実行するコマンドを指定できます。
「Dockerfile」でインストールしていないけど開発時には使いたいコマンドをインストールするときなどに利用できます。

{
  // ...

  // Uncomment the next line to run commands after the container is created - for example installing curl.
  // "postCreateCommand": "apt-get update && apt-get install -y curl",

  // ...
}

例えばgitコマンドなんかはコンテナ内にインストールされていないとVSCode上で差分表示ができないのでここで入れることも出来ます。
もちろん「Dockerfile」内ですべて必要なものがインストールしてあれば不要です。 しかし、開発のために「Dockerfile」を変更したくないときはこちらを使うといいでしょう。

-  // "postCreateCommand": "apt-get update && apt-get install -y curl",
+  "postCreateCommand": "apt-get update && apt-get install -y git",
}

11. remoteUser

root以外のユーザーを使う際に指定します。
ユーザーはコンテナ内に予め作っておく必要があります。

{
  // ...

  // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
  // "remoteUser": "vscode"
}

Remote Containerのカスタマイズ例

.devcontainer/devcontainer.json の設定は最終的にはこの様にしました。

// .devcontainer/devcontainer.json
{
  "name": "Denoアプリケーション",
  "dockerComposeFile": [
    "../docker-compose.yml",
  ],
  "service": "app",
  "workspaceFolder": "/usr/src/app",
  "settings": {
    "deno.enable": true,
    "deno.lint": true
  },
  "extensions": [
    "denoland.vscode-deno",
    "editorconfig.editorconfig",
    "streetsidesoftware.code-spell-checker"
  ],
  "postCreateCommand": "apt-get update && apt-get install -y git",
}

この設定でRemote Containerを起動します。
もう一度Remote Containerを起動するには左下の緑色の領域をクリックします。

f:id:toranoana-lab:20211203211204g:plain

早速使ってみます。

f:id:toranoana-lab:20211203211221g:plain

まとめ

Remote Containerを使うことにより、ホストマシンでVSCodeを使うときと遜色ない開発環境を用意することが出来ます。
ぜひ使ってみてください。

P.S.

採用情報
■募集職種
yumenosora.co.jp

カジュアル面談も随時開催中です
■お申し込みはこちら!
news.toranoana.jp

■ToraLab.fmスタートしました!
メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm
■Twitterもフォローしてくださいね!
ツイッターでも随時情報発信をしています
twitter.com