实际环境: 在云服务器的docker中安装consul组件,并配置好docker与linux的端口映射在目的:实现consul服务注册、健康检查、服务发现等功能
localhost
本地有两种服务:基于 gin
的HTTP
服务和基于gprc
的微服务问题
问题一本地可以发出注册请求,但是在
consule
UI界面中显示健康检查失败
因为家庭网络是内网,云服务器无法根据本地IP访问
解决方案:
用ngrok
实现内网穿透
version: "2"
authtoken: 27sAzowEvjTnza9rriOfHcYKMpb_4xEo68z822vLAMZBqtqtu
tunnels:
web-user:
proto: http
addr: 192.168.0.103:2222
srv-user:
proto: tcp
addr: 192.168.0.103:3333
问题二
consul注册ngrok提供的外网IP和端口号,仍然无法访问
解决方案:
网络穿透协议定义需要正确,在http服务中监听的协议采用http,因此在ngrok
中需要配置http协议;而在grpc微服务中监听的协议采用tcp,因此在ngrok
中需要配置tcp协议,如果协议不一致,会导致域名访问失败。
ngrok
tcp 协议映射的ip为grpc
微服务的ip地址,端口为3333
http 协议映射的ip为HTTP
服务的ip地址,端口为2222
http服务
func Register(address string, port int, name string, tags []string, id string) error {
cfg := api.DefaultConfig()
cfg.Address = fmt.Sprintf("%s:%d",
global.ServerConfig.ConsulInfo.Host,
global.ServerConfig.ConsulInfo.Port) // consul服务地址
client, err := api.NewClient(cfg)
if err != nil {
panic(err)
}
// 生成注册对象
registration := new(api.AgentServiceRegistration)
//生成对应的检查对象
check := &api.AgentServiceCheck{
// PS: 注意一定要按照该格式,即使将https换成http也会出错
HTTP: fmt.Sprintf("https://%s:%d/u/v1/base/health", address, port), // 健康检查服务的通信地址,
Timeout: "5s",
Interval: "5s",
DeregisterCriticalServiceAfter: "10s",
}
registration.Name = name
registration.Port = port
registration.Tags = tags
registration.ID = id
registration.Address = address
registration.Check = check
err = client.Agent().ServiceRegister(registration)
if err != nil {
panic(err)
}
return nil
}
调用
// 注意切忌把https://传递到函数中
Register("4075-113-245-36-120.jp.ngrok.io","web", []string{"xxx", "xxxx", "xxxx"}, "web")
health服务路由
// 注意一定要自己实现路由函数,自定义的注册路径是/u/v1/base/health,否则健康检查结果会得到404 no page
func HealthCheck(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"msg": "服务健康检查通过",
})
}
grpc
服务
func Register(address string, port int, name string, tags []string, id string) error {
cfg := api.DefaultConfig()
cfg.Address = fmt.Sprintf("%s:%d",
global.ServerConfig.ConsulInfo.Host,
global.ServerConfig.ConsulInfo.Port) // consul服务地址
client, err := api.NewClient(cfg)
if err != nil {
panic(err)
}
// 生成注册对象
registration := new(api.AgentServiceRegistration)
//生成对应的检查对象
check := &api.AgentServiceCheck{
// PS 必须按照该格式,不可加前缀https:// 或者tcp:// 也不能加后缀路径,除非自己实现health接口
GRPC: fmt.Sprintf("%s:%d", address, port), // 健康检查的服务的通信地址,
Timeout: "5s",
Interval: "5s",
DeregisterCriticalServiceAfter: "10s",
}
registration.Name = name
registration.Port = port
registration.Tags = tags
registration.ID = id
registration.Address = address
registration.Check = check
err = client.Agent().ServiceRegister(registration)
if err != nil {
panic(err)
}
return nil
}
调用
// PS 注意不要将tcp://前缀传入
Register("0.tcp.jp.ngrok.io","web", []string{"xxx", "xxxx", "xxxx"}, "grpc")
结论
经过多次尝试和排查,得出以下结论:
域名和端口格式一定要写正确,在HTTP协议中需要加上前缀http:// 或https://,因映射地址而异,在本映射地址中必须采用https://前缀协议,可以通过curl
命令测试映射外网域名是否可用,注意如果在curl中对https://前缀域名使用http://的前缀会得到permanent redirect
,查看consul官方doc可以发现该response仍然被定义为健康检查失败的。内网穿透的协议必须与服务特性保持一致,即HTTP服务需用HTTP协议,GRPC服务需用TCP协议,当然需要根据自己的代码灵活变动。在这里主要是强调一致性
。HTTP服务中需要自定义好/heath检查的路由控制函数,否则得到404 no page
的response。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)