はじめに
Java 系 の Web アプリケーションを Azure で動かしたいと考えたとき、Web Apps や Azure Spring Cloud を使ってそのまま動かすのもありですが、最近 GA した Azure Static Web Apps を使ってよりサーバーレスにもっていけたりしないかな?と考えてみています。
Static Web Apps は Angular / React / Vue などで作ったシングルページアプリケーションのデプロイに最適なサービスで、静的サイトのホスティング + Azure Functions によるバックエンド API のセットで構成されています。
しかしこのバックエンド API、通常は Static Web Apps 専用の Functions が裏に用意されるのですが、現状 JS / C# / Python しかサポートされていません。
しかし、GA された Static Web Apps には、有料のスタンダードプランで使うことのできる「Bring your own functions」機能があり、これなら別途用意した Azure Functions をバックエンド API としてつなぐことができるため、Java の Azure Functions を使うことができます。
これを使って別途 Functions で作成した Java ベースなバックエンドを Static Web App につないでしまおうという寸法ですが、既存の Java のバックエンドのコードをどれだけ Functions に流用できるかが勝負です。
この流用をしやすくするために、Micronaut というマイクロサービスフレームワークが適しているのではないか?と考えています。
ちょうど業務のほうでも、以前から Azure 上で Grails 1 の Web アプリケーションを運用していて、もろもろのコストを考えてもう少しサーバーレスなかたちに移行したいと考えていたので、それを想定しつつ Java 系 Web アプリの移行先としての Azure Static Web Apps + Micronaut for Azure Functions を考えてみたいと思います。
なお、フロントエンドは Vue.js を使っていきます(これしかまともに書けない…)。
Micronaut とは
JVM ベースのマイクロサービス開発向けフレームワークです。
前にも少し紹介させていただきましたが、Azure Functions を公式にサポートしていて、Micronaut フレームワークを使って Function App の開発ができます。
Micronaut の利点としては、
というのが挙げられます。
今回は Grails からの移行ということで、同じ Groovy 言語が使える、DI があるので移行元で使っていたサービスクラスをそのまま流用できるなどの利点が見込めそうです(これがこの構成をとるいちばんの理由)。
ローカルでの環境構築・開発
ということで、ローカルに環境を作って動かすところまでやってみます。
今回は Mac 想定で進めるので、Windows だと多少コマンドなど異なるかもしれません。そのあたりはご注意ください。
今回の検証環境:
開発環境構築
まずは以下をいれておきます。
VS Code と拡張機能
エディターは VS Code を使います。
以下の拡張機能を入れておきます。
SDKMAN!
Java や Groovy、Micronaut などをインストール・アップデートできる SDK マネージャーです。
Home - SDKMAN! the Software Development Kit Manager
未インストールであれば
curl -s "https://get.sdkman.io" | bash
でインストールし、インストール済みであれば以下で更新しておきます。
sdk update
JDK
Java 8 を使う必要があるので、JDK 8 を入れておきます。
sdk install java 8.0.292-zulu sdk default java 8.0.292-zulu
java -version
して入れた JDK が出てくるようになっていれば OK です。
SDKMAN ではなくインストーラー経由で別バージョンの JDK を入れている場合はなおすのがちょっと面倒かもしれませんので、JDK は SDKMAN で管理するように切り替えておくとよいでしょう。
Micronaut
続いて Micronaut の本体です。
sdk install micronaut
vue-cli
Vue.js 開発用。Vue を使わない場合は当然不要です。
npm install -g @vue/cli
Static Web Apps CLI
ローカルで Static Web Apps を動かしたりできる CLI ツールです。
npm install -g @azure/static-web-apps-cli
とりあえず、使うツールは以上です。
フロントエンド(Vue.js)プロジェクトの作成
適当なフォルダに、Vue.js のアプリをつくります。ターミナルから
vue create static-web-app-micronaut-sample
を実行します。
Manually select features で、今回はこんなかんじにしておきます(このあたりはなんでもよいはず)。
? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, Router ? Choose a version of Vue.js that you want to start the project with 2.x ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
できあがったら、 cd して code を開きます。
cd static-web-app-micronaut-sample/
code .
ここから先は VS Code で作業です。
バックエンド(Micronaut)プロジェクトの作成
フロントエンドの Vue のプロジェクトを VS Code で開いたところですが、ここでバックエンドのプロジェクトを作成します。
フロントエンドとバックエンドは同一リポジトリにあげる monorepo で運用すると楽なので、Vue のプロジェクトのフォルダ内に Micronaut のプロジェクトを作っていきます。
VS Code のターミナルから、以下のコマンドを実行します。
mn create-function-app --build=gradle --jdk=8 --lang=groovy --test=spock --features=azure-function com.example.swa.api
パッケージ名とかは適当ですが、最後の api
という部分が生成されるフォルダ名になるので、バックエンド・API あることがわかりやすい名前にしておくとよいでしょう。
ほぼ Java の簡易版なコード & Grails からの移行を見越している、ということでここでは言語を Groovy にしていますが、もちろん Java でも Kotlin でも大丈夫です。
ちなみに、上記のコマンドはこちらのサイトで生成可能です。
使いたい機能を選択すると、オプションつきのコマンド文字列が得られます。ひながたを ZIP で落とすことも可能。
では、少し実装をいじっていきます。
GreetingService.groovy
DI を試したいので、簡単なサービスクラスを作っておきます。
package com.example.swa.services import javax.inject.Singleton @Singleton class GreetingService { String greet(String name) { "Hello, ${name}!" } }
Function.groovy
ひながたにある Function.groovy
をそのまま使って、DI によるサービスクラスの利用をやってみます。
package com.example.swa import com.microsoft.azure.functions.HttpStatus import com.microsoft.azure.functions.ExecutionContext import com.microsoft.azure.functions.HttpRequestMessage import com.microsoft.azure.functions.HttpMethod import com.microsoft.azure.functions.HttpResponseMessage import com.microsoft.azure.functions.annotation.AuthorizationLevel import com.microsoft.azure.functions.annotation.FunctionName import com.microsoft.azure.functions.annotation.HttpTrigger import com.example.swa.services.GreetingService import io.micronaut.azure.function.AzureFunction import java.util.Optional import javax.inject.Inject public class Function extends AzureFunction { @Inject GreetingService service @FunctionName("HttpTrigger") public HttpResponseMessage hello( @HttpTrigger( name = "req", methods = [HttpMethod.GET], authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, ExecutionContext context) { String message = service.greet("sample") request.createResponseBuilder(HttpStatus.OK).body(message).build() } }
クラスの先頭で GreetingService
を DI しているだけのシンプルな処理で、これを HttpTrigger
という名前の関数にしています。
HelloWorld.vue
Vue.js で最初から作られている src/components/HelloWorld.vue
に以下のような処理を追記します。
<template> <div class="hello"> <h1>{{ msg }}</h1> <p>from api: {{ apiMessage }}</p> <!-- 中略 --> </template> <script> import axios from 'axios' export default { name: 'HelloWorld', props: { msg: String }, data: () => { return { apiMessage: '' } }, created: function() { axios.get('/api/HttpTrigger') .then(response => { console.log(response.data); this.apiMessage = response.data; }).catch(err => { console.log(err.response); this.apiMessage = err.response.statusText; }); } } </script> <!-- 以下略 -->
axios を使って /api/HttpTrigger
を叩いて、返ってきた内容を画面に表示させています。
npm install axios
しておきましょう。
Static Web Apps のいいところのひとつが、こうやってフロントエンドと同一のルートからのパスで API が叩けるところですね。
ローカルでの実行
ここまできたら実行してみましょう。
コマンドから、まずはフロントエンドとバックエンドを VS Code でそれぞれ別のターミナルから立ち上げます。
フロントエンド(Vue.js)
npm run serve
バックエンド(Micronaut)
ターミナルをもうひとつ開き、以下のコマンドを実行します。
cd api
./gradlew clean azureFunctionsRun
Static Web App としての実行
SWA CLI の機能で、同一のルートにフロントエンドもバックエンドも配置されている状況を再現できます。
さらにターミナルを立ち上げて、以下のコマンドを実行します。
swa start http://localhost:8080/ --api http://localhost:7071
するとこのように、Static Web Apps 同様、同一の URL にフロントエンドもバックエンドもあるような状態をローカルでエミュレートしてくれます。
表示された URL にアクセスすると、このように表示されます。
ちゃんと Micronaut の API も呼んでくれているのがわかりますね。
まとめ
Micronaut 自体がおもしろいフレームワークですが、Azure Static Web Apps との組み合わせもなかなか強力そうな予感がしています!
今回はとりあえずローカル実行するところまで書いてみましたが、長くなりそうなので続きは別記事にしていきたいと思います。
このあとは、
- Azure AD の適用
- Azure へのデプロイ
- CI/CD まわり
あたりを検証していこうかなと思っています。