Ocelot + Consul + Registrator 基於Docker 實現服務發現、服務自動注冊


關於這個工具的介紹這里就不多說了,網上、官網都很詳細,這里直接記錄一下搭建過程。另外最后有幾個疑惑還未解決,希望各位前輩答疑解惑。

1. Consul集群搭建

我們基於Docker搭建三個Server和兩個Client的DC。

  • server1
docker run -d --name server1 consul agent -server -node=server1 -bootstrap-expect=3
# 獲取server1IP地址,方便后續節點接入集群
JOIN_IP="$(sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' server1)"
  • server2
docker run -d --name server2 consul agent -server -node=server2 -join $JOIN_IP
  • server3
docker run -d --name server3 consul agent -server -node=server3 -join $JOIN_IP
  • client1
docker run -d --name client1 consul agent -node=client1 -join $JOIN_IP
  • client2
docker run -d --name client2 -p 8400:8400 -p 8500:8500 -p 8600:53/udp  consul agent -ui -node=client2 -client=0.0.0.0 -join $JOIN_IP

運行效果:

Consul集群.png

1.1 F&Q

Consul官方推薦的host網絡模式運行

查看Consul官方文檔,官方推薦Consul以Docker的host網絡模式運行。但是這樣的話,一個Docker寄宿主機只運行一個consul agent?生產中的Docker集群是如何搭建的?

2. Registrator服務注冊工具

啟動Registrator工具容器,Registrator使用主機網絡模式,使用-internal選項,注冊基於expose端口的服務。

docker run -d --name registrator --net host --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator -internal consul://172.17.0.6:8500

Consul管理UI服務截圖,Registrator會把Consul也作為服務注冊到Consul。這也是可以理解的,因為Registrator的觀點是任何監聽在端口的程序都是服務。

Registrator注冊服務.png

2.1 F&Q

Registrator懸掛服務

正常情況下,這里應該是沒有clientservice的,但是由於我之前測試沒有正常按順序啟停容器,形成了懸掛服務,一直沒有清除。我看Registrator文檔中有-cleanup選項可以清理懸掛服務,后續嘗試一下。

Registrator的-internal選項

不指定這個選項時,Registrator使用容器的發布端口(映射到寄宿主機的端口)自動注冊服務,這時候一般要用-ip選項指定主機的IP地址,因為Registrator一般很難推斷出主機的IP地址。當使用-internal選項時,Registrator使用服務所在容器分配的內部地址自動注冊服務。

3. clientservice服務Demo

clientservice是一個web api項目,由於是自動服務發現和注冊,因此clientservice跟無需做特別的配置。
我僅僅指定服務的端口為5000,修改了ValueController,返回服務調用情況。

3.1 Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://*:5000")
                .UseStartup<Startup>();
    }

3.2 ValuesController.cs

...
[HttpGet]
        public ActionResult<RequestInfo> Get()
        {
            var clientHost = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            var serverHost = HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString();
            var path = HttpContext.Request.Path;
            return new RequestInfo{
                RemoteIp = clientHost,
                RemotePort = HttpContext.Connection.RemotePort,
                LocalIp = serverHost,
                LocalPort = HttpContext.Connection.LocalPort,
                Path = path,
                Host = HttpContext.Request.Host.ToUriComponent()
            };
        }
...

3.3 Dockerfile

#基於microsoft/dotnet:latest構建Docker image
FROM microsoft/dotnet:latest

#進入docker中的/usr/local/src目錄,創建DockerWebAPI目錄
RUN cd /usr/local/src&&mkdir DockerWebAPI

#設置工作路徑
WORKDIR /usr/local/src/DockerWebAPI

#將當前文件夾下的所有文件全部復制到工作目錄
COPY ./ ./

#向外界暴露5000端口
EXPOSE 5000

#執行dotnet *.dll命令
CMD ["dotnet","clientservice.dll"]

3.4 制作鏡像並啟動容器

  • 制作鏡像
docker build -t zhangdk/clientservice .
  • 啟動容器
docker run -d zhangdk/clientservice

