NodeJS 基於 Dapr 構建雲原生微服務應用快速入門教程

Dapr 是一個可移植的、事件驅動的運行時,它使任何開發人員能夠輕松構建出彈性的、無狀態和有狀態的應用程序,並可運行在雲平臺或邊緣計算中,它同時也支持多種編程語言和開發框架。Dapr 確保開發人員專註於編寫業務邏輯,不必分神解決分佈式系統難題,從而顯著提高瞭生產力。Dapr 降低瞭構建微服務架構類現代雲原生應用的門檻。

安裝 Dapr CLI

MacOS & Dapr 1.8:

sudo curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash

Linux/Windows 安裝方式:

https://docs.dapr.io/getting-started/install-dapr-cli/

本地環境中初始化 Dapr

Dapr 初始化包括:

  • 運行一個用於狀態存儲和消息代理的 Redis 容器實例
  • 運行一個用於提供可觀察性的 Zipkin 容器實例
  • 創建具有上述組件定義的默認組件文件夾
  • 運行用於本地 actor(我們的服務) 支持的 Dapr placement 服務容器實例

運行初始化 CLI 命令

dapr init

驗證 Dapr 版本

dapr -v
CLI version: 1.8.0
Runtime version: 1.8.0

驗證容器是否正在運行

如前所述,dapr init 命令會啟動幾個容器,這些容器將幫助您開始使用 Dapr。 驗證您有運行 daprio/dapropenzipkin/zipkinredis 映像的容器實例:

驗證組件目錄是否已初始化

dapr init 上,CLI 還會創建一個默認組件文件夾,其中包含幾個 YAML 文件,其中包含狀態存儲、Pub/subZipkin 的定義。Dapr sidecar 將讀取這些組件並使用:

  • 用於狀態管理和消息傳遞的 Redis 容器。
  • 用於收集蹤跡的 Zipkin 容器。

通過打開您的組件目錄進行驗證:

  • Windows, 在 %UserProfile%\.dapr
  • Linux/MacOS, 在 ~/.dapr
ls $HOME/.dapr
bin components config.yaml

使用 Dapr API

運行 Dapr sidecar 並試用 state API

運行 Dapr sidecar

dapr run 命令啟動一個應用程序,以及一個 sidecar。

啟動一個 Dapr sidecar,它將在端口 3500 上偵聽名為 myapp 的空白應用程序:

dapr run --app-id myapp --dapr-http-port 3500

由於沒有使用上述命令定義自定義組件文件夾,因此 Dapr 使用在 dapr init 流程期間創建的默認組件定義。

保存狀態

使用對象更新狀態。新狀態將如下所示:

[
  {
    "key": "name",
    "value": "Bruce Wayne"
  }
]

請註意,包含在狀態中的每個對象都有一個分配有值為 namekey。您將在下一步中使用該 key

使用以下命令保存新的狀態對象:

curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne"}]' http://localhost:3500/v1.0/state/statestore

獲取狀態

使用帶有 key 為 name 的狀態檢索您剛剛存儲在 state 中的對象。在同一終端窗口中,運行以下命令:

curl http://localhost:3500/v1.0/state/statestore/name

查看狀態如何存儲在 Redis 中

docker exec -it dapr_redis redis-cli

列出 Redis 鍵以查看 Dapr 如何使用您提供給 dapr run 的 app-id 作為 key 的前綴創建鍵值對:

keys *
"myapp||name"

運行以下命令查看狀態值:

hgetall "myapp||name"

1) "data"
2) "\"Bruce Wayne\""
3) "version"
4) "1"

使用以下命令退出 Redis CLI:

exit

刪除狀態

在同一終端窗口中,從狀態存儲中刪除 name 狀態對象。

curl -v -X DELETE -H "Content-Type: application/json" http://localhost:3500/v1.0/state/statestore/name

上手實戰指南

所有官方示例筆者均在 MacOS/NodeJs v16.16.0 下實戰完成。

1. 服務調用

使用 Dapr 的服務調用構建塊,您的應用程序可以與其他應用程序可靠且安全地通信。

示例倉庫

git clone https://github.com/dapr/quickstarts.git

運行 order-processor 服務

從 quickstarts 的根目錄導航到 order-processor 目錄。

cd service_invocation/javascript/http/order-processor

安裝依賴項:

npm install

與 Dapr sidecar 一起運行 order-processor 服務。

dapr run --app-port 5001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- npm start
app.post('/orders', (req, res) => {
    console.log("Order received:", req.body);
    res.sendStatus(200);
});

運行 checkout 服務

