開篇
很早之前就想做一套案例,介紹.NET下如何從零開始搭建一個雲原生的應用程式。不過這個話題有點大,會要包含很多內容。我本打算從新建一個ASP.NET Core Web API應用程式開始介紹,但又覺得即便是從零開始,也無法完全涵蓋每一個步驟細節,而且很多基礎性的東西其實並沒有太大的介紹價值,倒不如就先略過服務端RESTful API和Blazor WebAssembly的開發部分,直接研究討論與雲原生相關的內容。如需瞭解ASP.NET Core的基礎和開發相關的內容,請點選【這裡】;如需瞭解Blazor WebAssembly客戶端開發,請點選【這裡】。
那什麼是雲原生?如果你問ChatGPT,大概可以得到下面的解釋:
雲原生(Cloud Native)是指構建和執行應用程式的方法,這些應用程式充分利用了雲端計算模型的優勢。雲原生應用程式通常設計為在現代雲環境中高效執行,具有以下特點:
容器化:應用程式和服務被打包在容器中,這提供了隔離、快速啟動和一致性。
微服務:應用程式被分解為小的、獨立的服務,每個服務執行單一的業務功能。
動態管理:使用容器編排工具(如Kubernetes)動態地管理容器的生命週期。
持續交付:自動化部署流程,以實現頻繁和可靠的程式碼釋出。
雲原生應用程式旨在在雲環境中實現彈性、可伸縮性、可維護性和快速迭代。
嗯,不錯,這是ChatGPT說的,或許每個人對雲原生概念的理解有所不同,無論如何,這段解釋正好說明了我做這個案例所要介紹的內容:基於ASP.NET Core Web API和Blazor WebAssembly實現一個以微服務架構和容器化為基礎的分散式的應用程式。在實踐的過程中,我會將主要技術的具體實現以及相關細節問題介紹清楚,內容估計會比較多,或許有時候更新會比較慢,還望讀者海涵。
說明:自從.NET 5開始,原則上不應繼續使用.NET Core這個名稱來指代跨平臺版本的.NET,.NET 5/6/7/8以及即將釋出的.NET 9,都是跨平臺的版本。本系列文章中,如不作特殊說明,.NET指代跨平臺的.NET版本,而不是經典的.NET Framework。
案例介紹
本系列文章打算使用“貼紙牆”(Stickers)作為案例進行介紹。“貼紙”,就是平時用來記錄今天打算做的事情的小卡片,在上面書寫完後,可以貼在電腦上或者桌子上作為提醒,它很像ToDo List,大概是這麼個東西:
我們要開發的應用程式就是實現這樣的功能:使用者可以增刪改查自己建立的“貼紙”,為了讓需求足夠簡單以便更高效地討論技術,我們不考慮每個貼紙的佈局,也不考慮給貼紙進行顏色分類,所以,從使用者的角度,大概就是這樣的效果:
整個應用的業務很簡單,就是對於貼紙物件的增刪改查,然後維護一下當前登入賬戶的資訊。正如本文一開始提到的那樣,這個系列文章不會從頭開始介紹程式碼級別的程式設計細節,而是介紹.NET雲原生應用實踐的各個方面,所以每篇文章的內容也會相對獨立,文章之間不一定會連貫,但希望透過這個系列,能夠把.NET雲原生的相關內容都覆蓋到。
所需知識
閱讀本系列文章,你需要一定的C#程式設計基礎和一些物件導向和架構設計的思想,在介紹案例的過程中,我會對一些現實問題進行分析並從設計層面提供一些思路,然後一步步地實現這種設計。透過閱讀,你可以瞭解這些現實問題的解決過程,相信會給你帶來一定的收穫。總結起來,所需知識結構如下(或者說將會涵蓋如下相關的內容,排名不分先後,後續文章也不一定會按這個順序進行介紹):
- C#程式設計基礎
- 物件導向分析與設計(以及某些設計模式)
- ASP.NET Core Web API基礎
- Blazor WebAssembly基礎
- 領域驅動設計初步概念
- SaaS與多租戶基本概念
- 分層架構與微服務架構
- 關係型資料庫基礎
- nginx與反向代理
- Docker與應用程式容器化
- 基於Docker Compose的編譯和部署
- .NET Aspire初步
- Kubernetes初步
- DevOps相關基礎知識
- Azure DevOps以及Azure雲端部署
- ElasticSearch基礎知識(擴充套件)
- 大語言模型的應用(擴充套件)
P.S.:最後兩個擴充套件話題會在實現完整個應用程式的基本功能後進行補充擴充,在前期暫不牽涉過多相關內容。接下來,我們就從搭建專案框架結構開始。
專案框架結構搭建
在做PPT或者使用文字編輯軟體來撰寫文章,第一步要做的事情並不是直接從文章正文開始寫,而是先把整篇文章的提綱結構定好,然後在文字編輯軟體中對字型和段落樣式進行設定,以便針對不同的文章組成部分可以很方便地應用不同的樣式,這樣不僅在樣式查詢和處理時可以做到事半功倍,而且整篇文章的結構排版都會非常清晰。軟體專案開發也是如此,在理解了需要幹什麼之後,第一步就是思考如何搭建整個框架結構(也就是所謂的“腳手架”)。根據上文的案例設定,我們的專案大致會有如下的拓撲結構:
整體上看,整個分散式應用程式會包含5個docker容器,這些容器使用不同的技術實現了應用程式的不同部分,具體地說:
- API閘道器:採用nginx反向代理實現的API閘道器,客戶端(瀏覽器)透過API閘道器訪問後端API微服務和前端資源
- Keycloak:Stickers應用程式的認證和授權機構,為應用程式提供認證授權服務
- Sticker微服務:後端API服務,使用ASP.NET Core Web API實現,目前提供“貼紙”的管理功能(簡單地說,就是增刪改查)
- Sticker前端應用:使用.NET Blazor WebAssembly實現,由nginx容器託管
- pgsql資料庫:PostgreSQL資料庫,不用多說,API微服務和Keycloak都依賴它
第一階段我們先實現上面的這些內容,後續隨著功能的擴充套件,我們會討論更多的東西,比如訊息佇列、快取、微服務治理、微服務通訊、分散式事務等等
如果是開發一個實際的產品專案,團隊可以考慮在一定的設計規約基礎上,不同的人同時工作在不同的微服務上,這也是微服務架構帶來的優勢之一,它允許擅長不同技術的團隊成員在異構的技術體系下協同工作。但目前我是在做案例,所以,我還是會一步步進行下去,首先第一步就是實現Sticker微服務,它是一個後端服務,暫時僅提供“貼紙”的管理功能,然後再接入Keycloak完成登入使用者的認證和資源訪問的授權。
工具和IDE
在開始這個案例的介紹和演練之前,請確保開發機器上已經安裝如下工具和IDE:
- .NET 8 SDK
- Visual Studio 2022,如果在Linux下開發,可以使用Visual Studio Code搭配微軟官方的C#外掛,也可以選擇使用JetBrains Rider IDE,不過這個是收費的
- Docker和Docker Compose
從Sticker微服務開始
現在開始建立我們的程式碼專案,首先新建一個資料夾:
$ mkdir stickers
然後,在這個資料夾下,新建src
資料夾,用來儲存所有的開發程式碼檔案:
$ cd stickers
$ mkdir src
進入src
資料夾,新建一個.NET solution(解決方案)檔案,然後,建立一個ASP.NET Core Web API專案,並將這個專案加入到新建的solution下:
$ cd src
$ dotnet new sln -n stickers
$ dotnet new webapi -n Stickers.WebApi --no-https --use-controllers
$ dotnet sln stickers.sln add Stickers.WebApi/Stickers.WebApi.csproj
於是,你將在src
目錄下得到一個stickers.sln
的解決方案檔案,以及一個Stickers.WebApi
的子目錄,在這個子目錄下,包含了我們接下來會對之進行編輯修改的Sticker微服務的程式碼。現在,進入Stickers.WebApi
子目錄,然後執行dotnet run
命令,你會看到類似下面的輸出:
daxnet@daxnet-HP-ZBook:~/Projects/stickers/src/Stickers.WebApi$ dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5141
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: /home/daxnet/Projects/stickers/src/Stickers.WebApi
開啟瀏覽器,訪問http://localhost:5141/swagger/index.html(注意,埠有可能不同,以上面的輸出結果為準),就可以看到API服務的Swagger頁面:
只不過目前只有一個預設的由ASP.NET Core Web API模板自帶的GET /WeatherForecast
API,但專案是已經建立成功了。從下一篇文章開始,我們就開始開發Stickers微服務。
總結
今天做了一個開篇,打算把基於微服務架構的.NET雲原生應用程式的開發做個系列介紹一下,也不知道是不是會有讀者有興趣去了解這部分內容,如果有好的建議,歡迎留言。
原始碼
一如既往以MIT許可協議開源,為方便國內讀者,程式碼託管到碼雲,程式碼庫為:https://gitee.com/daxnet/stickers,每個章節的程式碼都會放在以“chapter_XXX”為名的分支下,所以,本章程式碼在這裡:https://gitee.com/daxnet/stickers/tree/chapter_1/。