标签:代理 移除 自动转换 pattern 有用 展望 tput 推送 举例
最近一直在研究微服务体系架构。微服务概念一直很火,但是作为一个初学者往往由于更多由于面对众说纷纭的高深理论和纷繁多样的技术,而失去了方向,不知道从何处开始,也就是传说中的从入门到劝退。_,还没开始就已经放弃了。所以还是不得不夸一夸微软一切以开发者为中心的价值观:好文档,好工具。
首先我们从微软的微服务架构的白皮书(中文版,英文版)入手,开卷有益,这是一本只要你是哪个平台的技术人员,只要想学习微服务,理解微服务,那么这都是非常值得一读的,虽然技术是.NET,但是书中更多的内容是介绍的微服务思想,理论,最佳实践,其他平台同样适用,这适用于我们整体把控微服务架构体系中的核心问题:
虽然不一定能够全部理解书中的理论概念,但是总能给到一些启发,开拓思维。
然后就是微软架构师利用.net core技术,基于docker容器技术,实现的适用于容器化 .NET 应用程序的体系结构微服务架构demo项目-eShopOnContainer,这个项目在上面的白皮书中也有介绍。
下面大概介绍一下这个项目的架构,虽然是一个demo,其中有部分具有一定的局限性且并适合生产环境,但是这并不妨碍我们去理解微服务体系架构。
eShopOnContainer是一个在客户端、服务端同时可以跨平台的项目。这都得益于 .NET Core能够跑在不同系统的容器上,windows或者linux。项目还有Xamarin移动APP,ASP.NET Core Web MVC 和一个SPA。
eShopOnContainer的架构,是一种面向微服务体系架构的实现。这些微服务都是可以自我治理的:
项目中有一个简化的事件抽象总线,来处理集成事件。这个抽象事件总线在项目中有两个实现:
这里对于生产级别的解决方案,微软建议使用更加健壮的组件。
整体架构中还包括了API网关和BFF模式的实现:
这些API网关是通过Envoy实现的,我顺带翻阅了下官网,使用Envoy的公司还比较多,基本都是耳熟能详,Uber
,ebay
,airbnb
,amazon
,Google
,IBM
,Microsoft
,还有腾讯等等。在架构中,Envoy实现的网关,只执行向内部微服务和自定义聚合器的请求转发,从而为客户端提供单一基本的URL.其实还可以通过Envoy实现:
项目中,除了API网关之外,还提供了一组“自定义聚合器”。这些聚合器为某些操作的客户端提供了一个简单的API。
之前eShop使用的是Ocelot实现网关的。对于Ocelot,官方给的说法是欲抑先扬:Ocelot很好,很优秀,也是.net core 优秀的开源项目,也支持许多特性,它可以作为.net core项目网关实现候选组件。但是,Ocelot缺乏对gRPC的支持,所以在最新的项目(这个eShopOnContainer项目一直在迭代更新与维护,从众多分支就可以看出)中就换为Envoy提供网关服务。
这个主要用于公开一个具有涉及内部各个微服务之间的复杂方法的HTTP/JSON API,每个自定义聚合器的方法都能调用1个或者多个内部微服务,根据逻辑聚合多个结果并提供给客户端。从聚合器到微服务的调用的都是使用gRPC
在众多微服务之间,大多数微服务都是通过事件总线和发布者/观察者模式进行异步通信。但是,自定义的聚合器和内部微服务之间的同步通信是用gRPC实现的。gRPC是一种基于RPC的协议,具有良好的性能,带宽占比也低,是内部微服务通信协议中的最佳候选协议。项目中使用了4个网关实现BFF,目前它们是通过Envoy
来实现的。每个BFF为其客户端提供一个唯一的端点,然后将调用转发到特定的微服务或自定义聚合器。
当调用直接从Envoy转发到内部微服务时,它是使用HTTP/JSON执行的。也就是说,现在内部微服务公开了一组混合的方法:
这里微软官方进行了展望"这可能会在未来发生变化”,即所有的微服务方法都可以使用gRPC,如果需要,Envoy可以在gRPC和HTTP/JSON之间自动转换。
不同类型的微服务可能采用不同的内部架构模式和方法,这取决于微服务的用途。
SQL Server
,部署在同一个容器内主要是降低内存的需求,生产部署不建议这样做,应该使用High-availability的解决方案。
Redis
实例,单独一个容器MongoDb
实例,单独一个容器Redis
和MongoDb
都是单独的容器,作为两个广泛使用的NO-SQL数据库的示例。
项目中除了,上面的架构内容,还有DDD领域驱动开发(Domain Drive Design),CQRS命令与查询职责分离(Command and Query Responsibility Segregation)的实践,日志,健康检查等内容。所以涵盖的范围蛮广,个人觉得非常值得研习。
铺垫了这么多,终于要进入本篇文章的主题,对于我们的微服务化的应用,我们可以说,我们的应用都是跑在容器上的,或者说我们所有的微服务都跑再容器上(当然容器指的就是docker,docker容器几乎成为了行业标准)。我们如何进行开发呢,这里再夸一下微软,在白皮书中有
下面就将开始把我的一个应用以容器的方式跑起来,根据上面的工作流进行实践与书写
项目概述
这本身是一个公司推送集中平台,接受公司多个产品线的推送请求,然后通过阿里进行移动推送,然后每一次推送都有后台记录,进行存储。由于我接下来实践的Docker应用开发的工作流,所以实际只有一个webapi项目,也并不打算去拆分,这对我们实践意义也不太大。
我们的目标
开发环境拆分为多个docker容器,且调试时能够正常运行。
docker引擎需要运行在linux上,那么win10就需要装装虚拟机:hyper-v
,实际上docker是跑在这个虚拟机上,windows上的docker适用于测试和开发。生产环境还是linux哈。
即便是win10也请注意下版本:Docker Desktop requires Windows 10 Pro/Enterprise (15063+) or Windows 10 Home (19018+).
选择虚拟机cpu颗数,内存大小
docker容器能够通过volume挂载宿主机操作系统(linux)的文件目录或目录,宿主操作系统在Windows的Docker Desktop中,就是指是 Hyper-v 里的 Linux 系统。但是,如果只能从hyper-v中的linux系统中进行挂载,显然不足以达到我们的需求,最方便的方式肯定是直接从Hyper-v的宿主windows里挂载文件咯。(有点绕,多理解下,windows>hyper-v>docker) 最终效果:Docker 容器直接挂载主机系统的目录,我们可以先将目录挂载到虚拟 Linux 系统上,,再利用 Docker 挂载到容器之中。这个过程被集成在了 Docker Desktop 系列软件中,我们不需要人工进行任何操作,整个过程已经实现了自动化。这就是FILE SHARING选项的意义。如果还不好理解,往下看。
配置阿里云镜像加速器,使用加速器可以提升获取Docker官方镜像的速度,亲测还是有用,但是,2018 年五月之后,微软将后续发布的所有 docker image
都推送到了 自家的MCR (Miscrosoft Container Registry)
,但在中国大陆,由于众所周知的原因,它的速度实在是令人发指。后续有解决方案,文章会讲到。
由于项目是现成的,那么这一步我们可以省略,这个跟您开发一个webapi项目没有任何区别,原来怎么做的,现在还是怎么做。我只说一个关键点,那就是数据初始化,我们的推送数据需要存入数据库中,你也可以等mysql容器启动后,再去初始化容器中的mysql数据库,但是我们能用代码一步到位:
在program.cs
:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AliMobilePush.Webapi
{
public class Program
{
public static void Main(string[] args)
{
//CreateHostBuilder(args).Build().Run();
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
//...CreateHostBuilder
}
}
SeedData.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace AliMobilePush.Infrastructure
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new PushContext(
serviceProvider.GetRequiredService<
DbContextOptions<PushContext>>()))
{
context.Database.EnsureCreated();
context.SaveChanges();
}
}
}
}
无论是通过Visual Studio
自动部署,还是通过Docker CLI
。都需要为应用创建Dockerfile
。一般情况,Dockerfile是放到应用或者服务的根文件夹下。这里有三种方式创建dockerfile。
不管哪种方式,一定会或者要在项目根目录下增加Dockerfile
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Webapi/AliMobilePush.Webapi.csproj", "Webapi/"]
COPY ["Infrastructure/AliMobilePush.Infrastructure/AliMobilePush.Infrastructure.csproj", "Infrastructure/AliMobilePush.Infrastructure/"]
COPY ["Domain/AliMobilePush.Domain/AliMobilePush.Domain.csproj", "Domain/AliMobilePush.Domain/"]
COPY ["Application/AliMobilePush.Application/AliMobilePush.Application.csproj", "Application/AliMobilePush.Application/"]
RUN dotnet restore "Webapi/AliMobilePush.Webapi.csproj"
COPY . .
WORKDIR "/src/Webapi"
RUN dotnet build "AliMobilePush.Webapi.csproj" -o /app/build
FROM build AS publish
RUN dotnet publish "AliMobilePush.Webapi.csproj" -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AliMobilePush.Webapi.dll"]
上面dockerfile分为了base
,build
,publish
三个阶段的多阶段构建.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
Debian10的asp.net core 运行时image开头,并创建公开端口80,443的中间image base
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Webapi/AliMobilePush.Webapi.csproj", "Webapi/"]
COPY ["Infrastructure/AliMobilePush.Infrastructure/AliMobilePush.Infrastructure.csproj", "Infrastructure/AliMobilePush.Infrastructure/"]
COPY ["Domain/AliMobilePush.Domain/AliMobilePush.Domain.csproj", "Domain/AliMobilePush.Domain/"]
COPY ["Application/AliMobilePush.Application/AliMobilePush.Application.csproj", "Application/AliMobilePush.Application/"]
RUN dotnet restore "Webapi/AliMobilePush.Webapi.csproj"
COPY . .
WORKDIR "/src/Webapi"
RUN dotnet build "AliMobilePush.Webapi.csproj" -o /app/build
build阶段是从编译工具—sdk镜像开始,而不是aspnet
,那是因为只有sdk
镜像用后构建编译工具,所以sdk镜像也比aspnet镜像大。先还原restore
,再
FROM build AS publish
RUN dotnet publish "AliMobilePush.Webapi.csproj" -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AliMobilePush.Webapi.dll"]
最后阶段再次从base
开始,包括COPY --from=publish /app/publish .
将发布的输出复制到最终镜像中。由于无需包含sdk
镜像中的构建编译工具,因此此过程可以使最终镜像小得多。
官方最佳实践,多阶段构建镜像,这样生成过程更高效,并使容器更小。官方文档,整个多阶段构建 可以让后一个阶段构建可以使用前一个阶段构建的产物,形成一条构建阶段的chain;最终结果仅产生一个image,避免产生冗余的多个临时images或临时容器对象,这正是我们所需要的:我们只需要个结果。
一个服务对应一个镜像,需要知道,在Visual Studio
的强大功能下,docker镜像是自动创建的。
作为开发者,只要功能没完成,或者代码不提交到版本控制。都是需要在本地部署和测试的。那么这就意味你需要在本地的docker主机上创建docker镜像,部署docker容器,并在这些容器上去运行,测试,调试。使用 Visual Studio
创建具有 Docker 支持的项目时,不会显示的创建映像。 而是在按下 F5(或 Ctrl-F5)运行docker 化的应用程序或服务时创建映像 。 Visual Studio
会自动执行这个操作,开发人员不会看到该过程,但务必要了解其原理。
定义服务,创建多容器应用,主要是可以在docker-compose.yml
中定义一系列的服务。通过部署命令将其部署为组合应用程序。 它还配置其依赖项关系和运行时配置。在主解决方案文件夹或根解决方案文件夹中创建该docker-compose.yml
文件,docker-compose.yml
是可以拆分成多个docker-compose
文件。然后根据不同的环境去覆盖值。添加docker-compose.yml文件也有两种方式
docker-compose.yml
,这个后续博文会详细介绍,亦不是本篇的重点。所以下面重点介绍第一种方式:第一次作Solution Explorer > Add>Container Orchestrator Support操作
Dockerfile
,如果原本没有的话docker-compose.dcproj
docker-compose.override.yml
docker-compose.yml
.dockerignore
docker-compose.yml
version: ‘3.4‘
services:
webapi:
build:
context: .
dockerfile: Webapi/Dockerfile
networks:
- asp-net
depends_on:
- "cachedata"
- "sqldata"
cachedata:
image: redis
networks:
- asp-net
sqldata:
image: mysql
networks:
- asp-net
networks:
asp-net:
driver: bridge
docker-compose.override.yml
version: ‘3.4‘
services:
webapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "5000:5000"
- "5001:5001"
volumes:
- ./docker/log/alipush.log:/app/alipush.log
cachedata:
ports:
- "6379:6379"
volumes:
- ./docker/data/redis:/data
sqldata:
ports:
- "3307:3306"
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./docker/data/mysql:/var/lib/mysql
这里需要注意,所有有用到镜像间的通信的地方,我们都需要使用镜像名进行指代,例如我们需要修改程序的数据库访问字符串的服务器地址
Mysql:
"ConnectionStrings": {
"PushContext": "Persist Security Info=False;database=pushcenter;server=sqldata;Connect Timeout=30;user id=pushcenter; pwd=123456"
},
Redis:
"Redis": {
"ConnectionString": "cachedata,defaultDatabase=1",
"Instance": "push_request_",
"Timeout": 1
},
如果是单容器应用,直接跑。
如果多服务容器应用,就有两个选择
docker-compose up
Visual Studio
使用docker命令,docker run
即可
docker run -t -d -p 80:5000 cesardl/netcore-webapi-microservice-docker:first
使用docker-compose
命令,docker-compose up
使用 docker-compose up
和 docker run
命令(或在 Visual Studio
中运行和调试容器)足以在开发环境中测试容器。 但不应该将这种方法用于生产部署,在生产部署中应该以业务流程协调程序为目标,,比如K8S,或者docker swarm
。
docker-compose
项目,Solution Explorer > Set as a Startup ProjectF5
开始运行调试吧可以在output-build窗口下观察:
实际上,是visual studio帮我们直接执行了docker-compose -f docker-compose.yml
的命令
然后紧接着,docker-compose就会
构建的过程中,win10会一直提示,文件是否共享,会一直不停的点share it.这时我们去观察下:
docker-desktop>Resources>FILE SHARING
没错,我们把这些主机(win10)文件夹挂载到hyper-v(虚拟机,docker宿主机),hyper-v又挂载到容器,实现主机文件夹与容器文件夹的映射。
再看下结果:镜像与容器
然后就可以打断点调试容器应用了。
如果你发现构建的镜像与容器有问题,想重新来过,vs大法提供了如下方法:
Solution>Clean Solution
再在output-build窗口下观察:
应用容器倒是停了并且删除了,但是mysql,redis这些容器数据服务,仅仅只是停了。
注意:dockerfile里面的mcr.microsoft.com/dotnet/core/sdk:3.1-buster
镜像,下载巨慢,构建一次,一碗番茄煎蛋面都要做好了。
https://github.com/newbe36524/Newbe.McrMirror
使用docker-mcr下载镜像
dotnet tool install newbe.mcrmirror -g
docker-mcr -i mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim
docker-mcr -i mcr.microsoft.com/dotnet/core/sdk:3.1-buster
把构建过程需要下载的镜像,先提前下下来吧。
推送下班,避免996
或者继续开发
实际上,使用 Visual Studio
进行开发的工作流比使用编辑器或CLI 方法的工作流简单得多。 Visual Studio
隐藏或简化了 Docker 需要执行的与 Dockerfile 和 docker-compose.yml 文件相关的大部分步骤
为微软以开发者为中心的价值观,为开发者省了不少事,Visual Studio不愧为宇宙第一的IDE。
https://www.cnblogs.com/xianwang/p/12039922.html
https://zhuanlan.zhihu.com/p/147369525
http://www.imooc.com/article/259789
https://my.oschina.net/u/4285813/blog/3661653/print
https://github.com/dotnet-architecture/eShopOnContainers
https://docs.microsoft.com/zh-cn/dotnet/architecture/microservices/
【One by one系列】微服务:一步步开发与调试容器化的 .NET 应用程序
标签:代理 移除 自动转换 pattern 有用 展望 tput 推送 举例
原文地址:https://www.cnblogs.com/RandyField/p/13171259.html