Visual Studio Code Remote Development のRuby環境を作ってみた。

https://code.visualstudio.com/assets/docs/remote/containers/architecture-containers.png

VS Code の次期目玉機能であるRemote Developmentを試してみました。

TL;DR

Visual Studio Code Remote Development って?

先日発表されたVisual Studio Codeの一押し拡張機能で、リモートにあるソースコードや実行環境を利用した開発をVS Code上から実行できるというもの。 接続先には、

  • SSH
  • Container(Docker)
  • WSL

があります。

CPUやメモリ、ビデオカードなど特殊な環境を利用した開発環境をVMで作成し、そこにSSHで接続したり、共通した開発環境をコンテナで揃えるなどができるので便利そうです。 チーム開発時の開発環境を共通化するのが楽になりそうで期待しています。

Remote Development拡張はまだ正式にはリリースされておらず、開発版のVS Code Insidersでのみ利用できます。

普段Macで開発しているので、Mac上でDockerコンテナ上のRuby開発環境を利用するための設定を書いてみました*1

サンプルアプリ

Sinatraで簡単なウェブアプリを作りました。 http://localhost:4567 にアクセスすると、"Hello, World!"が表示されるだけです。 なので、

  • プロジェクトの依存するgemとしてsinatraがあり、
  • コンテナにポート4567で接続できる

ような環境が必要になります。

構成

Remote Developmentで接続するコンテナについて、下記のファイルがポイントになります。

  • devcontainer.json
  • Dockerfile

Remote Develop拡張のドキュメントの通りにやればVS CodeからRubyで開発するためのこれらのファイルを生成してくれます。

ですが、

  • リポジトリ内のファイルを利用したコンテナを作れない
  • bundlerを使うことを想定してない

ようなものだったので、書き換えてみました。

.devcontainer.json

このファイルは、接続するコンテナやリモートにインストールする拡張、そしてその設定などを記述するためのファイルです。 .devcontainer/devcontainer.json にも配置することができるのですが、リポジトリのルートに.devcontainer.jsonに置くことにしました。どうやら、.devcontainerディレクトリ内にDockerfileなどまとめておくのも良いのですが、リポジトリ内のファイルなどをDockerfileでCOPYすることが出来ないようです。

今回は下記のような設定ファイルを書きました。

// See https://aka.ms/vscode-remote/devcontainer.json for format details.
{
    "name": "Ruby 2",
    "dockerFile": "Dockerfile",

    // Uncomment the next line if you want to publish any ports.
    "appPort": [
        4567
    ],

    // Uncomment the next line if you want to add in default container specific settings.json values
    "settings":  {
        "solargraph.useBundler": true,
    },

    // Uncomment the next line to run commands after the container is created.
    // "postCreateCommand": "",

    "extensions": [
        "rebornix.Ruby",
        "noku.rails-run-spec-vscode",
        "castwide.solargraph"
    ]
}
  • appPort: サンプルで書いたSinatraで公開するポート
  • settings: リモートにインストールするVS Codeの拡張の設定。今回はSolargraphを起動する時にbundle execを利用するための設定を追加しています。
  • extensions: リモートにインストールする拡張。

リモートでインストールできる拡張には制限があるようで、UIやThemeなどに関する拡張はインストールできません。

Dockerfile

Remote Development拡張が生成するDockerfileには、bundlerやGemfileに関する扱いが記述されていません。 ここでは、bundlerで依存管理をする開発環境を想定して、Dockerfileに

  • GemfileおよびGemfile.lockをCOPY
  • bundle install を実行して、依存しているgemをインストール

させ、依存するgemをコンテナのレイヤーとして入れています。

先程の.devcontainer.jsonpostCreateCommandbundle installを指定することで、コンテナ生成後にbundle installを実行することができます。 ですが、この方法だと依存関係が変わっていなくても、コンテナを再構築やプロジェクトをVS Codeで開くたびにgemのインストールが実行されてしまいます。

FROM ruby:2.6.3

# Install ruby-debug-ide and debase
RUN gem install ruby-debug-ide
RUN gem install debase

# To install the latest version of bundler
RUN gem install bundler:2.0.1

COPY Gemfile /root/
COPY Gemfile.lock /root/
RUN cd /root/ && bundle install

# Install git, process tools
RUN apt-get update && apt-get -y install git procps

# Clean up
RUN apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

# Set the default shell to bash instead of sh
ENV SHELL /bin/bash

gemのコマンドを実行するには

例えば、Ruby Solargraphのように、gemが提供するコマンドを実行する拡張を使う場合、以下の2通りある。

  1. 環境変数PATHに、/usr/local/bundle/binを追加
  2. Gemfile にgemの依存を記述し、bundle execでコマンドを実行する

今回は1ではなく2の方式で作成してみた。 開発の用途も含めて、プロジェクトで利用するgemはGemfileに記述しておくことで明示的になるし、セットアップの手順もbundle installにまとめられるので、個人的にはこの方式が望ましいと思っています。

おわりに

VS Code Remote DevelopmentのRubyコンテナを使った簡単な開発環境を作ってみました。 これまでもDockerを使って環境を揃えるなどはやったことはありますが、docker execを使ってコマンドを実行するといった煩わしさがありました。 Remote DevelopmentでTerminalを開くとコンテナ内に入った状態から始まるので、スムーズに作業ができるのが嬉しいですね。 そういった環境をコンテナで整備できるので、Remote Development拡張をインストールしたVS Codeがあればすぐに開発が始められそうなので、重宝しそうです。

はやく正式リリースされないかなー

参考

*1:SSH接続も試してみたかったのですがVMを作ったりするのが面倒でお金も掛かりそうで断念しました。