Consul管理UI截圖,如果你是第一次搭建集群並啟動Clientservice的話,后面應該有小標1。我這里由於懸掛服務的問題,有啟動前的1現在變成了2。

啟動ClientService.png

clientservice注冊信息(多余的是懸掛服務的注冊信息),要注意查看ServiceAddress和ServicePort是否正確:

clientservice注冊信息.png

4. Ocelot網關Demo

VS Code創建空web項目dotnet new web,安裝ocelot庫dot add package ocelot,主要修改三個文件:

4.1 Program.cs:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls("http://*:5010")  //服務監聽在5010端口,后期可以調整為從外部讀取,方便配置
                .ConfigureAppConfiguration((context,builder)=>{
                    builder.AddJsonFile("configuration.json",false,true); //讀取Ocelot配置文件
                });
    }

4.2 Startup.cs:

public class Startup
    {
        public Startup(IConfiguration configuration){
            Configuration = configuration;
        }

        public IConfiguration Configuration{get;set;}
        
        public void ConfigureServices(IServiceCollection services) => services.AddOcelot(Configuration); //注冊Ocelot服務

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseOcelot().Wait();   //啟用Ocelot中間件
        }
    }

4.3 添加配置文件configuration.json:

{
    "ReRoutes": [
      {
        "UseServiceDiscovery": true,  //啟用服務發現
        "DownstreamPathTemplate": "/api/{url}",
        "DownstreamScheme": "http",
        "ServiceName": "clientservice",
        "LoadBalancerOptions": {
          "Type": "RoundRobin"
        },
        "UpstreamPathTemplate": "/api/clientservice/{url}",
        "UpstreamHttpMethod": [ "Get", "Post" ],
        "ReRoutesCaseSensitive": false
      }
    ],
    "GlobalConfiguration": {
      "ServiceDiscoveryProvider": {
        "Host": "172.17.0.6",  //Consul client IP
        "Port": 8500  //Consul HTTP API端口
      }
    }
  }

4.4 Dockerfile文件編寫

#基於microsoft/dotnet:latest構建Docker image
FROM microsoft/dotnet:latest

#進入docker中的/usr/local/src目錄,創建DockerWebAPI目錄
RUN cd /usr/local/src&&mkdir DockerWebAPI

#設置工作路徑
WORKDIR /usr/local/src/DockerWebAPI

#將當前文件夾下的所有文件全部復制到工作目錄
COPY ./ ./

#向外界暴露5010端口
EXPOSE 5010

#執行dotnet *.dll命令
CMD ["dotnet","oceletgateway.dll"]

4.5 發布項目,制作鏡像,並啟動容器

  • 發布項目
dotnet publish
  • 拷貝Dockfile到Demo的publish文件夾,打開終端
docker build -t zhangdk/ocelotgateway .
  • 運行OcelotGateway服務容器
docker run -d --name=ocelotgateway zhangdk/ocelotgateway

通過Ocelot網關服務訪問clientservice

Ocelot網關訪問服務.png

直接訪問clientservice

Clientservice直接訪問.png

4.6 F&Q

Ocelot服務發現地址怎么配置

剛開始的我以為應該配置Leader server的地址,但是由於leader server的端口並沒有暴露,因此容器間無法訪問。嘗試使用client的地址,發現也是可以成功的。

Ocelot的服務發現地址配置

Consul在集群模式運行時,單個server或者client agent節點掛掉后仍然可以通過投票等協議正常運行。但是,Ocelot網關服務中配置了唯一的一個agent地址,那豈不是意味着這個節點掛掉后,Ocelot網關服務就和Consul集群的服務發現就失去了聯系,那這里的Consul集群有什么意義?

5 總結

初步按照自己的思路搭建起來的服務發現,自動注冊的架構,后續會繼續完善權限驗證、負載均衡等網關的其他功能。搭建的過程中也有許多困惑還沒有想明白,后續邊想邊做。微服務這一塊也是剛剛接觸,有什么問題或錯誤,還希望各位前輩指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM