Py学习  »  docker

Dapr牵手.NET学习笔记:状态管理之docker-compose发布

dotNET跨平台 • 2 年前 • 329 次点击  

Dapr牵手.NET学习笔记:想入非非的服务调用

Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用

Dapr牵手.NET学习笔记:用docker-compose部署服务


说明:为了给出demo的全貌,这篇有点长,如果有上一篇的基础,会更容易阅读一些。

在分布式应用,有状态服务是常态,特别是多副本应用,就需要共用缓存来解决数据统一的状况,所以dapr也把状态管理做成一个标准组件。

下面通过docker-compose来发布OrderSystem项目和PaymentSystem项目,他们分别有自己的状态数据,并且测试它们之间的访问性。


下面是项目的目录结构,components文件是dapr组件配置文件夹,B2C是docker-compose的文件夹


OrderSystem项目

HomeController.cs

using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Logging;using System;using System.Net;using System.Net.Http;using System.Threading.Tasks;
namespace OrderSystem.Controllers;[ApiController][Route("[controller]")]public class HomeController : ControllerBase{ private readonly ILogger _logger; private readonly IHttpClientFactory _clientFactory; private readonly string? _payUrl; private readonly string _stateUrl; public HomeController(ILogger logger, IHttpClientFactory clientFactory, IConfiguration configuration) { _stateUrl = configuration.GetSection("StateUrl").Value; _payUrl = configuration.GetSection("payurl").Value; _clientFactory = clientFactory; _logger = logger; } [HttpGet("/order")] public async Task Order() { try { _logger.LogInformation($"下单开始"); await Task.Delay(400); _logger.LogInformation($"订单完成 调用支付系统"); var client = _clientFactory.CreateClient(); var content = await client.GetStringAsync(_payUrl); return new JsonResult(new { order_result = "订单成功", pay_result = content }); } catch (Exception exc) { _logger.LogCritical(exc, exc.Message); return new JsonResult(new { order_result = "订单成功,支付失败", message = exc.Message }); } }


[HttpPost("/writekeys")] public async Task WriteKeys([FromBody] KeyEntity[] keys) { var client = _clientFactory.CreateClient(); var jsonContent = System.Text.Json.JsonSerializer.Serialize(keys); var content = new StringContent(jsonContent); var response = await client.PostAsync(_stateUrl, content); return Ok(await response.Content.ReadAsStringAsync()); }
[HttpGet("/readekey/{key}")] public async Task ReadKey(string key) { var client = _clientFactory.CreateClient(); var response = await client.GetAsync($"{_stateUrl}/{key}"); return new JsonResult(new { key = await response.Content.ReadAsStringAsync(), host = Dns.GetHostName() }); } [HttpPost("/readekeys")] public async Task ReadKeys([FromBody] string[] keys) { var client = _clientFactory.CreateClient(); var jsonContent = System.Text.Json.JsonSerializer.Serialize(keys); var content = new StringContent(jsonContent); var response = await client.PostAsync($"{_stateUrl}/bulk", content); return Ok(await response.Content.ReadAsStringAsync()); }
[HttpDelete("/deletekey/{key}")] public async Task DeleteData(string key) { var client = _clientFactory.CreateClient(); var response = await client.DeleteAsync($"{_stateUrl}/{key}"); return Ok(await response.Content.ReadAsStringAsync()); }}public class KeyEntity{ public string Key { get; set; } public string Value { get; set; }}

appsettings.json

{  "Urls": "http://*:80",  "Logging": {    "LogLevel": {      "Default": "Information",      "Microsoft": "Warning",      "Microsoft.Hosting.Lifetime": "Information"    }  },  "AllowedHosts": "*",  "PayUrl": "http://localhost:3500/v1.0/invoke/pay/method/pay",  "StateUrl": "http://localhost:3500/v1.0/state/statestore"}


OrderSystem项目的Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS baseWORKDIR /appEXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS buildWORKDIR /srcCOPY ["/OrderSystem/OrderSystem.csproj", "OrderSystem/"]RUN dotnet restore "OrderSystem/OrderSystem.csproj"COPY . .WORKDIR "/src/OrderSystem"RUN dotnet build "OrderSystem.csproj" -c Release -o /app/build
FROM build AS publishRUN dotnet publish "OrderSystem.csproj" -c Release -o /app/publish
FROM base AS finalWORKDIR /app COPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "OrderSystem.dll"]



PaymentSystem项目

HomeControllers.cs与OrderSystem的状态代码是一样的,这里就不占篇幅。

PaymentSystem项目的appsettings.json

{  "Urls": "http://*:80",  "Logging": {    "LogLevel": {      "Default": "Information",      "Microsoft": "Warning",      "Microsoft.Hosting.Lifetime": "Information"    }  },  "AllowedHosts": "*",  "StateUrl": "http://localhost:3500/v1.0/state/statestore"}

