まだanyenv使ってるの？ Docker使ってもっと楽にいこうぜ？

## Windowsなどのホストに環境を入れる際に起きる欠点

よくあるのがバージョン差異です。

そして何よりもインストールが面倒。
そしてnodeやmavenがどんどんローカル環境を圧迫していく。

そして発生するMacとWindowsでの環境差異の問題。

極め付けばenvの設定ミスで違うバージョンが使われる。

## devcontainerのススメ

devcontainerは、Docker上に開発環境を構築してそこで開発を全て行うための技術です。

GitHub codespaces(Visual Studio codespaces)を利用する場合のコア技術だったりもします。

簡単にいうと開発用の仮想マシンを内部にぽこじゃか作っていくことになるので、

Window AppやモバイルなどのGUIアプリの開発には若干不向きですが、
Web系は基本的にこれで事足ります。

そのため、nodeやRuby、PythonといったものをVSCodeで実行するのであれば、devcontainerで済ませることができます。


### 必要なもの

- Docker Desktop
- Visual Stidio Code
   - Remote Developmentの拡張機能

## devcontainerを試しに使ってみる

今回は、例としてnodejs + Express + mongodbを使うことを前提とします。
ただし、mongoは立てるだけで実アクセスはしないことにします。

### devcontainerの設定

.devcontainerというディレクトリを作り、その中にdevcontainer.jsonとdockerのコンテナに関する情報を格納します。

```
 Root Directory
  ├ .devcontainer 
  │   ├ devcontainer.json
  │   ├ docker-compose.yml
  │   └ Dockerfile
  └ 各ソース   
```

### devcontainerを作る

コンテナとそこで動くVSCodeに関する情報を記載します。

```json:.devcontainer/devcontainer.json
{
    // コンテナ名
    "name": "Express Sample",

    // docker-composeのファイル名
    "dockerComposeFile": "docker-compose.yml",

    // コンテナにアタッチされたプロジェクトのルートディレクトリ
    "workspaceFolder": "/work",

    // docker-composeが複数コンテナの場合、
    //  どのコンテナに入るのかを指定
    "service": "app",
    // 外部から接続するポート(開放ポート)を指定
    "appPort": 3000,

    // インストールする拡張機能を設定
    "extensions": [
        "VisualStudioExptTeam.vscodeintellicode",
        "dbaeumer.vscode-eslint",
        "stevencl.addDocComments",
        "eg2.tslint"
    ]
}
```

ここに記載した拡張機能はホストのVSCodeとはまた違う領域にインストールされます。

そのため、違う言語・プラットフォームに切り替えた際もVSCodeがクソ重くなるようなことは回避することができます。

### Dockerの設定ファイルを作る

Dockerfileとdocker-compose.ymlを作成します。
これはdevcontainerに関係なく、開発用で使っているものをそのまま流用することも可能です。

```:.devcontainer/Dockerfile
FROM node:15.2.0-alpine3.10

EXPOSE 3000
```

```:.devcontainer/docker-compose.yml
version: '3'

services:
  app:
    build: .
    ports:
      - 3000:3000
    volumes:
      - ../:/work
    tty: true

  db:
    image: mongo:3.6.20-xenial
    # 本来ならポートやボリュームアタッチが必要。
```

### 開き直し

画面をリロードすると、開き直す？と聞かれるので「Reopen in Container」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97156/3fc9a3b1-5f30-d634-1908-81e7671020b2.png)

あとは画面がリロードされ、イメージの展開とコンテナの生成がおこなれれます。
VSCode関連のインストールも走るので、気長に待ちましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97156/c598a3c0-1e40-8aec-a596-050cf77a807f.png)

無事起動したら、nodeが動いていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97156/9d18e891-3903-9853-6a58-bf20fff18cee.png)

この時点で、VSCodeのターミナルはdockerコンテナのターミナルを指していますので、
基本的にはVSCode内のこのターミナルを利用するようにしてください。

## アプリの開発

npm initしpackage.jsonを作ります。

```
# npm init -y
# nom install -S express
```

次に、以下のコードを作成します。

```javascript:index.js
'use strict'

const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

app.get('/', (req, resp) => {
    resp.send('Hello, JS WORLD!');
})


app.listen(port, () =>{ 
    console.log(`Example app listening on Port ${port}`);
});
```

実行してみます。

```
# node index.js
node index.js
Example app listening on Port 3000
```

この状態でホストから接続してみましょう。

うまく表示されたら完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97156/40b62100-754f-14ce-804e-9c2d79e8f1ba.png)


あとは通常のVSCodeと同じように開発を進めることができます。

## 他の開発者への展開

他の開発者へ展開する場合も、devcontainerさえ作っておけば簡単に構築できます。

必要なのはVSCodeとリモート開発のための拡張機能のみです。


## Node.js以外の設定

今回はnode.jsで行いましたが、PythonでもRubyでもJavaでも基本的な使い方は同じです。

次の2点についてのみ気をつけていれば、基本的に困りません。

- コンテナのベースイメージ
- インストールする拡張機能

## さいごに

コンテナ単位で環境やバージョンを切り分けることができますので、
xEnvを使うよりも安全にバージョン問題を解決することができます。

また、開発環境としてDockerを用いているのであれば、簡単なjsonを書くだけで済みます。


もしVSCodeを使っているのであれば、devcontainerを用いて環境構築を簡略化してはいかがでしょうか。