Kabanero を使ったクラウド・ネイティブなアプリ開発(VSCode + Codewind)を体験 - その後 

2020年7月8日に実施された [初夏のIBM Dojo #9 Kabaneroを使ったクラウド・ネイティブなアプリ開発を体験](https://ibm-developer.connpass.com/event/178322/) ワークショップに参加してきました。講師 @osonoi さんです。

以前に翻訳した [Kabanero](https://qiita.com/yamachan360/items/7b4a53758ecdbe876a5f) と、それと関連する [Developer Experience](https://qiita.com/yamachan360/items/1550887f76f3a0a8f47d) にある「VS Code を使用して Kabanero を試す」を体験できるオンラインセッションでした。[セッション資料](https://speakerdeck.com/osonoi/chu-xia-falseibm-dojo-number-9-kabanerowoshi-tutakuraudoneiteibunaapurikai-fa-woti-yan) がわかりやすいので、ぜひ参照してください。

> VSCode + codewind の環境、とっても手軽で便利。監視、ビルド、実行など全て Docker 環境で実行され、処理系のインストール無しでさくさく試せる。いろんな言語/環境を試してみたい。

と、Twitter で呟きましたが、すごく参考になったので、ちょっと自分でも中身を確認してみました。自分なりに迷いつつのメモなので、間違えていたり、意味不明だったらスミマセン。

# お手軽に開発環境をセットアップ

セッション資料に従い、アプリケーション開発環境をセットアップしてみます。前提となるソフトウェアは以下の2つだけ。

* [Docker](https://www.docker.com/get-started) : 仮想マシン実行環境
* [VSCode](https://azure.microsoft.com/ja-jp/products/visual-studio-code/) : テキストエディタ

VSCode の 拡張機能 (Extension) で ``Codewind`` を探してインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/e7de07f2-e5b8-2108-5712-0244ef826c57.png)
新規プロジェクト作成で、Kabanero リポジトリにある ``Kabanero Node.js Express scaffold template`` を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/e9f7d032-18ac-5f55-8d2b-aeef93a4e196.png)
後は開発環境などが自動でセットアップされます。ビルド環境も実行環境も Docker コンテナ化されているため、Node.js など開発に必要なツールがインストールされていなくても問題ありません。今回のセットアップも Docker 上にコンテナが追加されるだけで、ローカルにインストールされないため、気軽に試すことができます。

アプリを起動すると Node.js Express が動作し、シンプルな Webページが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/dd225731-c734-b5a8-fcff-1259e7365949.png)
さあ、後はサンプルコードを修正して、いろいろ試すだけ。ソースコードに修正を保存すれば、ビルドが実施され、すぐにWebページに反映されます。

以上、ここまでの手順の詳細は IBM Dojo の [セッション資料](https://speakerdeck.com/osonoi/chu-xia-falseibm-dojo-number-9-kabanerowoshi-tutakuraudoneiteibunaapurikai-fa-woti-yan) をご参照ください。[IBM Developer Dojo](https://ibm-developer.connpass.com/) のどれかに参加すると、Dojo サポート用の Slack チャネルに招待されるので、そこで質問もできます。

# 生成された環境を眺めてみる

さてこのまま、環境はブラックボックスとして、Node.js + Express のアプリ開発を開始してもいいのですが… せっかくですから、自動生成された環境を少し眺めてみましょう。

## VSCode のワークスペース

まず VSCode のワークスペースを見てみると、以下のような構成になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/199c8d60-8282-2425-b8ac-701630732ed1.png)
ページを表示しているのは ``routes/index.js`` ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/1bf0f4dc-b863-342c-b8bf-54cfdb052a80.png)
表示に利用されている Pug 形式のテンプレート ``views/index.pug`` は以下のように非常にシンプルでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/d2a27d66-31f8-1c57-a849-641c19a8e20e.png)
これらなのですが、探してみると GitHub の appsody アカウントにある [stacks リポジトリ](https://github.com/appsody/stacks) 配下にある [/incubator/nodejs-express/templates/scaffold](https://github.com/appsody/stacks/tree/master/incubator/nodejs-express/templates/scaffold) フォルダが元になっているようです。

## Docker で動作するコンテナについて

さて、上記の Web ページを表示中、Docker は以下のように3つのコンテナを実行していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/3c670562-8fa3-036c-8ffa-d6f8605a881d.png)

