VSCodeのRemote Developmentを使ってDocker上のNode.js、Redis環境で作業する

2019年5月に公開された、Visual Studio Code でリモートマシン、コンテナ、Windows Subsystem for Linux (WSL) 上のワークスペースを開くことができるようになる拡張機能群「Remote Development Extension Pack」を使ってみました。
remote-development0.JPG
https://code.visualstudio.com/docs/remote/remote-overview
この拡張パックを導入すると、手元の「Visual Studio Code」からリモート環境へ接続し、そこでアプリ開発等を行うことが可能になります。 今回は、Microsoftのレポジトリ VSCode Remote Try Nodeを元に、Node.jsからRedisを扱うDockerコンテナに接続する設定をやってみます。

1 Visual Studio Codeのバージョン確認

Stable 版では (version 1.35) リリース以降で Remote Development 拡張が利用可能です。
バージョンが古い場合は、Visual Studio Code の [ヘルプ]->[更新の確認] または https://code.visualstudio.com/updates 等から最新版にアップデートしてください。

2 拡張機能Remote Developmentのインストール

vscode0.JPG
Visual Studio Codeで拡張機能”Remote Development”を検索し、インストールしてください。

3 プロジェクトの構成

Microsoftのレポジトリ VSCode Remote Try Nodeをクローンし、最低限のディレクトリ構成を揃えた後、必要なファイルを加除していきます。
[Project Home]
|_ .devcontainer
|    |_  devcontainer.json 
|    |_ ubuntu-bionic-core-cloudimg-amd64-root.tar.gz
|  
|_ .vscode
|    |_  launch.json
|  
|_  build
|    |_  server.js
|_  src
|    |_  server
|         |_  main.ts
|_  store
|    |_  redis
|         |_  .gitkeep
| 
|_  Dockerfile
|_  docker-compose.yml
|_  package.json
|_ tsconfig.json
|_ tslint.json
|_  webpack.config.js
公式ではDockerfileを .devcontainer 以下に配置していますが、 ホームディレクトリ上のローカルフォルダ store/redis とDockerコンテナ上のディレクトリを同期してデータ永続化したいので、ホームディレクトリ直下に配置しています。 また、公式では、node:10イメージをベースを使っていますが、 今回は、Linuxイメージ上に npm, node.jsをインストールしたコンテナを作成し、redis コンテナとリンクする構成をやってみたいと思います。 当初、軽量Linuxの代表格alpineをベースにしようとしましたが、どうやら Stable版のVSCode上で動くRemote Developmentではalpineをサポートしていないようなので、やむなくMinimum Ubuntuを使うことにしました。 MInimum Ubuntuのイメージファイルは以下のレポジトリからダウンロードし、.devcontainer以下に配置しました。
https://github.com/tianon/docker-brew-ubuntu-core/blob/59aa7dfef17153ecc812adbf26516675ce67e8aa/bionic/Dockerfile

4 Remote Development の設定

devcontainer.json

{
    "name": "node.js and redis sample ",
    "dockerComposeFile": [
        "../docker-compose.yml"
    ],
    "service": "node",
    "appPort": 3000,
    "extensions": [
        "VisualStudioExptTeam.vscodeintellicode",
        "dbaeumer.vscode-eslint",
        "eg2.tslint"
    ],
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "shutdownAction": "none" 
}
主要な設定項目としては、
>
  • service で node.jsを稼働するコンテナのサービス名を指定
  • appPort で node.js上でlistenするportを指定
  • dockerComposeFileでdocker-compose.ymlの相対パスを指定
  • extensions でリモート上のVSCodeで使う拡張機能を追加
ちなみに、普段使っているVSCodeの拡張機能一覧は
code --list-extensions | xargs -L 1 echo code --install-extension
で取得できます。

5 Docker の設定

Dockerfile

FROM scratch
ADD .devcontainer/ubuntu-bionic-core-cloudimg-amd64-root.tar.gz /
RUN set -xe \
    \
    && echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
    && echo 'exit 101' >> /usr/sbin/policy-rc.d \
    && chmod +x /usr/sbin/policy-rc.d \
    \
    && dpkg-divert --local --rename --add /sbin/initctl \
    && cp -a /usr/sbin/policy-rc.d /sbin/initctl \
    && sed -i 's/^exit.*/exit 0/' /sbin/initctl \
    \
    && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
    \
    && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
    && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
    && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
    \
    && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
    \
    && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes \
    \
    && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests

