基于内网穿透下的go语言consul注册中心对远程GRPC和HTTP服务进行健康检查

基于内网穿透下的go语言consul注册中心对远程GRPC和HTTP服务进行健康检查,第1张

问题背景

目的:实现consul服务注册、健康检查、服务发现等功能

实际环境: 在云服务器的docker中安装consul组件,并配置好docker与linux的端口映射在localhost本地有两种服务:基于 ginHTTP服务和基于gprc微服务
问题

本地可以发出注册请求,但是在consuleUI界面中显示健康检查失败

问题一

因为家庭网络是内网,云服务器无法根据本地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。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/994838.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存