楔子

公司即将新开项目,打算用点时髦的技术,需要探探路。之前没做过微服务项目,没有技术栈方面的积(负)累(债),

干脆就上微软的分布式运行时Dapr......嗯......用来服务发现,然后等测试用的服务开发好了,就开始纠结用啥反向代理/网关,nginx都没怎么用过,更别提其他复杂网关了,这时看了一篇微软的YARP(Yet Another Reverse Proxy)的文章,发现已经preview.10了,还挺简单的,二次开发也方便,就用它先顶上吧。

开发环境

  1. WSL

    windows下跨平台开发的优秀方案,Linux 分发版我用的Ubuntu 20.04
  2. Docker Desktop

    虽然Docker不是Dapr开发环境的唯一选择,但Docker的跨平台做的很好,尤其Docker Desktop可视化,还自带Docker-Compose,安装也方便,可以弹射起步。

    安装完打开后,打开控制台,验证一下:
    docker --version
  3. dotnet SDK

    YARP最低支持.NET Core 3.1,这个时间点(2021.04),推荐.NET 5

    验证:
    dotnet --version
  4. Dapr

    Dapr安装我记得挺快的,之后的初始化dapr init,网不好的话,可能要多试几次。

    初始化确认Docker Desktopdapr_placementdapr_redisdapr_zipkin 3个容器都在正常运行
  5. Tye

    Tye 是微软开发提供的一款简化分布式应用开发的辅助命令行工具。用.NET写的,自带Dapr扩展。

    dotnet tool全局安装后,可以如下验证:
    tye --version

知识储备

  1. Yarp配置

    Yarp主要要配置的东西就是Cluster(集群)和ProxyRoute(路由),

    本例中,ProxyRoute通过配置文件加载,Cluster指向Dapr-sidecar,由程序动态添加。

原理

  1. Yarp服务收到http请求
  2. 自定义Yarp转换:
    http(s)://<Yarp服务>/api/<服务名>/XXXXX
    转为
    http://<Dapr-sidecar>/v1.0/invoke/<服务名>/method/XXXXX

    注:这里的<Dapr-sidecar>可能是动态的,因此不应该写死在配置文件里

  3. 请求转给Dapr-sidecar
  4. Dapr 服务发现 终端服务并调用
  5. 返回响应

