Experience Dapr - Run on K8s
上一篇 整理了體驗 Dapr 在本機模式的 Hello World,Dapr 在官方文件稱為 Self-Hosted,這篇要體驗則是 Run on K8s。
Preparation
K8s
在開始之前,請先確認以下:
- K8s Cluster
- 有足夠的權限對 K8s Cluster 操作。
- 如果沒有 K8s 環境可以做 Lab,可以使用輕量化 K8s,像是 minikube、K3s、K0s、K8s on Docker。
- 或者跟我一樣 自裝 K8s Cluster。
- K8s Controller / Client / GUI
確認:在開始之前,先確認你的 k8s config 是否有正確的 context 可以使用,可以透過 kubectl config current-context
知道現在狀況。
底下的筆記,我在 自裝 K8s Cluster 以及 K3s 上都跑過。
Setup: Dapr Control Plane
Dapr v1.0 預設所有的 cli 只要加 -k
參數,就會直接把同樣的動作,透過 K8s 權限直接 apply,所以跟上一篇的步驟都一樣。
1 | ## 直接初始化 |
順利完成後,可以發現多了一個叫做 dapr-system
的 namespace,查看狀況如下:
1 | ~$ k get po,deploy,svc -n dapr-system |
與 上一篇 的本機比較起來,有著明顯的差異,在 k8s 上有以下的 pod 以及大致上的功能:
dashboard
: 這個與本機透過dapr dashboard
看到的東西一樣operator
: operator 會與 sidecar-injector 一起協作,用來依據 app 的 annotation 的宣告,然後動態在 pod 裡面放入 sidecar container,也就是 daprd (Dapr Daemon)placement
: 這個是負責處理 actor 的 building block ,actor pattern 是用來處理平行運算的分散式演算法。Dapr 實作 Virtual Actor pattern 。sentry
: Dapr 支援在 pod 之間的傳輸加密,使用的機制為 mTLS (mutual authentication TLS),透過一個叫做Sentry
的角色作為 集中式 CA (Certificate Authority).sidecar-injector
: 與 operator 配合,動態置入 sidecar container 到 Pod 裡面。
關於 Actor Pattern 的資訊以及相關論文,整理如下:
上述的 pod 稱為 dapr control Plane
。
除了標準的初始化流程,也可以額外指定其他參數,整理如下:
1 | ## 指定 namespace |
Dapr 更版,例如從 v1.0.0
to v1.1.0
:
1 | ~$ dapr upgrade --runtime-version 1.1.0 -k |
注意,Dapr APP 的 Sidecar 不會自動更版,但只要重新建立 Pod 就 sidecar-injector 就會發配新版。
Hello World - Run on K8s
直接開始主題,同樣使用 官方的範例,下圖是官方提供的架構圖。
一些基礎相關資訊請參考 上一篇的介紹。
我在圖中註記 Pod A, Pod B, Pod C,分別摘要說明:
Pod A: Dapr.Operator
: 是放在 dapr-system ns 裡的 Pod,與 sidecar-injector 配合,動態在 pod 裡面配置 sidecar containerPod B: DaprApp.PythonApp
: 模擬 Client 的應用程式,使用 pythonPod C: DaprApp.NodeApp
: 主要的訂單處理與狀態紀錄
- 應用程式:使用 node.js 開發
- 狀態管理:透過 Dapr 的 state management (building block 的一種),在 K8s 則透過自定義 (CRD) 的 component 宣告,使用 redis。這段後面整理詳細概念。
dapr-system
: 這個 ns 是一開始dapr init -k
建立的 nsdapr-lab02
: 這是這個 lab 的 app 預定放置的 ns,包含 redis
Pod B, Pod C 都有額外的 Dapr Runtime Container,也就是前面提到的 sidecar。
安裝步驟
1. 準備 redis
我直接在 rancher 上透過 application management 安裝。
2. 定義 component
Dapr 透過 K8s 的 Component 宣告有哪一些 Building Block 要使用,然後 APP 可以直接透過 Dapr Runtime 的 API 對 Component 的實際資源做操作。
底下是官方提供的 Component 定義,要注意的是 redisHost
要指對,如果錯了 Pod 會起不來。
1 | apiVersion: dapr.io/v1alpha1 |
3. apply deployments, service
官方的範例有兩個 services: nodeapp, pythonapp,依照官方文件步驟 apply 即可。
1 | kubectl apply -f ./deploy/node.yaml |
這兩個 yaml 內容要特別說明的是這段 annotations:
1 | template: |
Dapr control plane 會依據這段 annotations:
- 動態增加 Dapr sidecar 到 pod 裡
- 同時增加一個叫做
<appneme>-dapr
的 Headless Service (No ClusterIP)
4. 檢查
完成部署後,檢查會看到以下資源
1 | ~$ k get po,deploy,svc,components |
過程可能會遇到因為 docker rate limit 問題而無法建立 Container: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
觀察上述的 Pod 與 Service 的內容:
- Pod 裡面除了 NodeAPP, PytonnApp 之外,他們都自動產生一個 Dapr Sidecar,如下圖:
- 如前述,自動產生名為
nodeapp-dapr
,pythonapp-dapr
的 Headless Service.
上述 pod 的結構如下圖:
圖片來源:Dapr at 20,000 feet
最後可以透過 dapr dashboard 看看,先確認右上角的 scope 是正確的 ns,然後 overview 會看到兩個 Dapr Applications,如下圖:
測試
用以下位址測試 NodeApp,順利的話,會回傳 DAPR 的 HTTP / gRPC 的 Ports。
1 | ~$ kubectl port-forward service/nodeapp-service 8080:80 |
pythonapp 是模擬 下訂單的服務,每秒會對 nodeapp 的 /neworder
打一次,所以直接對 node container 看 log 會看到以下訊息:
1 | ~$ k logs -f nodeapp-d5b697767-v9tms |
我這已經跑一段時間了,所以序號已經跑到 47xx 了 XDD
如果出現以下訊息,則表示 redis 有問題,component 定義沒問題:
1 | ~$ k logs -f nodeapp-d5b697767-62js6 node |
component 定義有問題,則 pod 會起不來。但如果 pod 啟動後,redis 壞了,則會出現上述問題,同時無法再長新的 pod,如下:
1 | ~$ k get po |
完整使用情境:下訂單、取得訂單
發送一個 POST 給 Application,如下:
1 | ## 啟動 forward |
上述的進入點和 Lab01 是不一樣的。
進入點的差異
在了解架構時,清楚 E2E 經過的路徑很重要,在 系統發生異常時,第一時間如何快速止血? 一文中的第一點就提到這樣的思路。
所以如果有跟著上一篇做過一次,就會發現這次打的 endpoint 路徑跟上次的不一樣,整理兩次的進入點 (entry point),底下是第一次的 Lab01 - Self-Hosted:
底下這張圖是這次的 Run on K8s Lab02 的進入點:
我嘗試把 Lab02 測試,調整到 Dapr sidecar,如下:
1 | ## 啟動 forward |
結果是不行的,因為在 K8s 裡的 Dapr Sidecar Service,預設 Headless Service,所以不會有 ClusterIp,透過 Ingress 就可以存取。如果是使用 minikube 記得把 ingress 打開。
Q&A
Q1: Run on K8s 的 外部
請求,應該打 NodeApp 的 Service ?還是打 Dapr Sidecar?
可以,只要 Ingress 指定到
<appid>-dapr
service 的 80 ,然後就可以打 Dapr API,例如/v1.0/metadata
可以當 health check.這牽涉到整體架構
規劃
與設計
問題,以目前 Dapr 的設計 Sidecar 是內部通訊使用的,外部通訊則還是透過 Ingress。
規劃
: 指的是整個服務的應用對象與場景設計
: 是能否滿足應用場景的需求能力。
這段後面有個更完整應用案例整理。
Q2: 如何針對 Dapr App 做 Health Check?
參考 Dapr 官方文件:Sidecar healthz
Q3: 怎麼配置 sidecar 的設定?範圍是怎麼圈的?
Dapr 每個應用程式都可以有自己的
Sidecar Config
和Control-plane
的 Configuration,詳細參閱 Dapr configuration options
Q4: Sidecar 透過 annotation 設定,有哪一些可以使用?
Q5: K8s Service / Ingress 可以直接接到 Dapr Sidecar Service?
可以。
實際使用情境同 Q1:Dapr Sidecar 的用途是 App 之間溝通使用的,也就是內部通訊的介面,對外的 入口還是會直接到 app 而不會經過 sidecar。更實際的案例可以參考這個: eShopOnDapr
Q6: mTLS 是 E2E 外部的資料加密?
他是 Dapr Instance 之間的通訊加密,不是 E2E。官方說明:
Dapr supports in-transit encryption of communication between Dapr instances using Sentry, a central Certificate Authority
。詳細參閱 Sidecar-to-sidecar communication
Q7: Dapr Sidecar 都沒有 log,怎麼 debug?
目前官方文件沒找到可以調整的。
20210407 Updated: v1.1.0 會提供 debug flag, 參閱 K8S debug support #3008
Q8: dapr 的 sidecar 是從 docker.io 抓,遇到 rate limit 怎麼辦?
底下討論串有這議題,看起來暫時是:
ImagePullPolicy
for Dapr sidecar Docker image fromAllways
toIfNotPresent
上面 Issue 已經在 1.0.0M2 Merge PR, Source Code 也 Merge 了,但是文件沒有提到如何設定。
但是在 Dapr Control Plane 的
dapr-sidecar-injector
,環境變數有找到以下變數可以設定:
SIDECAR_IMAGE_PULL_POLICY
: v1.0.0 預設是Always
,v1.1.0 改成IfNotPresent
SIDECAR_IMAGE
: 可以改成自己的 private registry.
Troubleshooting
Q: Dapr App 的 Pod 起不來?
先到 Pod 裡面看看是否每個 Container 都正常,如果是 daprd
有問題,那可能是 Component 定義的 redisHost
問題,可以從 log 中確認狀況,如下:
1 | daprd time="2021-03-18T14:47:30.141871173Z" level=warning msg="error initializing state store statestore (state.redis/v1): redis store: err |
確認問題,把 component 定義檔修好,長新的 pod 應該就好了。
小結
這個案例的過程,帶出 Dapr 設計背後的意圖,也就是解決大型分散式系統的核心問題:
複雜度
降低複雜度的原則是 分而治之
,Dapr 最核心的概念就是 Sidecar Pattern + Building Block
,如下圖:
圖片來源:Dapr at 20,000 feet
Sidecar Pattern
: 透過職責分離與 Container 的隔離特性,降低應用程式的複雜度。更多 Container 隔離的概念參閱: 為什麼要使用容器?、Java Obsolete in the Age of DockerBuilding Block
: 類似於積木組裝的想法,透過 Dapr 提供的核心組件 (Component),分離與抽象化系統架構。
下一篇 將整理 Dapr 核心的重要設計概念與實踐。
延伸閱讀
Dapr 系列文章
- 摘要 Dapr 的設計與概念
- Experience Dapr - Hello World
- Experience Dapr - Run on K8s
- Experience Dapr - Secret Store
- Experience Dapr - Pub/Sub
分散式系統系列文章
- 聊聊分散式系統
- 分散式一致性問題與共識演算法
- CAP Theorem
- Distributed Message Systems
- Eventually Consistent 與 Dynamo NWR 模型
- 淺談分散式交易
- Design Patterns for Distributed Systems
- 分散式系統設計 - 正體中文版翻譯記事
站內文章
參考資料
- Dapr at 20,000 feet
- The world is distributed
- eShopOnDapr
- Sidecar Pattern in Action
- K8s Service - Headless Service