0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dapr と React と Spring Boot でマイクロサービスを構成する:Docker 編

Last updated at Posted at 2023-07-27

Dapr と React と Spring Boot でマイクロサービスを構成する:Docker 編

こんにちは、@studio_meowtoon です。今回は、WSL Ubuntu 22.04 で Dapr と React と Spring Boot を利用してマイクロサービスを構成する方法を紹介します。
dapr_on_Docker.png

目的

分散アプリケーションの為のランタイム Dapr の理解を深めます。

実現すること

Ubuntu の Docker 環境にて、Dapr、React、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

※ この記事では基本的に 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

CORS への対応のため、アプリケーションクラスを修正します。

$ vim src/main/java/com/example/springdapr/Application.java

ファイルの内容

Application.java
package com.example.springdapr;

import java.util.Map;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
@RequestMapping("/api")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @CrossOrigin
    @GetMapping("/data")
    public Map<String, String> getData() {
        Map<String, String> map = Map.of("message", "Hello World!");
        return map;
    }
}

Java アプリをビルドします。

$ mvn clean package

ここまでの手順で、target/app.jar Java アプリが作成されました。

コンテナイメージをビルド

Dockerfile を作成します。

$ vim Dockerfile

ファイルの内容

Dockerfile
FROM adoptopenjdk/openjdk11:jdk-11.0.11_9-alpine-slim

WORKDIR /app

COPY target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java","-jar","app.jar"]

コンテナイメージをビルドします。

$ docker build -t app-hello-spring-boot .

確認します。

$ docker images | grep app-hello-spring-boot
app-hello-spring-boot   latest    2ee39bcf1346   11 seconds ago   278MB

コンテナを起動する

バックエンドサービスのコンテナを実行します。

$ docker run --rm --name app-backend \
    -p 8080:8080 app-hello-spring-boot

別ターミナルからリクエストします。

$ curl http://localhost:8080/api/data -w '\n'

出力

{"message":"Hello World!"}

ここまでの手順で、バックエンドのサービスを作成することができました。

フロントエンドアプリを実装

こちらの以前の記事をご参照いただけます。

プロジェクトフォルダの作成

プロジェクトフォルダを作成します。
※ ~/tmp/hello-react をプロジェクトフォルダとします。

$ mkdir -p ~/tmp/hello-react
$ cd ~/tmp/hello-react

JS ファイルの作成

index.js JS ファイルを作成します。

$ mkdir -p src
$ vim src/index.js

ファイルの内容

src/index.js
import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const App = () => {
    const [data, setData] = useState(null);
    // ボタンがクリックされたときにデータを取得する関数
    const fetchData = () => {
        fetch('http://localhost:8080/api/data')
            .then(response => response.json())
            .then(data => {
                setData(data); // レスポンスのデータを state にセット
            })
            .catch(error => {
                console.error('Error fetching data:', error);
            });
    };

    return (
        <div>
            {data ? (
                <h1>{data.message}</h1>
            ) : (
                <div>
                    <h2>Loading...</h2>
                    <button onClick={fetchData}>データを取得</button>
                </div>
            )}
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("app"));

HTML ファイルの作成

index.html ファイルを作成します。

$ vim src/index.html

ファイルの内容

src/index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>React</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

webpack 設定の作成

webpack.config.js ファイルを作成します。

$ vim webpack.config.js

ファイルの内容

webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
    })
  ]
};

プロジェクトの初期化

プロジェクトの初期化を行います。

$ npm init -y

package.json を修正します。

$ vim package.json

ファイルの内容

