Dapr と Express と Spring Boot でマイクロサービスを構成する:Azure 編
こんにちは、@studio_meowtoon です。今回は、Azure Container Apps にて、Dapr と Express と Spring Boot を利用してマイクロサービスを構成する方法を紹介します。
目的
分散アプリケーションの為のランタイム Dapr の理解を深めます。
実現すること
Microsoft Azure Container Apps 環境にて、Dapr、Express、Spring Boot で構成する、シンプルなマイクロサービスを実装します。
こちらの記事の続きになります。
開発環境
- Windows 11 Home 22H2 を使用しています。
WSL の Ubuntu を操作していきますので macOS の方も参考にして頂けます。
WSL (Microsoft Store アプリ版) ※ こちらの関連記事からインストール方法をご確認いただけます
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
Ubuntu ※ こちらの関連記事からインストール方法をご確認いただけます
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
npm ※ こちらの関連記事からインストール方法をご確認いただけます
$ node -v
v19.8.1
$ npm -v
9.5.1
Java JDK ※ こちらの関連記事からインストール方法をご確認いただけます
$ java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
Maven ※ こちらの関連記事からインストール方法をご確認いただけます
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Docker ※ こちらの関連記事からインストール方法をご確認いただけます
$ docker --version
Docker version 23.0.1, build a5ee5b1
Dapr ※ こちらの関連記事からインストール方法をご確認いただけます
$ dapr --version
CLI version: 1.11.0
Runtime version: 1.11.2
Azure CLI ※ こちらの関連記事からインストール方法をご確認いただけます
$ az --version
azure-cli 2.45.0
core 2.45.0
telemetry 1.0.8
※ この記事では基本的に Ubuntu のターミナルで操作を行います。
作成する Web アプリケーションの仕様
No | エンドポイント | HTTPメソッド | MIME タイプ |
---|---|---|---|
1 | /api/data | GET | application/json |
説明を開きます。
/api/data というエンドポイントを実装するバックエンドサービスと、HTTP GET リクエストを送信して、JSON データを取得するフロントエンドのクライアントアプリを実装します。
バックエンドサービスを実装
前回の記事からご確認いただけます。
プロジェクトフォルダに移動
プロジェクトフォルダに移動します。
※ ~/tmp/hello-spring-dapr をプロジェクトフォルダとします。
$ cd ~/tmp/hello-spring-dapr
Java アプリをビルド
Java アプリをビルドします。
$ mvn clean package
ここまでの手順で、target/app.jar Java アプリが作成されました。
コンテナイメージをビルド
コンテナイメージをビルドします。
$ docker build -t app-hello-spring-boot .
コンテナイメージを Docker Hub にプッシュ
こちらの関連記事で手順がご確認いただけます。
Docker Hub にログインします。
$ docker login
Login Succeeded
コンテナイメージにタグを付けます。
$USER の部分はご自身のコンテナリポジトリに読み替えて下さい。
$ docker tag app-hello-spring-boot $USER/app-hello-spring-boot:latest
Docker Hub にコンテナイメージをプュシュします。
$ docker push $USER/app-hello-spring-boot:latest
ここまでの手順で、Docker Hub に Spring Boot アプリのコンテナイメージを公開することができました。
フロントエンドアプリを実装
Azure Container Apps の構成ではフロントエンドアプリの React コンテナからバックエンドサービスの Spring Boot コンテナに直接 Dapr API を通してアクセスすることはできません。代わりにこの記事ではサーバーサイドで動作する Express を使用してフロントエンドアプリを実装します。
プロジェクトフォルダの作成
プロジェクトフォルダに移動します。
※ ~/tmp/hello-express をプロジェクトフォルダとします。
$ mkdir -p ~/tmp/hello-express
$ cd ~/tmp/hello-express
JS ファイルの作成
server.js JS ファイルを作成します。
$ mkdir -p src
$ vim src/server.js
ファイルの内容
import express from 'express';
import fetch from 'node-fetch';
const app = express();
const port = 3000;
const fetchData = async () => {
try {
const response = await fetch('http://localhost:3500/v1.0/invoke/app-hello-spring/method/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('データの取得中にエラーが発生しました:', error);
throw error;
}
};
app.get('/', async (req, res) => {
try {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Hello Express</title>
</head>
<body>
<div id="message"><h2>Loading...</h2></div>
<button id="fetchButton" onclick="fetchData()">データを取得</button>
<script>
const messageDiv = document.getElementById('message');
const fetchButton = document.getElementById('fetchButton');
const fetchData = () => {
fetch('/api/data')
.then(response => response.json())
.then(data => {
messageDiv.innerHTML = '<h1>' + data.message + '</h1>';
fetchButton.style.display = 'none';
})
.catch(error => {
console.error('Error fetching data:', error);
});
};
</script>
</body>
</html>
`);
} catch (error) {
console.error('エラーが発生しました:', error);
res.status(500).send('エラーが発生しました');
}
});
app.get('/api/data', async (req, res) => {
try {
const data = await fetchData();
res.json(data);
} catch (error) {
console.error('データの取得中にエラーが発生しました:', error);
res.status(500).json({ error: 'データの取得中にエラーが発生しました' });
}
});
app.listen(port, () => {
console.log(`サーバーは http://localhost:${port} で実行されています`);
});
webpack 設定の作成
webpack.config.js ファイルを作成します。
$ vim webpack.config.js
ファイルの内容
const path = require('path');
module.exports = {
mode: 'development',
target: 'node',
entry: './src/server.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'server.bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
プロジェクトの初期化
プロジェクトの初期化を行います。
$ npm init -y
package.json を修正します。
$ vim package.json
ファイルの内容
{
"name": "hello-express",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"start": "node build/server.bundle.js",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC"
}
ライブラリをインストールします。
$ npm install express node-fetch --save
$ npm install babel-loader @babel/core @babel/preset-env \
webpack webpack-cli --save-dev
ローカルでビルド・実行してエラーが出ないか確認します。
$ npm run build
$ npm start
コンテナイメージをビルド
Dockerfile を作成します。
$ vim Dockerfile
ファイルの内容
FROM node:lts-alpine as build-env
WORKDIR /app
COPY package.json package-lock.json /app/
COPY src /app/src
COPY webpack.config.js /app/
RUN npm install
RUN npm run build
FROM node:lts-alpine
WORKDIR /app
COPY --from=build-env /app/build /app/build
RUN npm install express
EXPOSE 3000
CMD ["node", "build/server.bundle.js"]
コンテナイメージをビルドします。
$ docker build -t app-hello-express .
コンテナイメージを確認します。
$ docker images | grep app-hello-express
app-hello-express latest 58d8acb77435 21 minutes ago 184MB
コンテナイメージを Docker Hub にプッシュ
コンテナイメージにタグを付けます。
$USER の部分はご自身のコンテナリポジトリに読み替えて下さい。
$ docker tag app-hello-express $USER/app-hello-express:latest
Docker Hub にコンテナイメージをプュシュします。
$ docker push $USER/app-hello-express:latest
ここまでの手順で、Docker Hub に Express アプリのコンテナイメージを公開することができました。
Azure 環境へのデプロイ
シェル変数の作成
シェル変数として、Ubuntu に以下の値を作成します。
location_name=japaneast
resource_group_name=rg-hello
containerapp_env_name=cae-hello
Azure 環境にサインイン
こちらの関連記事からご確認いただけます。
Azure CLI でログインします。
$ az login
Azure 環境の作成
リソースグループ
リソースグループを作成します。
$ az group create \
--name $resource_group_name \
--location $location_name
コンテナ アプリ環境
コンテナ アプリ環境を作成します。
※ Kubernetes 基盤の環境がベースとなっているので少し時間がかかります。
$ az containerapp env create \
--resource-group $resource_group_name \
--name $containerapp_env_name \
--location $location_name
ここまでの手順で、Azure に Container Apps 環境を作成することができました。
バックエンドサービスをデプロイ
プロジェクトフォルダに移動
プロジェクトフォルダに移動します。
$ cd ~/tmp/hello-spring-dapr
シェル変数の作成
シェル変数として、Ubuntu に以下の値を作成します。状況により、コンテナ アプリの名前を変える必要があります。
resource_group_name=rg-hello
containerapp_env_name=cae-hello
containerapp_name=ca-hello-spring-boot
container_image_name=app-hello-spring-boot:latest
コンテナ アプリ
コンテナ アプリの作成とデプロイを行います。
$ az containerapp create \
--resource-group $resource_group_name \
--environment $containerapp_env_name \
--name $containerapp_name \
--image $USER/$container_image_name \
--target-port 8080 \
--ingress 'external' \
--min-replicas 1 \
--enable-dapr true \
--dapr-app-id app-hello-spring \
--dapr-app-port 8080 \
--dapr-app-protocol http
コンテナに接続
バックエンドサービスの Dapr が有効になっているか確認します。
Container Apps のデフォルト構成では、Dapar API はクラウド環境の外部に公開されていません。
コンテナ アプリに接続します。
$ az containerapp exec \
--resource-group $resource_group_name \
--name $containerapp_name
コンテナ アプリに curl をインストールします。
※ コンテナから出るときは ctrl + D を押します。
# apk update
# apk add curl
# curl --version
curl 8.0.1 (x86_64-alpine-linux-musl) libcurl/8.0.1 OpenSSL/1.1.1k zlib/1.2.11 brotli/1.0.9 nghttp2/1.43.0
コンテナ アプリから Dapr API をリクエストして確認します。
# curl http://localhost:3500/v1.0/invoke/app-hello-spring/method/api/data -w '\n'
出力
{"message":"Hello World!"}
ここまでの手順で、Container Apps に、Dapr サイドカーを有効にしたバックエンドサービスをデプロイすることができました。
フロントエンドアプリをデプロイ
プロジェクトフォルダに移動
プロジェクトフォルダに移動します。
$ cd ~/tmp/hello-express
シェル変数の作成
シェル変数として、Ubuntu に以下の値を作成します。状況により、コンテナ アプリの名前を変える必要があります。
resource_group_name=rg-hello
containerapp_env_name=cae-hello
containerapp_name=ca-hello-express
container_image_name=app-hello-express:latest
コンテナ アプリ
コンテナ アプリの作成とデプロイを行います。
$ az containerapp create \
--resource-group $resource_group_name \
--environment $containerapp_env_name \
--name $containerapp_name \
--image $USER/$container_image_name \
--target-port 3000 \
--ingress 'external' \
--min-replicas 1 \
--enable-dapr true \
--dapr-app-protocol http
Container Apps で構成する場合、フロントエンドアプリのコンテナでも Dapr サイドカーの設定が必須です。
コンテナ アプリを削除する場合は以下のコマンドを実行します。
$ az containerapp delete \
--resource-group $resource_group_name \
--name $containerapp_name
コンテナ動作の確認
コンテナ アプリの FQDN を Ubuntu のシェル変数 containerapp_fqdn に取得します。
$ containerapp_fqdn=$(az containerapp show \
--resource-group $resource_group_name \
--name $containerapp_name \
--query 'properties.configuration.ingress.fqdn' \
--output tsv)
コマンドから Web ブラウザを立ち上げます。
$ sudo apt update
$ sudo apt install wslu
$ wslview https://$containerapp_fqdn/
フロントエンドアプリからバックエンドサービスのデータを取得します。
ここまでの手順で、フロントエンドアプリ、バックエンドサービスのそれぞれの Dapr サイドカーを通して連携動作させることができました。
まとめ
- Dapr、Express、Spring Boot で構成する、シンプルなマイクロサービスを実装することが出来ました。
- この記事の例ではまだ Spring Boot 側のアプリに Dapr への依存関係はありません。
- 今後さらに Spring Boot から Dapr クライアントオブジェクトを操作する方法を学ぶ必要があります。
どうでしたか? WSL Ubuntu で Dapr を使用したマイクロサービス開発環境が手軽に構築できます。ぜひお試しください。今後も Ubuntu の開発環境などを紹介していきますので、ぜひお楽しみにしてください。