いしぐめも

プログラミングとかしたことを書きます。

【VSCode】コンテナを利用した開発環境の構築について【devcontainer】

Dockerコンテナを使った開発が結構便利で人にもオススメできるレベルになってきたのでご紹介します!正直コンテナって聞いただけで「ウッ」となってしまう方もいると思うので、極力メリットとかも書いてみたいと思います。

Dockerコンテナ×開発環境

そもそも、なんでDockerコンテナを開発環境で使おうという発想に至るのでしょうか?個人的には以下のような「Dockerコンテナが開発環境構築に向いているわけ」があると思います。

Dockerコンテナが開発環境構築に向いているわけ

その①:揮発性・冪等性

コンテナイメージは内部的にレイヤごとに分かれた構成になっていて、commitしない限りはそのコンテナイメージに変更が加わることはありません。つまり、変更をコミットせずにコンテナを落としてしまうと良くも悪くも変更した内容は消えてしまうわけです。本番でDockerコンテナを使用しようとするとこの特性は最初面倒に感じてしまうこともありますが、逆に言えば再現したい状態をコミットしておくことで、新しく作れば毎回同じ状態が再現される というのは試行錯誤するうえではとてもメリットがあるのです。 つまりこれは、ゴチャゴチャになった開発環境をリセットしたい!! という開発環境あるあるを解決できます。

その②:エコシステム

Dockerコンテナを立ち上げるときに使用するイメージはもちろん自分でDockerfileを利用して1から組み立てることもできますが、Dockerが優秀なのはその イメージをベンダーが提供していたり、またそれがレジストリから落とすことができる「エコシステム」 にあると思います。

たいていのミドルウェアはコンテナイメージも簡単に入手できるようになっており、開発環境構築はこのイメージを持ってくるだけで完了してしまうことが多いんじゃないでしょうか。

その③:軽量

上にあげたメリットはうまくやればVMでもディスクイメージを取っておいて使いまわせば達成できなくもないですが、Dockerコンテナの場合はカーネルはホストOSが担うので、軽量ですし起動も早いと言われています。VM立ち上がるの待たなきゃ~~~っていうのがなくなりますね。

また、VMを複数立ち上げると複数のカーネルが立ち上がってしまうのでそこでメモリなりCPUなりリソースを少なからず消費するということも頭に入れておきましょう。別個のカーネルで動いていなければならない要件がなければ、カーネルを複数の環境で使いまわせるコンテナを使った開発環境がリソース的には有利になります。(まぁそんなカツカツな環境で開発するなというのはありますが)

Dockerコンテナを開発環境に組み込む3パターン

ではそんなDockerコンテナの開発環境への活用ですが、以下のように3パターンぐらい考えることができます。

パターン1: 依存しているものを1つでもDockerコンテナにしてみる

例えば開発にelasticsearchを使っていたら、開発機にインストールしているelasticsearchをDockerコンテナに置き換えてみましょう!

docker run -d -p 9200:9200 elasticsearch 

といった感じで使っているポート番号と同じポートでバインドするようにして起動すれば今までと同様に開発をすることができます。

汚れてきて気に食わなくなったらコンテナを落としてみましょう。コマンド1つできれいさっぱり、メリットにあげた「揮発性」の素晴らしさを体感できることでしょう。

パターン2: docker-compose.ymlを書いてみる

パターン1では開発環境の一部に単体のDockerコンテナを使用しましたが、さらに踏み込んで docker-compose.yml を書いてみましょう。今までいちいちdockerコマンドを叩いていたのが、docker-compose up -d で済みますし、何より開発環境に必要なコンテナ一式を一挙に管理できる のが便利です。

パターン3: 開発環境そのものをdockerコンテナ化する(devcontainer)

パターン2を使っていると自身がコードを書いている開発環境自体もDockerコンテナにしたくなるはずです!

