使用Dapr、Express和Spring Boot构建微服务:Azure篇

用Dapr、Express和Spring Boot构建微服务:Azure版本

dapr_on_azure-container-apps.png

为了的目标

加深对用于分散式应用的运行时 Dapr 的理解。

实现

我們將在Microsoft Azure容器應用程序環境中使用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.47Ubuntu ※您可以从相关文章中查看安装方法
$ lsb_release -a
没有可用的LSB模块。
分发商ID:Ubuntu
描述:Ubuntu 22.04.1 LTS
发布:22.04

npm ※您可以从相关文章中查看安装方法
$ node -v
v19.8.1

$ npm -v
9.5.1

Java JDK ※您可以从相关文章中查看安装方法
$ java -version
openjdk版本:“11.0.18” 2023-01-17
OpenJDK运行时环境(版本11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64位服务器VM(版本11.0.18+10-post-Ubuntu-0ubuntu122.04,共享模式)

Maven ※您可以从相关文章中查看安装方法
$ mvn -version
Apache Maven 3.6.3
Maven主页:/usr/share/maven
Java版本:11.0.18,供应商:Ubuntu,运行时:/usr/lib/jvm/java-11-openjdk-amd64

Docker ※您可以从相关文章中查看安装方法
$ docker –version
Docker版本23.0.1,构建a5ee5b1

Dapr ※您可以从相关文章中查看安装方法
$ dapr –version
CLI版本:1.11.0
运行时版本:1.11.2

Azure CLI ※您可以从相关文章中查看安装方法
$ az –version
azure-cli 2.45.0
core 2.45.0
遥测 1.0.8

※ 本文大致上将在Ubuntu终端中进行操作。

创建Web应用的规范

NoエンドポイントHTTPメソッドMIME タイプ1/api/dataGETapplication/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
通过这些步骤,可以将Spring Boot应用的容器镜像发布到Docker Hub。

实现前端应用程序

在 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

文件的内容 de

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

文件的内容 de

{
  "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

文件的内容 de

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
通过这些步骤,您可以将Express应用程序的容器镜像发布到Docker Hub。

将应用程序部署到Azure环境

创建Shell变量

在Ubuntu上创建以下值作为Shell变量。
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

容器化应用环境 huà

创建容器应用环境。
※ 基于Kubernetes基础设施,因此需要一些时间。

$ az containerapp env create \
    --resource-group $resource_group_name \
    --name $containerapp_env_name \
    --location $location_name
image.png
通过上述步骤,您可以在Azure上创建Container Apps环境。

部署后端服务

进入项目文件夹

我移动到项目文件夹。

$ cd ~/tmp/hello-spring-dapr

创建Shell变量

在Ubuntu上,我们将创建以下值作为shell变量。根据情况,可能需要更改容器应用的名称。
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
image.png

将容器连接

确认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!"}
在这个过程中,我们已经成功地将Dapr边车功能应用于Container Apps的后端服务进行了部署。

部署前端应用程序

前往项目文件夹。

我会转移到项目文件夹。

$ cd ~/tmp/hello-express

创建Shell变量

将以下值作为Ubuntu的shell变量创建。根据情况,可能需要更改容器应用的名称。
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的Sidecar。
如果要删除容器应用程序,请执行以下命令:
$ az containerapp delete \
–resource-group $resource_group_name \
–name $containerapp_name
image.png

确认容器操作

获取容器应用的FQDN并将其存储在Ubuntu的shell变量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/
image.png
通过上述步骤,我们可以通过前端应用程序和后端服务的各自Dapr Sidecar来实现协作操作。

概括

    • Dapr、Express、Spring Boot で構成する、シンプルなマイクロサービスを実装することが出来ました。

 

    • この記事の例ではまだ Spring Boot 側のアプリに Dapr への依存関係はありません。

 

    今後さらに Spring Boot から Dapr クライアントオブジェクトを操作する方法を学ぶ必要があります。

你觉得怎么样?在 WSL Ubuntu 上可以轻松搭建使用 Dapr 进行微服务开发的环境。请不要错过试用的机会。我们将继续介绍关于 Ubuntu 开发环境的内容,请敬请期待。

请参阅相关资料。

    Dapr SDK Java
广告
将在 10 秒后关闭
bannerAds