Last updated on 9 months ago
Nginx
配置Conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream ServiceInstance{ server localhost:5726; server localhost:5727; server localhost:5728; } server { listen 8080; server_name localhost; location / { proxy_pass http://ServiceInstance; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
创建应用
执行多个应用
执行:
1 2 3 dotnet run urls="http://*:5726" dotnet run urls="http://*:5727" dotnet run urls="http://*:5728"
启动Nginx 1 D:\nginx-1.18.0\nginx-1.18.0>start nginx
停止Nginx 1 D:\nginx-1.18.0\nginx-1.18.0>nginx.exe -s stop
重启Nginx
访问流程
访问结果
最后 Nginx 不能伸缩
也就是再加一个端口,要把端口加进来让Nginx发现,需要修改配置并且重启Nginx,做不到热处理
看下面的Consul吧
Consul
Consul 服务注册 参考:.NET 5.0实现Consul服务注册 - 半山上的人 - 博客园 (cnblogs.com)
Consul 1.7.2 http://localhost:8500 1.7.2 长这样
consul 1.11.1 http://localhost:8500 1.11.1 长这样
API appsetting.json 配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { "Logging" : { "LogLevel" : { "Default" : "Information" , "Microsoft" : "Warning" , "Microsoft.Hosting.Lifetime" : "Information" } } , "AllowedHosts" : "*" , "ConsulConfig" : { "ServiceId" : "d72e7de8b01a43acac640b1a00b26c81" , "ServiceName" : "HarrisService" , "ServiceIP" : "127.0.0.1" , "ServicePort" : 5726 , "ConsulIP" : "127.0.0.1" , "ConsulPort" : 8500 } }
Model 实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 namespace ConsulTest.Models { public class ServiceConfig { public string ServiceId { get ; set ; } public string ServiceIP { get ; set ; } public int ServicePort { get ; set ; } public string ServiceName { get ; set ; } public string ConsulIP { get ; set ; } public int ConsulPort { get ; set ; } public int weight { get ; set ; } } }
AppBuilderExtensions 帮助类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 using Consul;using ConsulTest.Models;using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.Hosting;using System;namespace ConsulTest.Untiy { public static class AppBuilderExtensions { public static IApplicationBuilder RegisterConsul (this IApplicationBuilder app, IHostApplicationLifetime lifetime, ServiceConfig serviceConfig ) { var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceConfig.ConsulIP} :{serviceConfig.ConsulPort} " )); var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5 ), Interval = TimeSpan.FromMinutes(1 ), HTTP = $"http://{serviceConfig.ServiceIP} :{serviceConfig.ServicePort} /api/health" , Timeout = TimeSpan.FromSeconds(20 ), }; var registerAgent = new AgentServiceRegistration() { Check = httpCheck, Checks = new [] { httpCheck }, ID = serviceConfig.ServiceId, Name = serviceConfig.ServiceName, Address = serviceConfig.ServiceIP, Port = serviceConfig.ServicePort, Tags = new [] { $"urlprefix-/{serviceConfig.ServiceName} " } }; consulClient.Agent.ServiceRegister(registerAgent).Wait(); lifetime.ApplicationStopped.Register(() => { consulClient.Agent.ServiceDeregister(registerAgent.ID).Wait(); }); return app; } } }
Startup 注册Consul 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 using ConsulTest.Models;using ConsulTest.Untiy;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;using Microsoft.OpenApi.Models;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace ConsulTest { public class Startup { public Startup (IConfiguration configuration ) { Configuration = configuration; } public IConfiguration Configuration { get ; } public void ConfigureServices (IServiceCollection services ) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1" , new OpenApiInfo { Title = "ConsulTest" , Version = "v1" }); }); } public void Configure (IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime,IConfiguration configuration ) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json" , "ConsulTest v1" )); } app.UseRouting(); app.UseAuthorization(); #region 注册Consul服务 var serviceConfig = Configuration.GetSection("ConsulConfig" ).Get<ServiceConfig>(); int weight = string .IsNullOrWhiteSpace(configuration["weight" ]) ? 1 : int .Parse(configuration["weight" ]); serviceConfig.weight = weight; serviceConfig.ServiceId = "Service" + Guid.NewGuid().ToString(); int port = int .Parse(configuration["port" ]); serviceConfig.ServicePort = port; Console.WriteLine(port); app.RegisterConsul(lifetime, serviceConfig); #endregion app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }
启动Consul consul agent -dev(如果需要其他机器访问,命令为consul agent -dev -client 0.0.0.0 -ui)
启动API应用 1 2 3 4 dotnet run --urls="http://*:5726" --ip=127.0.0.1 --port=5726 --weight=2 dotnet run --urls="http://*:5727" --ip=127.0.0.1 --port=5727 --weight=3 dotnet run --urls="http://*:5728" --ip=127.0.0.1 --port=5728 --weight=4 dotnet run --urls="http://*:5729" --ip=127.0.0.1 --port=5729 --weight=5
Consul 应用界面
Consul 服务发现
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 using Consul;using CustomerDemo.Models;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Logging;using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Threading.Tasks;namespace CustomerDemo.Controllers { public class HomeController : Controller { private readonly ILogger<HomeController> _logger; private static int iSeed = 0 ; public HomeController (ILogger<HomeController> logger ) { _logger = logger; } public IActionResult Index () { #region Consul 服务发现 ConsulClient client = new ConsulClient(c => { c.Address = new Uri("http://localhost:8500" ); c.Datacenter = "dc1" ; }); var response = client.Agent.Services().Result.Response; string url = "http://HarrisService/WeatherForecast" ; Uri uri = new Uri(url); string groupName = uri.Host; AgentService service = null ; var serviceDictionary = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase)).ToList(); { } { } { List<KeyValuePair<string , AgentService>> serviceList = new List<KeyValuePair<string , AgentService>>(); foreach (KeyValuePair<string , AgentService> agentService in serviceDictionary) { int count = int .Parse(agentService.Value.Tags[0 ]); for (int i = 0 ; i < count; i++) { serviceList.Add(agentService); } } service = serviceList[new Random(iSeed++).Next(0 , serviceList.Count())].Value; } url = $"{uri.Scheme} ://{service.Address} :{service.Port} {uri.PathAndQuery} " ; string content = Untiy.WebApiHelperExtend.InvokeApi(url); var weather = Newtonsoft.Json.JsonConvert.DeserializeObject<List<WeatherForecast>>(content); this .ViewData["weather" ] = weather; this .ViewData["Url" ] = url; #endregion return View(); } public IActionResult Privacy () { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true) ] public IActionResult Error () { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } }
Index.cshtml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @{ ViewData["Title" ] = "Home Page" ; } <div class ="text-center" > <h1 class ="display-4" >Welcome</h1> <h2>Weather</h2> <ul> @foreach (WeatherForecast item in ViewData["weather" ] as List<WeatherForecast>) { <li>@item.summary +@item.date.ToString()+ @item.summary+@item.temperatureC+@item.temperatureF </li> } </ul> <h2>@this.ViewData["Url" ]</h2> <p>Learn about <a href="https://docs.microsoft.com/aspnet/core" >building Web apps with ASP.NET Core</a>.</p> </div>
WebApiHelperExtend.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System;using System.Net.Http;namespace CustomerDemo.Untiy { public static class WebApiHelperExtend { public static string InvokeApi (string url ) { using (HttpClient httpClient = new HttpClient()) { HttpRequestMessage message = new HttpRequestMessage(); message.Method = HttpMethod.Get; message.RequestUri = new Uri(url); var result = httpClient.SendAsync(message).Result; string content = result.Content.ReadAsStringAsync().Result; return content; } } } }
实体 1 2 3 4 5 6 7 public class WeatherForecast { public DateTime date { get ; set ; } public int temperatureC { get ; set ; } public int temperatureF { get ; set ; } public string summary { get ; set ; } }
结果
Docker For Consul 安装 1 2 $ docker pull consul $ docker pull consul:1.6.1
运行第一个节点 leader 1 docker run --publish 8600:8600 --publish 8500:8500 --publish 8300:8300 --publish 8301:8301 --publish 8302:8302 --name consul-01 --restart always --volume D:\docker\Consul\Consul-01\data:/consul/data --volume D:\docker\Consul\Consul-01\config:/consul/config consul:latest agent --server --bootstrap-expect=1 --ui --bind=0.0.0.0 --client=0.0.0.0
1 docker run --publish 8600:8600 --publish 8500:8500 --publish 8300:8300 --publish 8301:8301 --publish 8302:8302 --name consul-01 --volume /docker/consul/data:/consul/data --volume /docker/consul/config:/consul/config consul:latest agent --server --bootstrap-expect=1 --ui --bind=0.0.0.0 --client=0.0.0.0
其中,端口示意:
8500
端口,用于Consul的HTTP接口及Web UI界面。
8600
端口,用于Consul已注册服务的DNS服务。
8300
端口,用于同一数据中心内Consul Server的RPC通信。
8301
端口,用于同一数据中心内Consul Server的gossip serf lan通信。
8302
端口,用于不同数据中心内Consul Server的gossip serf wan通信。
其中,参数示意:
–net=host
docker参数, 使得docker容器越过了net namespace的隔离,免去手动指定端口映射的步骤
-server
consul支持以server或client的模式运行, server是服务发现模块的核心, client主要用于转发请求
-advertise
将本机私有IP传递到consul
-retry-join
指定要加入的consul节点地址,失败后会重试, 可多次指定不同的地址
-client
指定consul绑定在哪个client地址上,这个地址可提供HTTP、DNS、RPC等服务,默认是>127.0.0.1
-bind
绑定服务器的ip地址;该地址用来在集群内部的通讯,集群内的所有节点到地址必须是可达的,>默认是0.0.0.0
allow_stale
设置为true则表明可从consul集群的任一server节点获取dns信息, false则表明每次请求都会>经过consul的server leader
-bootstrap-expect
数据中心中预期的服务器数。指定后,Consul将等待指定数量的服务器可用,然后>启动群集。允许自动选举leader,但不能与传统-bootstrap标志一起使用, 需要在server模式下运行。
-data-dir
数据存放的位置,用于持久化保存集群状态
-node
群集中此节点的名称,这在群集中必须是唯一的,默认情况下是节点的主机名。
-config-dir
指定配置文件,当这个目录下有 .json 结尾的文件就会被加载,详细可参考https://www.consul.io/docs/agent/options.html#configuration_files
-enable-script-checks
检查服务是否处于活动状态,类似开启心跳
-datacenter
数据中心名称
-ui
开启ui界面
-join
指定ip, 加入到已有的集群中
查看已存在节点的IP 1 docker inspect --format='{{.NetworkSettings.IPAddress}}' consul-01
开启第二个节点 1 docker run --publish 8501:8500 --name consul-02 --restart always --volume D:\docker\Consul\Consul-02\data:/consul/data --volume D:\docker\Consul\Consul-02\config:/consul/config consul:latest agent --server --ui --bind=0.0.0.0 --client=0.0.0.0 --join 172.17.0.2
开启第三个节点 1 docker run --publish 8502:8500 --name consul-03 --restart always --volume D:\docker\Consul\Consul-03\data:/consul/data --volume D:\docker\Consul\Consul-03\config:/consul/config consul:latest agent --server --ui --bind=0.0.0.0 --client=0.0.0.0 --join 172.17.0.2
查看Consul集群信息 1 docker exec -it consul-01 consul members
查看容器IP 1 2 3 4 5 6 docker inspect NAMES # 查看容器所有状态信息; docker inspect --format='{{.NetworkSettings.IPAddress}}' # 查看 容器ip 地址 docker inspect --format '{{.Name}} {{.State.Running}}' # 容器运行状态
net core 发布
新建Dockerfile 1 2 3 4 5 6 7 FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 80 WORKDIR /app COPY . /app ENTRYPOINT ["dotnet", "ConsulTest.dll"]
build 1 docker build -t consultest02:v2.0 .
run 1 docker run --name consultest02 -p 80:80 -d consultest02:v2.0
宿主访问容器 1 2 3 4 添加路由 route -p add 172.17.0.0 MASK 255.255.255.0 192.168.65.2 删除路由 route delete 172.17.0.0