見出し画像

VS Code + Dev Containerでコンテナ内でデバッグ可能なNode.js開発環境を整える

はじめに

こんにちは、SHIFTの開発部門に所属している Katayama です。

開発環境に Node.js をインストールせずに、Docker コンテナで Node.js を実行して開発するでは、Node.js の実行環境として Docker を利用する、という事をやった。今回は実行環境だけでなく、開発環境をまるっと Docker コンテナにするという事をやってみたいと思う。また、Docker コンテナ内でのデバック実行もやってみたいと思う。

Dev Container とは

VS Code には、Developing inside a Containerに書かれている通り、Dev Containers という拡張機能があり、これを導入すると Docker コンテナを VS Code で開発をする際の環境として利用することができ、すぐにデバッグ実行などを行えるようになる。

つまり、ローカル(ホスト)に実行環境を構築したり、開発のためのツールをインストールすることなく開発を行えるので、ローカルをきれいに保ったまま開発ができるというメリットや、一度コンテナを削除して再度Dev Containerを構築しなおすことで何度でも同じ環境を立ち上げられる(冪等性がある)ので色々操作して環境がぐちゃぐちゃになりトラブルシューティングできない…という事も減らせるメリットもあるだろう。
また、各言語ごとに必要なものは違うが、既に用意されているテンプレートを利用する事で直ぐに開発を開始できる。

以下では、実際に Node.js の開発環境を Dev Container で構築し、デバック実行をやってみる。また、アプリケーションが他のサービスに依存している場合に(MySQL や Redis など)、docker-compose で依存サービスを起動する場合の開発方法についても見ていく。

  • ①Node.js の開発環境を Dev Container で構築し、デバック実行する

  • ②docker-compose でアプリケーションが依存するサービスを起動して開発する

①Node.js の開発環境を Dev Container で構築し、デバック実行する

まずは、以下のようなシンプルな Express アプリケーション(package.json に"type": "module"を指定して ES Module を実行できる環境で開発しているものとする)の開発を Dev Container で行ってみる。

srv/index.jsimport express from 'express';

const app = express();
app.get('/hello', (req, res) => {
	res.json({ msg: 'hello' });
});
app.listen(3000);

Dev Container を利用するには、プロジェクトに以下のような".devcontainer/devcontainer.json"を作成する(前提条件・事前準備はSystem requirementsInstallationにそれぞれ書かれている。今回は前提条件と事前準備として必要なホスト OS への Docker のインストール、拡張機能Dev Containersのインストールは完了している事を前提にしている)。

.devcontainer/devcontainer.json{
	"name": "Node.js",
	"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
	"appPort": ["3000:3000"],
	"postCreateCommand": "yarn install",
	"customizations": {
		"vscode": { "extensions": ["esbenp.prettier-vscode"] }
	}
}

少し上記のファイルについて補足する。

  • image Microsoft の方で用意しているjavascript-nodeのイメージを指定している。あらかじめ Node.js18.14.0 など Node.js の開発に必要なものがインストール済みになっている。

  • appPort Docker の port と同じで、コンテナ内のポートをホスト側に公開するための設定。今回はホストの 3000 ポートとコンテナの 3000 ポートをマッピングしているので、localhost:3000 でコンテナ内の 3000 ポートに接続できる。

  • postCreateCommand 開発用コンテナの作成時にコンテナのセットアップが行われるが、その最後に実行されるコマンド。今回は開発の時に node_moduels を作成する手順が絶対にあるので、その手順として yarn install を設定している。ちなみに、Formatting string vs. array propertiesに書かれている通り、配列形式・文字列形式の書き方があり、配列形式だと shell を介さずに実行され、文字列形式だと shell を介して実行されるという違いがある。

  • customizations.vscode Dev Container では、コンテナを起動したときに VS Code Server が立ち、それにより Editor として VS Code を利用できるようになるが、その VS Code の設定を行っている部分で、Extensions(拡張機能)や settings.json の設定ができる。今回は Prettier の拡張機能がインストールされた状態で起動するように設定している(ちなみに、javascript-nodeを利用する場合、dbaeumer.vscode-eslintが暗黙的にインストール済みになる)。

上記のように devcontainer.json を設定すると、以下のように Dev Container の設定があるので再度 Dev Container でプロジェクトを開き直すか?が通知されるので、「Reopnen in Container」をクリックすると、Dev Container を起動できる。

※上記のように通知が出ない場合でも、以下のように VS Code の左下の接続の表示をクリックして、表示される Remote 接続メニューからも Dev Container を起動できる(拡張機能Remote Developmentが VS Code にインストールされている前提)。

Dev Container を起動すると、以下の動画のように色々な処理が動き、yarn install も実行され、最終的に Node.js の開発環境として Dev Container が立ちあがる事が確認できる。

後はいつも通り、サーバーを起動して実装を行う事ができる。

デバック実行

