🐳

DockerとVS Code Remote Containersを用いたフロントエンド開発環境構築

2021/12/29に公開約9,000字2件のコメント

背景

プロジェクトの新規立ち上げや、新しくプロジェクトに新規メンバーが入った場合に環境構築に手間取ることが多いため、Docker+VS Code Remote Containersのフロントエンドアプリケーション開発環境構築ができるリポジトリを作成しました。

本記事では上記リポジトリを用いた環境構築手順とCreate React Appによる簡単なアプリ開発例を説明します。
また、上記リポジトリをgit cloneしなくても一から同じ環境を構築できるように、リポジトリに含まれるファイル群についてもそれぞれ説明します。

本記事の対象はフロントエンドですが、バックエンドのプロジェクト構築も基本的には同じ知識で構築できるはずです。

前提条件

本記事では以下を前提条件とします。ただし、WindowsやLinuxでも基本的には問題ないはずです。

  • macOS Monterey
  • Visual Studio Code
  • VS Code拡張機能 Remote - Containers
  • Docker Desktop

環境構築手順

環境構築手順を説明します。

はじめに、リポジトリをクローンします。
(用意するファイルは大してないので、手動でファイル群を作成しても良いですが、説明を簡単にするためここでは私の作成したリポジトリを使用します)

git clone https://github.com/LeftLetter/vscode-compose-template.git

uiディレクトリをVS Codeで開き(注:プロジェクトルートを開くわけではない)、左下の緑色のアイコンをクリックします。

Repoen in Containerを選択します。

コンテナのビルドが走るのでしばし待ちます。
画面右下にポップアップが表示され、「show log」をクリックするとログが表示されます。

ビルドが正常に完了した場合、VS Codeの左下にコンテナ名が表示されているはずです。

これでVS Codeからコンテナの中身を直接触ることができるようになります。全てはコンテナ内で完結するので、リンターやフォーマッタをローカルにインストールする必要はありません。

また、カレントディレクトリはバインドマウントされるため、万が一コンテナが消えてしまってもホスト側にファイルは残ります。

次章では構築したコンテナ環境にCreate React Appでフロントエンドアプリケーションを作成し、デバッグする方法を説明します。

Create React Appでアプリを作成し、デバッグしてみる

VS Code内のターミナルで、以下のコマンドを実行し、Reactアプリのテンプレートを作成します。