开发

  1. 创建两个Asp.Net Core项目:

    1. GatewayDemo 网关Demo
    2. ServiceSample 示例服务
  2. 完成 ServiceSample

    这个示例比较简单,所以不需要引用Dapr SDK,只需加一个测试用的Controller就好了:

    [Controller]
    [Route("sample")]
    public class SampleController
    {
    [HttpGet("{account}")]
    public ActionResult Get(string account)
    {
    return new JsonResult(new
    {
    Account = account,
    Balance = 100
    });
    }
    }
  3. 添加引用

    1. GatewayDemo.csproj 增加包引用: <PackageReference Include="Yarp.ReverseProxy" Version="1.0.0-preview.10.*" />

      注:Yarp.ReverseProxy从preview.10开始包名字变了,之前叫"Microsoft.ReverseProxy"。

    2. 这个示例比较简单,不需要引用Dapr的SDK
  4. 动态添加Yarp的Clusters自定义配置

    public static IConfigurationBuilder AddDaprConfig(this IConfigurationBuilder configurationBuilder)
    {
    var httpEndpoint = DaprDefaults.GetDefaultHttpEndpoint(); //参考Dapr.Client,获取到dapr-sidecar的url
    return configurationBuilder.AddInMemoryCollection(new[]
    {
    new KeyValuePair<string, string>("Yarp:Clusters:dapr-sidecar:Destinations:d1:Address", httpEndpoint),
    });
    }
    //GatewayDemo的Program.cs
    Host.CreateDefaultBuilder(args)
    ...
    .ConfigureAppConfiguration((_, builder) => builder.AddDaprConfig())
  5. GatewayDemo appsettings 增加Yarp相关配置

    Yarp:
    Routes:
    - RouteId: r-module-master
    ClusterId: dapr-sidecar
    Match:
    Path: api/service-sample/{**catch-all}
    Metadata:
    Dapr: method #标注Dapr

    不用在意为什么是yaml,而不是json。

  6. 添加Yarp的自定义转换

    public class DaprTransformProvider : ITransformProvider
    {
    public void ValidateRoute(TransformRouteValidationContext context)
    {
    } public void ValidateCluster(TransformClusterValidationContext context)
    {
    } public void Apply(TransformBuilderContext context)
    {
    string daprAct = null;
    if (context.Route.Metadata?.TryGetValue(DaprYarpConst.MetaKeys.Dapr, out daprAct) ?? false) //通过元数据判断是否是Dapr服务,在配置文件中设置
    {
    switch (daprAct)
    {
    case DaprYarpConst.DaprAct.Method:
    context.AddRequestTransform(transformContext =>
    {
    var index = transformContext.Path.Value!.IndexOf('/', 5); // format: /api/<服务>/xxxx
    var appId = transformContext.Path.Value.Substring(5, index - 5);
    var newPath = transformContext.Path.Value.Substring(index);
    transformContext.ProxyRequest.RequestUri = new Uri($"{transformContext.DestinationPrefix}/v1.0/invoke/{appId}/method{newPath}");
    return ValueTask.CompletedTask;
    });
    break;
    }
    }
    }
    } //GatewayDemo的Startup
    public class Startup
    {
    private readonly IConfiguration _configuration;
    public Startup(IConfiguration configuration)
    {
    _configuration = configuration;
    }
    public void ConfigureServices(IServiceCollection services)
    {
    services.AddReverseProxy()
    .LoadFromConfig(_configuration.GetSection("Yarp"))
    .AddTransforms<DaprTransformProvider>(); //加上自定义转换
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
    endpoints.MapReverseProxy();
    //endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); });
    });
    }
    }
  7. 配置tye

    参考:

    name: dapr-yarp.sample
    extensions:
    - name: dapr
    components-path: "./components/"
    config: dapr-config
    exclude-placement-container: true
    placement-port: 6050
    - name: zipkin
    services:
    - name: gateway-demo #服务名称最好不要有大写,容易出问题
    project: ./GatewayDemo/GatewayDemo.csproj
    - name: service-sample #服务名称最好不要有大写,容易出问题
    project: ./ServiceSample/ServiceSample.csproj
    - name: zipkin #dapr的追踪服务
    external: true
    bindings:
    - name: http
    port: 9411
    ingress:
    - name: ingress
    rules:
    - service: gateway-demo
    path: /
    bindings:
    - name: ingress
    protocol: https
    port: 44363 #对外端口

    ./componnets/文件夹下还有一些配置文件,这里就不贴了

  8. 用tye同时运行多个项目

    确保dapr那3个容器服务正常运行后,运行 tye run,通过tye的Dapr扩展,运行显示以下几个服务:

    1. gateway-demo
    2. service-sample
    3. zipkin
    4. gateway-demo-dapr
    5. service-sample-dapr
    6. ingress
  9. 测试:

    浏览器直接打开:https://localhost:44363/api/service-sample/sample/1234

    如果显示 {"account":"1234","balance":100} 就说明通了。

附上Demo代码

github

尾声

因为目前没有用到对外的grpc调用和Actor、发布订阅等功能,所以本示例没有相关代码演示。

Yarp虽然还在preview,但有兴趣的.NET技术栈的玩家已经可以用它来做些简单的反向代理了。

