天天看點

雲原生-dapr 入門(一)hello world實踐

Dapr是一套開源可移植事件驅動型運作時,能夠幫助開發人員輕松建構起能夠運作在雲端及邊緣位置的高彈性、微服務、無狀态/有狀态應用程式。Dapr當中包含多種程式設計語言與開發者架構,同時顯著簡化了應用程式(例如示例中提到的電子商務應用)的建構流程。

為什麼要使用Dapr:

解決了以下問題:

Distributed App Challenges

  1. Hard to incrementally migrate from existing code to a microservices architecture.(難以從已有的代碼逐漸遷移到微服務架構)
  2. Many programming model runtimes have narrow language support and tightly controlled feature sets.(很多運作時模型支援的較少的開發語言及對功能特性有較多的強制限制)
  3. Event-driven architectures and state handling are complicated making them difficult to scale.(事件驅動架構的狀态處理導緻他們很難水準擴充)
  4. Many runtimes only target specific infrastructure platforms with limited code portability across clouds and edge.(很多運作時指定內建架的構平台,限制了代碼在雲及邊緣計算的可移植性。)

使用Dapr :

Streamlined Microservices(效率更高的微服務)

  1. Dapr enables developers using any language or framework to easily write microservices, providing industry best practices to solve distributed systems problems.(dapr 允許開發者使用任何語言與架構與開發微服務,提供工業級最好的實踐去解決分布式系統的問題)
  2. Dapr provides consistency and portability through open APIs and extensible components that are community-driven.(dapr 通過開放的API與社群提供的擴充元件提供一緻性與擴充性)
  3. Dapr handles state, resource bindings and pub/sub messaging, which enable event-driven, resilient architectures that scale.(dapr 可以處理有狀态,資源綁定,訂閱/發送 消息,進而支援可伸縮的事件驅動,彈性架構)
  4. Dapr is platform agnostic and runs on any infrastructure, including public clouds and edge devices with its open APIs.(Dapr與平台無關,可以在任何基礎設施上運作,包括公共雲和具有開放api的邊緣裝置)

實踐一下,從Hello World 開始

  • 環境準備
  • hello world 

環境準備

參考官方:https://github.com/dapr/docs/blob/master/getting-started/environment-setup.md

這裡采用helm 安裝。

>helm repo add dapr https://dapr.github.io/helm-charts/
"dapr" has been added to your repositories

>helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "dapr" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈


>helm install dapr dapr/dapr --namespace dapr-system

NAME: dapr
LAST DEPLOYED: Mon Oct  5 09:00:38 2020
NAMESPACE: dapr-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Thank you for installing Dapr: High-performance, lightweight serverless runtime for cloud and edge

Your release is named dapr.

To get started with Dapr, we recommend using our quickstarts:
https://github.com/dapr/quickstarts

For more information on running Dapr, visit:
https://dapr.io
           

hello world 實踐

官方文檔在這裡: https://github.com/dapr/quickstarts/tree/master/hello-world

  1. 下載下傳代碼
    >git clone -b release-0.11 https://github.com/dapr/quickstarts.git
    正克隆到 'quickstarts'...
    remote: Enumerating objects: 19, done.
    remote: Counting objects: 100% (19/19), done.
    remote: Compressing objects: 100% (19/19), done.
    remote: Total 1963 (delta 5), reused 1 (delta 0), pack-reused 1944
    接收對象中: 100% (1963/1963), 9.61 MiB | 27.00 KiB/s, 完成.
    處理 delta 中: 100% (1147/1147), 完成.
               

    2. 分析下nodejs服務方代碼

  •          nodejs 暴露3000端口,dapr暴露端口為3500.
  •          nodejs 服務暴露3個endpoint:

          /order  擷取order的endpoint

         /neworder 建立order的endpoint

        /order/:id 删除order的endpoint        

       這三個endpoint通過dapr state管理持久化到statestore.

// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------

const express = require('express');
const bodyParser = require('body-parser');
require('isomorphic-fetch');

const app = express();
app.use(bodyParser.json());

const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateStoreName = `statestore`;
const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;
const port = 3000;

app.get('/order', (_req, res) => {
    fetch(`${stateUrl}/order`)
        .then((response) => {
            if (!response.ok) {
                throw "Could not get state.";
            }

            return response.text();
        }).then((orders) => {
            res.send(orders);
        }).catch((error) => {
            console.log(error);
            res.status(500).send({message: error});
        });
});

app.post('/neworder', (req, res) => {
    const data = req.body.data;
    const orderId = data.orderId;
    console.log("Got a new order! Order ID: " + orderId);

    const state = [{
        key: "order",
        value: data
    }];

    fetch(stateUrl, {
        method: "POST",
        body: JSON.stringify(state),
        headers: {
            "Content-Type": "application/json"
        }
    }).then((response) => {
        if (!response.ok) {
            throw "Failed to persist state.";
        }

        console.log("Successfully persisted state.");
        res.status(200).send();
    }).catch((error) => {
        console.log(error);
        res.status(500).send({message: error});
    });
});