在新的終端窗口中,從 quickstarts 根目錄導航到 checkout 目錄。

cd service_invocation/javascript/http/checkout

安裝依賴項:

npm install

與 Dapr sidecar 一起運行 checkout 服務。

dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start

checkout 服務中,您會註意到無需重寫您的應用程序代碼即可使用 Dapr 的服務調用。您可以通過簡單地添加 dapr-app-id header 來啟用服務調用,該 header 指定目標服務的 ID。

let axiosConfig = {
  headers: {
      "dapr-app-id": "order-processor"
  }
};
const res = await axios.post(`${DAPR_HOST}:${DAPR_HTTP_PORT}/orders`, order , axiosConfig);
console.log("Order passed: " + res.config.data);

查看服務調用輸出

Dapr 在任何 Dapr 實例上調用應用程序。在代碼中,sidecar 編程模型鼓勵每個應用程序與其自己的 Dapr 實例通信。Dapr 實例隨後發現並相互通信。

checkout & order-processor 服務輸出:

2. 狀態管理

讓我們看一下 Dapr 的狀態管理構建塊。您將使用 Redis 進行狀態存儲,來保存、獲取和刪除你的狀態,您也可以將其換成任何一種受 Dapr 支持的狀態存儲。

操縱服務狀態

在終端窗口中,導航到 order-processor 目錄。

cd state_management/javascript/sdk/order-processor

安裝依賴項,其中將包括 JavaScript SDK 中的 dapr-client 包:

npm install

驗證您在服務目錄中包含以下文件:

  • package.json
  • package-lock.json

與 Dapr sidecar 一起運行 order-processor 服務。

dapr run --app-id order-processor --components-path ../../../components/ -- npm run start

order-processor 服務將 orderId key/value 寫入、讀取和刪除到 statestore.yaml 組件中定義的 statestore 實例。一旦服務啟動,它就會執行一個循環。

  const client = new DaprClient(DAPR_HOST, DAPR_HTTP_PORT);

  // 將 state 保存到 state store 中
  client.state.save(STATE_STORE_NAME, [
      {
          key: orderId.toString(),
          value: order
      }
  ]);
  console.log("Saving Order: ", order);

  // 從 state store 中獲取 state
  var result = client.state.get(STATE_STORE_NAME, orderId.toString());
  result.then(function(val) {
      console.log("Getting Order: ", val);
  });

  // 從 state store 中刪除 state
  client.state.delete(STATE_STORE_NAME, orderId.toString());    
  result.then(function(val) {
      console.log("Deleting Order: ", val);
  });

查看 order-processor 輸出

請註意,正如上面代碼中所指定的,代碼將應用程序狀態保存在 Dapr 狀態存儲中,讀取它,然後將其刪除

Order-processor 輸出:

statestore.yaml 組件文件

當你運行 dapr init 時,Dapr 會創建一個默認的 Redis statestore.yaml 並在你的本地機器上運行一個 Redis 容器,它位於:

  • Windows,%UserProfile%\.dapr\components\statestore.yaml
  • Linux/MacOS ,~/.dapr/components/statestore.yaml

使用 statestore.yaml 組件,您可以輕松切換狀態存儲,而無需更改代碼。

本快速入門包含的 Redis statestore.yaml 文件包含以下內容:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""
  - name: actorStateStore
    value: "true"

在 YAML 文件中:

  • metadata/name 是您的應用程序與組件對話的方式(在代碼示例中稱為 DAPR_STORE_NAME)。
  • spec/metadata 定義到組件使用的 Redis 實例的連接。

3. 發佈和訂閱

開始使用 Dapr 的發佈和訂閱構建塊

讓我們看一下 Dapr 的發佈和訂閱 (Pub/sub) 構建塊。您將運行發佈者微服務和訂閱者微服務,以演示 Dapr 如何啟用發佈/訂閱模式。

  • 使用發佈服務,開發人員可以重復發佈消息到 topic。
  • Pub/sub 組件對這些消息進行排隊或代理。我們下面的示例使用 Redis,您可以使用 RabbitMQ、Kafka 等。
  • 該 topic 的訂閱者從隊列中提取消息並處理它們。

訂閱 topic

在終端窗口中,從 quickstarts 根目錄導航到 order-processor 目錄。

cd pub_sub/javascript/sdk/order-processor

安裝依賴項,其中將包括 JavaScript SDK 中的 dapr-client 包:

npm install

驗證您在服務目錄中包含以下文件:

  • package.json
  • package-lock.json

與 Dapr sidecar 一起運行 order-processor subscriber 服務。

