M1 Macでも快適なVSCode Remote Container用イメージ作成を試す

（2021年9月22日更新）
公式イメージがarm64/aarch64に対応してました。
https://github.com/microsoft/vscode-dev-containers/issues/558#issuecomment-919299497

例えば「Node.js & TypeScript」用イメージだと

```json:/.devcontainer/devcontainer.json
"args": { "VARIANT": "14-bullseye" }
// "12-bullsey" や "16-bullsey" でもOK
```
とするだけ。便利になりました。

以下の内容は最早無駄作業ですが、過去の自分の作業記録として残しておきます。

# M1 Macでも環境を汚さずにVSCodeで開発したいが…

Apple M1チップに対応した「Docker Desktop」が一般リリースされました。

Visual Studio Codeの[「Remote - Containers」拡張機能](https://aka.ms/vscode-remote/download/containers)を試してみようと、まずは3ステップ（？）で簡単に試せる「[Quick start](https://code.visualstudio.com/docs/remote/containers#_quick-start-try-a-development-container)」通りの方法で、「[Node.js & TypeScript](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/typescript-node)」環境を選択して動かしてみると…

正直なところ、私の M1 Mac mini（メモリ8GB）環境では、動作がもっさりとしています。

よく見ると、Dockerイメージが x86-64 向けなのですね。

arm64 向けイメージをパッとは探せず、Intel Macもまだまだ使っているので、ここは[マルチプラットフォームのイメージ作成](https://docs.docker.com/buildx/working-with-buildx/#build-multi-platform-images)を試してみるいい機会だと思い立ちました。


## 試作したイメージ

- DockerHub: https://hub.docker.com/u/earth422

### 「Node.js & TypeScript」用イメージの使い方

```Dockerfile:/.devcontainer/Dockerfile
FROM earth422/vscode-dev-container-typescript-node:14

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
#     && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"

# [Optional] Uncomment if you want to install more global node packages
# RUN su node -c "npm install -g <your-package-list -here>"
```

```json:/.devcontainer/devcontainer.json
{
	"name": "Node.js & TypeScript",
	"build": {
		"dockerfile": "Dockerfile"
	},

	// Set *default* container specific settings.json values on container create.
	"settings": { 
		"terminal.integrated.shell.linux": "/bin/bash"
	},

	// Add the IDs of extensions you want installed when the container is created.
	"extensions": [
		"dbaeumer.vscode-eslint"
	],

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

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "yarn install",

	// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
	"remoteUser": "node"
}
```

1. ワークスペースに上の2つのファイルを作成する
    - docker-composeを使うこともできます。
1. コマンドパレット（F1キー）から、「Remote-Containers: Open Folder in Container...」を選択

私の環境では、もっさり感はなくなりました。


## イメージ作成方法

Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする方法は、[公式サイト](https://docs.docker.com/buildx/working-with-buildx/)のほか、こちらのサイトを参考にさせていただきました。

- [Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする](https://dev.classmethod.jp/articles/docker-multi-architecture-image-build/)

### 0. 「buildx」コマンドを使う準備をする

```
$ docker buildx create --name mybuilder
$ docker buildx use mybuilder
```
これだけでOKでした。

### 1. 公式イメージのルーツを調べる

詳しい方は一発で作成できるDockerfileを書けるのかもしれませんが、できるだけ労力をかけないで（ほとんど書き換えないで）やってみたいところ。

公式の「[Node.js & TypeScript](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/typescript-node)」用イメージは、「[Node.js & JavaScript](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/javascript-node)」用イメージから、その元は[Node.js公式](https://hub.docker.com/_/node)のbusterイメージから来ているようです。Node.js公式イメージはマルチプラットフォーム対応しているので、ここからスタートしてみました。

### 2. 「buildx」コマンドでビルドする

まず__ビルド環境と異なるプラットフォームのDockerイメージは出力することができない__ので、__ビルドしたDockerイメージをローカルに保持することなく「Docker Hub」へ直接出力する__ために、Docker Hubへのログインを行います。

次に、とりあえず自分が必要なNode14用のDockerfileと必要なスクリプト（docker-entrypoint.sh）をローカルに落とします。（後で、この部分は必要なかったと気づきましたが、buildxコマンド自体初めての体験だったこともあり、実際の作業を記録しておきます。）

この状態でビルドを実行します。

```
$ docker login
$ docker buildx build --platform linux/amd64,linux/arm64 -t earth422/node:14 --push .
```

元々マルチプラットフォーム対応しているので当然ですが、うまくビルドできたようです。

### 3. 公式を元にDockerfileを書き換えてビルドする

公式の「[Node.js & TypeScript](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/typescript-node)」用イメージのソースを見たところ、CPUアーキテクチャに依存するようなところはなさそうです。

本当は公式のDockerfileのままでマルチプラットフォーム対応版の「Node.js & JavaScript」用イメージを作成できるはずですが、私の場合は先ほどビルドしたイメージを元に作成しました。

直したのは、もちろん最初だけです。

```Dockerfile:/vscode-dev-container-node/Dockerfile
FROM earth422/node:14
```

先ほどと同様にビルドを実行します。

```
$ docker buildx build --platform linux/amd64,linux/arm64 -t earth422/vscode-dev-container-node:14 --push .
```

今度もうまくビルドできたようです。このイメージを元に、更にマルチプラットフォーム対応版の「Node.js & TypeScript」用イメージを作成します。

今度も修正するのは頭だけでした。

```Dockerfile:/vscode-dev-container-typescript-node/Dockerfile
FROM earth422/vscode-dev-container-node:14
```

```
$ docker buildx build --platform linux/amd64,linux/arm64 -t earth422/vscode-dev-container-typescript-node:14 --push .
```

すんなり成功しました。

特に目新しいこともありませんが、ご自分で作成されるのが面倒な方は自己責任で使ってください。

~~公式もマルチプラットフォームに対応するといいなぁ。~~ →対応してました。（2021年9月22日更新）


## 参考文献等

- [Docker Buildx](https://docs.docker.com/buildx/working-with-buildx/)
- [Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする](https://dev.classmethod.jp/articles/docker-multi-architecture-image-build/)
- [Developing inside a Container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/containers)
- [VS Code Remote / GitHub Codespaces Container Definitions](https://github.com/microsoft/vscode-dev-containers)
- [docker-node / 14 / buster](https://github.com/nodejs/docker-node/tree/main/14/buster)

## 最後に

読んでくださった方、ありがとうございました。

初めてのQiita投稿です。お手柔らかにお願いいたします。:sweat_smile: