スクエニ ITエンジニア ブログ

Dev Container Featuresでdevcontainerを簡単に作る

yotaです。本ブログでたびたび話題に上がっている Visual Studio Codeのdevcontainerの機能を私も常用しています。

なかでもdevcontainerの機能の一部であるDev Container Features が、チームで必須のツールとは別に個人的に使いたいツールをdevcontainerに導入する際に便利だと感じたので紹介します。

Dev Container Featuresとは

Dev Container Features で触れられていますが、Dev Container Featuresとは既存のimageにないツールを追加してdevcontainerを作ることを簡単に実現できる機能です。

Dockerでは通常以下のような Dockerfile を構成して所望のツールが入ったコンテナを作るアプローチを取りますが、

FROM ubuntu
# ubuntuイメージに追加のアプリケーションをinstallする
RUN apt-get install -y xxxx 

Dev Container Featuresではツールのインストール処理のみを配布しておくことで、 devcontainerの設定ファイルである devcontainer.json で組み合わせることを可能にします。

例えば、Ubuntu上にGolang(1.18)がインストールされたdevcontainerは、次のような設定で実現できます。

{
    "name": "golang-on-ubuntu",
    "image": "ubuntu",
    "features": {
        "ghcr.io/devcontainers/features/go:1.0.0": {
            "version": "1.18"
        }
    }
}

features フィールドで前述の「ツールのインストール処理」の配布場所を指定する形です(複数指定可能)。

他のFeatures

基本的には Dockerfile でインストールしなければホストOS上で使っているツールはコンテナ内で使えません。 ホストOS上ではインストールしているツールをコンテナ内で使いたいが、そのためにDockerfileを書くのも手間、ということがままあったのですが、featuresによって簡単にインストールできるので重宝しています。1

例えば GitHub Flavored Markdownをローカルでプレビューしたい で紹介したGitHub CLIも導入可能です。

"features": {
    "ghcr.io/devcontainers/features/github-cli:1": {}
}

また、GitHub CLIやGolangのランタイムのようなツールとは違う種類のfeatureとしてdocker-outside-of-docker を使うこともあります。 これは、devcontainer上から docker コマンドによるホストOS上のコンテナの操作を可能にします。

試してみましょう。

ホストOS

$ touch /tmp/is_hostos
$ docker run -d alpine tail -f /dev/null
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
31e352740f53: Pull complete
Digest: sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1
Status: Downloaded newer image for alpine:latest
318bb825d53f4ddbb805e2d817c47fdae0afb43c18b71149d60c83e58dd5214c
$ docker ps
CONTAINER ID   IMAGE
          COMMAND                  CREATED          STATUS          PORTS     NAMES
548ff01c1217   vsc-sample-repo-909021d9a8def8e30ae62e2b9263b878bd79b294d5e2a355c3aaa30f04e0d8ae
          "/bin/sh -c 'echo Co…"   6 minutes ago    Up 6 minutes              admiring_hoover
318bb825d53f   alpine
          "tail -f /dev/null"      9 minutes ago    Up 9 minutes              dazzling_saha

devcontainer

root@548ff01c1217:/# cat /etc/is_hostos
cat: /etc/is_hostos: No such file or directory
root@548ff01c1217:/# docker ps 
CONTAINER ID   IMAGE                                                                                                      COMMAND                  CREATED          STATUS          PORTS     NAMES
548ff01c1217   vsc-sample-repo-909021d9a8def8e30ae62e2b9263b878bd79b294d5e2a355c3aaa30f04e0d8ae                        "/bin/sh -c 'echo Co…"   4 minutes ago    Up 4 minutes              admiring_hoover
318bb825d53f   alpine                                                                                                     "tail -f /dev/null"      7 minutes ago    Up 7 minutes              dazzling_saha

双方から docker ps で参照できていますね。

Dev Container Featuresの仕組み

ところで、これらのfeaturesは ghcr.io/devcontainers/features/go のように GHCR (GitHub Container Registry)上のパスを指定していますが、featuresはコンテナイメージなのでしょうか。

https://containers.dev/implementors/features/ に記載の仕様によるとそうではなく、実際はfeature自体のmetadataを表す devcontainer-feature.json とツールのインストール処理を担う install.sh で構成されたtgzファイルとなっています。

Reference to feature in OCI registry() () OCI registry must implement the OCI Artifact Distribution Specification.

にあるとおり、featuresで指定するレジストリはOCI Artifact Distribution Specificationに則ったレジストリです。このため、コンテナイメージ以外も格納できるので、tgzを格納して配布しています。

また、docker-outside-of-docker ではホストOS上の他のコンテナを参照できていましたが、どのようにホストOS間との連携を実現しているのでしょうか。
これはdevcontainer-feature.json の中で追加でマウントしたいファイルを指定可能なことを活用しているようです。( docker-outside-of-dockerのdevcontainer-feature.json

他にも仕様によればコンテナ内の環境変数やインストールするVS Codeの拡張機能も設定可能 2 になっていたりと、柔軟な処理が実現できそうです。

一方、仕様でも次のように言及されていますが、

Note: While Features may be installed on top of any base image, the implementation of a Feature might restrict it to a subset of possible base images. For example, some Features may be authored to work with a certain Linux distro (e.g. debian-based images that use the apt package manager).

install.sh の実装によっては共に使えるimage (devcontainer.json で指定する "image" )が制限される場合があることには注意が必要です。
例えば install.shapt install -y curl としていた場合、 alpine linuxにはaptコマンドがないため正しく動作しません。

まとめ

devcontainerの機能として、簡単にツールのインストールのような追加の処理を実現できる機構であるfeaturesを紹介しました。

他に広く公開されているものはAvailable Dev Container Featuresに記載されており、例えばGolang以外にもいろいろな言語のランタイムやコンパイラ、kubectlなどのツールも導入可能なので便利です。

一方、追加で拡張機能のインストールや環境変数設定などのVS Codeの設定値を付与するものもあり注意が必要ですが、参考になれば幸いです。


  1. devcontainerにはインストールせず、そのツールを使いたいときだけホストOS上のシェルを使うことで事足りることが多いのですが、VS Codeの機能でコンテナのボリュームに git clone する機能を使うとこの限りではないという事情もあります。 ↩︎

  2. 例えば、冒頭で例にあげたgolangのfeatureではgolangの拡張機能もインストールするように設定されます 実装(GitHub) ↩︎

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!