開発環境自体をDockerコンテナ化することによるメリットとしては、例えばコンパイラやツール類のバージョンごとにコンテナイメージを作成することで、使用するコンテナイメージを切り替えるだけでパッとコーディングする環境自体を変えられることが挙げられます。

実際にPersoniumというOSSの開発ではJava1.8とJava17で同時に開発が走った時期があり、また、同時にelasticsearchの6系と7系の切り替えを検討するといったそれなりに環境に対してもインパクトのある改修を行ってきたんですが、それぞれDockerコンテナを用意して

みたいな4パターンを駆使して開発することがありました。これを手動でやっていたとすると、PATHだったりポートだったりもうゴチャゴチャになってしまい効率はすごく落ちていたと思います。

さらにdocker-compose.ymlにコーディングする環境自体を入れてしまうことによって得られるメリットとして、dockerネットワークが開発環境に活用できることがあります。いままで、開発環境がホスト側にある前提で構築してきた「パターン1」「パターン2」では、ホストへのポートのマッピングが必須でした。例えば、elasticsearchを3パターン用意するとしたら、9201, 9202, 9203といった感じで開発環境のパターンごとにポートを決め打ちで準備 する必要がありました。これってすごく面倒で、開発環境の設定も変えなきゃいけなくなります。

普段意識することは少ないんですが、composeを使用するとdocker-compose.ymlファイル(プロジェクト)ごとに dockerネットワーク というものが作成されています。dockerコンテナ間で通信をするときはコンテナごとに設定されたホスト名で通信できると思うんですが、これはdockerネットワーク単位で管理されます。つまり、A/docker-compose.ymlB/docker-compose.yml で別々のdockerネットワークが作成されていると、Aのコンテナ内で名前解決できるコンテナはAに閉じ、B内のコンテナに向くことはありません。

よって、必要な開発環境のバリエーションに合わせて「開発環境入りのdocker-compse.yml」を分けてしまえば、開発環境からは「同じcomposeファイルのxコンテナ9200番ポート」という設定のまま開発を行うことができ、また他の開発環境から独立して開発を進めていくことができるのです。

例: 実際の開発環境

と、ここまで書いて実践例もないのもアレかなと思い、拙作で恐縮ですが、自分がPersoniumというOSSの開発に使用しているdevcontainerについて紹介したいと思います。

github.com

devcontainerは、Visual Studio Codeでコンテナを使用した開発環境を構築できる拡張機能です。

Personiumの開発環境構成

Personiumではバックエンドに以下のようなものを使用しています。

また、バックグラウンドでタスク実行を行うエンジンと呼ばれるものがあります(Tomcat上で動かします)。

  • personium-engine (タスク実行エンジン)

動かし方

それでは使い方を説明します。

まずは開発環境を配置したいディレクトリで以下のコマンドを実行して、必要なソースコードを揃えます。

git clone https://github.com/yoh1496/personium-core-dev.git
git clone https://github.com/personium/personium-core.git
git clone https://github.com/personium/personium-plugins.git
git clone https://github.com/personium/personium-plugin-base.git
git clone https://github.com/personium/personium-lib-es-adapter.git

実行することで、以下のようなディレクトリ構成になることを確認してください。

┗┳ /personium-core-dev
 ┣ /personium-core
 ┣ /personium-plugins
 ┣ /personium-plugin-base
 ┗ /personium-lib-es-adapter

(とりあえずpersonium-coreが依存するリポジトリを全部入れてますが、personium-core-devとpersonium-coreだけでも大丈夫です)

次に、クローンしたpersonium-core-dev フォルダをvscodeで開きます。開けたら、左下の緑色のボタンをクリックし、「Reopen in container」をクリックします。

すると、vscodeの画面が更新され、左下には「Dev Container」と表示されていると思います。これはpersonium-core-devフォルダ内の.devcontainer/devcontainer.json が読み込まれ、指定されたコンテナにアタッチされている状態を示します。