$ create-react-app test_project
$ shopt -s dotglob
$ mv test_project/node_modules/* node_modules
$ mv test_project/* .
$ rm -rf test_project/

既にChromeが起動している場合、終了します。その後、以下のコマンドでChromeをデバッグモードで起動します。

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check

以下のコマンドでdevサーバを起動します。

$ yarn start

Chromeでlocalhost:3000にアクセスし、Create React Appのサンプルページが開くことを確認します。

F5キーを押下し、VS Codeのデバッガを起動します。
適当な箇所でブレークポイントを設定した後、Chromeをリフレッシュし、ブレークポイントでプログラムが停止すればOKです。

設定ファイルの説明

設定ファイル群についてそれぞれ詳細を説明します。

ディレクトリ構成

ディレクトリ構成は以下の通りです。serverディレクトリにはフロントエンドアプリケーション開発のためのモックサーバを、uiディレクトリには開発対象のフロントエンドアプリケーションを配置する想定です。

/
├server/
│ ├.devcontainer/
│ │ ├swagger.yml
│ │ ├Dockerfile
│ │ └devcontainer.json
├ui/
│ ├.devcontainer/
│ │ ├Dockerfile
│ │ └devcontainer.json
│ └.vscode/
│   └launch.json
├.gitignore
├README.md
└docker-compose.yml

ファイルの個別説明

docker-compose.yml

コンテナ起動のエントリーポイントとなります。

docker-compose.yml
version: "3"
services:
  ui:
    build:
      context: ./ui/.devcontainer
      dockerfile: Dockerfile
    volumes:
      - .:/workspace:cached
      - ui-node-modules:/workspace/ui/node_modules
      - ui-extensions:/root/.vscode-server/extensions
    command: /bin/sh -c "while sleep 1000; do :; done"
  server:
    build:
      context: ./server/.devcontainer
      dockerfile: Dockerfile
    command: /bin/sh -c "while sleep 1000; do :; done"
    entrypoint: "npm start"
    ports:
      - "8080:8080"
volumes:
  ui-node-modules:
  ui-extensions:

ボリューム

volumes:
  ui-node-modules:
  ui-extensions:

ui-node-modules:node-modulesのボリュームマウントです。これによりyarn addなどのコマンドの高速化が可能です。こちらは公式ドキュメントに書かれているテクニックです。必要に応じて、buildやdistなどのディレクトリもボリュームマウントすることでビルドの高速化が見込まれます。

参考:Use a targeted named volume

https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-a-targeted-named-volume

ui-extensions:はVS Codeの拡張機能のボリュームマウントです。再ビルドのたびに拡張機能のインストールを行うのを防ぎますが、devcontainers.jsonに新たにインストールしたい拡張機能を追加しても反映されないため、その際はボリュームを削除する必要があります。こちらも同様に、公式ドキュメントに書かれているテクニックです。

参考:Avoiding VS Code extension reinstalls

https://code.visualstudio.com/remote/advancedcontainers/avoid-extension-reinstalls

コマンド

    command: /bin/sh -c "while sleep 1000; do :; done"

通常、コンテナはエントリーポイントが終了するとシャットダウンされてしまいます。そのため、上記コマンドを設定することでコンテナを永続起動させます。

参考:Use Docker Compose

https://code.visualstudio.com/docs/remote/create-dev-container#_use-docker-compose

Dockerfile

コンテナで実行するコマンドなどを定義します。
フロント側はcreate-react-appでプロジェクトを作成することを想定しています。必要に応じてcreate-vue-appなどをインストールするように変更すれば良いと思います。

ui/Dockerfile
FROM node:16

RUN npm i -g create-react-app

モックサーバ側はswagger.ymlを配置してSwaggerサーバを起動する想定になっています。必要に応じてJSON Serverのイメージに変更したり、そもそも使用しないなど、開発環境に応じて変更すれば良いと思います。

server/Dockerfile
FROM openjdk:latest as builder
WORKDIR /opt
RUN microdnf install wget
COPY ./swagger.yml ./
RUN wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.30/swagger-codegen-cli-3.0.30.jar -O swagger-codegen-cli.jar
RUN java -jar /opt/swagger-codegen-cli.jar generate -i /opt/swagger.yml -l nodejs-server -o ./

FROM node:16
WORKDIR /opt
COPY --from=builder /opt /opt
RUN npm install

devcontainer.json

主にVS CodeやRemote - Containersの設定を定義します。

ui/devcontainer.json
{
  "name": "vscode-compose-template-ui",
  "dockerComposeFile": ["../../docker-compose.yml"],
  "service": "ui",
  "shutdownAction": "none",
  "workspaceFolder": "/workspace/ui",
  "extensions": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "styled-components.vscode-styled-components",
    "eamodio.gitlens",
    "mhutchie.git-graph"
  ],
  "settings": {
    "terminal.integrated.defaultProfile.linux": "bash",
    "editor.formatOnSave": true,
    "editor.tabSize": 2,
    "editor.detectIndentation": false,
    "editor.insertSpaces": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": true,
      "source.fixAll.eslint": true
    },
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "[jsonc]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "editor.formatOnSave": true
    },
    "[markdown]": {
      "editor.formatOnSave": false
    }
  }
}

※server側は省略

コンテナ設定関連

Remote - Containersの設定はここに定義します。基本的にname以外は変更しなくても問題ないと思います。

  "name": "vscode-compose-template-ui",
  "dockerComposeFile": ["../../docker-compose.yml"],
  "service": "ui",
  "shutdownAction": "none",
  "workspaceFolder": "/workspace/ui",

VS Codeの拡張機能

コンテナ内にインストールしたい拡張機能はここに定義します。必要に応じて変更してください。

  "extensions": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "styled-components.vscode-styled-components",
    "eamodio.gitlens",
    "mhutchie.git-graph"
  ],

VS Codeの設定

VS Codeの設定はここで定義します。ファイル保存時にESLintとPrettierを実行する設定などを書いています。必要に応じて変更してください。

ここでは、以下の設定をしています。

  • ファイル保存時にESLint+Prettierを実行
  • ファイル保存時にimportを整理
  • VS Codeの設定ファイル(jsonc)に対しても保存時にフォーマット
  • .mdファイルに対してはフォーマットしない(Prettierのフォーマットが日本語を含むマークダウンに対して微妙なため)
  "settings": {
    "terminal.integrated.defaultProfile.linux": "bash",
    "editor.formatOnSave": true,
    "editor.tabSize": 2,
    "editor.detectIndentation": false,
    "editor.insertSpaces": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": true,
      "source.fixAll.eslint": true
    },
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "[jsonc]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "editor.formatOnSave": true
    },
    "[markdown]": {
      "editor.formatOnSave": false
    }
  }

launch.json

VS Codeでデバッグするための設定はここで定義します。
フロント側はデバッグモードで起動したChromeにアタッチするようになっています。

"type": "chrome"となっている記事もありますが、非推奨の拡張機能「Debugger for Chrome」を使用する古い設定なので注意してください。"type": "pwa-chrome"とすることで、VS Code内蔵のデバッガを使用できます。

ui/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to chrome",
      "type": "pwa-chrome",
      "request": "attach",
      "port": 9222,
      "urlFilter": "http://localhost:3000/*",
      "webRoot": "${workspaceFolder}"
    }
  ]
}

おまけ1:Docker Desktop for Macが遅い問題について

Docker Desktop for Macのコンテナだとビルド等々がローカルより遅いという問題は広く知られています。
遅いのは事実ですが、千差万別のスキルを持ったメンバーが集まった時に、ローカルの環境を汚さないことと環境の共通化ができることのメリットの方が大きいと考えています。

また、まだExperimentalですが、ファイルシステムを変更することで高速化できる可能性があるようです。

参考:Docker for Macの新しいファイルシステムVirtioFSを試してみた

https://zenn.dev/takc923/articles/1eb61e531e3704

参考:Docker Desktop for Macを使ってる人はみんな今すぐvirtiofsを使うんだ! - Sweet Escape

https://www.keisuke69.net/entry/2022/03/25/083002

※ただし、手元のIntel Macではむしろ遅くなりました

おまけ2:Docker Desktop有料化について

あまり試していませんが、Rancher Desktop+Docker CLIで代替できそうです。

参考:Rancher Desktop

https://rancherdesktop.io/

参考:まるでDocker Desktop!!Rancher Desktopの登場です - Qiita

https://qiita.com/moritalous/items/14d4099023981dcf4fd2
GitHubで編集を提案

Discussion

ありがとうございます。修正しました。
どうやら記事を書いていた時とページ構成が変わっていたようです。

ログインするとコメントできます