网上一大堆Consul集群的文章,但是就是没有一篇完整的从Consul集群到微服务集群的文章,那么今天,我经过踩了无数个坑,终于写了这个“从头到尾”的文章,详细介绍,如果从Consul集群到和微服务集群搭建起来并且能运行的整个过程。
1.创建网络
docker network create --driver bridge --subnet 172.19.0.0/16 --gateway 172.19.0.1 kafkanet
2.Consul 集群部署的docker-compose.yml的文件内容
version: '3.6'
networks:
kafkanet:
external: true
services:
consul1:
image: consul:latest
container_name: consul1
restart: always
ports:
- 8501:8500
command: agent -server -bind=172.19.0.3 -client=0.0.0.0 -bootstrap-expect=3 -node=consul1
volumes:
- /root/consulGroup/consul1/data:/consul/data
- /root/consulGroup/consul1/config:/consul/config
networks:
kafkanet:
consul2:
image: consul:latest
container_name: consul2
restart: always
ports:
- 8502:8500
command: agent -server -bind=172.19.0.4 -client=0.0.0.0 -retry-join=consul1 -node=consul2
volumes:
- /root/consulGroup/consul2/data:/consul/data
- /root/consulGroup/consul2/config:/consul/config
networks:
kafkanet:
consul3:
image: consul:latest
container_name: consul3
restart: always
ports:
- 8503:8500
command: agent -server -bind=172.19.0.5 -client=0.0.0.0 -retry-join=consul1 -node=consul3
volumes:
- /root/consulGroup/consul3/data:/consul/data
- /root/consulGroup/consul3/config:/consul/config
networks:
kafkanet:
consul4:
image: consul:latest
container_name: consul4
restart: always
ports:
- 8500:8500
command: agent -bind=172.19.0.2 -client=0.0.0.0 -retry-join=consul1 -ui -node=client1
volumes:
- /root/consulGroup/consul4/data:/consul/data
- /root/consulGroup/consul4/config:/consul/config
networks:
kafkanet:
3.使用docker文件制作镜像
命令:docker build -t webappconsuljiqunimg
VS生成的Docker文件内容简化如下面这样,注意,这个是自己发布的,不是把整个项目拷贝过去
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "WebAppConsulJiQun.dll"]
4.微服务的docker-compose.yml文件内容(注意这里使用的是基于3创建的镜像):
version: '3.3'
networks:
kafkanet:
external: true
services:
service1:
image: webappconsuljiqunimg
networks:
kafkanet:
ipv4_address: 172.19.0.67
ports:
- 1501:80/tcp
command: ["dotnet", "/app/WebAppConsulJiQun"]
volumes:
- /root/webUseConsul/appsettings1501.json:/app/appsettings.json
service2:
image: webappconsuljiqunimg
networks:
kafkanet:
ipv4_address: 172.19.0.68
ports:
- 1502:80/tcp
command: ["dotnet", "/app/WebAppConsulJiQun"]
volumes:
- /root/webUseConsul/appsettings1502.json:/app/appsettings.json
service3:
image: webappconsuljiqunimg
networks:
kafkanet:
ipv4_address: 172.19.0.69
ports:
- 1503:80/tcp
command: ["dotnet", "/app/WebAppConsulJiQun"]
volumes:
- /root/webUseConsul/appsettings1503.json:/app/appsettings.json
5.基于4创建的3个微服务挂载的文件内容(微服务和Consul的注册配置就在这,一定要注意这里的IP配置和Consul地址的配置)(特别注意:ConsulAddress节点,可以是其他的Consul节点的IP,但,一定要记住,端口必须是8500)
另外:ip和port,要写成外网地址,因为后面服务发现时,要拿 的就是这个地址,如果你写成内网的,那么 你的服务怎么调用 ?
第一个文件appsettings1501.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ip": "172.19.0.67",
"port": 80,
"weight": 1,
"ConsulAddress": "http://172.19.0.2:8500/",
"ConsulCenter": "dc1"
}
第二个文件appsettings1502.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ip": "172.19.0.68",
"port": 80,
"weight": 2,
"ConsulAddress": "http://172.19.0.2:8500/",
"ConsulCenter": "dc1"
}
第三个文件appsettings1503.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ip": "172.19.0.69",
"port": 80,
"weight": 3,
"ConsulAddress": "http://172.19.0.2:8500/",
"ConsulCenter": "dc1"
}
6.注册服务的代码:
自己声名一个类:
public static class RegistService
{
public static void RegistMicService(this IConfiguration configuration)
{
try
{
string ip = configuration["ip"];
int port = int.Parse(configuration["port"]);
int weight = string.IsNullOrWhiteSpace(configuration["weight"]) ? 1 : int.Parse(configuration["weight"]);
using (ConsulClient client = new ConsulClient(c =>
{
c.Address = new Uri(configuration["ConsulAddress"]);
c.Datacenter = configuration["ConsulCenter"];
}))
{
try
{
client.Agent.ServiceRegister(new AgentServiceRegistration()
{
ID = "service " + ip + ":" + port,//Eleven 独一无二
Name = "consul",//分组---朝夕教育的老师
Address = ip,
Port = port,
Tags = new string[] { weight.ToString() },
Check = new AgentServiceCheck()
{
Interval = TimeSpan.FromSeconds(12),
HTTP = $"http://{ip}:{port}/home/helth",
Timeout = TimeSpan.FromSeconds(5),
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20)
}
}).Wait();
}
catch (Exception ex22)
{
Console.WriteLine(ex22.Message);
}
//命令行参数获取
Console.WriteLine($"服务地址:{ip}:{port}--weight:{weight},注册到的Consul服务器是{configuration["ConsulAddress"]}");
//client.KV.del
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
在Startup文件里的Configure调用 这个扩展方法
this.Configuration.RegistMicService();
最终 完成。。注意,看到这篇文章的小伙伴们,第一执行我上面的代码 的时候,千万不要修改里面的任何一个文字,否则,有可能会失败,要千万注意!!!
7.获取节点
/// <summary>
/// 获取Consul配置的真正的服务地址
/// </summary>
/// <returns></returns>
public string Index()
{
string serviceName = GetService();
string url = serviceName + "/home/datas";
return url;
}
/// <summary>
/// 根据Consul随机获取地址
/// </summary>
/// <returns></returns>
private string GetService()
{
var config = new ConsulClientConfiguration()
{
Address = new Uri("http://47.95.221.215:8500/"),
Datacenter = "dc1",
};
string url = "";
using (ConsulClient client = new ConsulClient(config))
{
var dic = client.Agent.Services().Result.Response;//这里也只能拿到 在 上面的 new Uri("http://47.95.221.215:8500/") 注册的节点,当然这里也在在一个问题,如果节点都注册到这个端上,那么如果这个端挂了,和这个端相关的微服务就全部找不到了
//所以,其实这块可以扩展从多个Consul端去获取服务地址,这个代码很简单,基本上就是把现在的代码复制几份改一下就行了
Random num = new Random();
var index = num.Next(0, dic.Keys.Count);
var keys = dic.Keys.Select(k => k).ToList();
var agent = dic[keys[index]];
url = "http://" + agent.Address + ":" + agent.Port;
}
return url;
}
7.1 从多个端获取服务地址
/// <summary>
/// 根据Consul随机获取地址
/// </summary>
/// <returns></returns>
private string GetService()
{
Dictionary<string, AgentService> dic = new Dictionary<string, AgentService>();
{
var config = new ConsulClientConfiguration()
{
Address = new Uri("http://47.95.221.215:8500/"),
Datacenter = "dc1",
};
using (ConsulClient client = new ConsulClient(config))
{
dic = client.Agent.Services().Result.Response;//这里也只能拿到 在 上面的 new Uri("http://47.95.221.215:8500/") 注册的节点
}
}
{
var config = new ConsulClientConfiguration()
{
Address = new Uri("http://47.95.221.215:8501/"),
Datacenter = "dc1",
};
using (ConsulClient client = new ConsulClient(config))
{
var dic1 = client.Agent.Services().Result.Response;//这里也只能拿到 在 上面的 new Uri("http://47.95.221.215:8500/") 注册的节点
foreach (var item in dic1)
{
dic.Add(item.Key, item.Value);
}
}
}
{
var config = new ConsulClientConfiguration()
{
Address = new Uri("http://47.95.221.215:8502/"),
Datacenter = "dc1",
};
using (ConsulClient client = new ConsulClient(config))
{
var dic1 = client.Agent.Services().Result.Response;//这里也只能拿到 在 上面的 new Uri("http://47.95.221.215:8500/") 注册的节点
foreach (var item in dic1)
{
dic.Add(item.Key, item.Value);
}
}
}
{
var config = new ConsulClientConfiguration()
{
Address = new Uri("http://47.95.221.215:8503/"),
Datacenter = "dc1",
};
using (ConsulClient client = new ConsulClient(config))
{
var dic1 = client.Agent.Services().Result.Response;//这里也只能拿到 在 上面的 new Uri("http://47.95.221.215:8500/") 注册的节点
foreach (var item in dic1)
{
dic.Add(item.Key, item.Value);
}
}
}
string url = "";
Random num = new Random();
var index = num.Next(0, dic.Keys.Count);
var keys = dic.Keys.Select(k => k).ToList();
var agent = dic[keys[index]];
url = "http://" + agent.Address + ":" + agent.Port;
return url;
}