DevContainerで快適開発

# はじめに
WEBアプリ開発の際、開発環境構築に無駄に時間がかかってしまいました。
今回は、それを防ぐためにDevContainerの学習をしたので共有します。

# DevContainerとは
Dockerのコンテナ技術を利用した、VSCodeで利用できる開発環境構築ツールです。

https://code.visualstudio.com/docs/devcontainers/containers

DevContainerは、公式テンプレートからの新規作成のほか、既存の`Dockerfile`、`compose.yaml`から作成することもできます。

# 開発環境の作成

:::note info
この記事の環境は以下の通りとなっています。
- Windows11 Home
- Docker Desktopインストール済み
:::


今回は、Microsoftが用意したDevContainer用のイメージではなく、`Dockerfile`と`compose.yaml`を用意してDevContainerを作成することにします。
まず以下の通り、ファイルを用意します。

```shell
DevContainer-test
│  compose.yaml
│
└─.devcontainer
        devcontainer.json
        Dockerfil
```

Goを使ったWEB APIサーバーを開発するため、Go開発用の`Dockerfile`を用意します。

```Dockerfile:Dockerfile
FROM golang:1.22.3-bullseye

RUN useradd -ms /bin/bash dev

USER dev

WORKDIR /app

EXPOSE 8080

COPY . /app

CMD ["go", "mod", "tidy"]

```

docker composeには、データベースserviceを用意して、通信できるようにします。
```yaml:compose.yaml
services:
  devcontainer:
    build:
      context: .
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - .:/app
    tty: true
    command: /bin/bash
    ports:
      - "8080:8080"

  database:
    image: postgres:13.15-bullseye
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: devTest
    ports:
      - "5432:5432"

```
肝心の`devcontainer.json`ファイルの中身を見ていきましょう。
```json:devcontainer.json
{
  "name": "DevContainer test",
  "dockerComposeFile": "../compose.yaml",
  "service": "devcontainer",
  "workspaceFolder": "/app",
  "customizations": {
    "vscode": {
      "extensions": [
        "golang.go"
      ]
    }
  }
}
```
## devcontainer.json

各プロパティについて説明していきます。

[公式リファレンス](https://containers.dev/implementors/json_reference/ "Dev Container metadata reference")

<dl>
  <dt>name</dt>
      <dd>左下の<code>><</code>や、上部の検索ボックスに表示される名前</dd>
  <dt>dockerComposeFile</dt>
      <dd><code>compose.yaml</code>があるファイルを相対パスで記述</dd>
  <dt>service</dt>
      <dd>どのserviceで作業するか</dd>
  <dt>workspaceFolder</dt>
      <dd>コンテナ接続時、自動で開くフォルダを選択</dd>
  <dt>customizations</dt>
      <dd><code>devcontainer.json</code><a href="https://containers.dev/supporting" title="Supporting tools and services">対応サービス固有の設定</a>が記述できる。ここでは、VSCodeを使用しているため、VSCodeの設定を記述</dd>
    <dd><code>extensions</code>で、コンテナ起動時に自動でインストールする拡張機能を設定できる</dd>
    <dd><code>settings</code>でVSCodeの設定ができるが、<code>settings.json</code>をワークスペースに用意したほうが直感的でわかりやすいため、ここには記述しないことにしました。</dd>
</dl>

# 最後に
以上で、開発環境を簡単に用意できました。
ただ、実際には全く簡単にできなくて、何度もコンテナがうまく作成できませんでした。
ここでは、その内容を説明していきます。
## 失敗談

### dockerComposeFileの指定
相対パスではなく、ただ`compose.yaml`とだけ書いていたため起動してもすぐエラーが出ました。

```diff_json
- "dockerComposeFile": "compose.yaml"
+ "dockerComposeFile": "../compose.yaml"
```

### `devcontainer`serviceが勝手に停止してしまう
DevContainerを開いても、すぐに`devcontainer`service(Go開発環境)が停止してしまい、VSCodeがエラーを吐いてしまいました。
そのため、`compose.yaml`に以下の2行を追加し、serviceが`bash`を起動し続けるようにしました。
```diff_yaml
services:
  devcontainer:
  #...
+    tty: true
+    command: /bin/bash
```

### データベースとの通信
当初は、`Dockerfile`だけ用意して、`compose.yaml`は用意していませんでした。
そのため、個別にDocker Networkを用意したり、DevContainerとデータベースコンテナを別々に起動する手間がありました。
その後、`compose.yaml`からもDevContainerを作成できると知って今回の方法になりました。

### コンテナのリビルド
コンテナの構成を変更するため、`Dockerfile` `compose.yaml` `devcontainer.json`の内容を書き換えても、コンテナのリビルドをしなければ変更が反映されません。リビルドの方法を紹介します。

![SnapCrab_DevContainer-test - Visual Studio Code_2024-5-22_10-41-22_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471738/7e40cf5d-e974-6aeb-a972-45f4695ef9c5.png)

`ctrl`+`SHIFT`+`P`でコマンドを表示し、`Dev Containers: Rebuild`と入力したら出てきます。

## 感想
なんとなく難しそうで避けていたDevContainerですが、いざ使ってみるとかなり便利そうでワクワクしました。
これまでは`WSL`上で開発していましたが、様々なアプリをインストールすることで環境が汚れてしまっているのが気になっていました。コンテナ上で開発すれば、その問題も解決できるので、今後も使っていきたいです。