🧮

Dapr Tutorials - Distributed Calculator をやってみた

2023/12/01に公開

はじめに

Dapr入門です。ひたすらチュートリアルをやります。

今回はこちら
https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator

ローカルでは動かさずに minikube を使って実行します。

環境

WSL2 Ubuntu 22.04
minikube v1.32.0
helm v3.13.1

構成

今回も公式より

Go が 加算
C# が 減算
Python が 乗算
Node が 除算
を行う分散電卓だそうです。
Dapr はメソッド呼び出しと永続化のところを担当しているそうな。ふむふむ。

事前準備

準備ができていたらこの章はスキップで。

  • クラスターを作成します。
$ minikube start --cpus=4 --memory=4096 --vm-driver=docker
  • dapr を初期化します。
$ dapr init --kubernetes --wait
  • 適当なディレクトリに git のコードをcloneします。
git clone https://github.com/dapr/quickstarts.git

Running the quickstart in a Kubernetes environment

  1. deploy ディレクトリに移動します。
$ cd quickstarts/tutorials/distributed-calculator/deploy
  1. Redis をセットアップします。
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
$ helm install redis bitnami/redis --set image.tag=6.2
  1. すべてのリソースをデプロイします。
$ kubectl apply -f .
configuration.dapr.io/appconfig created
deployment.apps/subtractapp created
deployment.apps/addapp created
deployment.apps/divideapp created
deployment.apps/multiplyapp created
service/calculator-front-end created
deployment.apps/calculator-front-end created
component.dapr.io/statestore created
  1. デプロイが完了したか確認します。
$ kubectl rollout status deploy/addapp
deployment "addapp" successfully rolled out

$ kubectl rollout status deploy/subtractapp
deployment "subtractapp" successfully rolled out

$ kubectl rollout status deploy/divideapp
deployment "divideapp" successfully rolled out

$ kubectl rollout status deploy/multiplyapp
deployment "multiplyapp" successfully rolled out

$ kubectl rollout status deploy/calculator-front-end
deployment "calculator-front-end" successfully rolled out

ポッドのステータスを確認します。

$ kubectl get pods
NAME                                   READY   STATUS    RESTARTS   AGE
addapp-dcff99c45-h8x99                 2/2     Running   0          5m48s
calculator-front-end-8d968cff6-5g9jr   2/2     Running   0          5m48s
divideapp-54565fdfb7-6x27d             2/2     Running   0          5m48s
multiplyapp-cb9f469f4-djjwr            2/2     Running   0          5m48s
redis-master-0                         1/1     Running   0          8m7s
redis-replicas-0                       1/1     Running   0          8m7s
redis-replicas-1                       1/1     Running   0          7m25s
redis-replicas-2                       1/1     Running   0          7m3s
subtractapp-5b6d4cd9db-lrzsk           2/2     Running   0          5m48s
  1. アクセスできるようにポートフォワードします。
kubectl port-forward service/calculator-front-end 8000:80

電卓大きい笑

  1. ブラウザの開発者ツールを開き、電卓に入力を入れて、コンソールログを確認します。

ボタンをクリックするたびに表示されますが、それが状態の永続性を示すログだそうです。つまり、フロントエンドからDapr経由でRedisに入っていると。

完全な式(12×3 とか)を入力するたびに、サービスの呼び出しが行われるそうです。

  1. 終わったらクリーンアップします。
kubectl delete -f .

仕組み

サービスの呼び出し

フロントエンドコンテナにいるExpress.js がサービスの呼び出しを行っていますが、Daprを使うと、どのIPで相手が存在するかは意識しなくてもよくなります。

たとえば、Go の add アプリに対しては以下のように呼び出しています。
キーとしては、URLに含まれる addapp がアプリのIDですね。

react-js/server.js
const daprPort = process.env.DAPR_HTTP_PORT ?? 3500;

const daprUrl = `http://localhost:${daprPort}/v1.0/invoke`;

/**
The following routes forward requests (using pipe) from our React client to our dapr-enabled services. Our Dapr sidecar lives on localhost:<daprPort>. We invoke other Dapr enabled services by calling /v1.0/invoke/<DAPR_ID>/method/<SERVICE'S_ROUTE>.
*/

app.post('/calculate/add', async (req, res) => {
  try {
      // Invoke Dapr add app
      const appResponse = await axios.post(`${daprUrl}/addapp/method/add`, req.body);

      // Return expected string result to client
      return res.send(`${appResponse.data}`); 
  } catch (err) {
      console.log(err);
  }
});

そのアプリIDはマニュフェストのアノテーションで指定されています。
これをすることでDaprに登録されるので、Daprは判断ができる、ということですね。なるほど。
(アプリIDなのかDAPR_IDなのかどう呼べばいいのかわからんですが)

deploy/go-adder.yaml
  template:
    metadata:
      labels:
        app: add
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "addapp"
        dapr.io/app-port: "6000"
        dapr.io/config: "appconfig"

ちなみに、状態管理もstateのURLを叩くだけでできて簡単ですね。

const stateStoreName = `statestore`;
const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;

// Forward state persistence to Dapr state endpoint
app.post('/persist', async (req, res) => {
  try {
     // Saving Dapr state
    const apiResponse = await axios.post(stateUrl, req.body);
    return res.send(apiResponse.data);  
  } catch (err) {
    console.log(err);
  }
});

ちゃんとDaprに登録さえしてしまえば、あとはよしなにやってくれて、賢いわ😲

おわりに

チュートリアルというかだいたい解説を読んで、ソースコードを読んで理解するって感じですが、少しわかってきたかも。
それでは、また次のチュートリアルで。

Discussion