DevContainerを使ってみたらかなり良かった話

# はじめに


VSCodeって便利ですよね。私は重宝してます。
VSCodeでPythonを書いたり、Terraformを書いたり、AWS CDKを書いたりしています。

しかし、使っていくと拡張機能がたっぷり入ってごちゃごちゃしてきます。

そうなると、プロジェクトごとに必要な拡張機能を分離したくなりませんか？

ついでに開発環境も分離して、なんならリポジトリをCloneしてすぐVSCodeで開発して実行できる状態にしたくなりませんか？

そんな素敵な夢を叶える方法の１つとしてDev Containerを紹介します。


# Dev Containerとは
Dev Containerを実行してローカルのVSCodeとDev Container内で実行されているVSCode Serverと接続して実行します。ローカルのVSCodeはクライアントとして動作します。

>![DevContainerImage](https://code.visualstudio.com/assets/docs/devcontainers/containers/architecture-containers.png)
https://code.visualstudio.com/docs/devcontainers/containers より引用

開発体験はローカルに近い状況ですが、VSCodeがDev Container内のVSCode Serverとして実行されているのでVSCodeの環境隔離が可能です。

VSCodeのTerminalもDev Containerで実行することになるので、付随するツールのバージョン管理もしやすくなります。



# Dev Container利用の強み

Dev Containerを活用することで、開発環境を明示的に管理し、ツールのバージョンや実行環境をプロジェクトごとに統一できます。たとえば、aws cliやgcloudなどのツール類もDev Container内で動かせるため、ローカル環境を汚すことなく、それらのバージョン管理や設定をコンテナ内で完結させることが可能です。

また、既存プロジェクトでアプリをコンテナで動かしてる場合でも、**Docker in Docker**または**Docker from Docker**が利用可能なので、大きく変更せずにDev Containerへ移行できます。

Dev Containerを導入することで、ローカル環境に依存しない開発体験を実現し、プロジェクトごとの環境分離が容易になります。



# Dev Containerの初め方

### 必要なローカル環境
- Docker
- VSCode

## 手順
新規プロジェクトを作成する話で進めます。

`devcontainer.json`を作成してDevContainerに入るまでの手順です。
今回はPython3.12の環境を用意する流れで行います。

以下のURLの手順を参考にしています
https://code.visualstudio.com/docs/devcontainers/containers
### 前提条件
- Dockerが稼働している
- VSCodeがインストールされている


### 1. Dev Container化したいディレクトリをVSCodeで開く
ディレクトリをVSCodeで開くとワークスペースとして開きます。
### 2. VSCodeのステータスバー左の`><`を押す
![processimage1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/fecbf771-6211-8af3-0cef-0f3ab39192e0.jpeg)

### 3. DevContainerを選択する
DevContainerを選択してください。拡張機能DevContainersが自動でインストールされます。
![スクリーンショット 2024-12-04 16.03.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/070140f4-c295-216d-3033-2de7da63afbf.jpeg)



自動でインストールされない場合は、拡張機能から`DevContainers`を検索して手動でインストールしてください。


以下のような表示だった場合には手順5に進んでください
![スクリーンショット 2024-12-04 16.11.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/6c193541-87ae-ee61-1ac8-145ee2b74d99.jpeg)
### 4. もう一度、ステータスバー左の`><`を押す

### 5. コンテナー構成ファイルを開くを押す
![スクリーンショット 2024-12-04 16.11.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/6c193541-87ae-ee61-1ac8-145ee2b74d99.jpeg)
### 6. ワークスペースに構成を追加するを押す
![スクリーンショット 2024-12-04 16.17.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/420c29fd-673f-df1e-bd3c-36e58ea3956d.jpeg)

### 7. コンテナ構成テンプレートを選ぶ
今回はPython3を使いたかったのでPython 3のコンテナ構成テンプレートを選びました。
![スクリーンショット 2024-12-04 16.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/4d214fdf-2118-ab6c-a414-b00bb9401f65.png)

### 8. その他オプションを選んでいく

今回はPython3.12を使いたいので、`3.12`を選びました。
![スクリーンショット 2024-12-04 16.18.22.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/f5633bca-ac1e-faf3-020d-2c809bd167c2.jpeg)

今回は、DevContainerに追加で入れるものがなかったので選びませんでしたが、
追加で入れるものがあれば選んでください。（結構いろいろあります）
![スクリーンショット 2024-12-04 16.18.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/2dc771d7-9757-fab8-4886-25f1233334ee.png)

DevContainerのイメージをチェックしてくれるGitHub Actionsですが、今回は不要なので外しました。
![スクリーンショット 2024-12-04 16.18.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/e9757e97-d9b3-f7cb-d617-0c911f80fdf2.jpeg)


### 9. ディレクトリに`.devcontainer/devcontainer.json`が作成される

作成されたdevcontainer.jsonは以下の通り
```json-doc:devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
    "name": "Python 3",
    // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
    "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye"
    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},
    // 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": "pip3 install --user -r requirements.txt",
    // Configure tool-specific properties.
    // "customizations": {},
    // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    // "remoteUser": "root"
}
```

### 10. ステータスバー左の`><`を押す

### 11. コンテナで再度開くを押す
![スクリーンショット 2024-12-04 16.19.16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/d4946ba8-896c-fc0d-f7ed-0933fd664110.jpeg)

### 12. VSCodeのウィンドウが開き直されてDevContainerとして動作する
開発コンテナーの表記があればDevContainerで動作しています。
![スクリーンショット 2024-12-04 16.19.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933250/3664b87b-ec36-b6b2-7e8e-0d92dc14c843.png)

初回起動時には、操作可能になるまで多少時間がかかりますので気長に待ちましょう。（裏でDocker Buildしたりなんだりをしています）





# Dev Containerのカスタマイズ
`devcontainer.json`に設定を加えることで、Dev Containerに以下のようなカスタマイズが可能です。
- Dev Containerに利用するDockerfile or Docker Composeの設定
- Dev Containerに追加する機能の設定
- マウントするディレクトリの設定
- 事前にインストールする拡張機能の設定



こちらのページで設定できる項目の記載があります。

https://containers.dev/implementors/json_reference/


最近作ったpython開発環境とgcloudを利用するDevContainerの設定例です。
```json-doc:devcontainer.json
{
	"name": "Python 3",
	"build": {
		"dockerfile": "Dockerfile"
	},
	"workspaceFolder": "/${localWorkspaceFolderBasename}",
	"workspaceMount": "source=${localWorkspaceFolder},target=/${localWorkspaceFolderBasename},type=bind,consistency=cached",
	"features": {
		"ghcr.io/devcontainers-contrib/features/zsh-plugins:0": {},
		"ghcr.io/nils-geistmann/devcontainers-features/zsh:0": {},
		"ghcr.io/devcontainers/features/git:1": {}
	},
	"onCreateCommand": "poetry install && exit",
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-python.python",
				"njpwerner.autodocstring",
				"ms-python.mypy-type-checker",
				"ms-python.debugpy",
				"charliermarsh.ruff",
				"ms-vscode.makefile-tools",
				"tamasfe.even-better-toml",
				"ryanluker.vscode-coverage-gutters",
				"ms-azuretools.vscode-docker"
			]
		}
	},

	"mounts": [
		"source=${localEnv:HOME}/.config/gcloud,target=/home/vscode/.config/gcloud,type=bind,consistency=cached"
	]
}

```



# チームでDev Containerを利用する場合
### 必要な拡張機能のインストールを必須にできる

Dev Containerを利用しないでも、必要な拡張機能を定義することができましたが、あくまでインストールを推奨するに留まっていました。

Dev Containerの場合はコンテナビルド時に拡張機能もインストールするので、必要な拡張機能を入れていないために発生した問題が起きなくなります。

### ローカルに入れていたツール類も統一できる

aws cliやgcloudなどはローカルに入れている場合もそこそこあるのではないかと思います。
各々の環境によってはうまく動かないなど問題が起きることもありますが、Dev Containerにツールを入れることで、そういった環境差異による問題を抑えることができます。



# Dev Containerの弱点

### Dev Containerのビルドに時間がかかる
Dev Containerがかなり重たいので、ビルドにある程度時間がかかります。
対策としては、Dev Container用のイメージリポジトリを用意してPullするだけにするなどあります。


### Macの場合、ファイル読み書きが遅くなることがある
Dev Containerというより、MacのDocker Desktopの弱点ではありますが、既知の通りファイルの読み書きが遅くなり待たされることがあります。
Docker Desktop 4.27で追加されたファイル同期機能を利用すればある程度改善するかと思いますが、事前に同期の設定をDocker Desktopに施す必要があるようなので、手間をとるか、体験をとるかといったところになるかと思います。


### チームで開発していた場合に、個人的に入れたい拡張機能をDev Containerを新規起動するたびに入れる必要がある
チームで利用していた場合に、共通で利用している拡張機能は起動時に自動で入りますが、個人的に拡張機能を入れたい場合は、Dev Containerを作り直すたびに入れる必要が出てきます。チームメンバーによってはデメリットになる可能性があります。


## Docker in Docker 、Docker from Dockerについて
DevContainerの弱点というわけではないですが、それぞれ一長一短があるので、最適な方法を選択すれば良いかなと思います。

### Docker in Docker
Docker in Dockerは、Dev Container内で Dockerを実行してDevContainer内でコンテナを実行します。コンテナ内でコンテナを動かすので重たいコンテナを動かす必要がある場合に辛くなってくるかもしれません。Docker ComposeでローカルとDev Containerどちらでも動かすことがある場合は、共通のdocker-compose.yamlでどちらも動かせると思います。

### Docker from Docker
Docker from Dockerはローカル環境のDockerに接続して、Dev ContainerからローカルのDockerを実行することができます。
Docker in Dockerと違い、ローカルでコンテナを実行できるので、処理速度的には多少有利になります。
Docker Composeで実行させる場合はVolumeの設定などをDev Container専用にする必要があるため、ローカルとDev Containerどちらでも動かしたい場合などはdocker-compose.yamlの作り分けが必要になりそうです。
# まとめ
以前からDev Containerの存在は知っていましたが、利用していませんでした。実際に利用してみて、かなり便利だったので今回紹介させていただきました。

いくつか弱点を挙げましたが、使い方によっては開発環境の準備が非常に楽になります。
ちょっとしたコードを書くときにもDevContainerでサクッと開発環境を用意して書くようになりました。環境分離されているので、ローカル環境の状況を気にせず始められるのが非常に便利です。

業務のプロジェクトも少しずつDevContainer化を進めて、布教活動をしています。

最近は, JetBrains IDEでもDevContainerが利用できるようになったようなので、さらにDevContainerの活用が進むかもしれません。

ワンクリックでVSCode含めて環境構築が完了する体験は非常に魅力的ですので、ぜひみなさまにも触っていただいて、この感動を感じていただければと思います。