最初のコンテナ (イメージは kabanero/nodejs-express:0.4) がアプリを実行している環境のようですので、コンテナに sh アクセスして、動作しているプロセスの状態を見てみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/177fdcb8-8374-7bdb-fd36-74faa0fa2153.png)
自身の /bin/sh と ps コマンド以外のプロセスは以下のような感じ。

```
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
default      1  1.8  0.3 105308  7492 pts/0    Ssl+ 09:43   7:34 /.appsody/appsody-controller --mode=run
default     42  0.0  2.2 743756 45576 ?        Ssl  09:43   0:00 npm
default     58  0.2  4.2 1268880 86480 ?       Sl   09:43   1:08 node server.js
```

ついでに真ん中のコンテナ(イメージは eclipse/codewind-performance-amd64:0.13.0) のプロセスはこちらで、ちょっと何やっているか不明なのですが、実行しているイメージ名から Codewind 本体のような気がします。アプリのビルド前から居ましたし。

```
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000         1  0.0  1.5 741756 30936 ?        Ssl  07:20   0:00 npm
1000        16  0.0  2.5 680096 52572 ?        Sl   07:20   0:00 node server.js
```

三番目のコンテナ (イメージは eclipse/codewind-pfe-amd64:0.13.0) のプロセスはこちらで、こちらはソースコードの更新をチェックしたり、最初のコンテナを起動してたり、いろいろ働いているようです。

```
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  11892  2652 ?        Ss   07:20   0:00 sh -c  /file-watcher/scripts/root-watcher.sh ${HOST_WORKSPACE_DIRECTORY} ${CONTAINER_WORKSPACE_DIRECTORY}
root        33  0.0  2.1 676736 43460 ?        Sl   07:20   0:00 npm
root        61  0.0  0.1  11896  2916 ?        S    07:20   0:00 /bin/bash ./npm-start.sh
root        62  0.0  2.1 676368 44708 ?        Sl   07:20   0:00 npm
root        73  0.0  5.6 972028 115352 ?       Sl   07:20   0:16 node server.js
root       535  0.0  0.1  11896  2760 ?        S    09:43   0:00 /bin/bash /codewind-workspace/.extensions/codewind-appsody-extension/appsody run --name cw-dojoyamacha
root       536  0.0  0.0  23032  1408 ?        S    09:43   0:00 /usr/bin/coreutils --coreutils-prog-shebang=tee /usr/bin/tee -a /codewind-workspace/.logs/dojo-yamacha
root       542  0.0  0.5 116632 11840 ?        Sl   09:43   0:00 /codewind-workspace/.extensions/codewind-appsody-extension/bin/appsody run --name cw-dojoyamachan-df39
root       603  0.0  1.4  45688 29636 ?        Sl   09:43   0:00 docker run --rm -P --name cw-dojoyamachan-df39b4d0-c0eb-11ea-97e7-d775ccf52e96 --network codewind_netw
root       620  0.0  0.0  23032  1320 ?        S    16:11   0:00 /usr/bin/coreutils --coreutils-prog-shebang=tail /usr/bin/tail -q -F -c +0 /codewind-workspace/.logs/d
```

三番目のコンテナ内の環境変数に、幾つか興味深い値がありましたので、転記します。

```
CODEWIND_VERSION=0.13.0
CONTAINER_WORKSPACE_DIRECTORY=/codewind-workspace
ENABLE_CODE_COVERAGE=false
HELM_HOME=/root/.helm
HOSTNAME=72958642fbc6
HOST_HOME=C:\Users\z
HOST_MAVEN_OPTS=
HOST_OS=windows
HOST_WORKSPACE_DIRECTORY=C:\codewind-data
IMAGE_BUILD_TIME=20200612-133352
JAVA_HOME=/opt/java/jre
LOG_LEVEL=info
NODE_ENV=production
PATH=/opt/java/jre/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PERFORMANCE_CONTAINER=codewind-performance-amd64:0.13.0
```

