Visual Studioのコードと同じDockerを使ってNode.jsアプリを開発する

このガイドでは、Ubuntu Linuxデスクトップ上でVisual Studio Codeを使って**Node.js**アプリを開発し、**Alibaba Cloud**上で**Docker**を使って同じアプリをデプロイしていきます。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/developing-node-js-apps-using-visual-studio-code-with-docker-on-simple-application-server_595352)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

#よくある質問
####Node.jsとは？
Node.jsはオープンソースでクロスプラットフォームなJavaScriptのランタイム環境で、サーバー上でJavaScriptを実行することができます。

####Express とは？
Expressは、最小限で柔軟性の高いNode.jsのWebアプリケーションフレームワークで、Webとモバイルアプリケーションのための堅牢な機能セットを提供しています。

####Dockerとは？
Dockerは非常に人気のあるコンテナプラットフォームで、アプリケーションやサービスを簡単にパッケージ化、デプロイ、消費することができます。

####Docker Hubとは？
Docker Hubは、Dockerユーザーやパートナーがコンテナイメージを作成、テスト、保存、配布するクラウドベースのリポジトリです。

####Visual Studio Codeとは？
Visual Studio Codeは、デスクトップ上で動作し、Windows、MacOS、Linuxに対応した軽量かつ強力なソースコードエディタです。JavaScript、TypeScript、Node.jsをビルトインでサポートしており、他の言語（C++、C#、Java、Python、PHP、Goなど）やランタイム（.NET、Unityなど）に対応した拡張機能の豊富なエコシステムを備えています。Visual Studio Codeでは、Dockerを使ったアプリケーションのデプロイを簡単に行うことができ、プロジェクトの種類に応じて適切なDockerファイルの生成と追加をサポートしています。

####Alibaba Cloud Simple Application Serverとは？
Simple Application Serverは、アプリケーションの起動と管理、ドメイン名解決の設定、ウェブサイトの構築、監視、保守を数回クリックするだけで行えるオールインワンのソリューションを提供します。プライベートサーバーの構築が格段に簡単になり、初心者がアリババクラウドを始めるのに最適な方法です。

#アプリケーションの開発例
####Ubuntu Linuxデスクトップに前提条件をインストール
私はバージョン16.04のUbuntu Linuxデスクトップを持っています。記載されている手順は、すべてのバージョンでほとんど同じです。

####Node.js
node.jsが既にインストールされているかどうかを確認します。

```
node –v
```

バージョン番号が表示されない場合は、以下の手順でインストールしてください。

```
sudo apt-get install curl python-software-properties
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash –
sudo apt-get install nodejs
```

ノードとnpmのバージョンを確認します。

```
node –v
npm –v
```

####Docker
DockerにはEnterprise版とCommunity版があります。今回はコミュニティ版のDocker CEをインストールします。

以前のバージョンがインストールされているかどうかを確認し、インストールされている場合はアンインストールしてください。

```
sudo apt-get remove docker docker-engine docker.io containerd runc
```

aptパッケージを更新します。

```
sudo apt-get update
```

aptがHTTPSでリポジトリを使用できるようにします。

```
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
           gnupg-agent \
    software-properties-common
```

GPGキーを追加

```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –
```

安定版リポジトリを設定してインストールします。

```
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
```

dockerをインストールします。

```
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
```

hello-worldイメージを実行して、Dockerが正しくインストールされているかどうかを確認します。

```
sudo docker run hello-world
```

このコマンドはイメージをダウンロードしてコンテナ内で実行し、そのコンテナ内でHello Worldを印刷します。

しかし、上記のコマンドはsudoまたはrootユーザのアクセスで実行されています。

次にインストールするVisual Studio CodeとそのDockerエクステンションをIDEとして使用する予定なので、非rootユーザで実行できるようにする必要があります。VS Codeは非rootユーザで動作し、拡張機能を使うことでコンテナ化されたアプリケーションの構築、管理、デプロイが容易になります。

Dockerグループを作成します。

```
sudo groupadd docker
```

ユーザーをdockerグループに追加します。

```
sudo usermod -aG docker $USER
```

ログアウトして再度ログインするか、グループのメンバーシップが再評価されるように再起動してください。

```
sudo reboot
```

再起動後、sudoなしでdockerコマンドが実行できることを確認します。

```
docker run hello-world
```

