介紹
Dapr簡化了雲原生開發,讓開發可以把焦點放在應用的業務邏輯上,從而讓代碼簡單、可移植,那作為一個.Net開發者,我們也希望項目可以快速用上dapr,那究竟應該如何做呢?
Dapr提出了Sidecar(邊車)的概念,在啟動項目時再額外啟動一個Sidecar, 通過Sidecar可以解決進程間通信,為此官方提供了兩種部署方式:
- 自托管方式下運行Dapr
- 在 Kubernetes 模式中部署和運行 Dapr
其中Kubernetes模式部署是通過Kubernetes來完成的,在開發中我們更多的是通過自托管模式使用Dapr,那自托管模式是怎么做的呢?
使用命令行工具,在項目根目錄輸入:
dapr run --app-id assignment-server --app-port 5038 dotnet run
參考以上詳細文檔操作后,我們就可以在命令行工具中執行dapr invoke --app-id assignment-server --method hello
或者Http請求來調用對應的應用的方法
看似好像也不是很復雜,但如果你需要調試dotnet項目呢?再復雜一點的需要啟動多個項目進行調試呢?端口一多起來的確會顯得很麻煩。
有沒有什么辦法可以解決呢?有,docker-compose。
但我還不想用這么重的東西,我想像平時開發項目一樣直接在windows上運行可不可以?
Masa.Utils.Development.Dapr.AspNetCore 它來了
協助管理dapr進程,用於開發時減少對docker compose的依賴
瞌睡了就有人送枕頭,一句話讓我們了解到了它的作用,正好解決了我們需要通過命令行來啟動dapr的問題,那下面我們看看這個怎么用:
入門
本着絕對不多寫一行代碼的心態,我們准備出發了……
-
從大佬doddgu的博客的鏈接中發現一份源碼地址,為防止后期文檔調整,先fork一份到自己倉庫
git clone https://github.com/zhenlei520/dapr-study-room.git
-
使用命令行工具打開目錄dapr-study-room\Assignment03,然后執行命令
dotnet add package Masa.Utils.Development.Dapr.AspNetCore --version 0.4.0-preview.3
或使用Visual Studio打開解決方案Assignment03,選中Assignment.Server並安裝Masa.Utils.Development.Dapr.AspNetCore
-
打開
Program.cs
,並添加DaprStarter(注意看有注釋的那一行)using Masa.Utils.Development.Dapr.AspNetCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDaprStarter();//添加DaprStarter即可 var app = builder.Build(); app.Map("/hello", () => Console.WriteLine("Hello World!")); app.Run();
-
使用命令行工具執行命令驗證dapr是否啟動成功
dapr invoke --app-id Assignment-Server-00D861D0C0B7 --method hello
此時會有小伙伴問了,為什么app-id是Assignment-Server-00D861D0C0B7?
查看文檔后發現Masa.Utils.Development.Dapr.AspNetCore
的app-id生成規則為:AppId + AppIdDelimiter + AppIdSuffix
,其中
- AppId默認:項目名.Replace(".","-")
- AppIdSuffix默認:網卡地址
由於我們的項目名為Assignment.Server,當前電腦的網卡地址是00D861D0C0B7,所以dapr最終的appid為Assignment-Server-00D861D0C0B7,到這里,Masa.Utils.Development.Dapr.AspNetCore的使用講解已經完成了
冷知識,為什么 . 要換成 - ?
因為Dapr的AppId采用FQDN:(Fully Qualified Domain Name)全限定域名:同時帶有主機名和域名的名稱。(通過符號“.”)
為什么要加網卡地址作為后綴?
因為目前自托管默認采用mDNS,會導致局域網內用戶的AppId互相污染。你的同事和你一起在開發,都啟動了A應用,你倆就自動負載了,那后果自然就是請求也到處跑了。
進階
如果我希望自己指定AppId而不是使用默認的規則怎么辦呢?目前支持三種寫法:
- 根據規則(配置默認裝配)
- 根據規則 + 代碼指定(配置自定義裝配)
- 根據配置文件(根據IConfiguration配置生成)
配置默認裝配(也是上面介紹的一行代碼的方式)
修改Program.cs
文件
// 省略上述代碼
builder.Services.AddDaprStarter();
根據規則 + 代碼指定(配置自定義裝配)
修改Program.cs
文件
// 省略上述代碼
builder.Services.AddDaprStarter(opt =>
{
opt.AppId = "masa-dapr-test";
opt.AppPort = 5001;
opt.AppIdSuffix = "";
opt.DaprHttpPort = 8080;
opt.DaprGrpcPort = 8081;
});
基於默認裝配的升級版,在默認裝配基礎上通過指定特殊參數完成特殊需求,未配置的參數將使用默認值
根據IConfiguration配置生成
- 修改
appsettings.json
{
"DaprOptions": {
"AppId": "masa-dapr-test",
"AppPort": 5001,
"AppIdSuffix": "",
"DaprHttpPort": 8080,
"DaprGrpcPort": 8081
}
}
- 修改
Program.cs
builder.Services.AddDaprStarter(builder.Configuration.GetSection("DaprOptions"));
優勢:更改appsettings.json配置后,dapr sidecar會自動更新,項目無需重啟
Masa.Utils.Development.Dapr.AspNetCore的設計思路
設計思路基於兩個方面,其一本機自動啟動dapr sidecar還可以正常調試.Net項目,其二簡化配置
技術選型
我們有兩種啟動dapr sidecar的方式:
- dapr run
- daprd
兩者之間的差別如下所示:
完整的對比可查看:https://docs.dapr.io/reference/arguments-annotations-overview/
通過對比我們發現,我們的目標使用daprd與Dapr CLI都可以實現,那為什么Masa.Utils.Development.Dapr選擇的是Dapr CLI,而不是daprd呢?
核心的原因是dapr可以通過dapr list命令很簡單的就獲取到當前運行的所有dapr程序,而daprd無法獲取。如果使用daprd,那我們就需要使用C#代碼通過操作dll獲取具體執行的dapr命令,且多平台支持不好,所以暫時用了Dapr CLI
更優秀的Dapr管理需要做到什么?
- 使用簡單
- 參數可配置
- 功能支持選擇性啟動
- Dapr保活
- 配置支持動態更新
為了能更方便的使用,我們做了以下約定:
- 針對dapr的非必填項,默認關閉不啟用,手動配置參數后開啟
- 針對dapr的必填項: app-id、app-port、dapr-http-port、dapr-grpc-port 自動生成並配置
app-id 生成規則
其中dapr的app-id默認生成規則為:AppId + AppIdDelimiter + AppIdSuffix
,其中
- AppId默認:項目名.Replace(".","-")
- AppIdDelimiter默認:-
- AppIdSuffix默認:當前機器網卡地址
當AppIdSuffix賦值為空字符串,dapr的AppId的生成規則為:AppId
app-port 獲取
private ushort GetAppPort(DaprOptions options)
{
var server = _serviceProvider.GetRequiredService<IServer>();
var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses;
if (addresses is { IsReadOnly: false, Count: 0 })
throw new Exception("Failed to get the startup port, please specify the port manually");
return addresses!
.Select(address => new Uri(address))
.Where(address
=> (options.EnableSsl is true && address.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
|| address.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
.Select(address => (ushort)address.Port).FirstOrDefault();
}
為了防止啟動過程中修改端口,過早的獲取到被棄用的端口。因此我們使用后台任務啟動dapr sidecar
dapr-http-port、dapr-grpc-port獲取
因為支持用戶配置,所以我們遵循下面的順序
-
如果指定端口,被占用則自動kill port所在進程,保證可以sidecar可以正常啟動
為什么端口占用就要先kill,復用不行嗎?
因為sidecar有初始化配置,程序調整的代碼影響到sidecar配置變更我們無法檢測,所以啟動時保證是最新的是比較合適的選擇
-
如果未指定端口,則交還給dapr,通過Dapr CLI的規則生成對應的http-port或grpc-port
Dapr保活
為了保證dapr進程是活躍的,我們在庫中建立了一個心跳檢查任務用來檢測當前的dapr進程是否是活躍的,當dapr進程意外停止后會被重啟,且配置信息與上一次成功的dapr配置保持不變
如果不需要保活機制的話可以將EnableHeartBeat改為false,則不啟用dapr保活機制
配置支持動態更新
我們通過IOptionsMonitor
變動
- 在
0.7.0
中 DaprStarter已重構, 包由原來的Masa.Utils.Development.Dapr.AspNetCore
修改為Masa.Contrib.Development.DaprStarter.AspNetCore
, 用法基本沒變
本章源碼
Assignment03
https://github.com/zhenlei520/dapr-study-room
開源地址
MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks
MASA.Contrib:https://github.com/masastack/MASA.Contrib
MASA.Utils:https://github.com/masastack/MASA.Utils
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
如果你對我們的 MASA Framework 感興趣,無論是代碼貢獻、使用、提 Issue,歡迎聯系我們