package.json
{
  "name": "hello-react",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

ライブラリをインストールします。

$ npm install \
    react react-dom \
    babel-loader @babel/core @babel/preset-env @babel/preset-react \
    webpack webpack-cli html-webpack-plugin \
    --save-dev

コンテナイメージをビルド

Dockerfile を作成します。

$ vim Dockerfile

ファイルの内容

Dockerfile
FROM node:lts-alpine as build-env

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build

FROM nginx:alpine

COPY --from=build-env /app/build /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

コンテナイメージをビルドします。

$ docker build -t app-hello-react .

確認します。

$ docker images | grep app-hello-react
app-hello-react         latest    e98d06760672   8 seconds ago    42.6MB

コンテナを起動する

フロントエンドアプリのコンテナを実行します。

$ docker run --rm --name app-frontend \
    -p 80:80 app-hello-react

WEBアプリにアクセスします。

http://localhost

フロントエンドアプリからバックエンドサービスのデータを取得します。
image.png
image.png

ここまでの手順で、バックエンドサービス、フロントエンドアプリの各コンテナを直接連携させて動作させることができました。

Dapr を通してコンテナを連携動作させる

フロントエンドアプリの修正

$ mkdir -p src
$ vim src/index.js

ファイルの内容※一部分

src/index.js
// ボタンがクリックされたときにデータを取得する関数
const fetchData = () => {
    fetch('http://localhost:3500/v1.0/invoke/app-hello-spring/method/api/data')
        .then(response => response.json())
        .then(data => {
            setData(data); // レスポンスのデータを state にセット
        })
        .catch(error => {
            console.error('Error fetching data:', error);
        });
};

コンテナイメージを再ビルドします。

$ docker build -t app-hello-react .

docker-compose.yml の作成

docker-compose.yml ファイルを作成します。

$ vim docker-compose.yml

ファイルの内容

version: '3'
services:
  ############################
  # React app
  app-react:
    image: app-hello-react
    depends_on:
      - redis
      - placement
    ports:
      - "80:80"
    networks:
      - net-hello
  ############################
  # Spring Boot app + Dapr sidecar
  app-spring:
    image: app-hello-spring-boot
    depends_on:
      - redis
      - placement
    ports:
      - "3500:3500"
    networks:
      - net-hello
  app-spring-dapr:
    image: daprio/daprd:edge
    command: [
      "./daprd",
      "--app-id", "app-hello-spring",
      "--app-port", "8080",
      "--dapr-http-port", "3500",
      "--dapr-grpc-port", "50051",
      "--placement-host-address", "placement:50006",
      "--components-path", "/components"
    ]
    volumes:
      - "./components/:/components"
    depends_on:
      - app-spring
    network_mode: "service:app-spring"
  ############################
  # Dapr placement service
  placement:
    image: daprio/dapr
    command: ["./placement", "-port", "50006"]
    ports:
      - "50006:50006"
    networks:
      - net-hello
  ############################
  # Redis state store
  redis:
    image: redis:alpine
    ports:
      - "6380:6379"
    networks:
      - net-hello
networks:
    net-hello:

Dapr を React、Spring Boot アプリのサイドカーとして設定しており、Spring Boot アプリのコンテナは 3500 番ポートでリッスンしています。

Docker 環境で起動する

コンテナを起動します。

$ docker-compose up -d
Creating hello-react_placement_1 ... done
Creating hello-react_redis_1     ... done
Creating hello-react_app-react_1  ... done
Creating hello-react_app-spring_1 ... done
Creating hello-react_app-spring-dapr_1 ... done

コンテナを確認します。

$ docker ps | grep hello
2ed6b9cdb78d   daprio/daprd:edge       "./daprd --app-id ap…"   47 seconds ago   Up 47 seconds                                                         hell -react_app-spring-dapr_1
c9b60a6a1fe8   app-hello-react         "/docker-entrypoint.…"   48 seconds ago   Up 47 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp                     hell -react_app-react_1
7c2c941d6bf5   app-hello-spring-boot   "java -jar app.jar"       48 seconds ago   Up 47 seconds   0.0.0.0:3500->3500/tcp, :::3500->3500/tcp, 8080/tcp   hello-react_app-spring_1
d4a8f2c769ad   redis:alpine            "docker-entrypoint.s…"   49 seconds ago   Up 47 seconds   0.0.0.0:6380->6379/tcp, :::6380->6379/tcp             hell -react_redis_1
216a0d2c9efe   daprio/dapr             "./placement -port 5…"   49 seconds ago   Up 47 seconds   0.0.0.0:50006->50006/tcp, :::50006->50006/tcp         hell -react_placement_1

フロントエンドアプリからバックエンドサービスのデータを取得します。
image.png
image.png

ここまでの手順で、フロントエンドアプリからバックエンドサービスの Dapr サイドカーを通して連携動作させることができました。

まとめ

  • Dapr、React、Spring Boot で構成する、シンプルなマイクロサービスを実装することが出来ました。
  • この記事の例ではまだ Spring Boot 側のアプリに Dapr への依存関係はありません。
  • 今後さらに Spring Boot から Dapr クライアントオブジェクトを操作する方法を学ぶ必要があります。

どうでしたか? WSL Ubuntu で Dapr を使用したマイクロサービス開発環境が手軽に構築できます。ぜひお試しください。今後も Ubuntu の開発環境などを紹介していきますので、ぜひお楽しみにしてください。

推奨コンテンツ

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?