😅

Devcontainerのfeatureはビルドキャッシュされていることを知らなかった

2024/08/11に公開

はじめに

Devcontainer、とても便利ですね。自分は仕事、プライベートともに Devcontainer を活用しています。そんな Devcontainer には、事前に用意された機能を簡単に組み込むための機能としてfeaturesがあります。

自分はこの features に関して大きな勘違いをしていました。というのは、features で拡張した機能は毎回 Devcontainer 起動時にビルドしているという思い込みがあり、これまで積極的に活用してこなかったのでした。

今回は、せっかくなので features がビルドキャッシュされていないという思い込みから、その思い込みが間違いと気づいたきっかけについて記録しておこうと思います。

なぜfeaturesはビルドキャ種されないという思い込みがあったのか

自分は次のように考えていました。

  1. Dockerfile で処理を明示的に記述していない
  2. features は単なる機能のアドオンであり、ビルドキャッシュされることはない
  3. だから、起動のたびに再ビルドしている

その結果、どういうことをしていたかといえば、例えば Docker Outside of Docker (dood) の機能を利用する場合、次のような Dockerfiledevcontainer.json を用意しました。

Dockerfile
FROM mcr.microsoft.com/devcontainers/javascript-node:1-22

RUN curl -fsSL https://raw.githubusercontent.com/devcontainers/features/main/src/docker-outside-of-docker/install.sh | bash

ENTRYPOINT [ "/usr/local/share/docker-init.sh" ]

CMD [ "sleep", "infinity" ]
devcontainer.json
{
	"name": "Node.js",
	"build": {
		"dockerfile": "Dockerfile"
	},
	"mounts": [
		{
			"source": "/var/run/docker.sock",
			"target": "/var/run/docker-host.sock",
			"type": "bind"
		}
	],
	"overrideCommand": false,
	"remoteEnv": {
		"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
	},
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-azuretools.vscode-docker"
			]
		}
	}
}

やっていることとしては、 featuresで提供されているdood機能Dockerfiledevcontainer にそれぞれ記述しているだけです。

本来は devcontainer.json で一文追加するだけで済む処理です。何かがおかしいですよね。

"features": {
    "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
}

本当にfeaturesはビルドキャッシュされていないのか?

改めて自分の思い込みが本当かどうかを調べてみてみました。

その結果、次のような discussion を見つけます。

https://github.com/orgs/community/discussions/45941

上記のやり取りからすると、2023年2月1日時点では確かにビルドキャッシュされていなかったようです。ただ、その後2023年2月8日のPull Requestにて改善が入り、ビルドキャッシュが効くようになったとのことです。

https://github.com/devcontainers/cli/pull/382

素晴らしいです。

というか、自分は使い始めたのが2024年に入ってからだと思うので、おそらくすでにこの対応は含まれた状態で試しており、「featuresはビルドキャッシュしていない」は単なる思い込みであったことがわかりました。恥ずかしい...

改めて確認してみる

下記のような devcontaienr.json を書いて、起動させてみます。Dockerfile を書かなくてよくなり、相当シンプルになりました。

devcontainer.json
{
	"name": "Node.js",
	"image": "mcr.microsoft.com/devcontainers/javascript-node:1-22",
	"features": {
		"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
	},
	"remoteEnv": {
		"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
	}
}

下記が二度目以降の Devcontainer の起動ログになりますが、docker-outside-of-dockerの導入処理がちゃんとキャッシュされていることがわかります。

[21277 ms] * Fetching feature: docker-outside-of-docker_0_oci
[21755 ms] * Fetched feature: docker-outside-of-docker_0_oci version 1.5.0
[21762 ms] Start: Run: docker buildx build --load --build-context dev_containers_feature_content_source=/var/folders/2r/xvl2jjqj2bv8sqtfbcqbf8480000gn/T/devcontainercli/container-features/0.65.0-1723363342921 --build-arg _DEV_CONTAINERS_BASE_IMAGE=mcr.microsoft.com/devcontainers/javascript-node:1-22 --build-arg _DEV_CONTAINERS_IMAGE_USER=root --build-arg _DEV_CONTAINERS_FEATURE_CONTENT_SOURCE=dev_container_feature_content_temp --target dev_containers_target_stage -f /var/folders/2r/xvl2jjqj2bv8sqtfbcqbf8480000gn/T/devcontainercli/container-features/0.65.0-1723363342921/Dockerfile.extended -t vsc-dood-sample-748888ecedf0dbacc0b905641a7830a853908c0c5eeb7bd2ba4a297521002780-features /Users/okhiroyuki/Library/Application Support/Code/User/globalStorage/ms-vscode-remote.remote-containers/data/empty-folder
[+] Building 4.2s (15/15)                                docker:rancher-desktop
 => [internal] load build definition from Dockerfile.extended              0.1s
[+] Building 4.3s (15/15) FINISHED                       docker:rancher-desktop
 => [internal] load build definition from Dockerfile.extended              0.1s
 => => transferring dockerfile: 2.45kB                                     0.0s
 => resolve image config for docker.io/docker/dockerfile:1.4               3.2s
 => CACHED docker-image://docker.io/docker/dockerfile:1.4@sha256:9ba7531b  0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load metadata for mcr.microsoft.com/devcontainers/javascri  0.0s
 => [context dev_containers_feature_content_source] load .dockerignore     0.1s
 => => transferring dev_containers_feature_content_source: 2B              0.0s
 => [context dev_containers_feature_content_source] load from client       0.1s
 => => transferring dev_containers_feature_content_source: 39.30kB         0.0s
 => [dev_containers_feature_content_normalize 1/3] FROM mcr.microsoft.com  0.0s
 => CACHED [dev_containers_target_stage 2/5] RUN mkdir -p /tmp/dev-contai  0.0s
 => CACHED [dev_containers_feature_content_normalize 2/3] COPY --from=dev  0.0s
 => CACHED [dev_containers_feature_content_normalize 3/3] RUN chmod -R 07  0.0s
 => CACHED [dev_containers_target_stage 3/5] COPY --from=dev_containers_f  0.0s
 => CACHED [dev_containers_target_stage 4/5] RUN echo "_CONTAINER_USER_HO  0.0s
 => CACHED [dev_containers_target_stage 5/5] RUN --mount=type=bind,from=d  0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:c351526c29dce32db32738b709a1d9afeb4aed8c0901b  0.0s
 => => naming to docker.io/library/vsc-dood-sample-748888ecedf0dbacc0b905  0.0s
[27768 ms] Start: Run: docker events --format {{json .}} --filter event=start
[27773 ms] Start: Starting container

改めて、素晴らしいです。

どんどんfeaturesを活用しよう

features がビルドキャッシュしているということがわかった今、 拡張容易性、保守性、再利用性など多くのメリットを持っているfeatures は使わない手はなく、今後はどんどん活用していこうと考えています。

Discussion