利用 Consul 服務註冊 API
Consul 除了如前篇文章所提的,用來儲存設定檔之外,最重要的功能就是負載平衡。而本篇文章將會介紹如何將 Web API 在啟動時向 Consul 註冊。
由於向 Consul 註冊 API 的參數相當複雜,這裡傾向使用第三方的 library,可以在 nuget 中搜尋 Consul,如以下畫面:
安裝後,在專案新增 ConsulInitExtension.cs 這支檔案,它是用來在網站啟動時對 Consul 做註冊。
public static class ConsulInitExtension
{
public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity)
{
var consulClient = new Consul.ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//請求註冊的 Consul 地址
var httpCheck = new Consul.AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //服務啟動多久後註冊
Interval = TimeSpan.FromSeconds(10), //health check 的間隔
HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}/api/Health", //url of health check
Timeout = TimeSpan.FromSeconds(5)
};
// register service with consul
var registration = new Consul.AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = serviceEntity.ServiceName,
Address = serviceEntity.IP,
Port = serviceEntity.Port,
// for Fabio
Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }
};
var registerResult = consulClient.Agent.ServiceRegister(registration);
registerResult.Wait();
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(registration.ID).Wait(); //服務停止時取消註冊
});
return app;
}
}
然後在 Startup.cs 新增下列程式碼:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
{
//...
// register service
string strHostName = Dns.GetHostName();
IPAddress[] ipaddresses = Dns.GetHostAddresses(strHostName);
ServiceEntity serviceEntity = new ServiceEntity
{
IP = ipaddresses[1].ToString(),
Port = Convert.ToInt32(Configuration["Service:Port"]),
ServiceName = Configuration["Service:Name"],
ConsulIP = Configuration["Consul:IP"],
ConsulPort = Convert.ToInt32(Configuration["Consul:Port"])
};
app.RegisterConsul(lifetime, serviceEntity);
}
前面的程式碼會讀取設定檔,而 appsettings.json 檔案的內容如下:
{
"AllowedHosts": "*",
"Service": {
"Name": "API.ConsulTestService",
"Port": "9000"
},
"Consul": {
"IP": "127.0.0.1",
"Port": "8500"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
之後將網站佈署到 IIS,測試時記得暫時關閉防火牆,以免 Consul 沒辦法做 health check。網站啟動後,到 Consul 頁面,可以看到以下成功的畫面:
要取得 API 位址時,可透過下列網址取得 json value:
http://[FQDN]]:8500/v1/catalog/service/[API Name]
json value 如下:
[
{
"ID": "3f95b2f2-85f9-8059-f77d-e0c308125790",
"Node": "1918da7ef151",
"Address": "172.17.0.2",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "172.17.0.2",
"wan": "172.17.0.2"
},
"NodeMeta": {
"consul-network-segment": ""
},
"ServiceKind": "",
"ServiceID": "62af3850-5d29-4110-90fe-3d29fcaf5b78",
"ServiceName": "API.ConsulTestService",
"ServiceTags": [
"urlprefix-/API.ConsulTestService"
],
"ServiceAddress": "192.168.50.41",
"ServiceWeights": {
"Passing": 1,
"Warning": 1
},
"ServiceMeta": {},
"ServicePort": 9000,
"ServiceEnableTagOverride": false,
"ServiceProxyDestination": "",
"ServiceProxy": {},
"ServiceConnect": {},
"CreateIndex": 182330,
"ModifyIndex": 182330
}
]
從裡面的 ServiceAddress 跟 ServicePort 就可以抓到 API 的位址。
參考資料