關於consul
的介紹就不寫了百度就行,我們直接開幹。
拉取consul的映象
docker pull consul
然後部署consul容器
docker run --name consul1 -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600 consul:latest agent -server -bootstrap-expect 2 -ui -bind='0.0.0.0' -client='0.0.0.0'
8500 http
埠,用於 http
介面和 web ui
8300 server rpc
埠,同一資料中心 consul server
之間通過該埠通訊8301 serf lan
埠,同一資料中心 consul client
通過該埠通訊8302 serf wan
埠,不同資料中心 consul server
通過該埠通訊8600 dns
埠,用於服務發現
-bbostrap-expect 2
: 叢集至少兩臺伺服器,才能選舉叢集leader
-ui
:執行 web
控制檯-bind
: 監聽網口,0.0.0.0
表示所有網口,如果不指定預設為127.0.0.1
,則無法和容器通訊-client
: 限制某些網口可以存取
-server
:表示該節點是server
節點,不宣告的話預設為client
節點,它們的不同是server
節點持久化資訊,但是client
不持久化會轉發給server
節點,並且server
節點會有leader
節點進行健康檢測和同步資訊到其他server
節點
然後我們獲取該consul1
容器的ip
,使用如下語句
docker inspect --format '{{ .NetworkSettings.IPAddress }}' consul1
獲取到了172.17.0.5
然後我們再新建另一個consul
容器,使用join
來加入第一個consul1
容器的叢集
docker run --name consul2 -d -p 18500:8500 -p 18300:8300 -p 18301:8301 -p 18302:8302 -p 18600:8600 consul:latest agent -server -ui -bind='0.0.0.0' -client='0.0.0.0' -join 172.17.0.5
我就建兩個節點能執行即可,server
一般建3-5
個,client
沒有上限,所以根據上面的語句自己建立即可。
然後我們存取地址http://localhost:8500/
可以進到控制介面。
為測試方便我們使用-dev
引數允許啟動一個Consul
服務。
docker run --name consul1 -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600 consul:latest agent -server -ui -bind='0.0.0.0' -client='0.0.0.0' -dev
我們新建一個專案,然後下載Consul包
Install-Package
Consul
然後我們新增一個健康檢查的介面
[Route("[controller]/[action]")] [ApiController] public class HealthController : Controller { [HttpGet("/healthCheck")] public IActionResult Check() => Ok("ok"); }
之後我們在appsetting.json
中設定我們的Consul
引數,這些引數我們用來註冊服務的一些資訊,引數解釋如下:
ServiceName
:是服務的名稱,同一個服務名的服務將會註冊到同一個服務下的範例
ServiceIP
:服務請求的主機地址
ServicePort
:服務請求的埠
ServiceHealthCheck
:服務健康檢測介面地址,此處是host.docker.internal
是因為Consul
在容器內需要存取宿主主機執行的服務
Address
:Consul
服務的請求地址
"Consul": { "ServiceName": "service-a", "ServiceIP": "127.0.0.1", "ServicePort": 5001, "ServiceHealthCheck": "http://host.docker.internal:5001/healthCheck", "Address": "http://127.0.0.1:8500" }
之後我們建立一個類名叫ConsulOption
,用於使用過Option
模式載入appsetting.json
中我們設定的引數,用於註冊
public class ConsulOption { /// <summary> /// 服務名稱 /// </summary> public string ServiceName { get; set; } /// <summary> /// 服務IP /// </summary> public string ServiceIP { get; set; } /// <summary> /// 伺服器埠 /// </summary> public int ServicePort { get; set; } /// <summary> /// 服務健康檢查地址 /// </summary> public string ServiceHealthCheck { get; set; } /// <summary> /// Consul 地址 /// </summary> public string Address { get; set; } }
然後建立一個Consul
服務註冊類ConsulBuilderExtensions
,對將本服務推播到Consul
中去,具體的引數解釋在程式碼註釋中了
public static class ConsulBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ConsulOption consulOption) { var consulClient = new ConsulClient(x => { x.Address = new Uri(consulOption.Address); }); var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(), Name = consulOption.ServiceName,// 服務名 Address = consulOption.ServiceIP, // 服務繫結IP Port = consulOption.ServicePort, // 服務繫結埠 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動多久後註冊 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔 HTTP = consulOption.ServiceHealthCheck,//健康檢查地址 Timeout = TimeSpan.FromSeconds(5) } }; // 服務註冊 consulClient.Agent.ServiceRegister(registration).Wait(); // 應用程式終止時,服務取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } }
最後我們注入本服務
builder.Services.AddSingleton(builder.Configuration.GetSection("Consul").Get<ConsulOption>()); //.... app.RegisterConsul(app.Lifetime, app.Services.GetRequiredService<ConsulOption>());
啟動專案就能看到服務已經註冊
Consul提供了http api可以讓我們進行查詢、註冊、接觸註冊等操作
http://127.0.0.1:8500/v1/health/service/service-a?passing
我們新建一個專案然後安裝包
Install-Package Ocelot.Provider.Consul
然後註冊服務
builder.Services.AddOcelot().AddPolly().AddConsul();
之後在組態檔中的GlobalConfiguration
節點下新增如下引數,這是必須的如果沒有指定主機Host
和埠Port
將會使用Consul
預設的,Scheme
預設為http
,Type
說明此服務發現由Consul
提供
"ServiceDiscoveryProvider": { "Scheme": "http", "Host": "localhost", "Port": 8500, "Type": "Consul" }
然後我們設定路由,新增我們剛註冊的服務,最好是配合負載均衡引數咯,我這裡沒寫
"Routes": [ { "DownstreamPathTemplate": "/{everything}", "DownstreamScheme": "http", "ServiceName": "service-a", "UpstreamPathTemplate": "/api/{everything}", "UpstreamHttpMethod": [ "Get", "Post" ] }
然後執行就可以看到結果了,需要注意的是請求是http
還是https
這些需要注意,我就卡在了這裡很久,請求路徑需要注意噢
最後,Ocelot
是每次請求都去Consul
獲取最新的服務,如果需要設定間隔多久去獲取Consul
的最新服務(可能會有微小的效能改進,但是不知道原有服務是否可用,可能會有錯誤的返回噢)可以如下設定:
"ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "PollConsul", "PollingInterval": 100 }