dapr run --app-port 5001 --app-id order-processing --app-protocol http --dapr-http-port 3501 --components-path ../../../components -- npm run start

在 order-processor 訂閱者中,我們訂閱名為 order_pub_sub 的 Redis 實例(如 pubsub.yaml 組件中所定義)和 topic orders。這使您的應用程序代碼能夠通過 Dapr sidecar 與 Redis 組件實例通信。

server.pubsub.subscribe("order_pub_sub", "orders", (data) => console.log("Subscriber received: " + JSON.stringify(data)));

發佈 topic

在新的終端窗口中,從 Quickstarts 克隆目錄的根目錄導航到 checkout 目錄。

cd pub_sub/javascript/sdk/checkout

安裝依賴項,其中將包括 JavaScript SDK 中的 dapr-client 包:

npm install

驗證您在服務目錄中包含以下文件:

  • package.json
  • package-lock.json

與 Dapr sidecar 一起運行 checkout 發佈者服務。

dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 --components-path ../../../components -- npm run start

checkout 發佈者服務中,我們將 orderId 消息發佈到名為 order_pub_sub 的 Redis 實例(在 pubsub.yaml 組件中定義)和 topic orders。服務一啟動,就會循環發佈:

const client = new DaprClient(DAPR_HOST, DAPR_HTTP_PORT);
await client.pubsub.publish(PUBSUB_NAME, PUBSUB_TOPIC, order);
   console.log("Published data: " + JSON.stringify(order));

查看發佈/訂閱輸出

請註意,正如上面代碼中所指定的,發佈者將一個隨機數推送到 Dapr sidecar,而訂閱者接收它。

發佈者 & 訂閱者輸出:

pubsub.yaml 組件文件

當你運行 dapr init 時,Dapr 會創建一個默認的 Redis pubsub.yaml 並在你的本地機器上運行一個 Redis 容器,它位於:

在 Windows 上,在 %UserProfile%\.dapr\components\pubsub.yaml 下在 Linux/MacOS 上,在 ~/.dapr/components/pubsub.yaml

使用 pubsub.yaml 組件,您可以輕松更換底層組件,而無需更改應用程序代碼。

本快速入門包含的 Redis pubsub.yaml 文件包含以下內容:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: order_pub_sub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""

在 YAML 文件中:

  • metadata/name 是您的應用程序與組件對話的方式。
  • spec/metadata 定義與組件實例的連接。
  • scopes 指定哪個應用程序可以使用該組件。

4. 輸入和輸出綁定

開始使用 Dapr 的 Binding 構建塊

讓我們看一下 Dapr 的 Bindings 構建塊。使用綁定,您可以:

  • 使用來自外部系統的事件觸發您的應用程序。
  • 與外部系統的接口。

接下來您將使用輸入 Cron binding 安排批處理腳本每 10 秒運行一次。該腳本使用 PostgreSQL Dapr binding 處理 JSON 文件並將數據輸出到 SQL 數據庫。

在本地運行 PostgreSQL Docker 容器

在您機器上的 Docker 容器中本地運行 PostgreSQL 實例。示例包含一個 Docker Compose 文件,用於在本地自定義、構建、運行和初始化帶有默認 orders 表的 postgres 容器。

在終端窗口中,從 quickstarts 根目錄導航到 bindings/db 目錄。

cd bindings/db

運行以下命令來設置容器:

docker compose up

安排一個 Cron job 並寫入數據庫

在新的終端窗口中,導航到 SDK 目錄。

cd bindings/javascript/sdk/batch

安裝依賴項:

npm install

與 Dapr sidecar 一起運行 batch-sdk 服務。

dapr run --app-id batch-sdk --app-port 5002 --dapr-http-port 3500 --components-path ../../../components -- node index.js 

process_batch 函數內的代碼每 10 秒執行一次(在 components 目錄的 binding-cron.yaml 中定義)。綁定觸發器在 Dapr sidecar 的 Flask 應用程序中查找通過 HTTP POST 調用的路由。

async function start() {
    await server.binding.receive(cronBindingName,processBatch);
    await server.start();
}

batch-sdk 服務使用 binding-postgres.yaml 組件中定義的 PostgreSQL 輸出綁定將 OrderId、Customer 和 Price 記錄插入到 orders 表中。

async function processBatch(){
    const loc = '../../orders.json';
    fs.readFile(loc, 'utf8', (err, data) => {
        const orders = JSON.parse(data).orders;
        orders.forEach(order => {
            let sqlCmd = `insert into orders (orderid, customer, price) values (${order.orderid}, '${order.customer}', ${order.price});`;
            let payload = `{  "sql": "${sqlCmd}" } `;
            console.log(payload);
            client.binding.send(postgresBindingName, "exec", "", JSON.parse(payload));
        });
        console.log('Finished processing batch');
      });
    return 0;
}