デバック実行を行うには、.vscode/launch.json の設定が必要になるのでそれを追加する。今回は ES Module のプロジェクトとして設定している事を前提にしているので、以下のような launch.json にすればデバック実行できる(Webpack で CommonJS にトランスパイルしているようなプロジェクトでのデバック実行のための設定についてはVSCode 上で Node.js(ES6 で実装)の debug をするための設定をしてみたを参照)。

.vscode/launch.json{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "node",
			"request": "launch",
			"name": "Debug express server",
			"skipFiles": ["<node_internals>/**"],
			"program": "${workspaceFolder}/srv/index.js"
		}
	]
}

上記の launch.json を設定した後は、以下の動画のようにデバック実行でき、ブレークポイントで処理が一時 Stop する事が確認できる。

②docker-compose でアプリケーションが依存するサービスを起動して開発する

続いて、よくあるアプリケーションが MySQL や Redis といったサーバーに依存している場合の Dev Container での開発についてみていく。簡単なのは Docker in Docker で、Docker コンテナ内で Docker でさらにコンテナを起動するという方法。

設定方法はdocker-in-dockerのテンプレートが参考になるが、以下のようになる。

.devcontainer/devcontainer.json{
	"name": "Node.js",
	"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
	"features": {
		"ghcr.io/devcontainers/features/docker-in-docker:2": {
			"version": "latest",
			"enableNonRootDocker": "true",
			"moby": "true"
		}
	},
	"appPort": ["3000:3000"],
	"postCreateCommand": "yarn install",
	"customizations": {
		"vscode": { "extensions": ["esbenp.prettier-vscode"] }
	}
}

ポイントは features の設定に docker-in-docker を設定している部分。Dev Container にはAvailable Dev Container Featuresに列挙されているツールを利用でき、今回はその中の Docker in Docker のためのツールを利用している。他にも AWS CLI をインストールして利用できるようにする feature もある。ちなみに、何をやっているのか?はinstall.shで確認できる。

上記のように設定した後、① でやった時同じ方法で Dev Container を起動して、アプリケーションのサーバーや docker-compose で MySQL を実行して動くか?を検証すると、API を実行した結果、DB のデータが返ってくる事が確認できる。

デバック実行

以下の動画の通り、デバック実行も問題なくできる事が確認できる。

※上記の動画のプロジェクトはVSCode 上で Node.js(ES6 で実装)の debug をするための設定をしてみたと同様、CommonJS にトランスパイルして実行するパターンなため、yarn dev では Webpack によるビルドを行い、yarn start:watch で nodemon による HMR を実現している。

まとめとして

今回は Dev Container を利用して Docker コンテナで開発を行い、デバック実行するということををやってみた。ローカル(ホスト)の OS に色々なものをインストールすることなく開発環境を用意でき、また開発では不可欠なデバック実行も問題なく行えるので、開発環境に Dev Container を利用するのも選択肢の 1 つになるのではないかと思った。ただ、Editor が VS Code になってしまうので、その辺りの自由度は落ちるが…。

おまけ トラブルシューティング

以下では Dev Container で開発をする上で、躓いた事とその解決方法を記している。

Dev Container 内から GitHub への SSH 接続をする

GitHub などに SSH 接続している場合、秘密鍵がないと fetch や push などはできない。かといって Dev Container を作成するごとに SSH のキーを発行するのもナンセンスだろう。

これを解決するには、Using SSH keysに書かれているように、ssh-agent に秘密鍵を登録する必要がある。

例えば、以下のように github・github.pub という組み合わせの公開鍵・秘密鍵で GitHub にアクセスしているのであれば、ssh-add ~/.ssh/github というコマンドで ssh-agent に秘密鍵を登録する事で、Dev Container の中で fetch や push ができるようになる。

実際にやってみると、以下のようにホスト側の ssh-agent の設定が Dev Container にも反映され、それにより git fetch ができている事が確認できる。

  • ホスト

  • Dev Container

※前提として、ssh-agent が実行されている必要がある。
実行されていない場合、手動で実行する(eval "$(ssh-agent -s)" コマンド)または、以下のようなシェルを"~/.bash_profile"に記載して、ログイン時に自動で ssh-agent が実行されるようにする。

if [ -z "$SSH_AUTH_SOCK" ]; then
   # Check for a currently running instance of the agent
   RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
   if [ "$RUNNING_AGENT" = "0" ]; then
        # Launch a new instance of the agent
        ssh-agent -s &> $HOME/.ssh/ssh-agent
   fi
   eval `cat $HOME/.ssh/ssh-agent`
fi

《この公式ブロガーの記事一覧》


執筆者プロフィール:Katayama Yuta
認証認可(SHIFTアカウント)や課金決済のプラットフォーム開発に従事。リードエンジニア。
経歴としては、SaaS ERPパッケージベンダーにて開発を2年経験。
SHIFTでは、GUIテストの自動化やUnitテストの実装などテスト関係の案件に従事したり、DevOpsの一環でCICD導入支援をする案件にも従事。その後現在のプラットフォーム開発に参画。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら  
https://recruit.shiftinc.jp/career/

みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!