0、目錄
整體架構目錄:ASP.NET Core分布式項目實戰-目錄
一、前言
在寫這篇文章之前,我看了很多關於consul的服務治理,但發現基本上都是直接在powershell或者以命令工具的方式在伺服器上面直接輸入consul agent .... 來搭建啟動consul叢集,一旦把命令工具關掉,則consul無法再後台啟動,尤其是在linux系統中。
如果在window系統中,採用bat檔案到時可以做成開機自啟,或者在linux中把命令做成一個service 服務檔案來啟動就可以實現後台運行。
因此為了社區能更好的發展技術,且能把consul應用在生產環境中,我認真回顧了在公司項目中的應用,特此把我開發及總結的分享給大家,此篇文章採用docker引擎,並且只涉及到consul叢集部署以及結合asp.net core微服務註冊。
當然如果內容有涉及安全隱患的,大家可以積極留言,共同進步。
註:以下所涉及到部署過程全部經過樓主我反覆的驗證,總結得來。大家在應用的過程中如果出現問題,可以留言諮詢。
二、部署consul叢集
1、介紹一下Consul
consul 關鍵特性
服務發現:支援服務發現。你可以通過 DNS 或 HTTP 的方式擷取服務資訊。
健全狀態檢查:支援健全狀態檢查。可以提供與給定服務相關聯的任何數量的健全狀態檢查(如 web 狀態代碼或 cpu 使用率)。
K/V 儲存:鍵/值對儲存。你可用通過 consul 儲存如動態配置之類的相關資訊。
多資料中心:支援多資料中心,開箱即用。
WEB UI:支援 WEB UI。點點點,你就能夠瞭解你的服務現在的運行情況,一目瞭然,對開發營運是非常友好的。
說明:
在Consul方案中,每個提供服務的節點上都要部署和運行Consul的Client Agent,所有運行Consul Agent節點的集合構成Consul Cluster。
Consul Agent有兩種運行模式:Server和Client。這裡的Server和Client只是Consul叢集層面的區分,與搭建在Cluster之上的應用服務無關。以Server模式啟動並執行Consul Agent節點用於維護Consul叢集的狀態,官方建議每個Consul Cluster至少有3個或以上的運行在Server Mode的Agent,Client節點不限。
Consul支援多資料中心,每個資料中心的Consul Cluster都會在運行於Server模式下的Agent節點中選出一個Leader節點,這個選舉過程通過Consul實現的raft協議保證,多個 Server節點上的Consul資料資訊是強一致的。處於Client Mode的Consul Agent節點比較簡單,無狀態,僅僅負責將請求轉寄給Server Agent節點。
Consul與其他工具的比較
consul的連接埠解釋
好了,該介紹的已經介紹了,接下來就是正式部署吧
2、Docker上運行Consul第一步:安全配置,適用授權和資料加密傳輸(生產環境是必須的)
為了consul的安全,需要進行gossip加密以及RPC加密結合TLS。
Gossip加密:主要用於節點間的接收發送叢集資訊安全。
RPC加密:主要用於Agent之間調用RPC授權的安全性。
此處大家可以參考官網或者一下資料:
www.jianshu.com/p/3d074ed76a68
www.consul.io/docs/agent/encryption.html
第二步:consul叢集部署
準備伺服器(可以採用虛擬機器部署)
|
名稱 |
IP |
CentOS7-1 |
server1 |
192.168.216.160 |
CentOS7-2 |
server2 |
192.168.216.161 |
CentOS7-3 |
server3 |
192.168.216.162 |
CentOS7-4 |
client1 |
192.168.216.163 |
vs 2017 |
project部署在docker上 |
192.168.216.163 |
部署server1
docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name consulServer1 consul agent -server -bind=192.168.216.160 -node=server1 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui
部署server2
docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cs2 consul agent -server -bind=192.168.216.161 -node=server2 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui -retry-join=192.168.216.160
部署server3
docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cs3 consul agent -server -bind=192.168.216.162 -node=server3 -bootstrap-expect 3 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -ui -retry-join=192.168.216.160
部署client-串連server
docker run -d --net=host -v $PWD/data:/consul/data -v $PWD/config:/consul/config --restart always --name cc1 consul agent -bind=192.168.216.163 -node=client1 -data-dir=/consul/data -config-file=/consul/config -client 0.0.0.0 -retry-join=192.168.216.160
註:(針對以上的參數以及配置解釋)
1、此處的資料掛載就是把容器內的data以及配置掛載到外部地址,$PWD代表目前的目錄即你運行docker命令時的目錄,當然$PWD可以替換為具體的路徑。
2、-data-dir=/consul/consul -config-file=/consul/config :這兩個地方代表在consul啟動後會把資料以及設定檔放到指定的目錄下,這個對於在伺服器模式下啟動並執行代理尤其重要,因為它們必須能夠保持群集狀態。
3、總結,以上兩點結合就是說明 consul產生的資料然後掛載在外部地址進行持久化儲存。
4、server端 的-client 參數可以不用,官方推薦是 服務註冊到client端,由client端再把資料統一提交到server端。
參數說明
-client : 0.0.0.0 代表綁定到所有介面的選項,如果沒有此選項,則asp.net core無法進行服務註冊使用
-bind :該地址用來在叢集內部的通訊,叢集內的所有節點到地址都必須是可達的
--net=host 使得docker容器越過了net namespace的隔離,免去手動指定連接埠映射的步驟
-retry-join 允許你在第一次失敗後進行嘗試,加入一個已經啟動的agent的ip地址
-bootstrap-expect 提供的server節點數目
-ui 啟動自有主機的介面
-data-dir :提供一個目錄用來存放agent的狀態,所有的agent允許都需要該目錄,該目錄必須是穩定的,系統重啟後都繼續存在
CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}:在0.7版本之後預設是true,因此不是必須的。
CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}:在0.7版本之後預設是true,因此不是必須的。如果啟用,當代理收到TERM訊號時,它將向Leave群集的其餘部分發送訊息並正常離開
開啟瀏覽器器查看 consul :
看所有consul節點情況
docker exec -t cs1 consul members
查看server的狀態,以及哪一個節點是leader
docker exec -t cs1 consul operator raft list-peers
註:
如果其中一台或者多台server端掛掉,則Consul叢集就會重新選舉新的Leader,
但是一旦掛掉阿的節點數量超過一半,則Consul叢集就無法工作了。
三、asp.net core微服務進行服務註冊
1、建立一個項目asp.net core webapi項目
引入 consul ,nuget包
2、在控制器中建立一個控制器Health,代表健全狀態檢查
[Produces("application/json")] [Route("api/Health")] public class HealthController : Controller { [HttpGet] public IActionResult Get() => Ok("ok"); }
3、然後在appsetting.json中添加設定檔
需要手動設定一下地址和連接埠號碼。
{ "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } }, "ServiceRegister": { //服務註冊 "IsActive": true, "ServiceName": "testconsul6", "ServiceHost": "192.168.216.163", "ServicePort": 5006, "Register": { "HttpEndpoint": "http://192.168.216.163:8500" } }}
4、這一步是服務註冊的類
ServiceRegisterOptions.cs
public class ServiceRegisterOptions { /// <summary> /// 是否啟用 /// </summary> public bool IsActive { get; set; } /// <summary> /// 服務名稱 /// </summary> public string ServiceName { get; set; } /// <summary> /// 服務IP或者網域名稱 /// </summary> public string ServiceHost { get; set; } /// <summary> /// 服務連接埠號碼 /// </summary> public int ServicePort { get; set; } /// <summary> /// consul登入位址 /// </summary> public RegisterOptions Register { get; set; } }
RegisterOptions.cs
public class RegisterOptions { public string HttpEndpoint { get; set; } }
5、在startup.cs 中的服務註冊
public void ConfigureServices(IServiceCollection services) { #region 服務註冊基礎資訊配置 services.Configure<ServiceRegisterOptions>(Configuration.GetSection("ServiceRegister")); services.AddSingleton<IConsulClient>(p => new ConsulClient(cfg => { var serviceConfiguration = p.GetRequiredService<IOptions<ServiceRegisterOptions>>().Value; if (!string.IsNullOrEmpty(serviceConfiguration.Register.HttpEndpoint)) { cfg.Address = new Uri(serviceConfiguration.Register.HttpEndpoint); } })); #endregion services.AddMvc(); }
在Configure 方法中配置代碼
private static void RegisterService(IApplicationBuilder app, IOptions<ServiceRegisterOptions> serviceRegisterOptions, IConsulClient consul, IApplicationLifetime appLife) { var serviceId = $"{serviceRegisterOptions.Value.ServiceName}_{serviceRegisterOptions.Value.ServiceHost}:{serviceRegisterOptions.Value.ServicePort}"; var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動多久後註冊 Interval = TimeSpan.FromSeconds(30),//健全狀態檢查時間間隔,或者稱為心跳間隔 HTTP = $"http://{serviceRegisterOptions.Value.ServiceHost}:{serviceRegisterOptions.Value.ServicePort}/api/health",//健全狀態檢查地址 }; var registration = new AgentServiceRegistration() { Checks = new[] { httpCheck }, Address = serviceRegisterOptions.Value.ServiceHost, ID = serviceId, Name = serviceRegisterOptions.Value.ServiceName, Port = serviceRegisterOptions.Value.ServicePort //Tags = new[] { $"urlprefix-/{serviceRegisterOptions.Value.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 標籤,以便 Fabio 識別 }; //.GetAwaiter().GetResult() consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult(); appLife.ApplicationStopping.Register(() => { consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();//服務停止時取消註冊 }); } #endregion
自此,可以把我們的項目部署到163伺服器上面的docker上啦。
我們看一下效果,成功註冊到了
參考資料:
Conusl TLS配置:
www.jianshu.com/p/3d074ed76a68
www.consul.io/docs/agent/encryption.html
consul 參數配置:
79622476
consul服務治理:
http://michaco.net/blog/ServiceDiscoveryAndHealthChecksInAspNetCoreWithConsul
www.cnblogs.com/myzony/p/9168851.html
www.cnblogs.com/edisonchou/p/9124985.html
asp.net Core 交流群:787464275 歡迎加群交流
如果您認為這篇文章還不錯或者有所收穫,您可以點擊右下角的【推薦】按鈕精神支援,因為這種支援是我繼續寫作,分享的最大動力!
LouieGuo
聲明:原創部落格請在時保留原文連結或者在文章開頭加上本人部落格地址,如發現錯誤,歡迎批評指正。凡是於本人的文章,不能設定打賞功能,如有特殊需求請與本人聯絡!
公眾號:歡迎關注 QQ技術交流群: 歡迎加群