PaymentSystem项目的Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS baseWORKDIR /appEXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS buildWORKDIR /srcCOPY ["/PaymentSystem/PaymentSystem.csproj", "PaymentSystem/"]RUN dotnet restore "PaymentSystem/PaymentSystem.csproj"COPY . .WORKDIR "/src/PaymentSystem"RUN dotnet build "PaymentSystem.csproj" -c Release -o /app/build
FROM build AS publishRUN dotnet publish "PaymentSystem.csproj" -c Release -o /app/publish
FROM base AS finalWORKDIR /appCOPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "PaymentSystem.dll"]


OrderSystem项目和PaymentSystem项目的Dockerfile中的路径要和docker-compose.yml中的设置有关,所以分享出来,以供参考。


B2C

docker-compose.yml,这里定义了一个b2c-dapr,作为互通网络,打通应用与redis等服务的通道。其中ordersystem对宿主机的端口还是3500,paymentsystem对宿主机的端口分别是3601,3602

version: '3.4'
services: #┌────────────────────────────────┐ #│ ordersystem app + Dapr sidecar │ #└────────────────────────────────┘ ordersystem: image: ${DOCKER_REGISTRY-}ordersystem depends_on: - redis - placement build: context: ../ dockerfile: /OrderSystem/Dockerfile ports: - "3500:3500" volumes: - ../OrderSystem:/OrderSystem networks: - b2c-dapr ordersystem-dapr: image: "daprio/daprd:latest" command: [ "./daprd", "-app-id", "order", "-app-port", "80","-placement-host-address", "placement:50006","-components-path","/components"] build: context: ../ depends_on: - ordersystem network_mode: "service:ordersystem" volumes: - ../components:/components #┌───────────────────────────────────┐ #│ paymentsystem1 app + Dapr sidecar │ #└───────────────────────────────────┘ paymentsystem1: image: ${DOCKER_REGISTRY-}paymentsystem build: context: ../ dockerfile: /PaymentSystem/Dockerfile ports: - "3601:3500" volumes: - ../PaymentSystem:/PaymentSystem networks: - b2c-dapr paymentsystem1-dapr: image: "daprio/daprd:latest" command: [ "./daprd", "-app-id", "pay", "-app-port", "80","-placement-host-address", "placement:50006","-components-path","/components" ] build: context: ../ depends_on: - paymentsystem1 network_mode: "service:paymentsystem1" volumes: - ../components:/components #┌───────────────────────────────────┐ #│ paymentsystem2 app + Dapr sidecar │ #└───────────────────────────────────┘ paymentsystem2: image: ${DOCKER_REGISTRY-}paymentsystem build: context: ../ dockerfile: /PaymentSystem/Dockerfile volumes: - ../PaymentSystem:/PaymentSystem ports: - "3602:3500" networks: - b2c-dapr paymentsystem2-dapr: image: "daprio/daprd:latest" command: [ "./daprd", "-app-id", "pay", "-app-port", "80" ,"-placement-host-address", "placement:50006","-components-path","/components"] build: context: ../ depends_on: - paymentsystem2 network_mode: "service:paymentsystem2" volumes: - ../components:/components
#┌────────────────────────┐ #│ Dapr placement service │ #└────────────────────────┘ placement: image: "daprio/dapr" command: ["./placement", "-port", "50006"] ports: - "50006:50006" networks: - b2c-dapr
#┌───────────────────┐ #│ Redis state store │ #└───────────────────┘ redis: image: "redis:latest" ports: - "6380:6379" networks: - b2c-daprnetworks: b2c-dapr:


Dapr组件配置

statestore.yaml,其中value的值要改成redis,而不是localhost,这里要连接同一个网络里的redis服务

apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: statestorespec:  type: state.redis  version: v1  metadata:  - name: redisHost    value: redis:6379  - name: redisPassword    value: ""  - name: actorStateStore    value: "true"


启动docker-compose

docker-compose up -d



启动后各服务的状态


测试:

对order服务进行设置状态,这里调用的是dpar服务调用对外的接口,3500是order服务sidecar对外端口

同理调用order服务的状态数据,返回设置的值



接下来测试从pay服务中调用order服务的状态,返回结果为空,这里的地址为:localhost:3601/v1.0/invoke/pay/method/readekey/USER00001


下面换成从pay1服务的3601中访问order服务的状态,结果有值,url为localhost:3601/v1.0/invoke/order/method/readekey/USER00001,根本原因可能你想到了,这本质上调的还是order服务的接口,只不过是利用pay1的sidecar调用order的sidecar实现的,因为服务调用是通着,所以能调用到,这里可以通过查看返回的host值证明。



接下来测试pay服务,两个副本,访问状态数据的case。下面是通过3601设置状态。


通过pay1的sidecar对外端口访问,url是localhost:3601/v1.0/invoke/pay/method/readekey/PAY00001


通过pay2的sidecar对外端口访问,url是localhost:3602/v1.0/invoke/pay/method/readekey/PAY00001


可见状态数据很好的被隔了,如果跨服务访问状态数据,可以通过服务开放api来实现。


最后看一眼redis数据吧,清晰的展示了服务和数据的关系。



Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/120605
 
329 次点击