YARP实现Dapr服务调用的反向代理的更多相关文章

  1. 生产环境中nginx既做web服务又做反向代理

    一.写对于初入博客园的感想 众所周知,nginx是一个高性能的HTTP和反向代理服务器,在以前工作中要么实现http要么做反向代理或者负载均衡.尚未在同一台nginx或者集群上同时既实现HTTP又实现 ...

  2. Dubbo服务调用的动态代理和负载均衡

    Dubbo服务调用的动态代理及负载均衡源码解析请参见:http://manzhizhen.iteye.com/blog/2314514

  3. 【Azure微服务 Service Fabric 】Service Fabric中应用开启外部访问端口及微服务之间通过反向代理端口访问问题

    问题描述 1) 当成功的在Service Fabric集群中部署了应用后,如何来访问呢?如果是一个Web服务,它的URL又是什么呢? 2) 当Service Fabric集群中,服务之间如需要相互访问 ...

  4. Linux服务-配置Nginx反向代理

    任务目标:实现基于轮询的方式调度三台web,并验证结果:实现基于权重的方式调度三台web,并验证结果:实现基于hash的方式调用三台web,并验证结果 由于刚刚做了nfs设置,为了提现实验结果,我在w ...

  5. docker学习(6) docker中搭建java服务及nginx反向代理

    先看下容器规划: 上图中mysql容器的搭建见上篇博客,service1/2为java rest service,创建脚本如下: docker run -d -h service1 \ -v /Use ...

  6. Nginx设置Https反向代理,指向Docker Gitlab11.3.9 Https服务

    目录 目录 1.GitLab11.3.9的安装 2.域名在阿里云托管,申请免费的1年证书 3.Gitlab 的 https 配置 4.Nginx 配置 https,反向代理指向 Gitlab 配置 目 ...

  7. nginx 为什么要反向代理 影藏后端 高效连接(给nginx,他自己返回) 端口冲突解决 多个服务

    nginx 为什么要反向代理  影藏后端   高效连接(给nginx,他自己返回)  端口冲突解决  多个服务 单机使用反向代理可以根据不同url匹配到不同站点   rsync 的工作原理和应用实例 ...

  8. Dapr初体验之服务调用

    初次理解服务调用 在微服务中,有一个难点就是:如果你想使用各个服务组件,你就得知道不同服务的地址和端口,也就是服务发现. 在传统应用我们是怎么做的?就是在web项目里配置上api地址,如下: 在一个w ...

  9. ngnix 反向代理

    1       课程目标 掌握nginx+tomcat反向代理的使用方法. 掌握nginx作为负载均衡器的使用方法. 掌握nginx实现web缓存方法. 2       nginx介绍 2.1    ...

随机推荐

  1. 翻译:《实用的Python编程》01_07_Functions

    目录 | 上一节 (1.6 文件) | 下一节 (2.0 处理数据) 1.7 函数 随着程序开始变大,我们会想要有条理地组织这些程序.本节简要介绍函数.库模块以及带有异常的错误处理. 自定义函数 对你 ...

  2. 你见过老外的 Java 面试题吗 (上)?

    前言 最近无聊的在逛某 tube 网站,本来想看看大家是怎么吐槽川普的,结果无意间点进了一个老外面试 Java 的视频,对于常年面试被吊打的我瑟瑟发抖,于是决定进去一探究竟. 毕竟不是专业的后台开发, ...

  3. 【不在混淆的C】指针函数、函数指针、回调函数

    一.指针函数 函数的返回值是指针类型. int* fun(int a,int b); 指针函数使用: 返回字符串 这里要注意,"1234567890abc"是字符串常量,*p指向的 ...

  4. 后端程序员之路 40、Pthreads

    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准.线程这个东西在操作系统原理里讲得比较清楚了,再加上对windows那一套进程线程的东西比较清楚,所以这里还是 ...

  5. 女朋友看了会生气的回答 URI和URL有什么区别?

    URL是什么 URL 代表着是统一资源定位符(Uniform Resource Locator).作用是为了告诉使用者 某个资源在 Web 上的地址.这个资源可以是一个 HTML 页面,一个 CSS ...

  6. 图文详解:阿里宠儿【小兔】RabbitMQ的养成攻略

  7. apicloud编译所需的ios证书的获取方法

    在我们通过apicloud或hbuilderX这些工具打包ios应用的时候,需要一个ios证书. 那么我们如何生成这个ios证书呢?网上介绍的方法都是需要使用mac电脑,然后用mac电脑的钥匙串访问的 ...

  8. 虚拟机测试cobbler,网络安装加载最后出现 dracut:/#

    1.cobbler的几个重要概念: distro:发行版系统容,我理解为镜像来源,提供了kernel 和 initrd 文件以及repo源 profile:kickstart文件,用于定制系统,定制安 ...

  9. 剑指 Offer 33. 二叉搜索树的后序遍历序列 + 根据二叉树的后序遍历序列判断对应的二叉树是否存在

    剑指 Offer 33. 二叉搜索树的后序遍历序列 Offer_33 题目详情 题解分析 本题需要注意的是,这是基于一颗二叉排序树的题目,根据排序二叉树的定义,中序遍历序列就是数据从小到大的排序序列. ...

  10. pytorch(16)损失函数(二)

    5和6是在数据回归中用的较多的损失函数 5. nn.L1Loss 功能:计算inputs与target之差的绝对值 代码: nn.L1Loss(reduction='mean') 公式: \[l_n ...