Dockerコンテナ内にJSの開発環境を構築し、VS Codeでリモート接続する


概要

エンジニア内で一人だけWindowsを使っていることもあり、他の方と微妙に環境が異なっていましたが、VS Codeはコンテナ内へ気軽にリモート接続出来るようになっているため、中で環境を構築してみました。
Dockerfile等で注意点もあったので、主にそちらを記載しています。
※Dockerにさほど詳しいわけではないので、誤りがあったらごめんなさい。

環境

  • VS Code 1.41.1
  • WSL1(Ubuntu)
  • docker desktop 2.1.0.5

前提

  • DockerやVS Codeはインストール済み
  • プロジェクト内のコンフィグファイル(package、tsconfig等)は設定済み

やりたかったこと

  • ビルド用のDockerイメージを作成
  • VS Codeで接続し、開発したりビルドしたり npm installしたり(←重要)できるようにする。
  • ホストマシンの方にいらないファイルを持ってこないようにする

手順

Dockerfile等の設定

環境変数を設定し、composeを経由してコンテナを立て直すスクリプトです。
こちらを叩けば開発環境用のコンテナが立ち上がります。

start.sh
#! /bin/bash

export CONTAINER_USER=dev
export CONTAINER_WORK=/home/$CONTAINER_USER/

docker-compose build
docker-compose down
docker-compose up -d

compose用の設定ファイルです。
動機は後述しますが、package.jsontsconfig.json等の設定ファイルはconfig_filesの中にまとめておき、Dockerfile内でシンボリックリンクを作成します。

docker-compose.yml

version: '3.7'
services:
  dev:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        USER: $CONTAINER_USER
        WORK: $CONTAINER_WORK
    tty: true
    volumes:
      - $PWD/src:$CONTAINER_WORK/src
      - $PWD/config_files:$CONTAINER_WORK/config_files
    user: $CONTAINER_USER

Dockerのイメージ作成部分です。
config_files以下にあるファイルのシンボリックリンク作成、およびモジュールのインストールを行います。

Dockerfile

FROM node:13.5 as env

ARG USER
ARG WORK

RUN addgroup ${USER} \
  && useradd -m -g ${USER} ${USER}

WORKDIR $WORK
COPY --chown=${USER}:${USER} ./config_files ${WORK}/config_files

RUN ls -a --file-type config_files | grep -v / | xargs -I {} -n1 ln -s "config_files/"{} {} \
  && npm ci

config_filesに設定ファイルをまとめる動機

node_modulesをホストと同期させたくない場合、該当ディレクトリを別のボリュームにマウントする方法がよく見つかりました。


volumes:
  - $PWD:$CONTAINER_WORK
  - $CONTAINER_WORK/node_modules

この方法だと、権限エラーが発生しコンテナ内でモジュールの追加・削除が出来ませんでした。
ホスト側で追加しイメージを再ビルドすれば解決できますが、作業前に一度node_moduelsを作らざるを得ないため、同期しない旨味が少なくなります。
また、今回ホーム直下に作成しているため、VS Codeで接続した際に作成される.bash_historyなどのファイルがホスト側にも同期されます。

次に考えたのが、volumesでファイルを直接指定する方法です。


volumes:
  - $PWD/src:$CONTAINER_WORK/src
  - $PWD/package.json:$CONTAINER_WORK/package.json
  # 以下マウントしたいファイルを列挙

この方法だとモジュールのインストールは出来ましたが、ロックエラー(EBUSY: resource busy or locked, rename '/home/user/package.json.3654907157' -> '/home/user/package.json')が発生し、追加したモジュールがpackage.jsonへ反映出来ませんでした。

最終的に、stackoverflowで見つけた下記の回答で解決できたため、コンフィグ類をまとめる形にして採用しました。
https://stackoverflow.com/questions/48960320/locked-package-json-files-in-docker-container-using-docker-compose/58880425#58880425

VS Codeの設定

  1. VS CodeにRemote - Containers(ms-vscode-remote.remote-containers)をインストール
    • WSL環境だと、Remote - WSLも必要かもしれません。Remote - SSHは同一マシン内だからか不要でした。

  1. 上で作ったstart.shを実行し、コンテナを起動
  2. リモートエクスプローラーで該当のコンテナに接続
    • 下のSSで、現在選択されているアイコンです

  1. 初回接続時、接続設定が作成されるので保存します。また、拡張機能はホスト側と同期しない?ので、入れ直す必要があります。
    • ホスト側で入れている拡張機能の一覧は表示されます。

Webpackの設定

webpack.config.jsの実体はconfig_filesにいるので、path.resolve(__dirname, '../src')という風にパスを補正してください。
忘れるとconfig_files以下に出力されていて、「あれ?ビルドしたのに更新されてない?」みたいな感じになります。

動作確認

あとは通常通りVS Codeでファイルを開いて編集したり、ターミナルでコマンドを叩いてみてください。
ビルドが正常に実行され、編集内容がホストマシンにも同期されていれば無事成功です。