【2019年10月版】GraalVMでNative化した Javalin のコンテナをcAdvisorでチェックしてみる

# どういうこと？

Javalin で構築した WebAPIのサーバーを GraalVM でネイティブの単一のバイナリとしてコンパイルし、さらに Docker イメージ化してコンテナとして動かしてみちゃうけど、ぶっちゃけどんくらい軽量なのよ？というのを確認するために cAdvisor + Prometheus & Grafana でコンテナの使用リソースをチェックしてみましょう、といった相変わらず情報量の多い~~ウザめの~~記事となっておりスマ。はい、すいません。。。

## 動作環境

OS: macOS Mojave 10.14.6
Docker: Docker Desktop Mac版 2.1.0.3 (Engine: 19.03.2, Comose: 1.24.1)

Graalvm SDK: 1.0.0-rc-6
Javalin: 2.2.0

Docker、Docker Compose が動く環境であればWindowsでも大丈夫かと思います。

Javalinについては深く触れませんが、Jettyをラッピングした軽量な(?)Webフレームワークです。

- [A simple web framework for Java and Kotlin](https://javalin.io/)

それでは早速、参りましょう。

## Javalin on Graal on Docker の構築

GraalとJavalinが最新版ではありませんが、今回は本家チュートリアル(?)に従いたいと思います。

- [Running Javalin on GraalVM (22MB total size)](https://javalin.io/2018/09/27/javalin-graalvm-example.html)

こちらの記事ではJavalinの簡易WebアプリをGraalVMでビルドし、そのままDockerコンテナにしてしまう手順が紹介されています。

さらに scratch イメージに構築する(実行形式バイナリそのままにする)ことで 22MBという極小サイズでJavaのWebアプリをコンテナ化できているらしいです。(実測はしてません。)

それでは早速、構築していきましょう。

### 1. サンプルのソースコードを入手

いきなりチートですが、今回のゴールはcAdvisor(+Prometheus+Grafana)でコンテナのチェックするところまでなので、Javalinのサンプル実装は構築済みの成果物をまるごと利用させていただきたいと思います。

以下のリポジトリをcloneしてしまいましょう。

```console
$ git clone git@github.com:tipsy/graal-javalin.git
```

### 2. docker-compose.yaml の記述

cloneはしましたが`graal-javalin`ディレクトリには入らず、引き続き同じディレクトリで以下の `docker-compose.yaml` を作成します。

```yaml:docker-compose.yaml
version : "3"
services:
    javalin-graalvm:
        build:
          context: graal-javalin
        ports:
          - 7000:7000
        stdin_open: true
        tty: true
```

clone してきたコードはそのまま動かしてしまいます。

### 3. Javalin on Graalvm のコンテナを実行

さて以下のコマンドでさっさと起動してしまいましょう。

```console
$ docker-compose up -d
```

そして curl でポート 7000番を叩いてみると・・・

```console
$ curl http://localhost:7000
{"someValue":"Hello World!"}
```

というわけでサクッとサンプルで構築した(?)REST APIの結果がjsonで返ってきました。

素晴らしい〜！

### 3-1. 余談：コンテナイメージ `scratch` について

上記のコンテナをビルドする Dockerfile では、GraalVMが含まれるコンテナでビルドしたバイナリを `scratch` イメージに*コピー*してコンテナ化するという２段階でイメージをビルドしていますが、`scratch`というイメージは特殊な`空っぽのイメージ`です。
つまり、GraalVMでビルドされたバイナリのほぼそのままが docker のプロセスによってキックされており、docker プロセスが動いている環境(OSやマシンのアーキテクチャ)が同じでないと動作しません。

今回は検証目的ですので気にせずいきますが、実際のプロダクション環境での採用はなかなか難しいと思います。[上記の記事](https://javalin.io/2018/09/27/javalin-graalvm-example.html)はあくまで"scratchで22MBしかないんだぜ!俺スゲー！"という内容です。~~察してあげてください。~~

## cAdvisor, Prometheus, Grafana を一撃で動かす

cAdvisor, Prometheus, Grafana のサービスを動かしてみましょう。
以下の記事に紹介されているプロジェクトが今回には持ってこいですね！

- [Prometheus、Grafana、cAdvisorによる監視をコマンド一つで行える「dockprom」](https://qiita.com/kontotto/items/dbd58db3f66ec388c42c)

というわけで "dockprom" のクローンを作成致します。

相変わらずディレクトリはそのままで・・・

```console
$ git clone git@github.com:stefanprodan/dockprom.git
```

そして、`docker-compose up` で立ち上げてしまいます！

```console
$ cd dockprom
$ docker-compose up -d
...
Creating alertmanager ... done
Creating prometheus   ... done
Creating caddy        ... done
Creating grafana      ... done
Creating pushgateway  ... done
Creating nodeexporter ... done
Creating cadvisor     ... done
```

イメージのダウンロードにはそこそこ時間がかかりますが気長に待ちます。しばらくして、コンテナが全て作成し終わったところで `grafana` コンテナが待ち受けている `http://localhost:3000` にアクセスしてみましょう。

## Grafana のダッシュボードをのぞいてみると・・・

初回は、パスワードのリセットなどありますが、そのまま問題なく使用できるはずです。いや〜、素晴らしい。。。

非常に簡単に Grafana 立ち上がるのでちょっと感動してしまいましたが気を取り直して、画面左上の"Dashboards"から `Docker Containers` を選んでください。先ほど立ち上げた、javalin-graalvmのコンテナが表示されていると思います。
賢いことにPrometheus,Grafanaなど監視用のコンテナは表示されず、監視用コンテナ以外のコンテナ**だけ**のstat情報が表示されているはずです。

<img width="1080" alt="スクリーンショット 2019-10-17 19.34.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/f4de3561-7323-6099-531f-768cf1616c69.png">

私の環境では上のような状態です。`http://localhost:7000` を叩いてJSON吐き出させてみましたが、**メモリ使用量、20MBも行かない**です。

Oh.... か、軽い。。。

画面のグラフはかなりリソースの消費量が急上昇しているように見えますが、そもそものメモリが５MiB単位なんで、小さな世界なんです。`It's a Small World` !!

そもそも`Hello World`返すだけのプログラムですけれどもぉ、Jetty+JRE相当のバイナリ同梱してますしぃ・・・JVMは動くだけでも数100MBオーダーのメモリは消費してしまうんではなかったかと！

## Spring や Micronaut も・・・

Micornaut や Spring も着々と GraalVM対応が進んでいるようです。

- [GraalVM の native image を使って Java で爆速 Lambda の夢を見る](https://qiita.com/kencharos/items/69e43965515f368bc4a3)
- [Spring Boot ApplicationをMicronaut for Springでnative-imageにしてみる](https://qiita.com/h-r-k-matsumoto/items/5b82177294cd71df5024)

どこまでGraalVMがネイティブ化対応できているか、については引き続き調査が必要ですが、GraalVMでネイティブ化したJavaアプリが超軽量なコンテナとしてバンバンDockerやK8sにデプロイできるようになると・・・ちょっと胸熱ですね！

本日はここまでと致します！