查看 job 的輸出

請註意,如上所述,代碼使用 OrderId、Customer 和 Price 作為 payload 調用輸出綁定。

你的輸出綁定的 print 語句輸出:

在新終端中,驗證是否已將相同的數據插入到數據庫中。

cd bindings/db

啟動交互式 Postgres CLI:

docker exec -i -t postgres psql --username postgres  -p 5432 -h localhost --no-password

admin=# 提示符下,更改為 orders 表:

\c orders;

orders=# 提示符下,選擇所有行:

select * from orders;

輸出應如下所示:

components\binding-cron.yaml 組件文件

當您執行 dapr run 命令並指定組件路徑時,Dapr sidecar:

  • 啟動 Cron 綁定構建塊
  • 每 10 秒調用一次綁定端點(批處理)

binding-cron.yaml 文件包含以下內容:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: cron
  namespace: quickstarts
spec:
  type: bindings.cron
  version: v1
  metadata:
  - name: schedule
    value: "@every 10s"

註意:binding-cron.yaml 的元數據部分包含一個 Cron 表達式,用於指定調用綁定的頻率。

component\binding-postgres.yaml 組件文件

當您執行 dapr run 命令並指定組件路徑時,Dapr sidecar:

  • 啟動 PostgreSQL 綁定構建塊
  • 使用 binding-postgres.yaml 文件中指定的設置連接到 PostgreSQL

使用 binding-postgres.yaml 組件,您可以輕松換出後端數據庫綁定,而無需更改代碼。

本快速入門包含的 PostgreSQL binding-postgres.yaml 文件包含以下內容:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: sqldb
  namespace: quickstarts
spec:
  type: bindings.postgres
  version: v1
  metadata:
  - name: url
    value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10"

在 YAML 文件中:

  • spec/type 指定 PostgreSQL 用於此綁定。
  • spec/metadata 定義到組件使用的 PostgreSQL 實例的連接。

5. Secrets 管理

開始使用 Dapr 的 Secrets Management 構建塊

Dapr 提供瞭一個專用的 secrets API,允許開發人員從 secrets store 中檢索 secrets。接下來:

  • 運行帶有 secret 存儲組件的微服務。
  • 在應用程序代碼中使用 Dapr secrets API 檢索 secrets。

檢索 secrets

在終端窗口中,導航到 order-processor 目錄。

cd secrets_management/javascript/sdk/order-processor

安裝依賴項:

npm install

與 Dapr sidecar 一起運行 order-processor 服務。

dapr run --app-id order-processor --components-path ../../../components/ -- npm start

在幕後

order-processor 服務

請註意下面的 order-processor 服務如何指向:

  • 在 local-secret-store.yaml 組件中定義的 DAPR_SECRET_STORE。
  • 在 secrets.json 中定義的 secret。
// index.js
const DAPR_SECRET_STORE = "localsecretstore";
const SECRET_NAME = "secret";

async function main() {
    // ...
    const secret = await client.secret.get(DAPR_SECRET_STORE, SECRET_NAME);
    console.log("Fetched Secret: " + JSON.stringify(secret));
}

local-secret-store.yaml 組件

DAPR_SECRET_STORE 定義在 local-secret-store.yaml 組件文件中,位於 secrets_management/components 中:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: localsecretstore
  namespace: default
spec:
  type: secretstores.local.file
  version: v1
  metadata:
  - name: secretsFile
    value: secrets.json
  - name: nestedSeparator
    value: ":"

在 YAML 文件中:

  • metadata/name 是您的應用程序引用組件的方式(在代碼示例中稱為 DAPR_SECRET_STORE)。
  • spec/metadata 定義與組件使用的 secret 的連接。

secrets.json 文件

SECRET_NAME 在位於 secrets_management/javascript/sdk/order-processorsecrets.json 文件中定義:

{ "secret": "YourPasskeyHere"}

查看 order-processor 輸出

正如上面的應用程序代碼中所指定的,order-processor 服務通過 Dapr secret 存儲檢索 secret 並將其顯示在控制臺中。

6. 官方示例

倉庫(源碼) https://github.com/dapr/quickstarts.git

到此這篇關於NodeJS 基於 Dapr 構建雲原生微服務應用,從 0 到 1 快速上手指南的文章就介紹到這瞭,更多相關NodeJS雲原生微服務應用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: