Docker Desktopを使ってNode.jsアプリをコンテナ上で動かしてみた

#Docker Desktopを使ってみたい！

先日、[こちらの投稿](https://qiita.com/gahoh/items/7b21377b5c9e3ffddf4a "【入門】はじめての Docker Desktop for Windows のインストールと CentOS の仮想環境構築のセットアップ")を拝見し、Docker Desktop for Windowsを無事にインストールできました。
せっかくなので、最近勉強しているNode.jsのアプリケーションをDocker Desktop上で動作させてみたいと思います。

参考サイト：[Node.js Web アプリケーションを Docker 化する](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/)

| 利用環境 | バージョン |
|:-:|:-:|
|  Windows 10 Pro 64bit | 1909  |
|  Visual Studio Code | 1.51.1  |
|  Docker Engine | 19.03.13  |
|  Node.js | 12.16.3  |
|  npm | 6.14.4  |

**この記事でやってみること**
①Dockerfileを使ってExpress.jsアプリを起動する
②VSCodeの拡張機能"Remote-Containers"を使ってみる


#①Dockerfileを使ってExpress.jsアプリを起動する

`node-docker`ディレクトリおよび`Dockerfile`ファイル、`.dockerignore`ファイルを作成します。

```powershell
mkdir node-docker
cd node-docker
New-Item -Type File Dockerfile
```

`Dockerfile`には、下記の通り入力します。

```dockerfile:Dockerfile

#ローカルの環境にあわせてバージョン12
FROM node:12

# アプリケーションディレクトリを作成する
WORKDIR /usr/src/app

# expressインストール
RUN npx express-generator --view=ejs .
RUN npm install nodemon
RUN npm install

EXPOSE 3000

#express-generatorで作成されたサンプルアプリをnodemonで起動
CMD [ "npx", "nodemon", "./bin/www" ]

```
この状態でDockerイメージのビルド＆起動します。

```powershell
#"flets708/myapp"という名前のDockerイメージを作成
docker build -t flets708/myapp .
#作成したDockerイメージを元にtestappという名前のコンテナを起動
docker run -it -d --rm -p 13000:3000 --name testapp flets708/myapp
```
ちなみに上記コマンドで`--rm`オプションをつけていますが、これをつけるとコンテナを停止した時に勝手に削除されます。たくさんコンテナつくって遊んでいると乱立したりするので、自動削除は便利だなと思います。

`docker ps`コマンドで起動状態を確認します。

```powershell
PS > docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                     NAMES
337cb52f6231        flets708/myapp           "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:13000->3000/tcp   testapp
```

無事にExpressのWelcomeページが表示されました！

![testapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820066/9c86a0de-1d1a-f7a3-ba26-6411dc659cd1.png)

#②VSCodeの拡張機能"Remote-Containers"を使ってみる

コンテナが無事に起動できたところで、VSCodeを使ってコンテナの中で直接開発できるとより良いなあとふと思いました。[色々調べた結果](https://ishida-it.com/blog/post/2019-11-22-docker-nodejs-vscode/ "DockerでNode.jsアプリケーションを開発する (2) VS Codeのリモート開発拡張機能を使う")、VSCodeの拡張機能「Remote-Containers」というのがあるらしいので早速使ってみました。
この拡張機能を使うと、Dockerコンテナ内で直接VSCodeを使った開発が可能とのこと。
個人的に特にメリットになりそうだなと感じたのは下記3点です。

**VSCodeを使ってDockerコンテナ内で開発するメリット**
a. 環境設定まるごとコンテナとして保存できる
b. ローカルの環境に左右されない
c. 拡張機能を直接設定できる。ESLintとかが良い感じに使える

aとbはコンテナそのもののメリット、cは"Remote-Containers"ならではのメリットという感じでしょうか。

ということで、以下の手順で導入してみました。

`node-docker`ディレクトリ内に`.devcontainer`ディレクトリを作成し、さらに`devcontainer.json`ファイルを作成します。

```powershell
cd ../node-docker
mkdir .devcontainer
cd .devcontainer
New-Item -Type File devcontainer.json
```
devcontainer.jsonには下記を記述します。それぞれの記述の説明はコメントを参照ください。

```json:devcontainer.json
{
	// Remote-Containersを使ってVSCodeを開いたときのウィンドウのタイトル。何でもいい。
	"name": "Existing Dockerfile",

	// 実行パスを指定。.devcontainerディレクトリの一階層上。
	"context": "..",

	// Dockerfile上で指定したワークスペースディレクトリにあわせる。
	"workspaceFolder": "/usr/src/app",

	// 利用するDockerfileの相対パス。
	"dockerFile": "..\\Dockerfile",

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

	// コンテナ作成時にインストールしたい拡張機能のIDを書く。
	"extensions": [
		"dbaeumer.vscode-eslint",
	],

	// ローカルの13000盤ポートとコンテナの3000番ポートを接続。
	"appPort": ["13000:3000"],

}
```


`extensions`部分に拡張機能を色々設定できるのが便利です。お好みで色々設定してみると良いと思います！

`devcontainer.json`の準備が終わったら、コマンドパレット上で`Remote-Containers: Open Folder in Container...`を選択します。出てこない人は拡張機能`Remote - Containers (ms-vscode-remote.remote-containers)`もしくは`Remote Development (ms-vscode-remote.vscode-remote-extensionpack)`を先にインストールしてください。
`Remote-Containers`は`Remote Development`のコンテナ接続部分だけに絞った拡張機能のようです。
![remote-containers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820066/e158979a-9043-a100-01cc-887e1373254b.png)

ディレクトリ選択画面が出るので、`node-docker`ディレクトリを指定した上でOpenすると、開発用コンテナのイメージ作成とコンテナ起動が自動で開始されます。
最終的に、下記画面になっていればOKです！
![remote-containers2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820066/975153e2-8e08-83a9-fa0a-88307f18c667.png)

ターミナルもコンテナ内のExpressインストールディレクトリになっていることが確認できます。
ちなみに、作成されたイメージとコンテナは下記のようになっていました。

```powershell
PS > docker images
REPOSITORY                                         TAG                 IMAGE ID            CREATED             SIZE
vsc-node-docker-ca6497fdb4b6eecf9b3f476bxxxxxxxx   latest              a853xxxxxxxx        4 hours ago         927MB
PS > docker ps
CONTAINER ID        IMAGE                                              COMMAND                   CREATED             STATUS              PORTS                     NAMES
376ab65ea05e        vsc-node-docker-ca6497fdb4b6eecf9b3f476xxxxxxxx   "/bin/sh -c 'echo Co…"   4 minutes ago       Up 4 minutes        0.0.0.0:13000->3000/tcp   bold_pasteur
PS >
```

#終わりに

今回初めてRemote-Containersを触ってみたので、まだまだ「やってみた」レベルですが、これからしばらく触ってみて、真価を探っていこうと思います。
自分の備忘のため、というのが一番の目的の記事ですが、もしどなたかのご参考になれば幸いです！