あとは煮るなり焼くなり開発することができるというわけです。

ちょっと解説

なぜこういう構成に至ったのかなどは過去記事を書いているのでそちらを参照してください。

yoh1496.hatenablog.com

yoh1496.hatenablog.com

当時に比べたらvscodeの.devcontainerは格段に取り回しやすく(以下の記事参照)なっており、ところどころ書いてあることが違ったりしますが根幹はあまり変わっておりません。

いつの間にかVSCode の Remote - Containersが超絶パワーアップしていた件【docker client 不要】 - いしぐめも

devcontainerのメリット: 開発環境構成のコード化

と、ここまでコンテナを開発環境に使用するメリットと実際に使用してみた例を紹介しましたが、もっとも重要なdevcontainerの利点の紹介が抜けていました。正直、ここまでの説明ではdocker-composeでコンテナあげて、アタッチしてVimで開発するのと何が違うの?という話にもなってしまうかなと思います。

コンテナを用いた開発環境を整える1つの方法として「devcontainer」を紹介しましたが、devcontainerの本当の利点はVSCodeを使用した開発環境構成一式をコード化できる」 点にあると思っています。

今回devcontainerを使うことで、vscodeとdocker環境を整えることができさえすればボタン一つで開発環境構築を行えることを紹介しました。言ってみれば自動化なわけですが、vscodeとdockerが動く環境であればどこでも開発できるのです。

また、それだけでなく開発環境構築を自動的に行えるようにすることで、今までにあったような躓きやすいステップバイステップの開発環境構築ドキュメントとは別の手段を提供できるようになります。Personiumプロジェクトでも、開発環境の構築方法をドキュメントとして公開していますが、これを初学者に順に追ってもらうのはとても大変で、おそらくこの時点で挫折してしまう人も多いのではないかと思います。

開発用環境の構築手順 · Personium

その点、devcontainerを使用した開発環境構築では、ボタン一つで開発環境が整うのです。つまり、ちょっと興味を持っただけの1OSSを開発するためにJavaの開発環境構築やらなにやらといったノウハウを身につける必要がなくなります。プログラミングの最初のハードルは開発環境構築だと言われている(著者調べ)中で、ここが簡単になるのは非常に助かるんじゃないでしょうか。

GitHub Codespaces

は?何言ってんだvscode導入もdocker環境構築も難しいじゃねえか!!

というご意見もあるかなと思います。ごもっともです。

そもそも開発環境用のリソースを準備できないんだが??

ごもっとも(?)です。

そういうケースでも、devcontainerを使った開発環境構築をできるようにしておくことで使える、便利なサービスがあります。

GitHub Codespaces です。

Codespaces | GitHub

このサービスはGitHub上で使用できるSaaSサービスで、リポジトリソースコードから開発環境がVM上に構築され、ブラウザから操作できるというものです。

新規Codespace作成画面

起動中…

devcontainerから構築された開発環境が!

拡張機能も使える!

ついに「vscodeとdocker環境を揃える」という手間も必要なくなってしまいました。後はお金を払うだけ!!! (個人向けのベータ版は現在無料で使えるみたいです。)

現在はベータ版が提供されています

こんな便利なサービスが使えてしまうなんて、我々は未来に来てしまったんだな~と感じずにはいられませんね。

そしてついについに、このCodespacesも全ユーザーに開放され、月に無料で60H使えるようになるらしいですね。素晴らしい!

www.publickey1.jp

終わりに

だらだらと書いていたらまとまりのつかない記事になってしまいましたが、Codespacesが無料開放というビッグニュースが出てしまったので、今まで下書き状態だったのを公開します。

devcontainer便利なので是非使ってみてください。他にもこんな便利な使い方あるよ~だとかこうするといいよ~といった内容があればコメントなどいただけると嬉しいです。Personium参加してみたいとかそういうのも大歓迎です。

ではでは、よいdevcontainerライフを