开篇
很早之前就想做一套案例,介绍.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/。