そして気がついていませんでしたが、ローカルPCに ``C:\codewind-data`` なんてフォルダが生成されていました… 作業ディレクトリとほぼ同じ構成ですが、``.vscode`` フォルダが無いかわりに空の ``node_modules`` フォルダが存在します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/a2d3b91f-25da-22dc-3056-da93cc4fc9fb.png)
試しに c:\ ドライブ全体を対象に ``appsody`` でファイル名検索した結果がこちら。``c:\work\codewind\dojo-yamachan`` がプロジェクト作成時に自身で指定した作業フォルダです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/fcab6af0-555a-adf3-47d7-49579a935b14.png)
ふーむ、なかなか興味深いですね。

# 実際の起動プロセス

さて、作成したアプリがどう起動されるか追ってみましょう。実行用コンテナで ``node server.js`` とあるので、sh でコンテナの中に入り、``server.js`` ファイルの中でそれっぽい部分を探してみます。

```JavaScript
// Register the user's app.
const basePath = __dirname + '/user-app/';

function getEntryPoint() {
    let rawPackage = fs.readFileSync(basePath + 'package.json');
    let package = JSON.parse(rawPackage);
    if (!package.main) {
        console.error("Please define a primary entrypoint of your application by adding 'main: <entrypoint>' to package.json.")
        process.exit(1)
    }
    return package.main;
}

const userApp = require(basePath + getEntryPoint());
app.use('/', userApp({
  server: server,
  app: app,
  log: pino,
}));
```

まずわかるのが、作成した自身のアプリが ``/project/user-app/`` ディレクトリに配置されているということです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/7771e2c7-1efd-ff2b-97b7-7e613b99b594.png)

そしてこのディレクトリですが、Docker ランタイムにより、さきほど発見したローカルPCの ``C:\codewind-data`` 配下のフォルダがマウントされ、永続化されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/ac21dd67-3b14-5f65-60f2-14ed9fd327cf.png)

たぶんですが、作業フォルダの内容をビルドした結果 (今回は Node.js で webpack など前処理もないので単にファイルコピーのみ？) がこのローカルPC上のフォルダに配置され、それを実行環境の Docker コンテナの ``/project/user-app/`` ディレクトリにマウントすることで、即時反映できている、という仕組みのようです。

で、さきほどの ``server.js`` ファイルのコードにある ``getEntryPoint()`` 関数の中を見ると、``package.json`` のなかの ``main`` エントリがアプリの本体を指定しているようで、今回だと ``app.js`` が指定されています。

```JavaScript:package.json
  "main": "app.js",
```

そしてこの ``app.js`` を見ると、これが Express アプリの本体で、これでようやく最初に出てきた ``routes/index.js`` や ``views/index.pug`` ファイルに繋がります。

```JavaScript:app.js
module.exports = (/*options*/) => {
  // Use options.server to access http.Server. Example of socket.io:
  //     const io = require('socket.io')(options.server)
  const app = require('express')()

  app.set('views', __dirname + "/views");
  app.set('view engine', 'pug');

  app.use('/', require('./routes'));
 
  return app;
};
```

起動順としては、以下のような感じですかね。

1. Appsody が用意した実行用コンテナの ``/project/user-app`` にローカルPCの ``c\codewind-data`` 配下のプロジェクト用フォルダがマウントされる 【Appsody共通】
2. Appsody が用意した実行用コンテナ内の ``/project/server.js`` が ``/project/user-app/package.json`` ファイルの main エントリを参照する【Appsody Node.js 系共通】
3. main エントリに指定された ``/project/user-app/app.js`` が実行される【Appsody Node.js Express 系共通？】
4. app.js によって Pug テンプレートエンジンがセットされ、``views/index.pug`` をテンプレートとして ``route/index.js`` が表示される。【今回の Stack 固有】

うん、これでやっとスッキリしました。

# というわけで

Appsody (VSCode + Codewind) で作成した Node.js + Express サンプルアプリの起動の仕組みをざっくり調べてみました。なかなか良く出来た仕組みだなー、と感心してみたり。

ただ、時間の関係もあり、ソースコードの変更をウォッチしているところ、ビルドしているところ、などはまだ調べていません。また時間を作って、コンパイルする Java などの環境(変化がわかりやすいので)を対象に調べてみたいな、などと思っています。なにかわかったら、メモ公開するかもしれません。

それではまた！