RUN rm -rf /var/lib/apt/lists/*

RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list

RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container

# Configure apt and install packages
RUN apt-get update && \
    yes | apt-get install \
    curl \
    git \
    npm \
    nodejs
WORKDIR /home
SHELL ["/bin/bash", "-c"]
基本的に、https://github.com/tianon/docker-brew-ubuntu-core/blob/59aa7dfef17153ecc812adbf26516675ce67e8aa/bionic/Dockerfile のままです。追加項目として、#Configure apt and install packages以下で、必要なモジュールをインストールするようにします。

docker-compose.yml

version: '3'
services:
  node:
    build:
       context: .
       dockerfile: Dockerfile  
    container_name: node-container
    volumes:
      - .:/home
    ports:     
       - 3000:3000
    command: sh -c 'npm install & node build/server.js'
    links:
      - "redis"
  redis:
    restart: always
    container_name: redis-container
    image: redis:latest
    volumes:
        - ./store/redis:/data
    ports:
        - "6379:6379"
    command: redis-server --appendonly yes
上記のDockerfileを走らせて作成するnodeイメージと、Official Imageのredis:latestイメージをリンクします。
特記事項として、redis側でローカルのstore/redisとコンテナ側のdataフォルダを同期し、データの永続化を行っています。

6 package.jsonの設定

今回は、Webpackを使ってTypeScriptをトランスパイルする例です。
2019年7月現在の、webpackの最新バージョン 4.29.0 では Maximum Call Stackのエラーが出てしまうため、旧バージョンを指定しています。
{
  "name": "node.js and redis sample",
  "version": "1.0.0",
  "devDependencies": {
    "@types/app-root-path": "",
    "@types/express": "",
    "@types/node": "",
    "@types/redis": "",
    "path": "",
    "ts-loader": "",
    "tslint": "",
    "tslint-loader": "",
    "typescript": "",
    "webpack": "4.17.1",
    "webpack-cli": "",
    "webpack-node-externals": ""
  },
  "dependencies": {
    "app-root-path": "",
    "express": "",
    "redis": ""
  },
  "private": true
}

7 Node.jsによるサーバ設定

expressでWebサーバを立ち上げ、redisでPOSTの回数をカウントするという例です。
'use strict';
import * as root from 'app-root-path';
import * as express from 'express';
import * as redis from 'redis';

/**
 * Configure Redis
 */
const client: redis.RedisClient = redis.createClient(6379, 'redis');
client.on('connect', () => console.log('Connected to Redis'));
client.set('visit', '0');

/**
 * Configure Web Server
 */
const app: express.Application = express();
app.use(express.static('.'));
app.post('/api',  (_req: express.Request, res: express.Response) => {
    client.get('visit', (_err: Error|null , visit: string) => {
      res.send('POST request received. Number of Visits:' + visit);
      client.set('visit', String(parseInt(visit, 10) + 1));
  });
});

// tslint:disable-next-line:typedef
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Server running on ${port}`));

8 実行

Inkedremote-development1.jpg
F1で拡張機能の一覧を表示するか、Visual Studioコードの左下の緑色のブラケットマークからRemoteデスクトップの機能一覧を表示します。
docker-compose up --build を既に一度走らせている場合は、「Attach to Running Container(水色)」を選択し、まだの場合は「Open Folder in Container(赤色)」で現在のホームディレクトリを指定すればdocker-compose up --build が自動的に走ります。ビルドに成功すると、Remote Development用のVSCodeのウィンドウが起動します。
Inkedremote-development2.jpg
後は開いたウィンドウ上で「フォルダを開く」から任意のフォルダを開くと、コンテナ上のファイルをVS Codeで編集することができます。
remote-development4.JPG

9 Redisの動作確認

Remote Developmentとは直接関係ありませんが、Redisがきちんと動作しているか確認するには、curl -X POST(ローカル、コンテナ側のどちらからでも結構です) で以下のAPIを叩き、
 curl -X POST http://localhost:3000/api
以下のようにPOSTの通算回数が返ってくれば成功です。
POST request received. Number of Visits:[POSTの回数]

10 参考にさせていただいたサイト

下記のページを参考にさせていただきました。
https://code.visualstudio.com/updates/v1_35
https://qiita.com/yoskeoka/items/01c52c069123e0298660
https://qiita.com/mizuhof/items/7bc20538c9fe1edcba40
https://katsu-tech.hatenablog.com/entry/2017/10/11/233024 https://blog.manabusakai.com/2018/08/minimal-ubuntu-dockerfile/ なお、今回の構成はGithubで公開していますので、ご指摘などあればよろしくお願いいたします。
https://github.com/snst-lab/vscode-remote-try-node-typescript-redis

Leave a Reply

Your email address will not be published. Required fields are marked *