####Visual Studioコード
VS Code をインストールする最も簡単な方法は、Snap パッケージとしてインストールすることです。スナップはすべての主要な Linux ディストリビューションで使用することができ、ほとんどの Ubuntu デスクトップにプリインストールされています。もしあなたのデスクトップにない場合は、[https://docs.snapcraft.io/installing-snapd](https://snapcraft.io/docs/installing-snapd?spm=a2c65.11461447.0.0.28726972BEDdJO) からインストールすることができます。

VSコードをインストールします。

```
sudo snap install --classic code
```

アプリケーション/プログラミングから同じものを選択するか、linuxターミナルでコードを入力してVisual Studioのコードを開きます。

「表示」→「拡張機能」に移動します。

Docker」を検索して、拡張機能をインストールします。拡張機能の詳細は [https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker](https://marketplace.visualstudio.com/items?spm=a2c65.11461447.0.0.28726972BEDdJO&itemName=ms-azuretools.vscode-docker) を参照してください。

####Node.jsプロジェクトの作成
アプリケーション/プログラミングから同じものを選択するか、linuxターミナルでコードを入力してVisual Studioのコードを開きます。

フォルダを開くを選択し、documentsディレクトリに移動します。ここでプロジェクトを作成します。

VS Codeにはシェルコマンドを実行するためのターミナルが統合されています。そこから直接Node.jsを実行することができます

Visual Studio Code のトップメニューから Terminal -> New Terminal を選択して Terminal を開きます。

Express用のテンプレエンジンをインストールするためにExpress Generatorをインストールします。

```
sudo npm install -g express-generator
```

新しいエクスプレスアプリケーションを足場にします。

```
express nodeexpress-alibaba-docker-tutorial --view=pug
```

これにより、nodeexpress-alibaba-docker-tutorialという名前の新しいフォルダが作成され、左のdocumentsの下にあるアプリケーションの内容を見ることができます。

####コードの編集と変更
ここに独自の開発コードを追加します。ここでは、いくつかの簡単な変更を行います。

routes フォルダの下にある index.js を選択します。

index.jsの中のres.renderを含むコードの行に移動します。

以下のように変更してください。

```
res.render('index', { title: 'Docker on Simple Application Server', data:'Alibaba Cloud' });
```

フォルダビューの下にあるindex.pugを選択します。

`Welcome to`を含む行の`データ`に`タイトル`を変更します。

####アプリケーションの実行
VSCodeターミナルで、ディレクトリをアプリケーションフォルダに変更します。

```
cd nodeexpress-alibaba-docker-tutorial
```

package.jsonファイルに存在するアプリケーションの依存関係をインストールします。

```
npm install
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5bac1ff9-202f-9962-a24c-2378c94ab166.png)

Package.jsonファイルには、Node.jsアプリケーションを実行するためのスタートスクリプトも含まれています。

```
npm start
```

ブラウザを開き、localhost:3000にアクセスしてアプリケーションを表示します。ポート番号はスタートスクリプトから呼び出されるbinフォルダ内のファイルwwwの中に設定されています。

Visual Studio Codeのトップメニューから「ファイル」→「フォルダを閉じる」を選択し、VS Codeでアプリケーションを閉じます。

####アプリケーションのDockerize例
パブリックリポジトリは、誰もが利用できるDockerイメージをホスティングするために使用することができます。Docker hubはパブリックリポジトリであり、利用するためのパブリックなDockerイメージのリストを見つけることができます。あとはそれらのイメージを引っ張ってきて、それを元にコンテナを起動し始めるだけです。Docker Hub上の公開リポジトリに公開することで、イメージを利用可能にしています。

####Docker Hubアカウントとリポジトリの作成
[https://hub.docker.com/](https://hub.docker.com/?spm=a2c65.11461447.0.0.28726972BEDdJO) にサインアップし、アカウントを作成したらログインします。

トップメニューからリポジトリを選択します。

アカウントを作成したばかりなので、リポジトリはありません。リポジトリの作成ボタンを選択してリポジトリを作成します。これがあなたの画像が保存されるリポジトリです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/fbe30dec-796b-51cd-8b01-8713223e0bdb.png)

次の画面では、リポジトリの名前と説明を指定します。ここでは下の画像のようにnodeexpress-alibaba-docker-tutorialという名前を指定します。

リポジトリを公開し、dockerhub上で検索できるようにしています。また、リポジトリを非公開にすることもできます。1つのプライベートリポジトリは無料で、課金プランを利用すればそれ以上の数のリポジトリを作成することができます。プライベートリポジトリは公開リポジトリと同じように動作しますが、閲覧や検索ができません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/b967ab62-fbf8-9e7c-f6da-03b2fac11c36.png)

Click on the Create button and your repository is ready.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/942ae4f7-5b3b-1e44-50e8-8978a30ea90d.png)

画面の右端にあるコマンドに注目してください。このコマンドを実行して画像をこのリポジトリにプッシュする必要があります。

画像は `[registry or username]/[image name]:[tag]` の形式である必要があります。

注：Alibaba Cloudは、[https://www.alibabacloud.com/product/container-registry]() で利用できる安全なコンテナレジストリも提供しています。

####アプリケーションをDockerizeする
フォルダを開くを選択し、documentsフォルダの下にあるnodeexpress-alibaba-docker-tutorialフォルダに移動し、アプリケーションを開きます。

Visual Studio Codeのトップメニューから「ターミナル」→「新規ターミナル」を選択してターミナルを開きます。

Dockerがインストールされて実行されていることを確認します。

```
docker –version
```

Visual Studio CodeのトップメニューからView->Command Paletteを選択してCommand Paletteを開きます。

ワークスペースにDockerファイルを追加と入力し、Dockerを選択して実行します。Dockerファイルをワークスペースに追加するコマンドを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/32c06ca9-15f0-e964-02ad-fc1d2391e3ee.png)

コマンドパレットでアプリケーションプラットフォームの選択を求められますので、Node.jsを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/2ce250f5-f1de-7a33-a320-2bd81bd0eb54.png)

また、アプリケーションがリスンするポートを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/65df74e8-8960-2089-6756-26b02a25928a.png)

これにより、ソースファイルの場所やコンテナ内でアプリを起動するコマンドなど、アプリの環境を記述するDockerfileと共にプロジェクトに特定のファイルが追加されます。

コマンドパレットでDocker: Build Imageを実行してイメージをビルドします。先ほど作成したDockerfileを選択し、Docker hubリポジトリの作成時に指定したフォーマットでイメージに名前を付けます。名前は......... `arnab74/nodeexpress-alibaba-docker-tutorial:firsttry`



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/58b7d62c-b225-045b-763f-4586817263f7.png)

ターミナルパネルが開き、Dockerコマンドが実行されます。ビルドが完了すると、DockerエクスプローラーのImagesの下にイメージが表示されます。

コマンドパレットでdocker runと入力し、Docker:Images runを選択してコンテナをビルドします。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/a7356f51-1448-1ff0-0291-11682e517530.png)

コマンドパレットで、イメージグループ `arnab74/nodeexpress-alibaba-docker-tutorial` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/2286eb70-5185-18ba-80ac-313f55426eed.png)

コマンドパレットで、Image firsttryを選択します。

ターミナルに表示された生成されたコマンドを実行します。

コマンドは'docker run'で、2つのフラグがあります。

-p : これはコンテナ上のポートを公開し、ホスト上のポートにマッピングします。ここでマッピングされたホスト上のポートも同様に3000です。

-d : バックグラウンドでコンテナを実行します。

詳細は [https://docs.docker.com/engine/reference/commandline/run/](https://docs.docker.com/engine/reference/commandline/run/?spm=a2c65.11461447.0.0.28726972BEDdJO) を参照してください。

実行中のコンテナを検査します。

```
Docker ps
```

ブラウザを http://your_server_ip:3000 または http://localhost:3000 に移動してアプリケーションを表示します。

実行中のアプリケーションコンテナを停止するには、実行中のコンテナを右クリックして、DOCKER explorer の Containers の下にある stop を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/12602e07-0f29-8985-57ca-f8af9649af30.png)

または、ターミナルで以下のコマンドを実行することができます。

```
docker stop [CONTAINER ID]
```

CONTAINER ID]を`Docker ps`コマンドで取得した自分のCONTAINER IDに置き換えてください。

####お試し追加ステップ
VSCode の docker 拡張機能によって自動的に生成される dockerfile を改良しました。

[https://hub.docker.com/_/node/](https://hub.docker.com/_/node/?spm=a2c65.11461447.0.0.28726972BEDdJO) から現在の nodejs LTS バージョンに基づいてアプリケーションのベースイメージを更新します。

コンテナをrootで実行することは避けなければなりません。Docker Nodeイメージには、rootではないノードのユーザが含まれています。ユーザーと同じにして、そのホームディレクトリを作業ディレクトリに設定します。

新しいDockerfileは以下のようになります。

```
FROM node:10.16-alpine
ENV NODE_ENV production
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
USER node
RUN npm install --production --silent && mv node_modules ../
COPY --chown=node:node . .
EXPOSE 3000
CMD npm start
```

前述のプロセスに従って、新しいイメージをビルドし、`arnab74/nodeexpress-alibaba-docker-tutorial:latest`という名前で実行してテストします。

####Docker Hubに画像をアップロードする
Docker Explorerで、レジストリセクションのConnect Registryを選択します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/c0a9cc70-ff16-2149-2d15-d09bb4b50227.png)

利用可能なオプションで、レジストリプロバイダとしてDocker Hubを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/51a21c47-38bc-ab77-2078-5a7634b02a96.png)

ユーザー名とパスワードを入力してログインします。

コマンドパレットでdockerタグを書き、Docker Images:Tagを選択します。

次のコマンドパレット画面で画像グループを選択します。

```
arnab74/nodeexpress-alibaba-docker-tutorial
```

次の画面でタグ付けする画像を選択

```
latest
```

新しいタグを提供

```
arnab74/nodeexpress-alibaba-docker-tutorial:0.1
```

コマンドパレットでdocker pushを書き、Docker Images:Pushを選択します。

次のコマンドパレット画面で画像グループを選択します。

```
arnab74/nodeexpress-alibaba-docker-tutorial
```

次の画面でDocker hubにプッシュするImageを選択します。

```
0.1
```

ターミナル上にDocker Pushコマンドが生成されるので、それに従ってください。

以下のようにターミナル上で上記の手順を行うこともできます。

```
docker login --username=arnab74
docker images

docker tag [IMAGE ID] arnab74/nodeexpress-alibaba-docker-tutorial:0.2
```

IMAGE ID を最新のタグ付けされた画像の画像 ID に置き換えてください。

```
docker push arnab74/nodeexpress-alibaba-docker-tutorial:0.2
```

アップロードされた画像は、Docker hubのサイトのリポジトリやDocker Explorerのレジストリで確認できるはずです。

#シンプルなアプリケーションサーバにアプリケーションをデプロイする
並行記事[Developing Node.js App in Visual Studio and Deploying on Simple Application Server](https://www.alibabacloud.com/blog/developing-node-js-app-in-visual-studio-and-deploying-on-simple-application-server_594543?spm=a2c65.11461447.0.0.28726972BEDdJO)をご覧いただき、Alibaba Cloud上にCentOS7でSimple Application Serverインスタンスを作成し、インスタンスへのパスワードを作成し、デスクトップ端末を使ってログインする方法をご紹介します（記事のようにputtyではなく）。

####サーバーに前提条件をインストールする
####yum
yumは、CentOSでソフトウェアパッケージを取得、インストール、削除、クエリ、管理するための主要なツールです。まず、ソフトウェアリポジトリを最新のバージョンにアップデートするために使います。

```
yum -y update
```

####Docker
古いバージョンがある場合は、アンインストールしてください。

```
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
```

必要なパッケージをインストールします。

```
sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
```

インストールするリポジトリの設定

```
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
```

Dockerのインストール

```
sudo yum install docker-ce docker-ce-cli containerd.io
```

Dockerの起動

```
sudo systemctl start docker
```

Dockerを非rootユーザーで動作させます。

```
sudo groupadd docker
sudo usermod -aG docker $USER
sudo reboot
Start Docker again
```

```
sudo systemctl start docker
```

コマンドが sudo なしで実行されているかどうかを確認します。

```
docker run hello-world
```

####アプリケーションのデプロイ
コンテナをビルドしてアプリケーションを実行します。マシンのローカルにイメージがない場合は、Dockerがリポジトリからイメージを引っ張ってきます。

```
docker run -d -p 80:3000 arnab74/nodeexpress-alibaba-docker-tutorial:0.1
```

ここでは、ホストに80番ポートを使用しました。そのため、簡易アプリケーションサーバの公開IP（サーバ管理画面で利用可能）を利用してサイトを閲覧する際には、ポート番号を使用する必要はありません。

http://public_ip にアクセスしてサイトをテストします。アプリケーションが起動しているのが確認できるはずです。

#結論
これらは、Ubuntu Linux上でビジュアルコードを使用してNode.jsアプリケーションを開発し、アプリケーション用のDockerイメージを作成し、Dockerハブリポジトリを作成してDockerハブにイメージをプッシュし、最後にCentOSを使用してAlibaba Cloudの[Simple Application Server](https://www.alibabacloud.com/ja/product/swas)上にDockerハブイメージをデプロイするための基本的なステップです。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*