我用的是Win 10的系统,但是安装了Docker Desktop,
然后用powershell进行docker的相关操作。
PS C:\Users\Zhanwei> docker pull consul
Using default tag: latest
latest: Pulling from library/consul
31603596830f: Pull complete
e424a2a1e4f7: Pull complete
2472846eab82: Pull complete
24473b564e4a: Pull complete
b3caf5938c68: Pull complete
b6f50757bb0c: Pull complete
Digest: sha256:1cb6f7247472638c470c1bcf059a1f74a4d54c6b49c57c80651feb08cc0a80cf
Status: Downloaded newer image for consul:latest
docker.io/library/consul:latest
PS C:\Users\Zhanwei>
PS C:\Users\Zhanwei> docker run -d -p 8500:8500 -v /data/consul:/consul/data -e CONSUL\_BIND\_INTERFACE='eth0' --name=consul\_server\_1 consul:latest agent -server -bootstrap -ui -node=node-1 -client='0.0.0.0' -datacenter=hangzhou
9d5e1c54ee6e44efc100e5a6fdf4e4f22ad2a177e0f0d937e54bb9b245e657cd
**参数说明:**
打开浏览器,如下所示,IP换成自己的IP
这样单机版的Consul就启动完成了,接下来我们新建个API服务。
PM>Install-Package Consul -Version 0.7.2.6
如果是主动退出服务,会执行取消注册的方法,好处是比心跳响应更快,但是心跳也是必不可少的,因为在微服务中,各种网络原因都有可能导致服务异常中断。
我这里是封装了一个方法来注册,代码如下所示:
public static void RegisterConsul(this IApplicationBuilder app,IApplicationLifetime lifetime, ServiceEntity serviceEntity)
{
var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔
HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}/api/health",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)
};
// Register service with consul
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = serviceEntity.ServiceName,
Address = serviceEntity.IP,
Port = serviceEntity.Port,
Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别
};
consulClient.Agent.ServiceRegister(registration).Wait();
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册
});
}
ID:正常环境中最好不要用guid,因为每次启动id都不一样,正常来讲没啥问题,但是快速启动时就会有个坑了。建议用,这样也是唯一的,并且不会重复。
ID=$"{serviceEntity.ServiceName}\_{serviceEntity.IP}\_{serviceEntity.Port}"
我想在用dotnet运行项目时,能够传入url,ip和port,所以在这里加了命令行参数。
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(build =>
{
build.AddCommandLine(args);//启动时可读取命令行参数
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Microsoft.AspNetCore.Hosting.IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//获取环境变量
var ip = Configuration.GetValue(typeof(String), "IP");
var port = Configuration.GetValue(typeof(String), "Port");
ServiceEntity serviceEntity = new ServiceEntity
{
IP = ip.ToString(),
Port = Convert.ToInt32(port),
ServiceName = Configuration["Service:Name"],
ConsulIP = Configuration["Consul:IP"],
ConsulPort = Convert.ToInt32(Configuration["Consul:Port"])
};
app.RegisterConsul(lifetime, serviceEntity);
}
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
// GET: api/Default
[HttpGet]
public ResultInfo Get()
{
ResultInfo result = new ResultInfo();
result.Code = 200;
result.CreateTime = DateTime.Now;
result.Message = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}";
result.Data = new {
name="zhanwei",
server="Api01"
};
return result;
}
}
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "result", "ok" };
}
}
public class ServiceEntity
{
public string IP { get; set; }
public int Port { get; set; }
public string ServiceName { get; set; }
public string ConsulIP { get; set; }
public int ConsulPort { get; set; }
}
"Service": {
"Name": "Api01"//注册到Consul中显示的服务名称
},
"Consul": {
"IP": "192.168.10.134",//改成实际Consul地址
"Port": "8500"//Consul的端口
}
dotnet CustomMiddleware.api01.dll --urls="http://\*:5001/" --ip="192.168.10.134" --port="5001"
我们可以看到分别访问两个接口都是能正常返回的,这两个接口后面介绍网关负载均衡的时候还会用到,可以从返回的信息里区别是从哪个实例返回的。
重复的过程就不再赘述了,我只是修改了下接口的路径,还有服务名称。
现在就完成了服务的自动注册功能,其实光注册进去是没什么作用的,这只是为后续做准备而已,后面我会利用Ocelot组件做一个简单的网关,网关又是什么?
总之后面很精彩,这才刚起步而已。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。