app.delete('/order/:id', (req, res) => {  
    const key = req.params.id;      
    console.log('Invoke Delete for ID ' + key);         

    const deleteUrl = stateUrl + '/' + key;

    fetch(deleteUrl, {
        method: "DELETE",        
        headers: {
            "Content-Type": "application/json"
        }
    }).then((response) => {
        if (!response.ok) {
            throw "Failed to delete state.";
        }

        console.log("Successfully deleted state.");
        res.status(200).send();
    }).catch((error) => {
        console.log(error);
        res.status(500).send({message: error});
    });    
});

app.listen(port, () => console.log(`Node App listening on port ${port}!`));
           

3. 啟動服務

>dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 node app.js
ℹ️  Starting Dapr with id nodeapp. HTTP Port: 3500. gRPC Port: 59682
           

dapr  啟動app-id為nodeapp 的服務。

4. 調用驗證

  • 通過dapr調用
雲原生-dapr 入門(一)hello world實踐
  • 通過post調用
雲原生-dapr 入門(一)hello world實踐
  • 通過python應用來調用

python 作為用戶端服務調用程式如下:

# ------------------------------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------------------------------

import os
import requests
import time

dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
dapr_url = "http://localhost:{}/v1.0/invoke/nodeapp/method/neworder".format(dapr_port)

n = 0
while True:
    n += 1
    message = {"data": {"orderId": n}}

    try:
        response = requests.post(dapr_url, json=message, timeout=5)
        if not response.ok:
            print("HTTP %d => %s" % (response.status_code,
                                     response.content.decode("utf-8")), flush=True)
        else:
            print("%s call %s success!"%(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),dapr_url))
    except Exception as e:
        print(e, flush=True)

    time.sleep(1)
           

程式很簡單,每隔1秒調用下服務端的/neworder  接口,列印調用結果

使用Dapr   啟動python 服務,如下:

⚙  /opt/tech/git/dapr/quickstarts/hello-world   release-0.11 ●  dapr run --app-id pythonapp python3.8 app.py

ℹ️  Starting Dapr with id pythonapp. HTTP Port: 50499. gRPC Port: 50500
ℹ️  Checking if Dapr sidecar is listening on HTTP port 50499
== DAPR == time="2020-10-08T11:00:18.265869+08:00" level=info msg="starting Dapr Runtime -- version 0.11.0 -- commit 71f9fb5" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.265925+08:00" level=info msg="log level set to: info" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.266216+08:00" level=info msg="metrics server started on :50501/" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.metrics type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.267382+08:00" level=info msg="standalone mode configured" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.267412+08:00" level=info msg="app id: pythonapp" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.267437+08:00" level=info msg="mTLS is disabled. Skipping certificate request and tls validation" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.268035+08:00" level=info msg="local service entry announced: pythonapp -> 192.168.0.155:50505" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.contrib type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.268127+08:00" level=info msg="Initialized name resolution to standalone" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.283064+08:00" level=info msg="component loaded. name: pubsub, type: pubsub.redis" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.320585+08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.320708+08:00" level=info msg="waiting for all outstanding components to be processed" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.320868+08:00" level=info msg="component loaded. name: zipkin, type: exporters.zipkin" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.320897+08:00" level=info msg="all outstanding components processed" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321177+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321369+08:00" level=info msg="enabled gRPC tracing middleware" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.grpc.api type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321362+08:00" level=info msg="starting connection attempt to placement service: localhost:50005" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321432+08:00" level=info msg="API gRPC server is running on port 50500" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.3215+08:00" level=info msg="enabled gRPC tracing middleware" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.grpc.internal type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321529+08:00" level=info msg="internal gRPC server is running on port 50505" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321771+08:00" level=info msg="enabled cors http middleware" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.http type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321791+08:00" level=info msg="enabled tracing http middleware" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.http type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321831+08:00" level=info msg="http server is running on port 50499" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.321858+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 54.486ms" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.327063+08:00" level=info msg="established connection to placement service at localhost:50005" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.331767+08:00" level=info msg="placement order received: lock" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.33185+08:00" level=info msg="placement order received: update" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.331871+08:00" level=info msg="placement tables updated, version: 0" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

== DAPR == time="2020-10-08T11:00:18.331901+08:00" level=info msg="placement order received: unlock" app_id=pythonapp instance=MacBook-Pro.local scope=dapr.runtime.actor type=log ver=0.11.0

ℹ️  Checking if Dapr sidecar is listening on GRPC port 50500
ℹ️  Dapr sidecar is up and running.
ℹ️  Updating metadata for app command: python3.8 app.py
✅  You're up and running! Both Dapr and your app logs will appear here.
           

此時服務端日志情況:(省略部分)

...
== APP == Got a new order! Order ID: 96

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 97

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 98

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 99

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 100

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 101

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 102

== APP == Successfully persisted state.

== APP == Got a new order! Order ID: 103
           

可以看到成功發起的調用,已經成功的儲存了狀态。

問題:

細心的會在想,為什麼暴露的服務是/v1.0/invoke/nodeapp/method/neworder ?

下篇分析。

繼續閱讀